Home | History | Annotate | Line # | Download | only in net
if.c revision 1.50
      1 /*	$NetBSD: if.c,v 1.50 1999/07/09 23:41:16 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the project nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1980, 1986, 1993
     34  *	The Regents of the University of California.  All rights reserved.
     35  *
     36  * Redistribution and use in source and binary forms, with or without
     37  * modification, are permitted provided that the following conditions
     38  * are met:
     39  * 1. Redistributions of source code must retain the above copyright
     40  *    notice, this list of conditions and the following disclaimer.
     41  * 2. Redistributions in binary form must reproduce the above copyright
     42  *    notice, this list of conditions and the following disclaimer in the
     43  *    documentation and/or other materials provided with the distribution.
     44  * 3. All advertising materials mentioning features or use of this software
     45  *    must display the following acknowledgement:
     46  *	This product includes software developed by the University of
     47  *	California, Berkeley and its contributors.
     48  * 4. Neither the name of the University nor the names of its contributors
     49  *    may be used to endorse or promote products derived from this software
     50  *    without specific prior written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     62  * SUCH DAMAGE.
     63  *
     64  *	@(#)if.c	8.5 (Berkeley) 1/9/95
     65  */
     66 
     67 #include "opt_inet.h"
     68 
     69 #include "opt_compat_linux.h"
     70 #include "opt_compat_svr4.h"
     71 #include "opt_compat_43.h"
     72 
     73 #include <sys/param.h>
     74 #include <sys/mbuf.h>
     75 #include <sys/systm.h>
     76 #include <sys/proc.h>
     77 #include <sys/socket.h>
     78 #include <sys/socketvar.h>
     79 #include <sys/protosw.h>
     80 #include <sys/kernel.h>
     81 #include <sys/ioctl.h>
     82 
     83 #include <net/if.h>
     84 #include <net/if_dl.h>
     85 #include <net/if_types.h>
     86 #include <net/radix.h>
     87 
     88 #ifdef INET6
     89 /*XXX*/
     90 #include <netinet/in.h>
     91 #endif
     92 
     93 int	ifqmaxlen = IFQ_MAXLEN;
     94 void	if_slowtimo __P((void *arg));
     95 
     96 #ifdef INET6
     97 /*
     98  * XXX: declare here to avoid to include many inet6 related files..
     99  * should be more generalized?
    100  */
    101 extern void nd6_setmtu __P((struct ifnet *));
    102 #endif
    103 
    104 /*
    105  * Network interface utility routines.
    106  *
    107  * Routines with ifa_ifwith* names take sockaddr *'s as
    108  * parameters.
    109  */
    110 void
    111 ifinit()
    112 {
    113 
    114 	if_slowtimo(NULL);
    115 }
    116 
    117 int if_index = 0;
    118 struct ifaddr **ifnet_addrs = NULL;
    119 struct ifnet **ifindex2ifnet = NULL;
    120 
    121 /*
    122  * Attach an interface to the
    123  * list of "active" interfaces.
    124  */
    125 void
    126 if_attach(ifp)
    127 	struct ifnet *ifp;
    128 {
    129 	unsigned socksize, ifasize;
    130 	int namelen, masklen;
    131 	register struct sockaddr_dl *sdl;
    132 	register struct ifaddr *ifa;
    133 	static size_t if_indexlim = 8;
    134 
    135 	if (if_index == 0)
    136 		TAILQ_INIT(&ifnet);
    137 	TAILQ_INIT(&ifp->if_addrlist);
    138 	TAILQ_INSERT_TAIL(&ifnet, ifp, if_list);
    139 	ifp->if_index = ++if_index;
    140 
    141 	/*
    142 	 * We have some arrays that should be indexed by if_index.
    143 	 * since if_index will grow dynamically, they should grow too.
    144 	 *	struct ifadd **ifnet_addrs
    145 	 *	struct ifnet **ifindex2ifnet
    146 	 */
    147 	if (ifnet_addrs == 0 || ifindex2ifnet == 0 || if_index >= if_indexlim) {
    148 		size_t n;
    149 		caddr_t q;
    150 
    151 		while (if_index >= if_indexlim)
    152 			if_indexlim <<= 1;
    153 
    154 		/* grow ifnet_addrs */
    155 		n = if_indexlim * sizeof(ifa);
    156 		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
    157 		bzero(q, n);
    158 		if (ifnet_addrs) {
    159 			bcopy((caddr_t)ifnet_addrs, q, n/2);
    160 			free((caddr_t)ifnet_addrs, M_IFADDR);
    161 		}
    162 		ifnet_addrs = (struct ifaddr **)q;
    163 
    164 		/* grow ifindex2ifnet */
    165 		n = if_indexlim * sizeof(struct ifnet *);
    166 		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
    167 		bzero(q, n);
    168 		if (ifindex2ifnet) {
    169 			bcopy((caddr_t)ifindex2ifnet, q, n/2);
    170 			free((caddr_t)ifindex2ifnet, M_IFADDR);
    171 		}
    172 		ifindex2ifnet = (struct ifnet **)q;
    173 	}
    174 
    175 	ifindex2ifnet[if_index] = ifp;
    176 
    177 	/*
    178 	 * create a Link Level name for this device
    179 	 */
    180 	namelen = strlen(ifp->if_xname);
    181 	masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + namelen;
    182 	socksize = masklen + ifp->if_addrlen;
    183 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
    184 	if (socksize < sizeof(*sdl))
    185 		socksize = sizeof(*sdl);
    186 	socksize = ROUNDUP(socksize);
    187 	ifasize = sizeof(*ifa) + 2 * socksize;
    188 	ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
    189 	bzero((caddr_t)ifa, ifasize);
    190 	sdl = (struct sockaddr_dl *)(ifa + 1);
    191 	sdl->sdl_len = socksize;
    192 	sdl->sdl_family = AF_LINK;
    193 	bcopy(ifp->if_xname, sdl->sdl_data, namelen);
    194 	sdl->sdl_nlen = namelen;
    195 	sdl->sdl_index = ifp->if_index;
    196 	sdl->sdl_type = ifp->if_type;
    197 	ifnet_addrs[if_index] = ifa;
    198 	ifa->ifa_ifp = ifp;
    199 	ifa->ifa_rtrequest = link_rtrequest;
    200 	TAILQ_INSERT_HEAD(&ifp->if_addrlist, ifa, ifa_list);
    201 	ifa->ifa_addr = (struct sockaddr *)sdl;
    202 	ifp->if_sadl = sdl;
    203 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
    204 	ifa->ifa_netmask = (struct sockaddr *)sdl;
    205 	sdl->sdl_len = masklen;
    206 	while (namelen != 0)
    207 		sdl->sdl_data[--namelen] = 0xff;
    208 	if (ifp->if_snd.ifq_maxlen == 0)
    209 	    ifp->if_snd.ifq_maxlen = ifqmaxlen;
    210 	ifp->if_broadcastaddr = 0; /* reliably crash if used uninitialized */
    211 }
    212 /*
    213  * Locate an interface based on a complete address.
    214  */
    215 /*ARGSUSED*/
    216 struct ifaddr *
    217 ifa_ifwithaddr(addr)
    218 	register struct sockaddr *addr;
    219 {
    220 	register struct ifnet *ifp;
    221 	register struct ifaddr *ifa;
    222 
    223 #define	equal(a1, a2) \
    224   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
    225 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    226 	    for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    227 		if (ifa->ifa_addr->sa_family != addr->sa_family)
    228 			continue;
    229 		if (equal(addr, ifa->ifa_addr))
    230 			return (ifa);
    231 		if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
    232 		    /* IP6 doesn't have broadcast */
    233 		    ifa->ifa_broadaddr->sa_len != 0 &&
    234 		    equal(ifa->ifa_broadaddr, addr))
    235 			return (ifa);
    236 	}
    237 	return ((struct ifaddr *)0);
    238 }
    239 
    240 /*
    241  * Locate the point to point interface with a given destination address.
    242  */
    243 /*ARGSUSED*/
    244 struct ifaddr *
    245 ifa_ifwithdstaddr(addr)
    246 	register struct sockaddr *addr;
    247 {
    248 	register struct ifnet *ifp;
    249 	register struct ifaddr *ifa;
    250 
    251 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    252 	    if (ifp->if_flags & IFF_POINTOPOINT)
    253 		for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    254 			if (ifa->ifa_addr->sa_family != addr->sa_family ||
    255 			    ifa->ifa_dstaddr == NULL)
    256 				continue;
    257 			if (equal(addr, ifa->ifa_dstaddr))
    258 				return (ifa);
    259 	}
    260 	return ((struct ifaddr *)0);
    261 }
    262 
    263 /*
    264  * Find an interface on a specific network.  If many, choice
    265  * is most specific found.
    266  */
    267 struct ifaddr *
    268 ifa_ifwithnet(addr)
    269 	struct sockaddr *addr;
    270 {
    271 	register struct ifnet *ifp;
    272 	register struct ifaddr *ifa;
    273 	struct ifaddr *ifa_maybe = 0;
    274 	u_int af = addr->sa_family;
    275 	char *addr_data = addr->sa_data, *cplim;
    276 
    277 	if (af == AF_LINK) {
    278 	    register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
    279 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
    280 		return (ifnet_addrs[sdl->sdl_index]);
    281 	}
    282 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    283 		for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    284 			register char *cp, *cp2, *cp3;
    285 
    286 			if (ifa->ifa_addr->sa_family != af ||
    287 			    ifa->ifa_netmask == 0)
    288 				next: continue;
    289 			cp = addr_data;
    290 			cp2 = ifa->ifa_addr->sa_data;
    291 			cp3 = ifa->ifa_netmask->sa_data;
    292 			cplim = (char *)ifa->ifa_netmask +
    293 				ifa->ifa_netmask->sa_len;
    294 			while (cp3 < cplim)
    295 				if ((*cp++ ^ *cp2++) & *cp3++)
    296 				    /* want to continue for() loop */
    297 					goto next;
    298 			if (ifa_maybe == 0 ||
    299 			    rn_refines((caddr_t)ifa->ifa_netmask,
    300 			    (caddr_t)ifa_maybe->ifa_netmask))
    301 				ifa_maybe = ifa;
    302 		}
    303 	return (ifa_maybe);
    304 }
    305 /*
    306  * Find the interface of the addresss.
    307  */
    308 struct ifaddr *
    309 ifa_ifwithladdr(addr)
    310 	struct sockaddr *addr;
    311 {
    312 	struct ifaddr *ia;
    313 
    314 	if ((ia = ifa_ifwithaddr(addr)) || (ia = ifa_ifwithdstaddr(addr))
    315 	    || (ia = ifa_ifwithnet(addr)))
    316 		return (ia);
    317 	return (NULL);
    318 }
    319 
    320 /*
    321  * Find an interface using a specific address family
    322  */
    323 struct ifaddr *
    324 ifa_ifwithaf(af)
    325 	register int af;
    326 {
    327 	register struct ifnet *ifp;
    328 	register struct ifaddr *ifa;
    329 
    330 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    331 		for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next)
    332 			if (ifa->ifa_addr->sa_family == af)
    333 				return (ifa);
    334 	return ((struct ifaddr *)0);
    335 }
    336 
    337 /*
    338  * Find an interface address specific to an interface best matching
    339  * a given address.
    340  */
    341 struct ifaddr *
    342 ifaof_ifpforaddr(addr, ifp)
    343 	struct sockaddr *addr;
    344 	register struct ifnet *ifp;
    345 {
    346 	register struct ifaddr *ifa;
    347 	register char *cp, *cp2, *cp3;
    348 	register char *cplim;
    349 	struct ifaddr *ifa_maybe = 0;
    350 	u_int af = addr->sa_family;
    351 
    352 	if (af >= AF_MAX)
    353 		return (0);
    354 	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    355 		if (ifa->ifa_addr->sa_family != af)
    356 			continue;
    357 		ifa_maybe = ifa;
    358 		if (ifa->ifa_netmask == 0) {
    359 			if (equal(addr, ifa->ifa_addr) ||
    360 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
    361 				return (ifa);
    362 			continue;
    363 		}
    364 		cp = addr->sa_data;
    365 		cp2 = ifa->ifa_addr->sa_data;
    366 		cp3 = ifa->ifa_netmask->sa_data;
    367 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
    368 		for (; cp3 < cplim; cp3++)
    369 			if ((*cp++ ^ *cp2++) & *cp3)
    370 				break;
    371 		if (cp3 == cplim)
    372 			return (ifa);
    373 	}
    374 	return (ifa_maybe);
    375 }
    376 
    377 #include <net/route.h>
    378 
    379 /*
    380  * Default action when installing a route with a Link Level gateway.
    381  * Lookup an appropriate real ifa to point to.
    382  * This should be moved to /sys/net/link.c eventually.
    383  */
    384 void
    385 link_rtrequest(cmd, rt, sa)
    386 	int cmd;
    387 	register struct rtentry *rt;
    388 	struct sockaddr *sa;
    389 {
    390 	register struct ifaddr *ifa;
    391 	struct sockaddr *dst;
    392 	struct ifnet *ifp;
    393 
    394 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
    395 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
    396 		return;
    397 	if ((ifa = ifaof_ifpforaddr(dst, ifp)) != NULL) {
    398 		IFAFREE(rt->rt_ifa);
    399 		rt->rt_ifa = ifa;
    400 		ifa->ifa_refcnt++;
    401 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
    402 			ifa->ifa_rtrequest(cmd, rt, sa);
    403 	}
    404 }
    405 
    406 /*
    407  * Mark an interface down and notify protocols of
    408  * the transition.
    409  * NOTE: must be called at splsoftnet or equivalent.
    410  */
    411 void
    412 if_down(ifp)
    413 	register struct ifnet *ifp;
    414 {
    415 	register struct ifaddr *ifa;
    416 
    417 	ifp->if_flags &= ~IFF_UP;
    418 	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next)
    419 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
    420 	if_qflush(&ifp->if_snd);
    421 	rt_ifmsg(ifp);
    422 }
    423 
    424 /*
    425  * Mark an interface up and notify protocols of
    426  * the transition.
    427  * NOTE: must be called at splsoftnet or equivalent.
    428  */
    429 void
    430 if_up(ifp)
    431 	register struct ifnet *ifp;
    432 {
    433 #ifdef notyet
    434 	register struct ifaddr *ifa;
    435 #endif
    436 
    437 	ifp->if_flags |= IFF_UP;
    438 #ifdef notyet
    439 	/* this has no effect on IP, and will kill all ISO connections XXX */
    440 	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
    441 	     ifa = ifa->ifa_list.tqe_next)
    442 		pfctlinput(PRC_IFUP, ifa->ifa_addr);
    443 #endif
    444 	rt_ifmsg(ifp);
    445 #ifdef INET6
    446 	in6_if_up(ifp);
    447 #endif
    448 }
    449 
    450 /*
    451  * Flush an interface queue.
    452  */
    453 void
    454 if_qflush(ifq)
    455 	register struct ifqueue *ifq;
    456 {
    457 	register struct mbuf *m, *n;
    458 
    459 	n = ifq->ifq_head;
    460 	while ((m = n) != NULL) {
    461 		n = m->m_act;
    462 		m_freem(m);
    463 	}
    464 	ifq->ifq_head = 0;
    465 	ifq->ifq_tail = 0;
    466 	ifq->ifq_len = 0;
    467 }
    468 
    469 /*
    470  * Handle interface watchdog timer routines.  Called
    471  * from softclock, we decrement timers (if set) and
    472  * call the appropriate interface routine on expiration.
    473  */
    474 void
    475 if_slowtimo(arg)
    476 	void *arg;
    477 {
    478 	register struct ifnet *ifp;
    479 	int s = splimp();
    480 
    481 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next) {
    482 		if (ifp->if_timer == 0 || --ifp->if_timer)
    483 			continue;
    484 		if (ifp->if_watchdog)
    485 			(*ifp->if_watchdog)(ifp);
    486 	}
    487 	splx(s);
    488 	timeout(if_slowtimo, NULL, hz / IFNET_SLOWHZ);
    489 }
    490 
    491 /*
    492  * Map interface name to
    493  * interface structure pointer.
    494  */
    495 struct ifnet *
    496 ifunit(name)
    497 	register char *name;
    498 {
    499 	register struct ifnet *ifp;
    500 
    501 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    502 		if (strcmp(ifp->if_xname, name) == 0)
    503 			return (ifp);
    504 
    505 	return (NULL);
    506 }
    507 
    508 
    509 /*
    510  * Map interface name in a sockaddr_dl to
    511  * interface structure pointer.
    512  */
    513 struct ifnet *
    514 if_withname(sa)
    515 	struct sockaddr *sa;
    516 {
    517 	char ifname[IFNAMSIZ+1];
    518 	struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
    519 
    520 	if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) ||
    521 	     (sdl->sdl_nlen > IFNAMSIZ) )
    522 		return NULL;
    523 
    524 	/*
    525 	 * ifunit wants a null-terminated name.  It may not be null-terminated
    526 	 * in the sockaddr.  We don't want to change the caller's sockaddr,
    527 	 * and there might not be room to put the trailing null anyway, so we
    528 	 * make a local copy that we know we can null terminate safely.
    529 	 */
    530 
    531 	bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
    532 	ifname[sdl->sdl_nlen] = '\0';
    533 	return ifunit(ifname);
    534 }
    535 
    536 
    537 /*
    538  * Interface ioctls.
    539  */
    540 int
    541 ifioctl(so, cmd, data, p)
    542 	struct socket *so;
    543 	u_long cmd;
    544 	caddr_t data;
    545 	struct proc *p;
    546 {
    547 	register struct ifnet *ifp;
    548 	register struct ifreq *ifr;
    549 	int error = 0;
    550 	short oif_flags;
    551 
    552 	switch (cmd) {
    553 
    554 	case SIOCGIFCONF:
    555 	case OSIOCGIFCONF:
    556 		return (ifconf(cmd, data));
    557 	}
    558 	ifr = (struct ifreq *)data;
    559 	ifp = ifunit(ifr->ifr_name);
    560 	if (ifp == 0)
    561 		return (ENXIO);
    562 	oif_flags = ifp->if_flags;
    563 	switch (cmd) {
    564 
    565 	case SIOCGIFFLAGS:
    566 		ifr->ifr_flags = ifp->if_flags;
    567 		break;
    568 
    569 	case SIOCGIFMETRIC:
    570 		ifr->ifr_metric = ifp->if_metric;
    571 		break;
    572 
    573 	case SIOCGIFMTU:
    574 		ifr->ifr_mtu = ifp->if_mtu;
    575 		break;
    576 
    577 	case SIOCSIFFLAGS:
    578 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    579 			return (error);
    580 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
    581 			int s = splimp();
    582 			if_down(ifp);
    583 			splx(s);
    584 		}
    585 		if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
    586 			int s = splimp();
    587 			if_up(ifp);
    588 			splx(s);
    589 		}
    590 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
    591 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
    592 		if (ifp->if_ioctl)
    593 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
    594 		break;
    595 
    596 	case SIOCSIFMETRIC:
    597 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    598 			return (error);
    599 		ifp->if_metric = ifr->ifr_metric;
    600 		break;
    601 
    602 	case SIOCSIFMTU:
    603 	{
    604 		u_long oldmtu = ifp->if_mtu;
    605 
    606 		error = suser(p->p_ucred, &p->p_acflag);
    607 		if (error)
    608 			return (error);
    609 		if (ifp->if_ioctl == NULL)
    610 			return (EOPNOTSUPP);
    611 		error = (*ifp->if_ioctl)(ifp, cmd, data);
    612 
    613 		/*
    614 		 * If the link MTU changed, do network layer specific procedure.
    615 		 */
    616 		if (ifp->if_mtu != oldmtu) {
    617 #ifdef INET6
    618 			nd6_setmtu(ifp);
    619 #endif
    620 		}
    621 		break;
    622 	}
    623 	case SIOCADDMULTI:
    624 	case SIOCDELMULTI:
    625 	case SIOCSIFMEDIA:
    626 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    627 			return (error);
    628 		/* FALLTHROUGH */
    629 	case SIOCGIFMEDIA:
    630 		if (ifp->if_ioctl == 0)
    631 			return (EOPNOTSUPP);
    632 		error = (*ifp->if_ioctl)(ifp, cmd, data);
    633 		break;
    634 
    635 	case SIOCSDRVSPEC:
    636 		/* XXX:  need to pass proc pointer through to driver... */
    637 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    638 			return (error);
    639 	/* FALLTHROUGH */
    640 	default:
    641 		if (so->so_proto == 0)
    642 			return (EOPNOTSUPP);
    643 #if !defined(COMPAT_43) && !defined(COMPAT_LINUX) && !defined(COMPAT_SVR4)
    644 		error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
    645 		    (struct mbuf *)cmd, (struct mbuf *)data,
    646 		    (struct mbuf *)ifp, p));
    647 #else
    648 	    {
    649 		int ocmd = cmd;
    650 
    651 		switch (cmd) {
    652 
    653 		case SIOCSIFADDR:
    654 		case SIOCSIFDSTADDR:
    655 		case SIOCSIFBRDADDR:
    656 		case SIOCSIFNETMASK:
    657 #if BYTE_ORDER != BIG_ENDIAN
    658 			if (ifr->ifr_addr.sa_family == 0 &&
    659 			    ifr->ifr_addr.sa_len < 16) {
    660 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
    661 				ifr->ifr_addr.sa_len = 16;
    662 			}
    663 #else
    664 			if (ifr->ifr_addr.sa_len == 0)
    665 				ifr->ifr_addr.sa_len = 16;
    666 #endif
    667 			break;
    668 
    669 		case OSIOCGIFADDR:
    670 			cmd = SIOCGIFADDR;
    671 			break;
    672 
    673 		case OSIOCGIFDSTADDR:
    674 			cmd = SIOCGIFDSTADDR;
    675 			break;
    676 
    677 		case OSIOCGIFBRDADDR:
    678 			cmd = SIOCGIFBRDADDR;
    679 			break;
    680 
    681 		case OSIOCGIFNETMASK:
    682 			cmd = SIOCGIFNETMASK;
    683 		}
    684 
    685 		error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
    686 		    (struct mbuf *)cmd, (struct mbuf *)data,
    687 		    (struct mbuf *)ifp, p));
    688 
    689 		switch (ocmd) {
    690 		case OSIOCGIFADDR:
    691 		case OSIOCGIFDSTADDR:
    692 		case OSIOCGIFBRDADDR:
    693 		case OSIOCGIFNETMASK:
    694 			*(u_int16_t *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
    695 		}
    696 	    }
    697 #endif /* COMPAT_43 */
    698 		break;
    699 	}
    700 
    701 	if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0) {
    702 #ifdef INET6
    703 		if ((ifp->if_flags & IFF_UP) != 0) {
    704 			int s = splimp();
    705 			in6_if_up(ifp);
    706 			splx(s);
    707 		}
    708 #endif
    709 	}
    710 
    711 	return (error);
    712 }
    713 
    714 /*
    715  * Return interface configuration
    716  * of system.  List may be used
    717  * in later ioctl's (above) to get
    718  * other information.
    719  */
    720 /*ARGSUSED*/
    721 int
    722 ifconf(cmd, data)
    723 	u_long cmd;
    724 	caddr_t data;
    725 {
    726 	register struct ifconf *ifc = (struct ifconf *)data;
    727 	register struct ifnet *ifp;
    728 	register struct ifaddr *ifa;
    729 	struct ifreq ifr, *ifrp;
    730 	int space = ifc->ifc_len, error = 0;
    731 
    732 	ifrp = ifc->ifc_req;
    733 	for (ifp = ifnet.tqh_first;
    734 	    space >= sizeof (ifr) && ifp != 0; ifp = ifp->if_list.tqe_next) {
    735 		bcopy(ifp->if_xname, ifr.ifr_name, IFNAMSIZ);
    736 		if ((ifa = ifp->if_addrlist.tqh_first) == 0) {
    737 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
    738 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
    739 			    sizeof(ifr));
    740 			if (error)
    741 				break;
    742 			space -= sizeof (ifr), ifrp++;
    743 		} else
    744 		    for (; space >= sizeof (ifr) && ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    745 			register struct sockaddr *sa = ifa->ifa_addr;
    746 #if defined(COMPAT_43) || defined(COMPAT_LINUX) || defined(COMPAT_SVR4)
    747 			if (cmd == OSIOCGIFCONF) {
    748 				struct osockaddr *osa =
    749 					 (struct osockaddr *)&ifr.ifr_addr;
    750 				ifr.ifr_addr = *sa;
    751 				osa->sa_family = sa->sa_family;
    752 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
    753 						sizeof (ifr));
    754 				ifrp++;
    755 			} else
    756 #endif
    757 			if (sa->sa_len <= sizeof(*sa)) {
    758 				ifr.ifr_addr = *sa;
    759 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
    760 						sizeof (ifr));
    761 				ifrp++;
    762 			} else {
    763 				space -= sa->sa_len - sizeof(*sa);
    764 				if (space < sizeof (ifr))
    765 					break;
    766 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
    767 						sizeof (ifr.ifr_name));
    768 				if (error == 0)
    769 				    error = copyout((caddr_t)sa,
    770 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
    771 				ifrp = (struct ifreq *)
    772 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
    773 			}
    774 			if (error)
    775 				break;
    776 			space -= sizeof (ifr);
    777 		}
    778 	}
    779 	ifc->ifc_len -= space;
    780 	return (error);
    781 }
    782