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