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