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