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