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