getkerninfo skipped defaults ``dupedkeyed'' behind the root node;
[unix-history] / usr / src / sys / net / if.c
CommitLineData
cb1c44c2 1/*
1810611d 2 * Copyright (c) 1980, 1986 Regents of the University of California.
5b519e94 3 * All rights reserved.
cb1c44c2 4 *
5b519e94 5 * Redistribution and use in source and binary forms are permitted
50c7758a
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5b519e94 16 *
f2eb28c8 17 * @(#)if.c 7.11 (Berkeley) %G%
cb1c44c2 18 */
1bfd8df7 19
a0369dcf 20#include "param.h"
ce355163 21#include "mbuf.h"
a0369dcf
JB
22#include "systm.h"
23#include "socket.h"
f211a0b7 24#include "socketvar.h"
a0369dcf 25#include "protosw.h"
a0369dcf
JB
26#include "user.h"
27#include "kernel.h"
28#include "ioctl.h"
29#include "errno.h"
30
31#include "if.h"
32#include "af.h"
02e54a34 33#include "if_dl.h"
1bfd8df7 34
17fcfec5
MK
35#include "ether.h"
36
1e977657
BJ
37int ifqmaxlen = IFQ_MAXLEN;
38
ee787340
SL
39/*
40 * Network interface utility routines.
41 *
f211a0b7
MK
42 * Routines with ifa_ifwith* names take sockaddr *'s as
43 * parameters.
ee787340
SL
44 */
45
85ce71f2
BJ
46ifinit()
47{
48 register struct ifnet *ifp;
49
50 for (ifp = ifnet; ifp; ifp = ifp->if_next)
aad26eac
MK
51 if (ifp->if_snd.ifq_maxlen == 0)
52 ifp->if_snd.ifq_maxlen = ifqmaxlen;
5248a70b 53 if_slowtimo();
85ce71f2
BJ
54}
55
a62dd253 56#ifdef vax
ee787340
SL
57/*
58 * Call each interface on a Unibus reset.
59 */
85ce71f2
BJ
60ifubareset(uban)
61 int uban;
62{
63 register struct ifnet *ifp;
64
65 for (ifp = ifnet; ifp; ifp = ifp->if_next)
8af3ca7c 66 if (ifp->if_reset)
9d6a72e7 67 (*ifp->if_reset)(ifp->if_unit, uban);
85ce71f2 68}
14fa60f2 69#endif
85ce71f2 70
02e54a34 71int if_index = 0;
ee787340
SL
72/*
73 * Attach an interface to the
74 * list of "active" interfaces.
75 */
405c9168
BJ
76if_attach(ifp)
77 struct ifnet *ifp;
78{
c4af8b24 79 register struct ifnet **p = &ifnet;
02e54a34
KS
80 unsigned socksize, ifasize;
81 int namelen, unitlen;
82 char workbuf[16];
83 register struct sockaddr_dl *sdl;
84 register struct ifaddr *ifa;
f2eb28c8 85 extern link_rtrequest();
405c9168 86
c4af8b24
BJ
87 while (*p)
88 p = &((*p)->if_next);
89 *p = ifp;
02e54a34 90 ifp->if_index = ++if_index;
f2eb28c8
KS
91 /*
92 * create a Link Level name for this device
93 */
02e54a34
KS
94 sprint_d(workbuf, ifp->if_unit);
95 namelen = strlen(ifp->if_name);
96 unitlen = strlen(workbuf);
97#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
98 socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
99 unitlen + namelen + ifp->if_addrlen;
100#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
101 socksize = ROUNDUP(socksize);
102 ifasize = sizeof(*ifa) + 2 * socksize;
103 ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
104 if (ifa == 0)
105 return;
106 bzero((caddr_t)ifa, ifasize);
107 sdl = (struct sockaddr_dl *)(ifa + 1);
108 ifa->ifa_addr = (struct sockaddr *)sdl;
109 ifa->ifa_ifp = ifp;
110 sdl->sdl_len = socksize;
111 sdl->sdl_family = AF_LINK;
112 bcopy(ifp->if_name, sdl->sdl_data, namelen);
113 bcopy((caddr_t)workbuf, namelen + (caddr_t)sdl->sdl_data, unitlen);
114 sdl->sdl_nlen = (namelen += unitlen);
115 sdl->sdl_index = ifp->if_index;
116 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
117 ifa->ifa_netmask = (struct sockaddr *)sdl;
118 sdl->sdl_len = socksize - ifp->if_addrlen;
119 while (namelen != 0)
120 sdl->sdl_data[--namelen] = 0xff;
121 ifa->ifa_next = ifp->if_addrlist;
f2eb28c8 122 ifa->ifa_rtrequest = link_rtrequest;
02e54a34 123 ifp->if_addrlist = ifa;
405c9168 124}
ee787340
SL
125/*
126 * Locate an interface based on a complete address.
127 */
4ad99bae 128/*ARGSUSED*/
f211a0b7
MK
129struct ifaddr *
130ifa_ifwithaddr(addr)
202403f4 131 register struct sockaddr *addr;
1bfd8df7
BJ
132{
133 register struct ifnet *ifp;
f211a0b7 134 register struct ifaddr *ifa;
1bfd8df7 135
ee787340 136#define equal(a1, a2) \
202403f4 137 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
f211a0b7
MK
138 for (ifp = ifnet; ifp; ifp = ifp->if_next)
139 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
202403f4 140 if (ifa->ifa_addr->sa_family != addr->sa_family)
ee787340 141 continue;
202403f4 142 if (equal(addr, ifa->ifa_addr))
f211a0b7 143 return (ifa);
ee787340 144 if ((ifp->if_flags & IFF_BROADCAST) &&
f211a0b7
MK
145 equal(&ifa->ifa_broadaddr, addr))
146 return (ifa);
ee787340 147 }
f211a0b7 148 return ((struct ifaddr *)0);
1bfd8df7 149}
ae674e00
KS
150/*
151 * Locate the point to point interface with a given destination address.
152 */
153/*ARGSUSED*/
154struct ifaddr *
155ifa_ifwithdstaddr(addr)
202403f4 156 register struct sockaddr *addr;
ae674e00
KS
157{
158 register struct ifnet *ifp;
159 register struct ifaddr *ifa;
160
161 for (ifp = ifnet; ifp; ifp = ifp->if_next)
162 if (ifp->if_flags & IFF_POINTOPOINT)
163 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
202403f4 164 if (ifa->ifa_addr->sa_family != addr->sa_family)
ae674e00 165 continue;
202403f4 166 if (equal(addr, ifa->ifa_dstaddr))
ae674e00
KS
167 return (ifa);
168 }
169 return ((struct ifaddr *)0);
170}
1bfd8df7 171
ee787340
SL
172/*
173 * Find an interface on a specific network. If many, choice
174 * is first found.
175 */
f211a0b7
MK
176struct ifaddr *
177ifa_ifwithnet(addr)
202403f4 178 struct sockaddr *addr;
ee787340
SL
179{
180 register struct ifnet *ifp;
f211a0b7 181 register struct ifaddr *ifa;
202403f4
KS
182 register char *cp, *cp2, *cp3;
183 register char *cplim;
184 u_int af = addr->sa_family;
ee787340 185
e65dcd4c
SL
186 if (af >= AF_MAX)
187 return (0);
f211a0b7
MK
188 for (ifp = ifnet; ifp; ifp = ifp->if_next)
189 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
202403f4 190 if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
ee787340 191 continue;
202403f4
KS
192 cp = addr->sa_data;
193 cp2 = ifa->ifa_addr->sa_data;
194 cp3 = ifa->ifa_netmask->sa_data;
195 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
196 for (; cp3 < cplim; cp3++)
197 if ((*cp++ ^ *cp2++) & *cp3)
198 break;
199 if (cp3 == cplim)
f211a0b7 200 return (ifa);
202403f4 201 }
f211a0b7 202 return ((struct ifaddr *)0);
1bfd8df7
BJ
203}
204
ee787340
SL
205/*
206 * Find an interface using a specific address family
207 */
f211a0b7
MK
208struct ifaddr *
209ifa_ifwithaf(af)
ee787340 210 register int af;
8a13b737 211{
ee787340 212 register struct ifnet *ifp;
f211a0b7 213 register struct ifaddr *ifa;
8a13b737 214
ee787340 215 for (ifp = ifnet; ifp; ifp = ifp->if_next)
f211a0b7 216 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
202403f4 217 if (ifa->ifa_addr->sa_family == af)
f211a0b7
MK
218 return (ifa);
219 return ((struct ifaddr *)0);
8a13b737 220}
f2eb28c8
KS
221
222#include "route.h"
223/*
224 * Default action when installing a route with a Link Level gateway.
225 * Lookup an appropriate real ifa to point to.
226 * This should be moved to /sys/net/link.c eventually.
227 */
228link_rtrequest(cmd, rt, sa)
229register struct rtentry *rt;
230struct sockaddr *sa;
231{
232 register struct ifaddr *ifa;
233 struct sockaddr *dst;
234 struct ifnet *ifp, *oldifnet = ifnet;
235
236 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
237 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
238 return;
239 ifnet = ifp;
240 if (((ifa = ifa_ifwithnet(dst)) && ifa->ifa_ifp == ifp) ||
241 ((ifa = ifa_ifwithaf(dst->sa_family)) && ifa->ifa_ifp == ifp)) {
242 ifnet = oldifnet;
243 rt->rt_ifa = ifa;
244 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
245 ifa->ifa_rtrequest(cmd, rt, sa);
246 } else
247 ifnet = oldifnet;
248}
f1b2fa5b 249
72e4f44e
SL
250/*
251 * Mark an interface down and notify protocols of
252 * the transition.
af0b24db 253 * NOTE: must be called at splnet or eqivalent.
72e4f44e
SL
254 */
255if_down(ifp)
256 register struct ifnet *ifp;
257{
f211a0b7 258 register struct ifaddr *ifa;
5248a70b 259
72e4f44e 260 ifp->if_flags &= ~IFF_UP;
f211a0b7 261 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
202403f4 262 pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
ce355163
MK
263 if_qflush(&ifp->if_snd);
264}
265
266/*
267 * Flush an interface queue.
268 */
269if_qflush(ifq)
270 register struct ifqueue *ifq;
271{
272 register struct mbuf *m, *n;
273
274 n = ifq->ifq_head;
275 while (m = n) {
276 n = m->m_act;
277 m_freem(m);
278 }
279 ifq->ifq_head = 0;
280 ifq->ifq_tail = 0;
281 ifq->ifq_len = 0;
72e4f44e 282}
de602274
SL
283
284/*
285 * Handle interface watchdog timer routines. Called
286 * from softclock, we decrement timers (if set) and
287 * call the appropriate interface routine on expiration.
288 */
289if_slowtimo()
290{
291 register struct ifnet *ifp;
202403f4 292 int s = splimp();
de602274 293
af0b24db
SL
294 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
295 if (ifp->if_timer == 0 || --ifp->if_timer)
296 continue;
297 if (ifp->if_watchdog)
de602274 298 (*ifp->if_watchdog)(ifp->if_unit);
af0b24db 299 }
202403f4 300 splx(s);
6e7edb25 301 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
de602274 302}
0c33c832
SL
303
304/*
a62dd253
SL
305 * Map interface name to
306 * interface structure pointer.
0c33c832 307 */
a62dd253
SL
308struct ifnet *
309ifunit(name)
310 register char *name;
0c33c832 311{
0c33c832 312 register char *cp;
a62dd253
SL
313 register struct ifnet *ifp;
314 int unit;
725d9baf
MK
315 unsigned len;
316 char *ep, c;
0c33c832 317
a62dd253 318 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
0c33c832
SL
319 if (*cp >= '0' && *cp <= '9')
320 break;
a62dd253
SL
321 if (*cp == '\0' || cp == name + IFNAMSIZ)
322 return ((struct ifnet *)0);
725d9baf
MK
323 /*
324 * Save first char of unit, and pointer to it,
325 * so we can put a null there to avoid matching
326 * initial substrings of interface names.
327 */
328 len = cp - name + 1;
329 c = *cp;
330 ep = cp;
331 for (unit = 0; *cp >= '0' && *cp <= '9'; )
332 unit = unit * 10 + *cp++ - '0';
333 *ep = 0;
0c33c832 334 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
725d9baf 335 if (bcmp(ifp->if_name, name, len))
0c33c832
SL
336 continue;
337 if (unit == ifp->if_unit)
a62dd253 338 break;
0c33c832 339 }
725d9baf 340 *ep = c;
a62dd253
SL
341 return (ifp);
342}
343
344/*
345 * Interface ioctls.
346 */
f211a0b7
MK
347ifioctl(so, cmd, data)
348 struct socket *so;
a62dd253
SL
349 int cmd;
350 caddr_t data;
351{
352 register struct ifnet *ifp;
353 register struct ifreq *ifr;
06c16dfa 354 int error;
0c33c832 355
0c33c832
SL
356 switch (cmd) {
357
a62dd253 358 case SIOCGIFCONF:
202403f4 359 case OSIOCGIFCONF:
a62dd253 360 return (ifconf(cmd, data));
0c33c832 361
799358ac 362#if defined(INET) && NETHER > 0
17fcfec5
MK
363 case SIOCSARP:
364 case SIOCDARP:
06c16dfa
KM
365 if (error = suser(u.u_cred, &u.u_acflag))
366 return (error);
17fcfec5
MK
367 /* FALL THROUGH */
368 case SIOCGARP:
202403f4 369 case OSIOCGARP:
17fcfec5
MK
370 return (arpioctl(cmd, data));
371#endif
a62dd253
SL
372 }
373 ifr = (struct ifreq *)data;
374 ifp = ifunit(ifr->ifr_name);
375 if (ifp == 0)
376 return (ENXIO);
377 switch (cmd) {
0c33c832 378
0c33c832
SL
379 case SIOCGIFFLAGS:
380 ifr->ifr_flags = ifp->if_flags;
381 break;
382
484ee22e
MK
383 case SIOCGIFMETRIC:
384 ifr->ifr_metric = ifp->if_metric;
385 break;
386
81889e84 387 case SIOCSIFFLAGS:
06c16dfa
KM
388 if (error = suser(u.u_cred, &u.u_acflag))
389 return (error);
81889e84
SL
390 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
391 int s = splimp();
392 if_down(ifp);
393 splx(s);
394 }
f211a0b7
MK
395 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
396 (ifr->ifr_flags &~ IFF_CANTCHANGE);
aad26eac
MK
397 if (ifp->if_ioctl)
398 (void) (*ifp->if_ioctl)(ifp, cmd, data);
81889e84
SL
399 break;
400
484ee22e 401 case SIOCSIFMETRIC:
06c16dfa
KM
402 if (error = suser(u.u_cred, &u.u_acflag))
403 return (error);
484ee22e
MK
404 ifp->if_metric = ifr->ifr_metric;
405 break;
406
0c33c832 407 default:
f211a0b7 408 if (so->so_proto == 0)
a62dd253 409 return (EOPNOTSUPP);
202403f4 410#ifndef COMPAT_43
f211a0b7
MK
411 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
412 cmd, data, ifp));
202403f4
KS
413#else
414 {
35c34494 415 int ocmd = cmd;
202403f4
KS
416
417 switch (cmd) {
418
419 case SIOCSIFDSTADDR:
420 case SIOCSIFADDR:
421 case SIOCSIFBRDADDR:
422 case SIOCSIFNETMASK:
423#if BYTE_ORDER != BIG_ENDIAN
424 if (ifr->ifr_addr.sa_family == 0 &&
425 ifr->ifr_addr.sa_len < 16) {
426 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
427 ifr->ifr_addr.sa_len = 16;
428 }
429#else
430 if (ifr->ifr_addr.sa_len == 0)
431 ifr->ifr_addr.sa_len = 16;
432#endif
433 break;
434
435 case OSIOCGIFADDR:
436 cmd = SIOCGIFADDR;
437 break;
438
439 case OSIOCGIFDSTADDR:
440 cmd = SIOCGIFDSTADDR;
441 break;
442
443 case OSIOCGIFBRDADDR:
444 cmd = SIOCGIFBRDADDR;
445 break;
446
447 case OSIOCGIFNETMASK:
448 cmd = SIOCGIFNETMASK;
449 }
450 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
451 cmd, data, ifp));
452 switch (ocmd) {
453
454 case OSIOCGIFADDR:
455 case OSIOCGIFDSTADDR:
456 case OSIOCGIFBRDADDR:
457 case OSIOCGIFNETMASK:
458 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
459 }
460 return (error);
461
462 }
463#endif
0c33c832
SL
464 }
465 return (0);
466}
467
468/*
469 * Return interface configuration
470 * of system. List may be used
471 * in later ioctl's (above) to get
472 * other information.
473 */
9e9695c7 474/*ARGSUSED*/
0c33c832
SL
475ifconf(cmd, data)
476 int cmd;
477 caddr_t data;
478{
479 register struct ifconf *ifc = (struct ifconf *)data;
480 register struct ifnet *ifp = ifnet;
f211a0b7 481 register struct ifaddr *ifa;
9b956fa5
SL
482 register char *cp, *ep;
483 struct ifreq ifr, *ifrp;
0c33c832
SL
484 int space = ifc->ifc_len, error = 0;
485
9b956fa5
SL
486 ifrp = ifc->ifc_req;
487 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
0c33c832 488 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
9b956fa5
SL
489 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
490 for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
0c33c832 491 ;
9b956fa5 492 *cp++ = '0' + ifp->if_unit; *cp = '\0';
f211a0b7
MK
493 if ((ifa = ifp->if_addrlist) == 0) {
494 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
495 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
496 if (error)
497 break;
498 space -= sizeof (ifr), ifrp++;
499 } else
500 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
202403f4
KS
501 register struct sockaddr *sa = ifa->ifa_addr;
502#ifdef COMPAT_43
503 if (cmd == OSIOCGIFCONF) {
504 struct osockaddr *osa =
505 (struct osockaddr *)&ifr.ifr_addr;
506 ifr.ifr_addr = *sa;
507 osa->sa_family = sa->sa_family;
508 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
509 sizeof (ifr));
510 ifrp++;
511 } else
512#endif
513 if (sa->sa_len <= sizeof(*sa)) {
514 ifr.ifr_addr = *sa;
515 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
516 sizeof (ifr));
517 ifrp++;
518 } else {
519 space -= sa->sa_len - sizeof(*sa);
520 if (space < sizeof (ifr))
521 break;
522 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
523 sizeof (ifr.ifr_name));
524 if (error == 0)
525 error = copyout((caddr_t)sa,
526 (caddr_t)&ifrp->ifr_addr, sa->sa_len);
527 ifrp = (struct ifreq *)
528 (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
529 }
f211a0b7
MK
530 if (error)
531 break;
202403f4 532 space -= sizeof (ifr);
f211a0b7 533 }
0c33c832
SL
534 }
535 ifc->ifc_len -= space;
536 return (error);
537}
02e54a34
KS
538
539static sprint_d(cp, n)
540register char *cp;
541u_short n;
542{
543 register int q, m;
544 do {
545 if (n >= 10000) m = 10000;
546 else if (n >= 1000) m = 1000;
547 else if (n >= 100) m = 100;
548 else if (n >= 10) m = 10;
549 else m = 1;
550 q = n / m;
551 n -= m * q;
552 if (q > 9) q = 10; /* For crays with more than 100K interfaces */
553 *cp++ = "0123456789Z"[q];
554 } while (n > 0);
555 *cp++ = 0;
556}