Fixed a couple of warnings from gcc2.
[unix-history] / sys / net / if.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1980, 1986 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)if.c 7.14 (Berkeley) 4/20/91
34 */
35
36#include "param.h"
37#include "mbuf.h"
38#include "systm.h"
39#include "socket.h"
40#include "socketvar.h"
41#include "protosw.h"
42#include "proc.h"
43#include "kernel.h"
44#include "ioctl.h"
45
46#include "if.h"
47#include "af.h"
48#include "if_dl.h"
49#include "if_types.h"
50
51#include "ether.h"
52
53int ifqmaxlen = IFQ_MAXLEN;
54
55/*
56 * Network interface utility routines.
57 *
58 * Routines with ifa_ifwith* names take sockaddr *'s as
59 * parameters.
60 */
61
62ifinit()
63{
64 register struct ifnet *ifp;
65
66 for (ifp = ifnet; ifp; ifp = ifp->if_next)
67 if (ifp->if_snd.ifq_maxlen == 0)
68 ifp->if_snd.ifq_maxlen = ifqmaxlen;
69 if_slowtimo();
70}
71
72#ifdef vax
73/*
74 * Call each interface on a Unibus reset.
75 */
76ifubareset(uban)
77 int uban;
78{
79 register struct ifnet *ifp;
80
81 for (ifp = ifnet; ifp; ifp = ifp->if_next)
82 if (ifp->if_reset)
83 (*ifp->if_reset)(ifp->if_unit, uban);
84}
85#endif
86
87int if_index = 0;
88struct ifaddr **ifnet_addrs;
89static char *sprint_d();
90
91/*
92 * Attach an interface to the
93 * list of "active" interfaces.
94 */
95if_attach(ifp)
96 struct ifnet *ifp;
97{
98 unsigned socksize, ifasize;
99 int namelen, unitlen;
100 char workbuf[12], *unitname;
101 register struct ifnet **p = &ifnet;
102 register struct sockaddr_dl *sdl;
103 register struct ifaddr *ifa;
104 static int if_indexlim = 8;
105 extern link_rtrequest(), ether_output();
106
107 while (*p)
108 p = &((*p)->if_next);
109 *p = ifp;
110 ifp->if_index = ++if_index;
111 if (ifnet_addrs == 0 || if_index >= if_indexlim) {
112 unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
113 struct ifaddr **q = (struct ifaddr **)
114 malloc(n, M_IFADDR, M_WAITOK);
115 if (ifnet_addrs) {
116 bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
117 free((caddr_t)ifnet_addrs, M_IFADDR);
118 }
119 ifnet_addrs = q;
120 }
121 /* XXX -- Temporary fix before changing 10 ethernet drivers */
122 if (ifp->if_output == ether_output) {
123 ifp->if_type = IFT_ETHER;
124 ifp->if_addrlen = 6;
125 ifp->if_hdrlen = 14;
126 }
127 /*
128 * create a Link Level name for this device
129 */
130 unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
131 namelen = strlen(ifp->if_name);
132 unitlen = strlen(unitname);
133#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
134 socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
135 unitlen + namelen + ifp->if_addrlen;
136#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
137 socksize = ROUNDUP(socksize);
138 if (socksize < sizeof(*sdl))
139 socksize = sizeof(*sdl);
140 ifasize = sizeof(*ifa) + 2 * socksize;
141 ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
142 if (ifa == 0)
143 return;
144 ifnet_addrs[if_index - 1] = ifa;
145 bzero((caddr_t)ifa, ifasize);
146 sdl = (struct sockaddr_dl *)(ifa + 1);
147 ifa->ifa_addr = (struct sockaddr *)sdl;
148 ifa->ifa_ifp = ifp;
149 sdl->sdl_len = socksize;
150 sdl->sdl_family = AF_LINK;
151 bcopy(ifp->if_name, sdl->sdl_data, namelen);
152 bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
153 sdl->sdl_nlen = (namelen += unitlen);
154 sdl->sdl_index = ifp->if_index;
155 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
156 ifa->ifa_netmask = (struct sockaddr *)sdl;
157 sdl->sdl_len = socksize - ifp->if_addrlen;
158 while (namelen != 0)
159 sdl->sdl_data[--namelen] = 0xff;
160 ifa->ifa_next = ifp->if_addrlist;
161 ifa->ifa_rtrequest = link_rtrequest;
162 ifp->if_addrlist = ifa;
163}
164/*
165 * Locate an interface based on a complete address.
166 */
167/*ARGSUSED*/
168struct ifaddr *
169ifa_ifwithaddr(addr)
170 register struct sockaddr *addr;
171{
172 register struct ifnet *ifp;
173 register struct ifaddr *ifa;
174
175#define equal(a1, a2) \
176 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
177 for (ifp = ifnet; ifp; ifp = ifp->if_next)
178 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
179 if (ifa->ifa_addr->sa_family != addr->sa_family)
180 continue;
181 if (equal(addr, ifa->ifa_addr))
182 return (ifa);
183 if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
184 equal(ifa->ifa_broadaddr, addr))
185 return (ifa);
186 }
187 return ((struct ifaddr *)0);
188}
189/*
190 * Locate the point to point interface with a given destination address.
191 */
192/*ARGSUSED*/
193struct ifaddr *
194ifa_ifwithdstaddr(addr)
195 register struct sockaddr *addr;
196{
197 register struct ifnet *ifp;
198 register struct ifaddr *ifa;
199
200 for (ifp = ifnet; ifp; ifp = ifp->if_next)
201 if (ifp->if_flags & IFF_POINTOPOINT)
202 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
203 if (ifa->ifa_addr->sa_family != addr->sa_family)
204 continue;
205 if (equal(addr, ifa->ifa_dstaddr))
206 return (ifa);
207 }
208 return ((struct ifaddr *)0);
209}
210
211/*
212 * Find an interface on a specific network. If many, choice
213 * is first found.
214 */
215struct ifaddr *
216ifa_ifwithnet(addr)
217 struct sockaddr *addr;
218{
219 register struct ifnet *ifp;
220 register struct ifaddr *ifa;
221 u_int af = addr->sa_family;
222
223 if (af >= AF_MAX)
224 return (0);
225 if (af == AF_LINK) {
226 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
227 if (sdl->sdl_index && sdl->sdl_index <= if_index)
228 return (ifnet_addrs[sdl->sdl_index - 1]);
229 }
230 for (ifp = ifnet; ifp; ifp = ifp->if_next)
231 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
232 register char *cp, *cp2, *cp3;
233 register char *cplim;
234 if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
235 continue;
236 cp = addr->sa_data;
237 cp2 = ifa->ifa_addr->sa_data;
238 cp3 = ifa->ifa_netmask->sa_data;
239 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
240 for (; cp3 < cplim; cp3++)
241 if ((*cp++ ^ *cp2++) & *cp3)
242 break;
243 if (cp3 == cplim)
244 return (ifa);
245 }
246 return ((struct ifaddr *)0);
247}
248
249/*
250 * Find an interface using a specific address family
251 */
252struct ifaddr *
253ifa_ifwithaf(af)
254 register int af;
255{
256 register struct ifnet *ifp;
257 register struct ifaddr *ifa;
258
259 for (ifp = ifnet; ifp; ifp = ifp->if_next)
260 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
261 if (ifa->ifa_addr->sa_family == af)
262 return (ifa);
263 return ((struct ifaddr *)0);
264}
265
266/*
267 * Find an interface address specific to an interface best matching
268 * a given address.
269 */
270struct ifaddr *
271ifaof_ifpforaddr(addr, ifp)
272 struct sockaddr *addr;
273 register struct ifnet *ifp;
274{
275 register struct ifaddr *ifa;
276 register char *cp, *cp2, *cp3;
277 register char *cplim;
278 struct ifaddr *ifa_maybe = 0;
279 u_int af = addr->sa_family;
280
281 if (af >= AF_MAX)
282 return (0);
283 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
284 if (ifa->ifa_addr->sa_family != af)
285 continue;
286 ifa_maybe = ifa;
287 if (ifa->ifa_netmask == 0) {
288 if (equal(addr, ifa->ifa_addr) ||
289 (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
290 return (ifa);
291 continue;
292 }
293 cp = addr->sa_data;
294 cp2 = ifa->ifa_addr->sa_data;
295 cp3 = ifa->ifa_netmask->sa_data;
296 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
297 for (; cp3 < cplim; cp3++)
298 if ((*cp++ ^ *cp2++) & *cp3)
299 break;
300 if (cp3 == cplim)
301 return (ifa);
302 }
303 return (ifa_maybe);
304}
305#include "route.h"
306/*
307 * Default action when installing a route with a Link Level gateway.
308 * Lookup an appropriate real ifa to point to.
309 * This should be moved to /sys/net/link.c eventually.
310 */
311link_rtrequest(cmd, rt, sa)
312register struct rtentry *rt;
313struct sockaddr *sa;
314{
315 register struct ifaddr *ifa;
316 struct sockaddr *dst;
317 struct ifnet *ifp, *oldifnet = ifnet;
318
319 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
320 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
321 return;
322 if (ifa = ifaof_ifpforaddr(dst, ifp)) {
323 rt->rt_ifa = ifa;
324 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
325 ifa->ifa_rtrequest(cmd, rt, sa);
326 }
327}
328
329/*
330 * Mark an interface down and notify protocols of
331 * the transition.
332 * NOTE: must be called at splnet or eqivalent.
333 */
334if_down(ifp)
335 register struct ifnet *ifp;
336{
337 register struct ifaddr *ifa;
338
339 ifp->if_flags &= ~IFF_UP;
340 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
341 pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
342 if_qflush(&ifp->if_snd);
343}
344
345/*
346 * Flush an interface queue.
347 */
348if_qflush(ifq)
349 register struct ifqueue *ifq;
350{
351 register struct mbuf *m, *n;
352
353 n = ifq->ifq_head;
354 while (m = n) {
355 n = m->m_act;
356 m_freem(m);
357 }
358 ifq->ifq_head = 0;
359 ifq->ifq_tail = 0;
360 ifq->ifq_len = 0;
361}
362
363/*
364 * Handle interface watchdog timer routines. Called
365 * from softclock, we decrement timers (if set) and
366 * call the appropriate interface routine on expiration.
367 */
368if_slowtimo()
369{
370 register struct ifnet *ifp;
371 int s = splimp();
372
373 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
374 if (ifp->if_timer == 0 || --ifp->if_timer)
375 continue;
376 if (ifp->if_watchdog)
377 (*ifp->if_watchdog)(ifp->if_unit);
378 }
379 splx(s);
380 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
381}
382
383/*
384 * Map interface name to
385 * interface structure pointer.
386 */
387struct ifnet *
388ifunit(name)
389 register char *name;
390{
391 register char *cp;
392 register struct ifnet *ifp;
393 int unit;
394 unsigned len;
395 char *ep, c;
396
397 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
398 if (*cp >= '0' && *cp <= '9')
399 break;
400 if (*cp == '\0' || cp == name + IFNAMSIZ)
401 return ((struct ifnet *)0);
402 /*
403 * Save first char of unit, and pointer to it,
404 * so we can put a null there to avoid matching
405 * initial substrings of interface names.
406 */
407 len = cp - name + 1;
408 c = *cp;
409 ep = cp;
410 for (unit = 0; *cp >= '0' && *cp <= '9'; )
411 unit = unit * 10 + *cp++ - '0';
412 *ep = 0;
413 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
414 if (bcmp(ifp->if_name, name, len))
415 continue;
416 if (unit == ifp->if_unit)
417 break;
418 }
419 *ep = c;
420 return (ifp);
421}
422
423/*
424 * Interface ioctls.
425 */
426ifioctl(so, cmd, data, p)
427 struct socket *so;
428 int cmd;
429 caddr_t data;
430 struct proc *p;
431{
432 register struct ifnet *ifp;
433 register struct ifreq *ifr;
434 int error;
435
436 switch (cmd) {
437
438 case SIOCGIFCONF:
439 case OSIOCGIFCONF:
440 return (ifconf(cmd, data));
441
442#if defined(INET) && NETHER > 0
443 case SIOCSARP:
444 case SIOCDARP:
445 if (error = suser(p->p_ucred, &p->p_acflag))
446 return (error);
447 /* FALL THROUGH */
448 case SIOCGARP:
449 case OSIOCGARP:
450 return (arpioctl(cmd, data));
451#endif
452 }
453 ifr = (struct ifreq *)data;
454 ifp = ifunit(ifr->ifr_name);
455 if (ifp == 0)
456 return (ENXIO);
457 switch (cmd) {
458
459 case SIOCGIFFLAGS:
460 ifr->ifr_flags = ifp->if_flags;
461 break;
462
463 case SIOCGIFMETRIC:
464 ifr->ifr_metric = ifp->if_metric;
465 break;
466
467 case SIOCSIFFLAGS:
468 if (error = suser(p->p_ucred, &p->p_acflag))
469 return (error);
470 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
471 int s = splimp();
472 if_down(ifp);
473 splx(s);
474 }
475 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
476 (ifr->ifr_flags &~ IFF_CANTCHANGE);
477 if (ifp->if_ioctl)
478 (void) (*ifp->if_ioctl)(ifp, cmd, data);
479 break;
480
481 case SIOCSIFMETRIC:
482 if (error = suser(p->p_ucred, &p->p_acflag))
483 return (error);
484 ifp->if_metric = ifr->ifr_metric;
485 break;
486
487 default:
488 if (so->so_proto == 0)
489 return (EOPNOTSUPP);
490#ifndef COMPAT_43
491 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
492 cmd, data, ifp));
493#else
494 {
495 int ocmd = cmd;
496
497 switch (cmd) {
498
499 case SIOCSIFDSTADDR:
500 case SIOCSIFADDR:
501 case SIOCSIFBRDADDR:
502 case SIOCSIFNETMASK:
503#if BYTE_ORDER != BIG_ENDIAN
504 if (ifr->ifr_addr.sa_family == 0 &&
505 ifr->ifr_addr.sa_len < 16) {
506 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
507 ifr->ifr_addr.sa_len = 16;
508 }
509#else
510 if (ifr->ifr_addr.sa_len == 0)
511 ifr->ifr_addr.sa_len = 16;
512#endif
513 break;
514
515 case OSIOCGIFADDR:
516 cmd = SIOCGIFADDR;
517 break;
518
519 case OSIOCGIFDSTADDR:
520 cmd = SIOCGIFDSTADDR;
521 break;
522
523 case OSIOCGIFBRDADDR:
524 cmd = SIOCGIFBRDADDR;
525 break;
526
527 case OSIOCGIFNETMASK:
528 cmd = SIOCGIFNETMASK;
529 }
530 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
531 cmd, data, ifp));
532 switch (ocmd) {
533
534 case OSIOCGIFADDR:
535 case OSIOCGIFDSTADDR:
536 case OSIOCGIFBRDADDR:
537 case OSIOCGIFNETMASK:
538 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
539 }
540 return (error);
541
542 }
543#endif
544 }
545 return (0);
546}
547
548/*
549 * Return interface configuration
550 * of system. List may be used
551 * in later ioctl's (above) to get
552 * other information.
553 */
554/*ARGSUSED*/
555ifconf(cmd, data)
556 int cmd;
557 caddr_t data;
558{
559 register struct ifconf *ifc = (struct ifconf *)data;
560 register struct ifnet *ifp = ifnet;
561 register struct ifaddr *ifa;
562 register char *cp, *ep;
563 struct ifreq ifr, *ifrp;
564 int space = ifc->ifc_len, error = 0;
565
566 ifrp = ifc->ifc_req;
567 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
568 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
569 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
570 for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
571 ;
572 *cp++ = '0' + ifp->if_unit; *cp = '\0';
573 if ((ifa = ifp->if_addrlist) == 0) {
574 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
575 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
576 if (error)
577 break;
578 space -= sizeof (ifr), ifrp++;
579 } else
580 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
581 register struct sockaddr *sa = ifa->ifa_addr;
582#ifdef COMPAT_43
583 if (cmd == OSIOCGIFCONF) {
584 struct osockaddr *osa =
585 (struct osockaddr *)&ifr.ifr_addr;
586 ifr.ifr_addr = *sa;
587 osa->sa_family = sa->sa_family;
588 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
589 sizeof (ifr));
590 ifrp++;
591 } else
592#endif
593 if (sa->sa_len <= sizeof(*sa)) {
594 ifr.ifr_addr = *sa;
595 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
596 sizeof (ifr));
597 ifrp++;
598 } else {
599 space -= sa->sa_len - sizeof(*sa);
600 if (space < sizeof (ifr))
601 break;
602 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
603 sizeof (ifr.ifr_name));
604 if (error == 0)
605 error = copyout((caddr_t)sa,
606 (caddr_t)&ifrp->ifr_addr, sa->sa_len);
607 ifrp = (struct ifreq *)
608 (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
609 }
610 if (error)
611 break;
612 space -= sizeof (ifr);
613 }
614 }
615 ifc->ifc_len -= space;
616 return (error);
617}
618
619static char *
620sprint_d(n, buf, buflen)
621 u_int n;
622 char *buf;
623 int buflen;
624{
625 register char *cp = buf + buflen - 1;
626
627 *cp = 0;
628 do {
629 cp--;
630 *cp = "0123456789"[n % 10];
631 n /= 10;
632 } while (n != 0);
633 return (cp);
634}