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