use multicast conventions
[unix-history] / usr / src / sys / net / if.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1980, 1986 Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)if.c 7.19 (Berkeley) %G%
8 */
9
10#include "param.h"
11#include "mbuf.h"
12#include "systm.h"
13#include "proc.h"
14#include "socket.h"
15#include "socketvar.h"
16#include "protosw.h"
17#include "kernel.h"
18#include "ioctl.h"
19
20#include "if.h"
21#include "af.h"
22#include "if_dl.h"
23#include "if_types.h"
24
25#include "ether.h"
26
27int ifqmaxlen = IFQ_MAXLEN;
28
29/*
30 * Network interface utility routines.
31 *
32 * Routines with ifa_ifwith* names take sockaddr *'s as
33 * parameters.
34 */
35
36ifinit()
37{
38 register struct ifnet *ifp;
39
40 for (ifp = ifnet; ifp; ifp = ifp->if_next)
41 if (ifp->if_snd.ifq_maxlen == 0)
42 ifp->if_snd.ifq_maxlen = ifqmaxlen;
43 if_slowtimo();
44}
45
46#ifdef vax
47/*
48 * Call each interface on a Unibus reset.
49 */
50ifubareset(uban)
51 int uban;
52{
53 register struct ifnet *ifp;
54
55 for (ifp = ifnet; ifp; ifp = ifp->if_next)
56 if (ifp->if_reset)
57 (*ifp->if_reset)(ifp->if_unit, uban);
58}
59#endif
60
61int if_index = 0;
62struct ifaddr **ifnet_addrs;
63static char *sprint_d();
64
65/*
66 * Attach an interface to the
67 * list of "active" interfaces.
68 */
69void
70if_attach(ifp)
71 struct ifnet *ifp;
72{
73 unsigned socksize, ifasize;
74 int namelen, unitlen, masklen;
75 char workbuf[12], *unitname;
76 register struct ifnet **p = &ifnet;
77 register struct sockaddr_dl *sdl;
78 register struct ifaddr *ifa;
79 static int if_indexlim = 8;
80 extern link_rtrequest(), ether_output();
81
82 while (*p)
83 p = &((*p)->if_next);
84 *p = ifp;
85 ifp->if_index = ++if_index;
86 if (ifnet_addrs == 0 || if_index >= if_indexlim) {
87 unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
88 struct ifaddr **q = (struct ifaddr **)
89 malloc(n, M_IFADDR, M_WAITOK);
90 if (ifnet_addrs) {
91 bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
92 free((caddr_t)ifnet_addrs, M_IFADDR);
93 }
94 ifnet_addrs = q;
95 }
96 /*
97 * create a Link Level name for this device
98 */
99 unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
100 namelen = strlen(ifp->if_name);
101 unitlen = strlen(unitname);
102#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
103 masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) +
104 unitlen + namelen;
105 socksize = masklen + ifp->if_addrlen;
106#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
107 socksize = ROUNDUP(socksize);
108 if (socksize < sizeof(*sdl))
109 socksize = sizeof(*sdl);
110 ifasize = sizeof(*ifa) + 2 * socksize;
111 if (ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK)) {
112 bzero((caddr_t)ifa, ifasize);
113 sdl = (struct sockaddr_dl *)(ifa + 1);
114 sdl->sdl_len = socksize;
115 sdl->sdl_family = AF_LINK;
116 bcopy(ifp->if_name, sdl->sdl_data, namelen);
117 bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
118 sdl->sdl_nlen = (namelen += unitlen);
119 sdl->sdl_index = ifp->if_index;
120 sdl->sdl_type = ifp->if_type;
121 ifnet_addrs[if_index - 1] = ifa;
122 ifa->ifa_ifp = ifp;
123 ifa->ifa_next = ifp->if_addrlist;
124 ifa->ifa_rtrequest = link_rtrequest;
125 ifp->if_addrlist = ifa;
126 ifa->ifa_addr = (struct sockaddr *)sdl;
127 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
128 ifa->ifa_netmask = (struct sockaddr *)sdl;
129 sdl->sdl_len = masklen;
130 while (namelen != 0)
131 sdl->sdl_data[--namelen] = 0xff;
132 }
133 /* XXX -- Temporary fix before changing 10 ethernet drivers */
134 if (ifp->if_output == ether_output)
135 ether_ifattach(ifp);
136}
137/*
138 * Locate an interface based on a complete address.
139 */
140/*ARGSUSED*/
141struct ifaddr *
142ifa_ifwithaddr(addr)
143 register struct sockaddr *addr;
144{
145 register struct ifnet *ifp;
146 register struct ifaddr *ifa;
147
148#define equal(a1, a2) \
149 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
150 for (ifp = ifnet; ifp; ifp = ifp->if_next)
151 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
152 if (ifa->ifa_addr->sa_family != addr->sa_family)
153 continue;
154 if (equal(addr, ifa->ifa_addr))
155 return (ifa);
156 if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
157 equal(ifa->ifa_broadaddr, addr))
158 return (ifa);
159 }
160 return ((struct ifaddr *)0);
161}
162/*
163 * Locate the point to point interface with a given destination address.
164 */
165/*ARGSUSED*/
166struct ifaddr *
167ifa_ifwithdstaddr(addr)
168 register struct sockaddr *addr;
169{
170 register struct ifnet *ifp;
171 register struct ifaddr *ifa;
172
173 for (ifp = ifnet; ifp; ifp = ifp->if_next)
174 if (ifp->if_flags & IFF_POINTOPOINT)
175 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
176 if (ifa->ifa_addr->sa_family != addr->sa_family)
177 continue;
178 if (equal(addr, ifa->ifa_dstaddr))
179 return (ifa);
180 }
181 return ((struct ifaddr *)0);
182}
183
184/*
185 * Find an interface on a specific network. If many, choice
186 * is most specific found.
187 */
188struct ifaddr *
189ifa_ifwithnet(addr)
190 struct sockaddr *addr;
191{
192 register struct ifnet *ifp;
193 register struct ifaddr *ifa;
194 struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
195 u_int af = addr->sa_family;
196 char *addr_data = addr->sa_data, *cplim;
197
198 if (af == AF_LINK) {
199 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
200 if (sdl->sdl_index && sdl->sdl_index <= if_index)
201 return (ifnet_addrs[sdl->sdl_index - 1]);
202 }
203 for (ifp = ifnet; ifp; ifp = ifp->if_next)
204 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
205 register char *cp, *cp2, *cp3;
206
207 if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
208 next: continue;
209 cp = addr_data;
210 cp2 = ifa->ifa_addr->sa_data;
211 cp3 = ifa->ifa_netmask->sa_data;
212 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
213 while (cp3 < cplim)
214 if ((*cp++ ^ *cp2++) & *cp3++)
215 goto next;
216 if (ifa_maybe == 0 ||
217 rn_refines(ifa->ifa_netmask, ifa_maybe->ifa_netmask))
218 ifa_maybe = ifa;
219 }
220 return (ifa_maybe);
221}
222
223/*
224 * Find an interface using a specific address family
225 */
226struct ifaddr *
227ifa_ifwithaf(af)
228 register int af;
229{
230 register struct ifnet *ifp;
231 register struct ifaddr *ifa;
232
233 for (ifp = ifnet; ifp; ifp = ifp->if_next)
234 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
235 if (ifa->ifa_addr->sa_family == af)
236 return (ifa);
237 return ((struct ifaddr *)0);
238}
239
240/*
241 * Find an interface address specific to an interface best matching
242 * a given address.
243 */
244struct ifaddr *
245ifaof_ifpforaddr(addr, ifp)
246 struct sockaddr *addr;
247 register struct ifnet *ifp;
248{
249 register struct ifaddr *ifa;
250 register char *cp, *cp2, *cp3;
251 register char *cplim;
252 struct ifaddr *ifa_maybe = 0;
253 u_int af = addr->sa_family;
254
255 if (af >= AF_MAX)
256 return (0);
257 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
258 if (ifa->ifa_addr->sa_family != af)
259 continue;
260 ifa_maybe = ifa;
261 if (ifa->ifa_netmask == 0) {
262 if (equal(addr, ifa->ifa_addr) ||
263 (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
264 return (ifa);
265 continue;
266 }
267 cp = addr->sa_data;
268 cp2 = ifa->ifa_addr->sa_data;
269 cp3 = ifa->ifa_netmask->sa_data;
270 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
271 for (; cp3 < cplim; cp3++)
272 if ((*cp++ ^ *cp2++) & *cp3)
273 break;
274 if (cp3 == cplim)
275 return (ifa);
276 }
277 return (ifa_maybe);
278}
279#include "route.h"
280/*
281 * Default action when installing a route with a Link Level gateway.
282 * Lookup an appropriate real ifa to point to.
283 * This should be moved to /sys/net/link.c eventually.
284 */
285link_rtrequest(cmd, rt, sa)
286 int cmd;
287 register struct rtentry *rt;
288 struct sockaddr *sa;
289{
290 register struct ifaddr *ifa;
291 struct sockaddr *dst;
292 struct ifnet *ifp, *oldifnet = ifnet;
293
294 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
295 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
296 return;
297 if (ifa = ifaof_ifpforaddr(dst, ifp)) {
298 rt->rt_ifa = ifa;
299 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
300 ifa->ifa_rtrequest(cmd, rt, sa);
301 }
302}
303
304/*
305 * Mark an interface down and notify protocols of
306 * the transition.
307 * NOTE: must be called at splnet or eqivalent.
308 */
309if_down(ifp)
310 register struct ifnet *ifp;
311{
312 register struct ifaddr *ifa;
313
314 ifp->if_flags &= ~IFF_UP;
315 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
316 pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
317 if_qflush(&ifp->if_snd);
318 rt_ifmsg(ifp);
319}
320
321/*
322 * Mark an interface up and notify protocols of
323 * the transition.
324 * NOTE: must be called at splnet or eqivalent.
325 */
326if_up(ifp)
327 register struct ifnet *ifp;
328{
329 register struct ifaddr *ifa;
330
331 ifp->if_flags |= IFF_UP;
332#ifdef notyet
333 /* this has no effect on IP, and will kill all iso connections XXX */
334 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
335 pfctlinput(PRC_IFUP, ifa->ifa_addr);
336#endif notyet
337 rt_ifmsg(ifp);
338}
339
340/*
341 * Flush an interface queue.
342 */
343if_qflush(ifq)
344 register struct ifqueue *ifq;
345{
346 register struct mbuf *m, *n;
347
348 n = ifq->ifq_head;
349 while (m = n) {
350 n = m->m_act;
351 m_freem(m);
352 }
353 ifq->ifq_head = 0;
354 ifq->ifq_tail = 0;
355 ifq->ifq_len = 0;
356}
357
358/*
359 * Handle interface watchdog timer routines. Called
360 * from softclock, we decrement timers (if set) and
361 * call the appropriate interface routine on expiration.
362 */
363if_slowtimo()
364{
365 register struct ifnet *ifp;
366 int s = splimp();
367
368 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
369 if (ifp->if_timer == 0 || --ifp->if_timer)
370 continue;
371 if (ifp->if_watchdog)
372 (*ifp->if_watchdog)(ifp->if_unit);
373 }
374 splx(s);
375 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
376}
377
378/*
379 * Map interface name to
380 * interface structure pointer.
381 */
382struct ifnet *
383ifunit(name)
384 register char *name;
385{
386 register char *cp;
387 register struct ifnet *ifp;
388 int unit;
389 unsigned len;
390 char *ep, c;
391
392 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
393 if (*cp >= '0' && *cp <= '9')
394 break;
395 if (*cp == '\0' || cp == name + IFNAMSIZ)
396 return ((struct ifnet *)0);
397 /*
398 * Save first char of unit, and pointer to it,
399 * so we can put a null there to avoid matching
400 * initial substrings of interface names.
401 */
402 len = cp - name + 1;
403 c = *cp;
404 ep = cp;
405 for (unit = 0; *cp >= '0' && *cp <= '9'; )
406 unit = unit * 10 + *cp++ - '0';
407 *ep = 0;
408 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
409 if (bcmp(ifp->if_name, name, len))
410 continue;
411 if (unit == ifp->if_unit)
412 break;
413 }
414 *ep = c;
415 return (ifp);
416}
417
418/*
419 * Interface ioctls.
420 */
421ifioctl(so, cmd, data, p)
422 struct socket *so;
423 int cmd;
424 caddr_t data;
425 struct proc *p;
426{
427 register struct ifnet *ifp;
428 register struct ifreq *ifr;
429 int error;
430
431 switch (cmd) {
432
433 case SIOCGIFCONF:
434 case OSIOCGIFCONF:
435 return (ifconf(cmd, data));
436
437#if defined(INET) && NETHER > 0
438 case SIOCSARP:
439 case SIOCDARP:
440 if (error = suser(p->p_ucred, &p->p_acflag))
441 return (error);
442 /* FALL THROUGH */
443 case SIOCGARP:
444 case OSIOCGARP:
445 return (arpioctl(cmd, data));
446#endif
447 }
448 ifr = (struct ifreq *)data;
449 ifp = ifunit(ifr->ifr_name);
450 if (ifp == 0)
451 return (ENXIO);
452 switch (cmd) {
453
454 case SIOCGIFFLAGS:
455 ifr->ifr_flags = ifp->if_flags;
456 break;
457
458 case SIOCGIFMETRIC:
459 ifr->ifr_metric = ifp->if_metric;
460 break;
461
462 case SIOCSIFFLAGS:
463 if (error = suser(p->p_ucred, &p->p_acflag))
464 return (error);
465 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
466 int s = splimp();
467 if_down(ifp);
468 splx(s);
469 }
470 if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
471 int s = splimp();
472 if_up(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 continue;
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}