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