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