Home | History | Annotate | Line # | Download | only in net
if.c revision 1.34
      1 /*	$NetBSD: if.c,v 1.34 1996/05/07 02:40:25 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 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
    132 	ifa->ifa_netmask = (struct sockaddr *)sdl;
    133 	sdl->sdl_len = masklen;
    134 	while (namelen != 0)
    135 		sdl->sdl_data[--namelen] = 0xff;
    136 }
    137 /*
    138  * Locate an interface based on a complete address.
    139  */
    140 /*ARGSUSED*/
    141 struct ifaddr *
    142 ifa_ifwithaddr(addr)
    143 	register struct sockaddr *addr;
    144 {
    145 	register struct ifnet *ifp;
    146 	register struct ifaddr *ifa;
    147 
    148 #define	equal(a1, a2) \
    149   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
    150 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    151 	    for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    152 		if (ifa->ifa_addr->sa_family != addr->sa_family)
    153 			continue;
    154 		if (equal(addr, ifa->ifa_addr))
    155 			return (ifa);
    156 		if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
    157 		    equal(ifa->ifa_broadaddr, addr))
    158 			return (ifa);
    159 	}
    160 	return ((struct ifaddr *)0);
    161 }
    162 /*
    163  * Locate the point to point interface with a given destination address.
    164  */
    165 /*ARGSUSED*/
    166 struct ifaddr *
    167 ifa_ifwithdstaddr(addr)
    168 	register struct sockaddr *addr;
    169 {
    170 	register struct ifnet *ifp;
    171 	register struct ifaddr *ifa;
    172 
    173 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    174 	    if (ifp->if_flags & IFF_POINTOPOINT)
    175 		for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    176 			if (ifa->ifa_addr->sa_family != addr->sa_family ||
    177 			    ifa->ifa_dstaddr == NULL)
    178 				continue;
    179 			if (equal(addr, ifa->ifa_dstaddr))
    180 				return (ifa);
    181 	}
    182 	return ((struct ifaddr *)0);
    183 }
    184 
    185 /*
    186  * Find an interface on a specific network.  If many, choice
    187  * is most specific found.
    188  */
    189 struct ifaddr *
    190 ifa_ifwithnet(addr)
    191 	struct sockaddr *addr;
    192 {
    193 	register struct ifnet *ifp;
    194 	register struct ifaddr *ifa;
    195 	struct ifaddr *ifa_maybe = 0;
    196 	u_int af = addr->sa_family;
    197 	char *addr_data = addr->sa_data, *cplim;
    198 
    199 	if (af == AF_LINK) {
    200 	    register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
    201 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
    202 		return (ifnet_addrs[sdl->sdl_index - 1]);
    203 	}
    204 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    205 		for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    206 			register char *cp, *cp2, *cp3;
    207 
    208 			if (ifa->ifa_addr->sa_family != af ||
    209 			    ifa->ifa_netmask == 0)
    210 				next: continue;
    211 			cp = addr_data;
    212 			cp2 = ifa->ifa_addr->sa_data;
    213 			cp3 = ifa->ifa_netmask->sa_data;
    214 			cplim = (char *)ifa->ifa_netmask +
    215 				ifa->ifa_netmask->sa_len;
    216 			while (cp3 < cplim)
    217 				if ((*cp++ ^ *cp2++) & *cp3++)
    218 				    /* want to continue for() loop */
    219 					goto next;
    220 			if (ifa_maybe == 0 ||
    221 			    rn_refines((caddr_t)ifa->ifa_netmask,
    222 			    (caddr_t)ifa_maybe->ifa_netmask))
    223 				ifa_maybe = ifa;
    224 		}
    225 	return (ifa_maybe);
    226 }
    227 /*
    228  * Find the interface of the addresss.
    229  */
    230 struct ifaddr *
    231 ifa_ifwithladdr(addr)
    232 	struct sockaddr *addr;
    233 {
    234 	struct ifaddr *ia;
    235 
    236 	if ((ia = ifa_ifwithaddr(addr)) || (ia = ifa_ifwithdstaddr(addr))
    237 	    || (ia = ifa_ifwithnet(addr)))
    238 		return (ia);
    239 	return (NULL);
    240 }
    241 
    242 /*
    243  * Find an interface using a specific address family
    244  */
    245 struct ifaddr *
    246 ifa_ifwithaf(af)
    247 	register int af;
    248 {
    249 	register struct ifnet *ifp;
    250 	register struct ifaddr *ifa;
    251 
    252 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    253 		for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next)
    254 			if (ifa->ifa_addr->sa_family == af)
    255 				return (ifa);
    256 	return ((struct ifaddr *)0);
    257 }
    258 
    259 /*
    260  * Find an interface address specific to an interface best matching
    261  * a given address.
    262  */
    263 struct ifaddr *
    264 ifaof_ifpforaddr(addr, ifp)
    265 	struct sockaddr *addr;
    266 	register struct ifnet *ifp;
    267 {
    268 	register struct ifaddr *ifa;
    269 	register char *cp, *cp2, *cp3;
    270 	register char *cplim;
    271 	struct ifaddr *ifa_maybe = 0;
    272 	u_int af = addr->sa_family;
    273 
    274 	if (af >= AF_MAX)
    275 		return (0);
    276 	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    277 		if (ifa->ifa_addr->sa_family != af)
    278 			continue;
    279 		ifa_maybe = ifa;
    280 		if (ifa->ifa_netmask == 0) {
    281 			if (equal(addr, ifa->ifa_addr) ||
    282 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
    283 				return (ifa);
    284 			continue;
    285 		}
    286 		cp = addr->sa_data;
    287 		cp2 = ifa->ifa_addr->sa_data;
    288 		cp3 = ifa->ifa_netmask->sa_data;
    289 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
    290 		for (; cp3 < cplim; cp3++)
    291 			if ((*cp++ ^ *cp2++) & *cp3)
    292 				break;
    293 		if (cp3 == cplim)
    294 			return (ifa);
    295 	}
    296 	return (ifa_maybe);
    297 }
    298 
    299 #include <net/route.h>
    300 
    301 /*
    302  * Default action when installing a route with a Link Level gateway.
    303  * Lookup an appropriate real ifa to point to.
    304  * This should be moved to /sys/net/link.c eventually.
    305  */
    306 void
    307 link_rtrequest(cmd, rt, sa)
    308 	int cmd;
    309 	register struct rtentry *rt;
    310 	struct sockaddr *sa;
    311 {
    312 	register struct ifaddr *ifa;
    313 	struct sockaddr *dst;
    314 	struct ifnet *ifp;
    315 
    316 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
    317 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
    318 		return;
    319 	if ((ifa = ifaof_ifpforaddr(dst, ifp)) != NULL) {
    320 		IFAFREE(rt->rt_ifa);
    321 		rt->rt_ifa = ifa;
    322 		ifa->ifa_refcnt++;
    323 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
    324 			ifa->ifa_rtrequest(cmd, rt, sa);
    325 	}
    326 }
    327 
    328 /*
    329  * Mark an interface down and notify protocols of
    330  * the transition.
    331  * NOTE: must be called at splsoftnet or equivalent.
    332  */
    333 void
    334 if_down(ifp)
    335 	register struct ifnet *ifp;
    336 {
    337 	register struct ifaddr *ifa;
    338 
    339 	ifp->if_flags &= ~IFF_UP;
    340 	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next)
    341 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
    342 	if_qflush(&ifp->if_snd);
    343 	rt_ifmsg(ifp);
    344 }
    345 
    346 /*
    347  * Mark an interface up and notify protocols of
    348  * the transition.
    349  * NOTE: must be called at splsoftnet or equivalent.
    350  */
    351 void
    352 if_up(ifp)
    353 	register struct ifnet *ifp;
    354 {
    355 #ifdef notyet
    356 	register struct ifaddr *ifa;
    357 #endif
    358 
    359 	ifp->if_flags |= IFF_UP;
    360 #ifdef notyet
    361 	/* this has no effect on IP, and will kill all ISO connections XXX */
    362 	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
    363 	     ifa = ifa->ifa_list.tqe_next)
    364 		pfctlinput(PRC_IFUP, ifa->ifa_addr);
    365 #endif
    366 	rt_ifmsg(ifp);
    367 }
    368 
    369 /*
    370  * Flush an interface queue.
    371  */
    372 void
    373 if_qflush(ifq)
    374 	register struct ifqueue *ifq;
    375 {
    376 	register struct mbuf *m, *n;
    377 
    378 	n = ifq->ifq_head;
    379 	while ((m = n) != NULL) {
    380 		n = m->m_act;
    381 		m_freem(m);
    382 	}
    383 	ifq->ifq_head = 0;
    384 	ifq->ifq_tail = 0;
    385 	ifq->ifq_len = 0;
    386 }
    387 
    388 /*
    389  * Handle interface watchdog timer routines.  Called
    390  * from softclock, we decrement timers (if set) and
    391  * call the appropriate interface routine on expiration.
    392  */
    393 void
    394 if_slowtimo(arg)
    395 	void *arg;
    396 {
    397 	register struct ifnet *ifp;
    398 	int s = splimp();
    399 
    400 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next) {
    401 		if (ifp->if_timer == 0 || --ifp->if_timer)
    402 			continue;
    403 		if (ifp->if_watchdog)
    404 			(*ifp->if_watchdog)(ifp);
    405 	}
    406 	splx(s);
    407 	timeout(if_slowtimo, NULL, hz / IFNET_SLOWHZ);
    408 }
    409 
    410 /*
    411  * Map interface name to
    412  * interface structure pointer.
    413  */
    414 struct ifnet *
    415 ifunit(name)
    416 	register char *name;
    417 {
    418 	register struct ifnet *ifp;
    419 	size_t namelen;
    420 
    421 	namelen = strlen(name);
    422 
    423 	for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next)
    424 		if (strlen(ifp->if_xname) == namelen &&
    425 		    strcmp(ifp->if_xname, name) == 0)
    426 			return (ifp);
    427 
    428 	return (NULL);
    429 }
    430 
    431 /*
    432  * Interface ioctls.
    433  */
    434 int
    435 ifioctl(so, cmd, data, p)
    436 	struct socket *so;
    437 	u_long cmd;
    438 	caddr_t data;
    439 	struct proc *p;
    440 {
    441 	register struct ifnet *ifp;
    442 	register struct ifreq *ifr;
    443 	int error;
    444 
    445 	switch (cmd) {
    446 
    447 	case SIOCGIFCONF:
    448 	case OSIOCGIFCONF:
    449 		return (ifconf(cmd, data));
    450 	}
    451 	ifr = (struct ifreq *)data;
    452 	ifp = ifunit(ifr->ifr_name);
    453 	if (ifp == 0)
    454 		return (ENXIO);
    455 	switch (cmd) {
    456 
    457 	case SIOCGIFFLAGS:
    458 		ifr->ifr_flags = ifp->if_flags;
    459 		break;
    460 
    461 	case SIOCGIFMETRIC:
    462 		ifr->ifr_metric = ifp->if_metric;
    463 		break;
    464 
    465 	case SIOCSIFFLAGS:
    466 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    467 			return (error);
    468 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
    469 			int s = splimp();
    470 			if_down(ifp);
    471 			splx(s);
    472 		}
    473 		if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
    474 			int s = splimp();
    475 			if_up(ifp);
    476 			splx(s);
    477 		}
    478 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
    479 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
    480 		if (ifp->if_ioctl)
    481 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
    482 		break;
    483 
    484 	case SIOCSIFMETRIC:
    485 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    486 			return (error);
    487 		ifp->if_metric = ifr->ifr_metric;
    488 		break;
    489 
    490 	case SIOCADDMULTI:
    491 	case SIOCDELMULTI:
    492 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    493 			return (error);
    494 		if (ifp->if_ioctl == 0)
    495 			return (EOPNOTSUPP);
    496 		return ((*ifp->if_ioctl)(ifp, cmd, data));
    497 
    498 	default:
    499 		if (so->so_proto == 0)
    500 			return (EOPNOTSUPP);
    501 #if !defined(COMPAT_43) && !defined(COMPAT_LINUX) && !defined(COMPAT_SVR4)
    502 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
    503 			(struct mbuf *) cmd, (struct mbuf *) data,
    504 			(struct mbuf *) ifp));
    505 #else
    506 	    {
    507 		int ocmd = cmd;
    508 
    509 		switch (cmd) {
    510 
    511 		case SIOCSIFADDR:
    512 		case SIOCSIFDSTADDR:
    513 		case SIOCSIFBRDADDR:
    514 		case SIOCSIFNETMASK:
    515 #if BYTE_ORDER != BIG_ENDIAN
    516 			if (ifr->ifr_addr.sa_family == 0 &&
    517 			    ifr->ifr_addr.sa_len < 16) {
    518 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
    519 				ifr->ifr_addr.sa_len = 16;
    520 			}
    521 #else
    522 			if (ifr->ifr_addr.sa_len == 0)
    523 				ifr->ifr_addr.sa_len = 16;
    524 #endif
    525 			break;
    526 
    527 		case OSIOCGIFADDR:
    528 			cmd = SIOCGIFADDR;
    529 			break;
    530 
    531 		case OSIOCGIFDSTADDR:
    532 			cmd = SIOCGIFDSTADDR;
    533 			break;
    534 
    535 		case OSIOCGIFBRDADDR:
    536 			cmd = SIOCGIFBRDADDR;
    537 			break;
    538 
    539 		case OSIOCGIFNETMASK:
    540 			cmd = SIOCGIFNETMASK;
    541 		}
    542 		error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
    543 						    (struct mbuf *) cmd,
    544 						    (struct mbuf *) data,
    545 						    (struct mbuf *) ifp));
    546 		switch (ocmd) {
    547 
    548 		case OSIOCGIFADDR:
    549 		case OSIOCGIFDSTADDR:
    550 		case OSIOCGIFBRDADDR:
    551 		case OSIOCGIFNETMASK:
    552 			*(u_int16_t *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
    553 		}
    554 		return (error);
    555 
    556 	    }
    557 #endif
    558 	}
    559 	return (0);
    560 }
    561 
    562 /*
    563  * Return interface configuration
    564  * of system.  List may be used
    565  * in later ioctl's (above) to get
    566  * other information.
    567  */
    568 /*ARGSUSED*/
    569 int
    570 ifconf(cmd, data)
    571 	u_long cmd;
    572 	caddr_t data;
    573 {
    574 	register struct ifconf *ifc = (struct ifconf *)data;
    575 	register struct ifnet *ifp;
    576 	register struct ifaddr *ifa;
    577 	struct ifreq ifr, *ifrp;
    578 	int space = ifc->ifc_len, error = 0;
    579 
    580 	ifrp = ifc->ifc_req;
    581 	for (ifp = ifnet.tqh_first;
    582 	    space >= sizeof (ifr) && ifp != 0; ifp = ifp->if_list.tqe_next) {
    583 		bcopy(ifp->if_xname, ifr.ifr_name, IFNAMSIZ);
    584 		if ((ifa = ifp->if_addrlist.tqh_first) == 0) {
    585 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
    586 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
    587 			    sizeof(ifr));
    588 			if (error)
    589 				break;
    590 			space -= sizeof (ifr), ifrp++;
    591 		} else
    592 		    for (; space >= sizeof (ifr) && ifa != 0; ifa = ifa->ifa_list.tqe_next) {
    593 			register struct sockaddr *sa = ifa->ifa_addr;
    594 #if defined(COMPAT_43) || defined(COMPAT_LINUX) || defined(COMPAT_SVR4)
    595 			if (cmd == OSIOCGIFCONF) {
    596 				struct osockaddr *osa =
    597 					 (struct osockaddr *)&ifr.ifr_addr;
    598 				ifr.ifr_addr = *sa;
    599 				osa->sa_family = sa->sa_family;
    600 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
    601 						sizeof (ifr));
    602 				ifrp++;
    603 			} else
    604 #endif
    605 			if (sa->sa_len <= sizeof(*sa)) {
    606 				ifr.ifr_addr = *sa;
    607 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
    608 						sizeof (ifr));
    609 				ifrp++;
    610 			} else {
    611 				space -= sa->sa_len - sizeof(*sa);
    612 				if (space < sizeof (ifr))
    613 					break;
    614 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
    615 						sizeof (ifr.ifr_name));
    616 				if (error == 0)
    617 				    error = copyout((caddr_t)sa,
    618 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
    619 				ifrp = (struct ifreq *)
    620 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
    621 			}
    622 			if (error)
    623 				break;
    624 			space -= sizeof (ifr);
    625 		}
    626 	}
    627 	ifc->ifc_len -= space;
    628 	return (error);
    629 }
    630