]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if.c
xnu-344.tar.gz
[apple/xnu.git] / bsd / net / if.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1980, 1986, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)if.c 8.3 (Berkeley) 1/4/94
55 * $FreeBSD: src/sys/net/if.c,v 1.85.2.9 2001/07/24 19:10:17 brooks Exp $
56 */
57
58 #include <sys/param.h>
59 #include <sys/malloc.h>
60 #include <sys/mbuf.h>
61 #include <sys/systm.h>
62 #include <sys/proc.h>
63 #include <sys/socket.h>
64 #include <sys/socketvar.h>
65 #include <sys/protosw.h>
66 #include <sys/kernel.h>
67 #include <sys/sockio.h>
68 #include <sys/syslog.h>
69 #include <sys/sysctl.h>
70
71 #include <net/if.h>
72 #include <net/if_arp.h>
73 #include <net/if_dl.h>
74 #include <net/if_types.h>
75 #include <net/if_var.h>
76 #include <net/radix.h>
77 #include <net/route.h>
78 #ifdef __APPLE__
79 #include <net/dlil.h>
80 //#include <string.h>
81 #include <sys/domain.h>
82 #endif
83
84 #if defined(INET) || defined(INET6)
85 /*XXX*/
86 #include <netinet/in.h>
87 #include <netinet/in_var.h>
88 #if INET6
89 #include <netinet6/in6_var.h>
90 #include <netinet6/in6_ifattach.h>
91 #endif
92 #endif
93
94 /*
95 * System initialization
96 */
97
98 static int ifconf __P((u_long, caddr_t));
99 static void if_qflush __P((struct ifqueue *));
100 static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *));
101
102 MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
103 MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
104
105 int ifqmaxlen = IFQ_MAXLEN;
106 struct ifnethead ifnet; /* depend on static init XXX */
107
108 #if INET6
109 /*
110 * XXX: declare here to avoid to include many inet6 related files..
111 * should be more generalized?
112 */
113 extern void nd6_setmtu __P((struct ifnet *));
114 extern int ip6_auto_on;
115 #endif
116
117 /*
118 * Network interface utility routines.
119 *
120 * Routines with ifa_ifwith* names take sockaddr *'s as
121 * parameters.
122 */
123
124 int if_index = 0;
125 struct ifaddr **ifnet_addrs;
126 struct ifnet **ifindex2ifnet = NULL;
127
128
129 /*
130 * Attach an interface to the
131 * list of "active" interfaces.
132 */
133 void
134 old_if_attach(ifp)
135 struct ifnet *ifp;
136 {
137 unsigned socksize, ifasize;
138 int namelen, masklen;
139 char workbuf[64];
140 register struct sockaddr_dl *sdl;
141 register struct ifaddr *ifa;
142 static int if_indexlim = 8;
143 static int inited;
144
145 if (ifp->if_snd.ifq_maxlen == 0)
146 ifp->if_snd.ifq_maxlen = ifqmaxlen;
147
148 if (!inited) {
149 TAILQ_INIT(&ifnet);
150 inited = 1;
151 }
152
153 TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
154 ifp->if_index = ++if_index;
155 /*
156 * XXX -
157 * The old code would work if the interface passed a pre-existing
158 * chain of ifaddrs to this code. We don't trust our callers to
159 * properly initialize the tailq, however, so we no longer allow
160 * this unlikely case.
161 */
162 TAILQ_INIT(&ifp->if_addrhead);
163 TAILQ_INIT(&ifp->if_prefixhead);
164 LIST_INIT(&ifp->if_multiaddrs);
165 getmicrotime(&ifp->if_lastchange);
166 if (ifnet_addrs == 0 || if_index >= if_indexlim) {
167 unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
168 struct ifaddr **q = (struct ifaddr **)
169 _MALLOC(n, M_IFADDR, M_WAITOK);
170 bzero((caddr_t)q, n);
171 if (ifnet_addrs) {
172 bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
173 FREE((caddr_t)ifnet_addrs, M_IFADDR);
174 }
175 ifnet_addrs = (struct ifaddr **)q;
176
177 /* grow ifindex2ifnet */
178 n = if_indexlim * sizeof(struct ifaddr *);
179 q = (struct ifaddr **)_MALLOC(n, M_IFADDR, M_WAITOK);
180 bzero(q, n);
181 if (ifindex2ifnet) {
182 bcopy((caddr_t)ifindex2ifnet, q, n/2);
183 _FREE((caddr_t)ifindex2ifnet, M_IFADDR);
184 }
185 ifindex2ifnet = (struct ifnet **)q;
186 }
187
188 ifindex2ifnet[if_index] = ifp;
189
190 /*
191 * create a Link Level name for this device
192 */
193 namelen = snprintf(workbuf, sizeof(workbuf),
194 "%s%d", ifp->if_name, ifp->if_unit);
195 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
196 masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen;
197 socksize = masklen + ifp->if_addrlen;
198 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
199 if (socksize < sizeof(*sdl))
200 socksize = sizeof(*sdl);
201 socksize = ROUNDUP(socksize);
202 ifasize = sizeof(*ifa) + 2 * socksize;
203 ifa = (struct ifaddr *) _MALLOC(ifasize, M_IFADDR, M_WAITOK);
204 if (ifa) {
205 bzero((caddr_t)ifa, ifasize);
206 sdl = (struct sockaddr_dl *)(ifa + 1);
207 sdl->sdl_len = socksize;
208 sdl->sdl_family = AF_LINK;
209 bcopy(workbuf, sdl->sdl_data, namelen);
210 sdl->sdl_nlen = namelen;
211 sdl->sdl_index = ifp->if_index;
212 sdl->sdl_type = ifp->if_type;
213 ifnet_addrs[if_index - 1] = ifa;
214 ifa->ifa_ifp = ifp;
215 ifa->ifa_rtrequest = link_rtrequest;
216 ifa->ifa_addr = (struct sockaddr *)sdl;
217 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
218 ifa->ifa_netmask = (struct sockaddr *)sdl;
219 sdl->sdl_len = masklen;
220 while (namelen != 0)
221 sdl->sdl_data[--namelen] = 0xff;
222 TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
223 }
224 }
225
226 /*
227 * Locate an interface based on a complete address.
228 */
229 /*ARGSUSED*/
230 struct ifaddr *
231 ifa_ifwithaddr(addr)
232 register struct sockaddr *addr;
233 {
234 register struct ifnet *ifp;
235 register struct ifaddr *ifa;
236
237 #define equal(a1, a2) \
238 (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
239 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
240 for (ifa = ifp->if_addrhead.tqh_first; ifa;
241 ifa = ifa->ifa_link.tqe_next) {
242 if (ifa->ifa_addr->sa_family != addr->sa_family)
243 continue;
244 if (equal(addr, ifa->ifa_addr))
245 return (ifa);
246 if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
247 /* IP6 doesn't have broadcast */
248 ifa->ifa_broadaddr->sa_len != 0 &&
249 equal(ifa->ifa_broadaddr, addr))
250 return (ifa);
251 }
252 return ((struct ifaddr *)0);
253 }
254 /*
255 * Locate the point to point interface with a given destination address.
256 */
257 /*ARGSUSED*/
258 struct ifaddr *
259 ifa_ifwithdstaddr(addr)
260 register struct sockaddr *addr;
261 {
262 register struct ifnet *ifp;
263 register struct ifaddr *ifa;
264
265 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
266 if (ifp->if_flags & IFF_POINTOPOINT)
267 for (ifa = ifp->if_addrhead.tqh_first; ifa;
268 ifa = ifa->ifa_link.tqe_next) {
269 if (ifa->ifa_addr->sa_family != addr->sa_family)
270 continue;
271 if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
272 return (ifa);
273 }
274 return ((struct ifaddr *)0);
275 }
276
277 /*
278 * Find an interface on a specific network. If many, choice
279 * is most specific found.
280 */
281 struct ifaddr *
282 ifa_ifwithnet(addr)
283 struct sockaddr *addr;
284 {
285 register struct ifnet *ifp;
286 register struct ifaddr *ifa;
287 struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
288 u_int af = addr->sa_family;
289 char *addr_data = addr->sa_data, *cplim;
290
291 /*
292 * AF_LINK addresses can be looked up directly by their index number,
293 * so do that if we can.
294 */
295 if (af == AF_LINK) {
296 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
297 if (sdl->sdl_index && sdl->sdl_index <= if_index)
298 return (ifnet_addrs[sdl->sdl_index - 1]);
299 }
300
301 /*
302 * Scan though each interface, looking for ones that have
303 * addresses in this address family.
304 */
305 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
306 for (ifa = ifp->if_addrhead.tqh_first; ifa;
307 ifa = ifa->ifa_link.tqe_next) {
308 register char *cp, *cp2, *cp3;
309
310 if (ifa->ifa_addr->sa_family != af)
311 next: continue;
312 #ifndef __APPLE__
313 /* This breaks tunneling application trying to install a route with
314 * a specific subnet and the local address as the destination
315 * It's breaks binary compatibility with previous version of MacOS X
316 */
317 if (
318
319 #if INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */
320 addr->sa_family != AF_INET6 &&
321 #endif
322 ifp->if_flags & IFF_POINTOPOINT) {
323 /*
324 * This is a bit broken as it doesn't
325 * take into account that the remote end may
326 * be a single node in the network we are
327 * looking for.
328 * The trouble is that we don't know the
329 * netmask for the remote end.
330 */
331 if (ifa->ifa_dstaddr != 0
332 && equal(addr, ifa->ifa_dstaddr))
333 return (ifa);
334 } else
335 #endif /* __APPLE__*/
336 {
337 /*
338 * if we have a special address handler,
339 * then use it instead of the generic one.
340 */
341 if (ifa->ifa_claim_addr) {
342 if ((*ifa->ifa_claim_addr)(ifa, addr)) {
343 return (ifa);
344 } else {
345 continue;
346 }
347 }
348
349 /*
350 * Scan all the bits in the ifa's address.
351 * If a bit dissagrees with what we are
352 * looking for, mask it with the netmask
353 * to see if it really matters.
354 * (A byte at a time)
355 */
356 if (ifa->ifa_netmask == 0)
357 continue;
358 cp = addr_data;
359 cp2 = ifa->ifa_addr->sa_data;
360 cp3 = ifa->ifa_netmask->sa_data;
361 cplim = ifa->ifa_netmask->sa_len
362 + (char *)ifa->ifa_netmask;
363 while (cp3 < cplim)
364 if ((*cp++ ^ *cp2++) & *cp3++)
365 goto next; /* next address! */
366 /*
367 * If the netmask of what we just found
368 * is more specific than what we had before
369 * (if we had one) then remember the new one
370 * before continuing to search
371 * for an even better one.
372 */
373 if (ifa_maybe == 0 ||
374 rn_refines((caddr_t)ifa->ifa_netmask,
375 (caddr_t)ifa_maybe->ifa_netmask))
376 ifa_maybe = ifa;
377 }
378 }
379 }
380 return (ifa_maybe);
381 }
382
383 /*
384 * Find an interface address specific to an interface best matching
385 * a given address.
386 */
387 struct ifaddr *
388 ifaof_ifpforaddr(addr, ifp)
389 struct sockaddr *addr;
390 register struct ifnet *ifp;
391 {
392 register struct ifaddr *ifa;
393 register char *cp, *cp2, *cp3;
394 register char *cplim;
395 struct ifaddr *ifa_maybe = 0;
396 u_int af = addr->sa_family;
397
398 if (af >= AF_MAX)
399 return (0);
400 for (ifa = ifp->if_addrhead.tqh_first; ifa;
401 ifa = ifa->ifa_link.tqe_next) {
402 if (ifa->ifa_addr->sa_family != af)
403 continue;
404 if (ifa_maybe == 0)
405 ifa_maybe = ifa;
406 if (ifa->ifa_netmask == 0) {
407 if (equal(addr, ifa->ifa_addr) ||
408 (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
409 return (ifa);
410 continue;
411 }
412 if (ifp->if_flags & IFF_POINTOPOINT) {
413 if (equal(addr, ifa->ifa_dstaddr))
414 return (ifa);
415 } else {
416 cp = addr->sa_data;
417 cp2 = ifa->ifa_addr->sa_data;
418 cp3 = ifa->ifa_netmask->sa_data;
419 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
420 for (; cp3 < cplim; cp3++)
421 if ((*cp++ ^ *cp2++) & *cp3)
422 break;
423 if (cp3 == cplim)
424 return (ifa);
425 }
426 }
427 return (ifa_maybe);
428 }
429
430 #include <net/route.h>
431
432 /*
433 * Default action when installing a route with a Link Level gateway.
434 * Lookup an appropriate real ifa to point to.
435 * This should be moved to /sys/net/link.c eventually.
436 */
437 static void
438 link_rtrequest(cmd, rt, sa)
439 int cmd;
440 register struct rtentry *rt;
441 struct sockaddr *sa;
442 {
443 register struct ifaddr *ifa;
444 struct sockaddr *dst;
445 struct ifnet *ifp;
446
447 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
448 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
449 return;
450 ifa = ifaof_ifpforaddr(dst, ifp);
451 if (ifa) {
452 rtsetifa(rt, ifa);
453 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
454 ifa->ifa_rtrequest(cmd, rt, sa);
455 }
456 }
457
458 /*
459 * Mark an interface down and notify protocols of
460 * the transition.
461 * NOTE: must be called at splnet or eqivalent.
462 */
463 void
464 if_unroute(ifp, flag, fam)
465 register struct ifnet *ifp;
466 int flag, fam;
467 {
468 register struct ifaddr *ifa;
469
470 ifp->if_flags &= ~flag;
471 getmicrotime(&ifp->if_lastchange);
472 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
473 if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
474 pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
475 if_qflush(&ifp->if_snd);
476 rt_ifmsg(ifp);
477 }
478
479 /*
480 * Mark an interface up and notify protocols of
481 * the transition.
482 * NOTE: must be called at splnet or eqivalent.
483 */
484 void
485 if_route(ifp, flag, fam)
486 register struct ifnet *ifp;
487 int flag, fam;
488 {
489 register struct ifaddr *ifa;
490
491 ifp->if_flags |= flag;
492 getmicrotime(&ifp->if_lastchange);
493 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
494 if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
495 pfctlinput(PRC_IFUP, ifa->ifa_addr);
496 rt_ifmsg(ifp);
497
498 #if INET6
499 if (ip6_auto_on) /* Only if IPv6 is on on configured on on all ifs */
500 in6_if_up(ifp);
501 #endif
502 }
503
504 /*
505 * Mark an interface down and notify protocols of
506 * the transition.
507 * NOTE: must be called at splnet or eqivalent.
508 */
509 void
510 if_down(ifp)
511 register struct ifnet *ifp;
512 {
513
514 if_unroute(ifp, IFF_UP, AF_UNSPEC);
515 }
516
517 /*
518 * Mark an interface up and notify protocols of
519 * the transition.
520 * NOTE: must be called at splnet or eqivalent.
521 */
522 void
523 if_up(ifp)
524 register struct ifnet *ifp;
525 {
526
527 if_route(ifp, IFF_UP, AF_UNSPEC);
528 }
529
530 /*
531 * Flush an interface queue.
532 */
533 static void
534 if_qflush(ifq)
535 register struct ifqueue *ifq;
536 {
537 register struct mbuf *m, *n;
538
539 n = ifq->ifq_head;
540 while ((m = n) != 0) {
541 n = m->m_act;
542 m_freem(m);
543 }
544 ifq->ifq_head = 0;
545 ifq->ifq_tail = 0;
546 ifq->ifq_len = 0;
547 }
548
549 /*
550 * Map interface name to
551 * interface structure pointer.
552 */
553 struct ifnet *
554 ifunit(const char *name)
555 {
556 char namebuf[IFNAMSIZ + 1];
557 const char *cp;
558 struct ifnet *ifp;
559 int unit;
560 unsigned len, m;
561 char c;
562
563 len = strlen(name);
564 if (len < 2 || len > IFNAMSIZ)
565 return NULL;
566 cp = name + len - 1;
567 c = *cp;
568 if (c < '0' || c > '9')
569 return NULL; /* trailing garbage */
570 unit = 0;
571 m = 1;
572 do {
573 if (cp == name)
574 return NULL; /* no interface name */
575 unit += (c - '0') * m;
576 if (unit > 1000000)
577 return NULL; /* number is unreasonable */
578 m *= 10;
579 c = *--cp;
580 } while (c >= '0' && c <= '9');
581 len = cp - name + 1;
582 bcopy(name, namebuf, len);
583 namebuf[len] = '\0';
584 /*
585 * Now search all the interfaces for this name/number
586 */
587 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
588 if (strcmp(ifp->if_name, namebuf))
589 continue;
590 if (unit == ifp->if_unit)
591 break;
592 }
593 return (ifp);
594 }
595
596
597 /*
598 * Map interface name in a sockaddr_dl to
599 * interface structure pointer.
600 */
601 struct ifnet *
602 if_withname(sa)
603 struct sockaddr *sa;
604 {
605 char ifname[IFNAMSIZ+1];
606 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
607
608 if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) ||
609 (sdl->sdl_nlen > IFNAMSIZ) )
610 return NULL;
611
612 /*
613 * ifunit wants a null-terminated name. It may not be null-terminated
614 * in the sockaddr. We don't want to change the caller's sockaddr,
615 * and there might not be room to put the trailing null anyway, so we
616 * make a local copy that we know we can null terminate safely.
617 */
618
619 bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
620 ifname[sdl->sdl_nlen] = '\0';
621 return ifunit(ifname);
622 }
623
624
625 /*
626 * Interface ioctls.
627 */
628 int
629 ifioctl(so, cmd, data, p)
630 struct socket *so;
631 u_long cmd;
632 caddr_t data;
633 struct proc *p;
634 {
635 register struct ifnet *ifp;
636 register struct ifreq *ifr;
637 struct ifstat *ifs;
638 int error = 0;
639 short oif_flags;
640 struct kev_msg ev_msg;
641 struct net_event_data ev_data;
642
643 switch (cmd) {
644
645 case SIOCGIFCONF:
646 case OSIOCGIFCONF:
647 return (ifconf(cmd, data));
648 }
649 ifr = (struct ifreq *)data;
650 ifp = ifunit(ifr->ifr_name);
651 if (ifp == 0)
652 return (ENXIO);
653 switch (cmd) {
654
655 case SIOCGIFFLAGS:
656 ifr->ifr_flags = ifp->if_flags;
657 break;
658
659 case SIOCGIFMETRIC:
660 ifr->ifr_metric = ifp->if_metric;
661 break;
662
663 case SIOCGIFMTU:
664 ifr->ifr_mtu = ifp->if_mtu;
665 break;
666
667 case SIOCGIFPHYS:
668 ifr->ifr_phys = ifp->if_physical;
669 break;
670
671 case SIOCSIFFLAGS:
672 error = suser(p->p_ucred, &p->p_acflag);
673 if (error)
674 return (error);
675 #ifndef __APPLE__
676 if (ifp->if_flags & IFF_SMART) {
677 /* Smart drivers twiddle their own routes */
678 } else
679 #endif
680 if (ifp->if_flags & IFF_UP &&
681 (ifr->ifr_flags & IFF_UP) == 0) {
682 int s = splimp();
683 if_down(ifp);
684 splx(s);
685 } else if (ifr->ifr_flags & IFF_UP &&
686 (ifp->if_flags & IFF_UP) == 0) {
687 int s = splimp();
688 if_up(ifp);
689 splx(s);
690 }
691 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
692 (ifr->ifr_flags &~ IFF_CANTCHANGE);
693
694 error = dlil_ioctl(so->so_proto->pr_domain->dom_family,
695 ifp, cmd, (caddr_t) data);
696
697 if (error == 0) {
698 ev_msg.vendor_code = KEV_VENDOR_APPLE;
699 ev_msg.kev_class = KEV_NETWORK_CLASS;
700 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
701
702 ev_msg.event_code = KEV_DL_SIFFLAGS;
703 strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
704 ev_data.if_family = ifp->if_family;
705 ev_data.if_unit = (unsigned long) ifp->if_unit;
706 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
707 ev_msg.dv[0].data_ptr = &ev_data;
708 ev_msg.dv[1].data_length = 0;
709 kev_post_msg(&ev_msg);
710 }
711 getmicrotime(&ifp->if_lastchange);
712 break;
713
714 case SIOCSIFMETRIC:
715 error = suser(p->p_ucred, &p->p_acflag);
716 if (error)
717 return (error);
718 ifp->if_metric = ifr->ifr_metric;
719
720
721 ev_msg.vendor_code = KEV_VENDOR_APPLE;
722 ev_msg.kev_class = KEV_NETWORK_CLASS;
723 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
724
725 ev_msg.event_code = KEV_DL_SIFMETRICS;
726 strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
727 ev_data.if_family = ifp->if_family;
728 ev_data.if_unit = (unsigned long) ifp->if_unit;
729 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
730 ev_msg.dv[0].data_ptr = &ev_data;
731
732 ev_msg.dv[1].data_length = 0;
733 kev_post_msg(&ev_msg);
734
735 getmicrotime(&ifp->if_lastchange);
736 break;
737
738 case SIOCSIFPHYS:
739 error = suser(p->p_ucred, &p->p_acflag);
740 if (error)
741 return error;
742
743 error = dlil_ioctl(so->so_proto->pr_domain->dom_family,
744 ifp, cmd, (caddr_t) data);
745
746 if (error == 0) {
747 ev_msg.vendor_code = KEV_VENDOR_APPLE;
748 ev_msg.kev_class = KEV_NETWORK_CLASS;
749 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
750
751 ev_msg.event_code = KEV_DL_SIFPHYS;
752 strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
753 ev_data.if_family = ifp->if_family;
754 ev_data.if_unit = (unsigned long) ifp->if_unit;
755 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
756 ev_msg.dv[0].data_ptr = &ev_data;
757 ev_msg.dv[1].data_length = 0;
758 kev_post_msg(&ev_msg);
759
760 getmicrotime(&ifp->if_lastchange);
761 }
762 return(error);
763
764 case SIOCSIFMTU:
765 {
766 u_long oldmtu = ifp->if_mtu;
767
768 error = suser(p->p_ucred, &p->p_acflag);
769 if (error)
770 return (error);
771 if (ifp->if_ioctl == NULL)
772 return (EOPNOTSUPP);
773 if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
774 return (EINVAL);
775
776 error = dlil_ioctl(so->so_proto->pr_domain->dom_family,
777 ifp, cmd, (caddr_t) data);
778
779 if (error == 0) {
780 ev_msg.vendor_code = KEV_VENDOR_APPLE;
781 ev_msg.kev_class = KEV_NETWORK_CLASS;
782 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
783
784 ev_msg.event_code = KEV_DL_SIFMTU;
785 strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
786 ev_data.if_family = ifp->if_family;
787 ev_data.if_unit = (unsigned long) ifp->if_unit;
788 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
789 ev_msg.dv[0].data_ptr = &ev_data;
790 ev_msg.dv[1].data_length = 0;
791 kev_post_msg(&ev_msg);
792
793 getmicrotime(&ifp->if_lastchange);
794 rt_ifmsg(ifp);
795 }
796 /*
797 * If the link MTU changed, do network layer specific procedure.
798 */
799 if (ifp->if_mtu != oldmtu) {
800 #if INET6
801 nd6_setmtu(ifp);
802 #endif
803 }
804 return (error);
805 }
806
807 case SIOCADDMULTI:
808 case SIOCDELMULTI:
809 error = suser(p->p_ucred, &p->p_acflag);
810 if (error)
811 return (error);
812
813 /* Don't allow group membership on non-multicast interfaces. */
814 if ((ifp->if_flags & IFF_MULTICAST) == 0)
815 return EOPNOTSUPP;
816
817 #ifndef __APPLE__
818 /* Don't let users screw up protocols' entries. */
819 if (ifr->ifr_addr.sa_family != AF_LINK)
820 return EINVAL;
821 #endif
822
823 if (cmd == SIOCADDMULTI) {
824 struct ifmultiaddr *ifma;
825 error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
826 ev_msg.event_code = KEV_DL_ADDMULTI;
827 } else {
828 error = if_delmulti(ifp, &ifr->ifr_addr);
829 ev_msg.event_code = KEV_DL_DELMULTI;
830 }
831 if (error == 0) {
832 ev_msg.vendor_code = KEV_VENDOR_APPLE;
833 ev_msg.kev_class = KEV_NETWORK_CLASS;
834 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
835 strncpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
836
837 ev_data.if_family = ifp->if_family;
838 ev_data.if_unit = (unsigned long) ifp->if_unit;
839 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
840 ev_msg.dv[0].data_ptr = &ev_data;
841 ev_msg.dv[1].data_length = 0;
842 kev_post_msg(&ev_msg);
843
844 getmicrotime(&ifp->if_lastchange);
845 }
846 return error;
847
848 case SIOCSIFPHYADDR:
849 case SIOCDIFPHYADDR:
850 #ifdef INET6
851 case SIOCSIFPHYADDR_IN6:
852 #endif
853 case SIOCSLIFPHYADDR:
854 case SIOCSIFMEDIA:
855 case SIOCSIFGENERIC:
856 case SIOCSIFLLADDR:
857 error = suser(p->p_ucred, &p->p_acflag);
858 if (error)
859 return (error);
860
861 error = dlil_ioctl(so->so_proto->pr_domain->dom_family,
862 ifp, cmd, (caddr_t) data);
863
864 if (error == 0)
865 getmicrotime(&ifp->if_lastchange);
866 return error;
867
868 case SIOCGIFSTATUS:
869 ifs = (struct ifstat *)data;
870 ifs->ascii[0] = '\0';
871
872 case SIOCGIFPSRCADDR:
873 case SIOCGIFPDSTADDR:
874 case SIOCGLIFPHYADDR:
875 case SIOCGIFMEDIA:
876 case SIOCGIFGENERIC:
877
878 return dlil_ioctl(so->so_proto->pr_domain->dom_family,
879 ifp, cmd, (caddr_t) data);
880
881 default:
882 oif_flags = ifp->if_flags;
883 if (so->so_proto == 0)
884 return (EOPNOTSUPP);
885 #if !COMPAT_43
886 return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
887 data,
888 ifp, p));
889 #else
890 {
891 int ocmd = cmd;
892
893 switch (cmd) {
894
895 case SIOCSIFDSTADDR:
896 case SIOCSIFADDR:
897 case SIOCSIFBRDADDR:
898 case SIOCSIFNETMASK:
899 #if BYTE_ORDER != BIG_ENDIAN
900 if (ifr->ifr_addr.sa_family == 0 &&
901 ifr->ifr_addr.sa_len < 16) {
902 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
903 ifr->ifr_addr.sa_len = 16;
904 }
905 #else
906 if (ifr->ifr_addr.sa_len == 0)
907 ifr->ifr_addr.sa_len = 16;
908 #endif
909 break;
910
911 case OSIOCGIFADDR:
912 cmd = SIOCGIFADDR;
913 break;
914
915 case OSIOCGIFDSTADDR:
916 cmd = SIOCGIFDSTADDR;
917 break;
918
919 case OSIOCGIFBRDADDR:
920 cmd = SIOCGIFBRDADDR;
921 break;
922
923 case OSIOCGIFNETMASK:
924 cmd = SIOCGIFNETMASK;
925 }
926 error = ((*so->so_proto->pr_usrreqs->pru_control)(so,
927 cmd,
928 data,
929 ifp, p));
930 switch (ocmd) {
931
932 case OSIOCGIFADDR:
933 case OSIOCGIFDSTADDR:
934 case OSIOCGIFBRDADDR:
935 case OSIOCGIFNETMASK:
936 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
937
938 }
939 }
940 #endif /* COMPAT_43 */
941
942 if (error == EOPNOTSUPP)
943 error = dlil_ioctl(so->so_proto->pr_domain->dom_family,
944 ifp, cmd, (caddr_t) data);
945
946 return (error);
947 }
948 return (0);
949 }
950
951 /*
952 * Set/clear promiscuous mode on interface ifp based on the truth value
953 * of pswitch. The calls are reference counted so that only the first
954 * "on" request actually has an effect, as does the final "off" request.
955 * Results are undefined if the "off" and "on" requests are not matched.
956 */
957 int
958 ifpromisc(ifp, pswitch)
959 struct ifnet *ifp;
960 int pswitch;
961 {
962 struct ifreq ifr;
963 int error;
964 int oldflags;
965
966 oldflags = ifp->if_flags;
967 if (pswitch) {
968 /*
969 * If the device is not configured up, we cannot put it in
970 * promiscuous mode.
971 */
972 if ((ifp->if_flags & IFF_UP) == 0)
973 return (ENETDOWN);
974 if (ifp->if_pcount++ != 0)
975 return (0);
976 ifp->if_flags |= IFF_PROMISC;
977 log(LOG_INFO, "%s%d: promiscuous mode enabled\n",
978 ifp->if_name, ifp->if_unit);
979 } else {
980 if (--ifp->if_pcount > 0)
981 return (0);
982 ifp->if_flags &= ~IFF_PROMISC;
983 log(LOG_INFO, "%s%d: promiscuous mode disabled\n",
984 ifp->if_name, ifp->if_unit);
985 }
986 ifr.ifr_flags = ifp->if_flags;
987 error = dlil_ioctl(0, ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
988 if (error == 0)
989 rt_ifmsg(ifp);
990 else
991 ifp->if_flags = oldflags;
992 return error;
993 }
994
995 /*
996 * Return interface configuration
997 * of system. List may be used
998 * in later ioctl's (above) to get
999 * other information.
1000 */
1001 /*ARGSUSED*/
1002 static int
1003 ifconf(cmd, data)
1004 u_long cmd;
1005 caddr_t data;
1006 {
1007 register struct ifconf *ifc = (struct ifconf *)data;
1008 register struct ifnet *ifp = ifnet.tqh_first;
1009 register struct ifaddr *ifa;
1010 struct ifreq ifr, *ifrp;
1011 int space = ifc->ifc_len, error = 0;
1012
1013 ifrp = ifc->ifc_req;
1014 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_link.tqe_next) {
1015 char workbuf[64];
1016 int ifnlen, addrs;
1017
1018 ifnlen = snprintf(workbuf, sizeof(workbuf),
1019 "%s%d", ifp->if_name, ifp->if_unit);
1020 if(ifnlen + 1 > sizeof ifr.ifr_name) {
1021 error = ENAMETOOLONG;
1022 break;
1023 } else {
1024 strcpy(ifr.ifr_name, workbuf);
1025 }
1026
1027 addrs = 0;
1028 ifa = ifp->if_addrhead.tqh_first;
1029 for ( ; space > sizeof (ifr) && ifa;
1030 ifa = ifa->ifa_link.tqe_next) {
1031 register struct sockaddr *sa = ifa->ifa_addr;
1032 #ifndef __APPLE__
1033 if (curproc->p_prison && prison_if(curproc, sa))
1034 continue;
1035 #endif
1036 addrs++;
1037 #ifdef COMPAT_43
1038 if (cmd == OSIOCGIFCONF) {
1039 struct osockaddr *osa =
1040 (struct osockaddr *)&ifr.ifr_addr;
1041 ifr.ifr_addr = *sa;
1042 osa->sa_family = sa->sa_family;
1043 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
1044 sizeof (ifr));
1045 ifrp++;
1046 } else
1047 #endif
1048 if (sa->sa_len <= sizeof(*sa)) {
1049 ifr.ifr_addr = *sa;
1050 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
1051 sizeof (ifr));
1052 ifrp++;
1053 } else {
1054 if (space < sizeof (ifr) + sa->sa_len -
1055 sizeof(*sa))
1056 break;
1057 space -= sa->sa_len - sizeof(*sa);
1058 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
1059 sizeof (ifr.ifr_name));
1060 if (error == 0)
1061 error = copyout((caddr_t)sa,
1062 (caddr_t)&ifrp->ifr_addr, sa->sa_len);
1063 ifrp = (struct ifreq *)
1064 (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
1065 }
1066 if (error)
1067 break;
1068 space -= sizeof (ifr);
1069 }
1070 if (error)
1071 break;
1072 if (!addrs) {
1073 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
1074 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
1075 sizeof (ifr));
1076 if (error)
1077 break;
1078 space -= sizeof (ifr);
1079 ifrp++;
1080 }
1081 }
1082 ifc->ifc_len -= space;
1083 return (error);
1084 }
1085
1086 /*
1087 * Just like if_promisc(), but for all-multicast-reception mode.
1088 */
1089 int
1090 if_allmulti(ifp, onswitch)
1091 struct ifnet *ifp;
1092 int onswitch;
1093 {
1094 int error = 0;
1095 int s = splimp();
1096
1097 if (onswitch) {
1098 if (ifp->if_amcount++ == 0) {
1099 ifp->if_flags |= IFF_ALLMULTI;
1100 error = dlil_ioctl(0, ifp, SIOCSIFFLAGS, (caddr_t) 0);
1101 }
1102 } else {
1103 if (ifp->if_amcount > 1) {
1104 ifp->if_amcount--;
1105 } else {
1106 ifp->if_amcount = 0;
1107 ifp->if_flags &= ~IFF_ALLMULTI;
1108 error = dlil_ioctl(0, ifp, SIOCSIFFLAGS, (caddr_t) 0);
1109 }
1110 }
1111 splx(s);
1112
1113 if (error == 0)
1114 rt_ifmsg(ifp);
1115 return error;
1116 }
1117
1118 /*
1119 * Add a multicast listenership to the interface in question.
1120 * The link layer provides a routine which converts
1121 */
1122 int
1123 if_addmulti(ifp, sa, retifma)
1124 struct ifnet *ifp; /* interface to manipulate */
1125 struct sockaddr *sa; /* address to add */
1126 struct ifmultiaddr **retifma;
1127 {
1128 struct sockaddr *llsa = 0;
1129 struct sockaddr *dupsa;
1130 int error, s;
1131 struct ifmultiaddr *ifma;
1132 struct rslvmulti_req rsreq;
1133
1134 /*
1135 * If the matching multicast address already exists
1136 * then don't add a new one, just add a reference
1137 */
1138 for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1139 ifma = ifma->ifma_link.le_next) {
1140 if (equal(sa, ifma->ifma_addr)) {
1141 ifma->ifma_refcount++;
1142 if (retifma)
1143 *retifma = ifma;
1144 return 0;
1145 }
1146 }
1147
1148 /*
1149 * Give the link layer a chance to accept/reject it, and also
1150 * find out which AF_LINK address this maps to, if it isn't one
1151 * already.
1152 */
1153 rsreq.sa = sa;
1154 rsreq.llsa = &llsa;
1155
1156 error = dlil_ioctl(sa->sa_family, ifp, SIOCRSLVMULTI, (caddr_t) &rsreq);
1157
1158 /* to be similar to FreeBSD */
1159 if (error == EOPNOTSUPP)
1160 error = 0;
1161
1162 if (error)
1163 return error;
1164
1165 MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
1166 MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
1167 bcopy(sa, dupsa, sa->sa_len);
1168
1169 ifma->ifma_addr = dupsa;
1170 ifma->ifma_lladdr = llsa;
1171 ifma->ifma_ifp = ifp;
1172 ifma->ifma_refcount = 1;
1173 ifma->ifma_protospec = 0;
1174 rt_newmaddrmsg(RTM_NEWMADDR, ifma);
1175
1176 /*
1177 * Some network interfaces can scan the address list at
1178 * interrupt time; lock them out.
1179 */
1180 s = splimp();
1181 LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
1182 splx(s);
1183 if (retifma)
1184 *retifma = ifma;
1185
1186 if (llsa != 0) {
1187 for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1188 ifma = ifma->ifma_link.le_next) {
1189 if (equal(ifma->ifma_addr, llsa))
1190 break;
1191 }
1192 if (ifma) {
1193 ifma->ifma_refcount++;
1194 } else {
1195 MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
1196 M_IFMADDR, M_WAITOK);
1197 MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
1198 M_IFMADDR, M_WAITOK);
1199 bcopy(llsa, dupsa, llsa->sa_len);
1200 ifma->ifma_addr = dupsa;
1201 ifma->ifma_lladdr = 0;
1202 ifma->ifma_ifp = ifp;
1203 ifma->ifma_refcount = 1;
1204 s = splimp();
1205 LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
1206 splx(s);
1207 }
1208 }
1209 /*
1210 * We are certain we have added something, so call down to the
1211 * interface to let them know about it.
1212 */
1213 s = splimp();
1214 dlil_ioctl(0, ifp, SIOCADDMULTI, (caddr_t) 0);
1215 splx(s);
1216
1217 return 0;
1218 }
1219
1220 /*
1221 * Remove a reference to a multicast address on this interface. Yell
1222 * if the request does not match an existing membership.
1223 */
1224 int
1225 if_delmulti(ifp, sa)
1226 struct ifnet *ifp;
1227 struct sockaddr *sa;
1228 {
1229 struct ifmultiaddr *ifma;
1230 int s;
1231
1232 for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1233 ifma = ifma->ifma_link.le_next)
1234 if (equal(sa, ifma->ifma_addr))
1235 break;
1236 if (ifma == 0)
1237 return ENOENT;
1238
1239 if (ifma->ifma_refcount > 1) {
1240 ifma->ifma_refcount--;
1241 return 0;
1242 }
1243
1244 rt_newmaddrmsg(RTM_DELMADDR, ifma);
1245 sa = ifma->ifma_lladdr;
1246 s = splimp();
1247 LIST_REMOVE(ifma, ifma_link);
1248 /*
1249 * Make sure the interface driver is notified
1250 * in the case of a link layer mcast group being left.
1251 */
1252 if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0)
1253 dlil_ioctl(0, ifp, SIOCDELMULTI, 0);
1254 splx(s);
1255 FREE(ifma->ifma_addr, M_IFMADDR);
1256 FREE(ifma, M_IFMADDR);
1257 if (sa == 0)
1258 return 0;
1259
1260 /*
1261 * Now look for the link-layer address which corresponds to
1262 * this network address. It had been squirreled away in
1263 * ifma->ifma_lladdr for this purpose (so we don't have
1264 * to call SIOCRSLVMULTI again), and we saved that
1265 * value in sa above. If some nasty deleted the
1266 * link-layer address out from underneath us, we can deal because
1267 * the address we stored was is not the same as the one which was
1268 * in the record for the link-layer address. (So we don't complain
1269 * in that case.)
1270 */
1271 for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1272 ifma = ifma->ifma_link.le_next)
1273 if (equal(sa, ifma->ifma_addr))
1274 break;
1275 if (ifma == 0)
1276 return 0;
1277
1278 if (ifma->ifma_refcount > 1) {
1279 ifma->ifma_refcount--;
1280 return 0;
1281 }
1282
1283 s = splimp();
1284 LIST_REMOVE(ifma, ifma_link);
1285 dlil_ioctl(0, ifp, SIOCDELMULTI, (caddr_t) 0);
1286 splx(s);
1287 FREE(ifma->ifma_addr, M_IFMADDR);
1288 FREE(sa, M_IFMADDR);
1289 FREE(ifma, M_IFMADDR);
1290
1291 return 0;
1292 }
1293
1294
1295 /*
1296 * We don't use if_setlladdr, our interfaces are responsible for
1297 * handling the SIOCSIFLLADDR ioctl.
1298 */
1299 #ifndef __APPLE__
1300 int
1301 if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
1302 {
1303 ...
1304 }
1305 #endif
1306
1307 struct ifmultiaddr *
1308 ifmaof_ifpforaddr(sa, ifp)
1309 struct sockaddr *sa;
1310 struct ifnet *ifp;
1311 {
1312 struct ifmultiaddr *ifma;
1313
1314 for (ifma = ifp->if_multiaddrs.lh_first; ifma;
1315 ifma = ifma->ifma_link.le_next)
1316 if (equal(ifma->ifma_addr, sa))
1317 break;
1318
1319 return ifma;
1320 }
1321
1322 SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
1323 SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
1324
1325
1326 /*
1327 * Shutdown all network activity. Used boot() when halting
1328 * system.
1329 */
1330 int if_down_all(void)
1331 {
1332 struct ifnet *ifp;
1333 int s;
1334
1335 s = splnet();
1336 TAILQ_FOREACH(ifp, &ifnet, if_link)
1337 if_down(ifp);
1338
1339 splx(s);
1340 return(0); /* Sheesh */
1341 }
1342
1343 /*
1344 * Delete Routes for a Network Interface
1345 *
1346 * Called for each routing entry via the rnh->rnh_walktree() call above
1347 * to delete all route entries referencing a detaching network interface.
1348 *
1349 * Arguments:
1350 * rn pointer to node in the routing table
1351 * arg argument passed to rnh->rnh_walktree() - detaching interface
1352 *
1353 * Returns:
1354 * 0 successful
1355 * errno failed - reason indicated
1356 *
1357 */
1358 static int
1359 if_rtdel(rn, arg)
1360 struct radix_node *rn;
1361 void *arg;
1362 {
1363 struct rtentry *rt = (struct rtentry *)rn;
1364 struct ifnet *ifp = arg;
1365 int err;
1366
1367 if (rt != NULL && rt->rt_ifp == ifp) {
1368
1369 /*
1370 * Protect (sorta) against walktree recursion problems
1371 * with cloned routes
1372 */
1373 if ((rt->rt_flags & RTF_UP) == 0)
1374 return (0);
1375
1376 err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
1377 rt_mask(rt), rt->rt_flags,
1378 (struct rtentry **) NULL);
1379 if (err) {
1380 log(LOG_WARNING, "if_rtdel: error %d\n", err);
1381 }
1382 }
1383
1384 return (0);
1385 }
1386
1387 /*
1388 * Removes routing table reference to a given interfacei
1389 * for a given protocol family
1390 */
1391
1392 void if_rtproto_del(struct ifnet *ifp, int protocol)
1393 {
1394
1395 struct radix_node_head *rnh;
1396
1397 if (((rnh = rt_tables[protocol]) != NULL) && (ifp != NULL))
1398 (void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
1399 }