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