xref: /csrg-svn/sys/net/if.c (revision 44463)
123157Smckusick /*
229061Smckusick  * Copyright (c) 1980, 1986 Regents of the University of California.
333183Sbostic  * All rights reserved.
423157Smckusick  *
5*44463Sbostic  * %sccs.include.redist.c%
633183Sbostic  *
7*44463Sbostic  *	@(#)if.c	7.13 (Berkeley) 06/28/90
823157Smckusick  */
94944Swnj 
1017036Sbloom #include "param.h"
1133984Skarels #include "mbuf.h"
1217036Sbloom #include "systm.h"
1317036Sbloom #include "socket.h"
1418544Skarels #include "socketvar.h"
1517036Sbloom #include "protosw.h"
1617036Sbloom #include "user.h"
1717036Sbloom #include "kernel.h"
1817036Sbloom #include "ioctl.h"
1917036Sbloom #include "errno.h"
2010872Ssam 
2117036Sbloom #include "if.h"
2217036Sbloom #include "af.h"
2340792Ssklower #include "if_dl.h"
2443335Ssklower #include "if_types.h"
254944Swnj 
2616220Skarels #include "ether.h"
2716220Skarels 
286207Swnj int	ifqmaxlen = IFQ_MAXLEN;
296207Swnj 
306333Ssam /*
316333Ssam  * Network interface utility routines.
326333Ssam  *
3318544Skarels  * Routines with ifa_ifwith* names take sockaddr *'s as
3418544Skarels  * parameters.
356333Ssam  */
366333Ssam 
375206Swnj ifinit()
385206Swnj {
395206Swnj 	register struct ifnet *ifp;
405206Swnj 
415206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
4224773Skarels 		if (ifp->if_snd.ifq_maxlen == 0)
4324773Skarels 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
448173Sroot 	if_slowtimo();
455206Swnj }
465206Swnj 
4713049Ssam #ifdef vax
486333Ssam /*
496333Ssam  * Call each interface on a Unibus reset.
506333Ssam  */
515206Swnj ifubareset(uban)
525206Swnj 	int uban;
535206Swnj {
545206Swnj 	register struct ifnet *ifp;
555206Swnj 
565206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
578974Sroot 		if (ifp->if_reset)
5815116Ssam 			(*ifp->if_reset)(ifp->if_unit, uban);
595206Swnj }
608393Swnj #endif
615206Swnj 
6240792Ssklower int if_index = 0;
6343335Ssklower struct ifaddr **ifnet_addrs;
646333Ssam /*
656333Ssam  * Attach an interface to the
666333Ssam  * list of "active" interfaces.
676333Ssam  */
685160Swnj if_attach(ifp)
695160Swnj 	struct ifnet *ifp;
705160Swnj {
7140792Ssklower 	unsigned socksize, ifasize;
7240792Ssklower 	int namelen, unitlen;
7340792Ssklower 	char workbuf[16];
7443335Ssklower 	register struct ifnet **p = &ifnet;
7540792Ssklower 	register struct sockaddr_dl *sdl;
7640792Ssklower 	register struct ifaddr *ifa;
7743335Ssklower 	static int if_indexlim = 8;
7843335Ssklower 	extern link_rtrequest(), ether_output();
795160Swnj 
805698Swnj 	while (*p)
815698Swnj 		p = &((*p)->if_next);
825698Swnj 	*p = ifp;
8340792Ssklower 	ifp->if_index = ++if_index;
8443335Ssklower 	if (ifnet_addrs == 0 || if_index >= if_indexlim) {
8543335Ssklower 		unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
8643335Ssklower 		struct ifaddr **q = (struct ifaddr **)
8743335Ssklower 					malloc(n, M_IFADDR, M_WAITOK);
8843335Ssklower 		if (ifnet_addrs) {
8943335Ssklower 			bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
9043335Ssklower 			free((caddr_t)ifnet_addrs, M_IFADDR);
9143335Ssklower 		}
9243335Ssklower 		ifnet_addrs = q;
9343335Ssklower 	}
9443335Ssklower 	/* XXX -- Temporary fix before changing 10 ethernet drivers */
9543335Ssklower 	if (ifp->if_output == ether_output) {
9643335Ssklower 		ifp->if_type = IFT_ETHER;
9743335Ssklower 		ifp->if_addrlen = 6;
9843335Ssklower 		ifp->if_hdrlen = 14;
9943335Ssklower 	}
10041923Ssklower 	/*
10141923Ssklower 	 * create a Link Level name for this device
10241923Ssklower 	 */
10340792Ssklower 	sprint_d(workbuf, ifp->if_unit);
10440792Ssklower 	namelen = strlen(ifp->if_name);
10540792Ssklower 	unitlen = strlen(workbuf);
10640792Ssklower #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
10740792Ssklower 	socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
10840792Ssklower 			       unitlen + namelen + ifp->if_addrlen;
10940792Ssklower #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
11040792Ssklower 	socksize = ROUNDUP(socksize);
11143335Ssklower 	if (socksize < sizeof(*sdl))
11243335Ssklower 		socksize = sizeof(*sdl);
11340792Ssklower 	ifasize = sizeof(*ifa) + 2 * socksize;
11440792Ssklower 	ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
11540792Ssklower 	if (ifa == 0)
11640792Ssklower 		return;
11743335Ssklower 	ifnet_addrs[if_index - 1] = ifa;
11840792Ssklower 	bzero((caddr_t)ifa, ifasize);
11940792Ssklower 	sdl = (struct sockaddr_dl *)(ifa + 1);
12040792Ssklower 	ifa->ifa_addr = (struct sockaddr *)sdl;
12140792Ssklower 	ifa->ifa_ifp = ifp;
12240792Ssklower 	sdl->sdl_len = socksize;
12340792Ssklower 	sdl->sdl_family = AF_LINK;
12440792Ssklower 	bcopy(ifp->if_name, sdl->sdl_data, namelen);
12540792Ssklower 	bcopy((caddr_t)workbuf, namelen + (caddr_t)sdl->sdl_data, unitlen);
12640792Ssklower 	sdl->sdl_nlen = (namelen += unitlen);
12740792Ssklower 	sdl->sdl_index = ifp->if_index;
12840792Ssklower 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
12940792Ssklower 	ifa->ifa_netmask = (struct sockaddr *)sdl;
13040792Ssklower 	sdl->sdl_len = socksize - ifp->if_addrlen;
13140792Ssklower 	while (namelen != 0)
13240792Ssklower 		sdl->sdl_data[--namelen] = 0xff;
13340792Ssklower 	ifa->ifa_next = ifp->if_addrlist;
13441923Ssklower 	ifa->ifa_rtrequest = link_rtrequest;
13540792Ssklower 	ifp->if_addrlist = ifa;
1365160Swnj }
1376333Ssam /*
1386333Ssam  * Locate an interface based on a complete address.
1396333Ssam  */
1404951Swnj /*ARGSUSED*/
14118544Skarels struct ifaddr *
14218544Skarels ifa_ifwithaddr(addr)
14337549Smckusick 	register struct sockaddr *addr;
1444944Swnj {
1454944Swnj 	register struct ifnet *ifp;
14618544Skarels 	register struct ifaddr *ifa;
1474944Swnj 
1486333Ssam #define	equal(a1, a2) \
14937549Smckusick   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
15018544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
15118544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
15237549Smckusick 		if (ifa->ifa_addr->sa_family != addr->sa_family)
1536333Ssam 			continue;
15437549Smckusick 		if (equal(addr, ifa->ifa_addr))
15518544Skarels 			return (ifa);
15643335Ssklower 		if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
15743335Ssklower 		    equal(ifa->ifa_broadaddr, addr))
15818544Skarels 			return (ifa);
1596333Ssam 	}
16018544Skarels 	return ((struct ifaddr *)0);
1614944Swnj }
16223933Ssklower /*
16323933Ssklower  * Locate the point to point interface with a given destination address.
16423933Ssklower  */
16523933Ssklower /*ARGSUSED*/
16623933Ssklower struct ifaddr *
16723933Ssklower ifa_ifwithdstaddr(addr)
16837549Smckusick 	register struct sockaddr *addr;
16923933Ssklower {
17023933Ssklower 	register struct ifnet *ifp;
17123933Ssklower 	register struct ifaddr *ifa;
1724944Swnj 
17323933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
17423933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
17523933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
17637549Smckusick 			if (ifa->ifa_addr->sa_family != addr->sa_family)
17723933Ssklower 				continue;
17837549Smckusick 			if (equal(addr, ifa->ifa_dstaddr))
17923933Ssklower 				return (ifa);
18023933Ssklower 	}
18123933Ssklower 	return ((struct ifaddr *)0);
18223933Ssklower }
18323933Ssklower 
1846333Ssam /*
1856333Ssam  * Find an interface on a specific network.  If many, choice
1866333Ssam  * is first found.
1876333Ssam  */
18818544Skarels struct ifaddr *
18918544Skarels ifa_ifwithnet(addr)
19037549Smckusick 	struct sockaddr *addr;
1914944Swnj {
1924944Swnj 	register struct ifnet *ifp;
19318544Skarels 	register struct ifaddr *ifa;
19437549Smckusick 	u_int af = addr->sa_family;
1954944Swnj 
1966619Ssam 	if (af >= AF_MAX)
1976619Ssam 		return (0);
19843335Ssklower 	if (af == AF_LINK) {
19943335Ssklower 	    register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
20043335Ssklower 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
20143335Ssklower 		return (ifnet_addrs[sdl->sdl_index - 1]);
20243335Ssklower 	}
20318544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
20418544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
20543335Ssklower 		register char *cp, *cp2, *cp3;
20643335Ssklower 		register char *cplim;
20737549Smckusick 		if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
2086333Ssam 			continue;
20937549Smckusick 		cp = addr->sa_data;
21037549Smckusick 		cp2 = ifa->ifa_addr->sa_data;
21137549Smckusick 		cp3 = ifa->ifa_netmask->sa_data;
21237549Smckusick 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
21337549Smckusick 		for (; cp3 < cplim; cp3++)
21437549Smckusick 			if ((*cp++ ^ *cp2++) & *cp3)
21537549Smckusick 				break;
21637549Smckusick 		if (cp3 == cplim)
21718544Skarels 			return (ifa);
21837549Smckusick 	    }
21918544Skarels 	return ((struct ifaddr *)0);
2206333Ssam }
2216333Ssam 
2226333Ssam /*
2236333Ssam  * Find an interface using a specific address family
2246333Ssam  */
22518544Skarels struct ifaddr *
22618544Skarels ifa_ifwithaf(af)
2276333Ssam 	register int af;
2285083Swnj {
2296333Ssam 	register struct ifnet *ifp;
23018544Skarels 	register struct ifaddr *ifa;
2315083Swnj 
2326333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
23318544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
23437549Smckusick 		if (ifa->ifa_addr->sa_family == af)
23518544Skarels 			return (ifa);
23618544Skarels 	return ((struct ifaddr *)0);
2375083Swnj }
2385104Swnj 
23943335Ssklower /*
24043335Ssklower  * Find an interface address specific to an interface best matching
24143335Ssklower  * a given address.
24243335Ssklower  */
24343335Ssklower struct ifaddr *
24443335Ssklower ifaof_ifpforaddr(addr, ifp)
24543335Ssklower 	struct sockaddr *addr;
24643335Ssklower 	register struct ifnet *ifp;
24743335Ssklower {
24843335Ssklower 	register struct ifaddr *ifa;
24943335Ssklower 	register char *cp, *cp2, *cp3;
25043335Ssklower 	register char *cplim;
25143335Ssklower 	struct ifaddr *ifa_maybe = 0;
25243335Ssklower 	u_int af = addr->sa_family;
25343335Ssklower 
25443335Ssklower 	if (af >= AF_MAX)
25543335Ssklower 		return (0);
25643335Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
25743335Ssklower 		if (ifa->ifa_addr->sa_family != af)
25843335Ssklower 			continue;
25943335Ssklower 		ifa_maybe = ifa;
26043335Ssklower 		if (ifa->ifa_netmask == 0) {
26143335Ssklower 			if (equal(addr, ifa->ifa_addr) ||
26243335Ssklower 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
26343335Ssklower 				return (ifa);
26443335Ssklower 			continue;
26543335Ssklower 		}
26643335Ssklower 		cp = addr->sa_data;
26743335Ssklower 		cp2 = ifa->ifa_addr->sa_data;
26843335Ssklower 		cp3 = ifa->ifa_netmask->sa_data;
26943335Ssklower 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
27043335Ssklower 		for (; cp3 < cplim; cp3++)
27143335Ssklower 			if ((*cp++ ^ *cp2++) & *cp3)
27243335Ssklower 				break;
27343335Ssklower 		if (cp3 == cplim)
27443335Ssklower 			return (ifa);
27543335Ssklower 	}
27643335Ssklower 	return (ifa_maybe);
27743335Ssklower }
27841923Ssklower #include "route.h"
2796333Ssam /*
28041923Ssklower  * Default action when installing a route with a Link Level gateway.
28141923Ssklower  * Lookup an appropriate real ifa to point to.
28241923Ssklower  * This should be moved to /sys/net/link.c eventually.
28341923Ssklower  */
28441923Ssklower link_rtrequest(cmd, rt, sa)
28541923Ssklower register struct rtentry *rt;
28641923Ssklower struct sockaddr *sa;
28741923Ssklower {
28841923Ssklower 	register struct ifaddr *ifa;
28941923Ssklower 	struct sockaddr *dst;
29041923Ssklower 	struct ifnet *ifp, *oldifnet = ifnet;
29141923Ssklower 
29241923Ssklower 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
29341923Ssklower 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
29441923Ssklower 		return;
29543335Ssklower 	if (ifa = ifaof_ifpforaddr(dst, ifp)) {
29641923Ssklower 		rt->rt_ifa = ifa;
29741923Ssklower 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
29841923Ssklower 			ifa->ifa_rtrequest(cmd, rt, sa);
29943335Ssklower 	}
30041923Ssklower }
30141923Ssklower 
30241923Ssklower /*
3036582Ssam  * Mark an interface down and notify protocols of
3046582Ssam  * the transition.
3059184Ssam  * NOTE: must be called at splnet or eqivalent.
3066582Ssam  */
3076582Ssam if_down(ifp)
3086582Ssam 	register struct ifnet *ifp;
3096582Ssam {
31018544Skarels 	register struct ifaddr *ifa;
3118173Sroot 
3126582Ssam 	ifp->if_flags &= ~IFF_UP;
31318544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
31437549Smckusick 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
31533984Skarels 	if_qflush(&ifp->if_snd);
3166582Ssam }
3177264Ssam 
3187264Ssam /*
31933984Skarels  * Flush an interface queue.
32033984Skarels  */
32133984Skarels if_qflush(ifq)
32233984Skarels 	register struct ifqueue *ifq;
32333984Skarels {
32433984Skarels 	register struct mbuf *m, *n;
32533984Skarels 
32633984Skarels 	n = ifq->ifq_head;
32733984Skarels 	while (m = n) {
32833984Skarels 		n = m->m_act;
32933984Skarels 		m_freem(m);
33033984Skarels 	}
33133984Skarels 	ifq->ifq_head = 0;
33233984Skarels 	ifq->ifq_tail = 0;
33333984Skarels 	ifq->ifq_len = 0;
33433984Skarels }
33533984Skarels 
33633984Skarels /*
3377264Ssam  * Handle interface watchdog timer routines.  Called
3387264Ssam  * from softclock, we decrement timers (if set) and
3397264Ssam  * call the appropriate interface routine on expiration.
3407264Ssam  */
3417264Ssam if_slowtimo()
3427264Ssam {
3437264Ssam 	register struct ifnet *ifp;
34437549Smckusick 	int s = splimp();
3457264Ssam 
3469184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
3479184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
3489184Ssam 			continue;
3499184Ssam 		if (ifp->if_watchdog)
3507264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
3519184Ssam 	}
35237549Smckusick 	splx(s);
3538692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
3547264Ssam }
35511576Ssam 
35611576Ssam /*
35713049Ssam  * Map interface name to
35813049Ssam  * interface structure pointer.
35911576Ssam  */
36013049Ssam struct ifnet *
36113049Ssam ifunit(name)
36213049Ssam 	register char *name;
36311576Ssam {
36413049Ssam 	register char *cp;
36511576Ssam 	register struct ifnet *ifp;
36613049Ssam 	int unit;
36736821Skarels 	unsigned len;
36836821Skarels 	char *ep, c;
36911576Ssam 
37013049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
37111576Ssam 		if (*cp >= '0' && *cp <= '9')
37211576Ssam 			break;
37313049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
37413049Ssam 		return ((struct ifnet *)0);
37536821Skarels 	/*
37636821Skarels 	 * Save first char of unit, and pointer to it,
37736821Skarels 	 * so we can put a null there to avoid matching
37836821Skarels 	 * initial substrings of interface names.
37936821Skarels 	 */
38036821Skarels 	len = cp - name + 1;
38136821Skarels 	c = *cp;
38236821Skarels 	ep = cp;
38336821Skarels 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
38436821Skarels 		unit = unit * 10 + *cp++ - '0';
38536821Skarels 	*ep = 0;
38611576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
38736821Skarels 		if (bcmp(ifp->if_name, name, len))
38811576Ssam 			continue;
38911576Ssam 		if (unit == ifp->if_unit)
39013049Ssam 			break;
39111576Ssam 	}
39236821Skarels 	*ep = c;
39313049Ssam 	return (ifp);
39413049Ssam }
39511576Ssam 
39613049Ssam /*
39713049Ssam  * Interface ioctls.
39813049Ssam  */
39918544Skarels ifioctl(so, cmd, data)
40018544Skarels 	struct socket *so;
40113049Ssam 	int cmd;
40213049Ssam 	caddr_t data;
40313049Ssam {
40413049Ssam 	register struct ifnet *ifp;
40513049Ssam 	register struct ifreq *ifr;
40637549Smckusick 	int error;
40713049Ssam 
40811576Ssam 	switch (cmd) {
40911576Ssam 
41013049Ssam 	case SIOCGIFCONF:
41137549Smckusick 	case OSIOCGIFCONF:
41213049Ssam 		return (ifconf(cmd, data));
41313049Ssam 
41425647Skarels #if defined(INET) && NETHER > 0
41516220Skarels 	case SIOCSARP:
41616220Skarels 	case SIOCDARP:
41737549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
41837549Smckusick 			return (error);
41916220Skarels 		/* FALL THROUGH */
42016220Skarels 	case SIOCGARP:
42137549Smckusick 	case OSIOCGARP:
42216220Skarels 		return (arpioctl(cmd, data));
42316220Skarels #endif
42413049Ssam 	}
42513049Ssam 	ifr = (struct ifreq *)data;
42613049Ssam 	ifp = ifunit(ifr->ifr_name);
42713049Ssam 	if (ifp == 0)
42813049Ssam 		return (ENXIO);
42913049Ssam 	switch (cmd) {
43013049Ssam 
43111576Ssam 	case SIOCGIFFLAGS:
43211576Ssam 		ifr->ifr_flags = ifp->if_flags;
43311576Ssam 		break;
43411576Ssam 
43526091Skarels 	case SIOCGIFMETRIC:
43626091Skarels 		ifr->ifr_metric = ifp->if_metric;
43726091Skarels 		break;
43826091Skarels 
43913053Ssam 	case SIOCSIFFLAGS:
44037549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
44137549Smckusick 			return (error);
44213053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
44313053Ssam 			int s = splimp();
44413053Ssam 			if_down(ifp);
44513053Ssam 			splx(s);
44613053Ssam 		}
44718544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
44818544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
44924773Skarels 		if (ifp->if_ioctl)
45024773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
45113053Ssam 		break;
45213053Ssam 
45326091Skarels 	case SIOCSIFMETRIC:
45437549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
45537549Smckusick 			return (error);
45626091Skarels 		ifp->if_metric = ifr->ifr_metric;
45726091Skarels 		break;
45826091Skarels 
45911576Ssam 	default:
46018544Skarels 		if (so->so_proto == 0)
46113049Ssam 			return (EOPNOTSUPP);
46237549Smckusick #ifndef COMPAT_43
46318544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
46418544Skarels 			cmd, data, ifp));
46537549Smckusick #else
46637549Smckusick 	    {
46741545Smckusick 		int ocmd = cmd;
46837549Smckusick 
46937549Smckusick 		switch (cmd) {
47037549Smckusick 
47137549Smckusick 		case SIOCSIFDSTADDR:
47237549Smckusick 		case SIOCSIFADDR:
47337549Smckusick 		case SIOCSIFBRDADDR:
47437549Smckusick 		case SIOCSIFNETMASK:
47537549Smckusick #if BYTE_ORDER != BIG_ENDIAN
47637549Smckusick 			if (ifr->ifr_addr.sa_family == 0 &&
47737549Smckusick 			    ifr->ifr_addr.sa_len < 16) {
47837549Smckusick 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
47937549Smckusick 				ifr->ifr_addr.sa_len = 16;
48037549Smckusick 			}
48137549Smckusick #else
48237549Smckusick 			if (ifr->ifr_addr.sa_len == 0)
48337549Smckusick 				ifr->ifr_addr.sa_len = 16;
48437549Smckusick #endif
48537549Smckusick 			break;
48637549Smckusick 
48737549Smckusick 		case OSIOCGIFADDR:
48837549Smckusick 			cmd = SIOCGIFADDR;
48937549Smckusick 			break;
49037549Smckusick 
49137549Smckusick 		case OSIOCGIFDSTADDR:
49237549Smckusick 			cmd = SIOCGIFDSTADDR;
49337549Smckusick 			break;
49437549Smckusick 
49537549Smckusick 		case OSIOCGIFBRDADDR:
49637549Smckusick 			cmd = SIOCGIFBRDADDR;
49737549Smckusick 			break;
49837549Smckusick 
49937549Smckusick 		case OSIOCGIFNETMASK:
50037549Smckusick 			cmd = SIOCGIFNETMASK;
50137549Smckusick 		}
50237549Smckusick 		error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
50337549Smckusick 							    cmd, data, ifp));
50437549Smckusick 		switch (ocmd) {
50537549Smckusick 
50637549Smckusick 		case OSIOCGIFADDR:
50737549Smckusick 		case OSIOCGIFDSTADDR:
50837549Smckusick 		case OSIOCGIFBRDADDR:
50937549Smckusick 		case OSIOCGIFNETMASK:
51037549Smckusick 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
51137549Smckusick 		}
51237549Smckusick 		return (error);
51337549Smckusick 
51437549Smckusick 	    }
51537549Smckusick #endif
51611576Ssam 	}
51711576Ssam 	return (0);
51811576Ssam }
51911576Ssam 
52011576Ssam /*
52111576Ssam  * Return interface configuration
52211576Ssam  * of system.  List may be used
52311576Ssam  * in later ioctl's (above) to get
52411576Ssam  * other information.
52511576Ssam  */
52612783Ssam /*ARGSUSED*/
52711576Ssam ifconf(cmd, data)
52811576Ssam 	int cmd;
52911576Ssam 	caddr_t data;
53011576Ssam {
53111576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
53211576Ssam 	register struct ifnet *ifp = ifnet;
53318544Skarels 	register struct ifaddr *ifa;
53411630Ssam 	register char *cp, *ep;
53511630Ssam 	struct ifreq ifr, *ifrp;
53611576Ssam 	int space = ifc->ifc_len, error = 0;
53711576Ssam 
53811630Ssam 	ifrp = ifc->ifc_req;
53911630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
54011576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
54111630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
54211630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
54311576Ssam 			;
54411630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
54518544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
54618544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
54718544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
54818544Skarels 			if (error)
54918544Skarels 				break;
55018544Skarels 			space -= sizeof (ifr), ifrp++;
55118544Skarels 		} else
55218544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
55337549Smckusick 			register struct sockaddr *sa = ifa->ifa_addr;
55437549Smckusick #ifdef COMPAT_43
55537549Smckusick 			if (cmd == OSIOCGIFCONF) {
55637549Smckusick 				struct osockaddr *osa =
55737549Smckusick 					 (struct osockaddr *)&ifr.ifr_addr;
55837549Smckusick 				ifr.ifr_addr = *sa;
55937549Smckusick 				osa->sa_family = sa->sa_family;
56037549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
56137549Smckusick 						sizeof (ifr));
56237549Smckusick 				ifrp++;
56337549Smckusick 			} else
56437549Smckusick #endif
56537549Smckusick 			if (sa->sa_len <= sizeof(*sa)) {
56637549Smckusick 				ifr.ifr_addr = *sa;
56737549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
56837549Smckusick 						sizeof (ifr));
56937549Smckusick 				ifrp++;
57037549Smckusick 			} else {
57137549Smckusick 				space -= sa->sa_len - sizeof(*sa);
57237549Smckusick 				if (space < sizeof (ifr))
57337549Smckusick 					break;
57437549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
57537549Smckusick 						sizeof (ifr.ifr_name));
57637549Smckusick 				if (error == 0)
57737549Smckusick 				    error = copyout((caddr_t)sa,
57837549Smckusick 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
57937549Smckusick 				ifrp = (struct ifreq *)
58037549Smckusick 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
58137549Smckusick 			}
58218544Skarels 			if (error)
58318544Skarels 				break;
58437549Smckusick 			space -= sizeof (ifr);
58518544Skarels 		}
58611576Ssam 	}
58711576Ssam 	ifc->ifc_len -= space;
58811576Ssam 	return (error);
58911576Ssam }
59040792Ssklower 
59140792Ssklower static sprint_d(cp, n)
59240792Ssklower register char *cp;
59340792Ssklower u_short n;
59440792Ssklower {
59540792Ssklower 	register int q, m;
59640792Ssklower 	do {
59740792Ssklower 	    if (n >= 10000) m = 10000;
59840792Ssklower 		else if (n >= 1000) m = 1000;
59940792Ssklower 		else if (n >= 100) m = 100;
60040792Ssklower 		else if (n >= 10) m = 10;
60140792Ssklower 		else m = 1;
60240792Ssklower 	    q = n / m;
60340792Ssklower 	    n -= m * q;
60440792Ssklower 	    if (q > 9) q = 10; /* For crays with more than 100K interfaces */
60540792Ssklower 	    *cp++ = "0123456789Z"[q];
60640792Ssklower 	} while (n > 0);
60740792Ssklower 	*cp++ = 0;
60840792Ssklower }
609