xref: /csrg-svn/sys/net/if.c (revision 43335)
123157Smckusick /*
229061Smckusick  * Copyright (c) 1980, 1986 Regents of the University of California.
333183Sbostic  * All rights reserved.
423157Smckusick  *
533183Sbostic  * Redistribution and use in source and binary forms are permitted
634844Sbostic  * provided that the above copyright notice and this paragraph are
734844Sbostic  * duplicated in all such forms and that any documentation,
834844Sbostic  * advertising materials, and other materials related to such
934844Sbostic  * distribution and use acknowledge that the software was developed
1034844Sbostic  * by the University of California, Berkeley.  The name of the
1134844Sbostic  * University may not be used to endorse or promote products derived
1234844Sbostic  * from this software without specific prior written permission.
1334844Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434844Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534844Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633183Sbostic  *
17*43335Ssklower  *	@(#)if.c	7.12 (Berkeley) 06/20/90
1823157Smckusick  */
194944Swnj 
2017036Sbloom #include "param.h"
2133984Skarels #include "mbuf.h"
2217036Sbloom #include "systm.h"
2317036Sbloom #include "socket.h"
2418544Skarels #include "socketvar.h"
2517036Sbloom #include "protosw.h"
2617036Sbloom #include "user.h"
2717036Sbloom #include "kernel.h"
2817036Sbloom #include "ioctl.h"
2917036Sbloom #include "errno.h"
3010872Ssam 
3117036Sbloom #include "if.h"
3217036Sbloom #include "af.h"
3340792Ssklower #include "if_dl.h"
34*43335Ssklower #include "if_types.h"
354944Swnj 
3616220Skarels #include "ether.h"
3716220Skarels 
386207Swnj int	ifqmaxlen = IFQ_MAXLEN;
396207Swnj 
406333Ssam /*
416333Ssam  * Network interface utility routines.
426333Ssam  *
4318544Skarels  * Routines with ifa_ifwith* names take sockaddr *'s as
4418544Skarels  * parameters.
456333Ssam  */
466333Ssam 
475206Swnj ifinit()
485206Swnj {
495206Swnj 	register struct ifnet *ifp;
505206Swnj 
515206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
5224773Skarels 		if (ifp->if_snd.ifq_maxlen == 0)
5324773Skarels 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
548173Sroot 	if_slowtimo();
555206Swnj }
565206Swnj 
5713049Ssam #ifdef vax
586333Ssam /*
596333Ssam  * Call each interface on a Unibus reset.
606333Ssam  */
615206Swnj ifubareset(uban)
625206Swnj 	int uban;
635206Swnj {
645206Swnj 	register struct ifnet *ifp;
655206Swnj 
665206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
678974Sroot 		if (ifp->if_reset)
6815116Ssam 			(*ifp->if_reset)(ifp->if_unit, uban);
695206Swnj }
708393Swnj #endif
715206Swnj 
7240792Ssklower int if_index = 0;
73*43335Ssklower struct ifaddr **ifnet_addrs;
746333Ssam /*
756333Ssam  * Attach an interface to the
766333Ssam  * list of "active" interfaces.
776333Ssam  */
785160Swnj if_attach(ifp)
795160Swnj 	struct ifnet *ifp;
805160Swnj {
8140792Ssklower 	unsigned socksize, ifasize;
8240792Ssklower 	int namelen, unitlen;
8340792Ssklower 	char workbuf[16];
84*43335Ssklower 	register struct ifnet **p = &ifnet;
8540792Ssklower 	register struct sockaddr_dl *sdl;
8640792Ssklower 	register struct ifaddr *ifa;
87*43335Ssklower 	static int if_indexlim = 8;
88*43335Ssklower 	extern link_rtrequest(), ether_output();
895160Swnj 
905698Swnj 	while (*p)
915698Swnj 		p = &((*p)->if_next);
925698Swnj 	*p = ifp;
9340792Ssklower 	ifp->if_index = ++if_index;
94*43335Ssklower 	if (ifnet_addrs == 0 || if_index >= if_indexlim) {
95*43335Ssklower 		unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
96*43335Ssklower 		struct ifaddr **q = (struct ifaddr **)
97*43335Ssklower 					malloc(n, M_IFADDR, M_WAITOK);
98*43335Ssklower 		if (ifnet_addrs) {
99*43335Ssklower 			bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
100*43335Ssklower 			free((caddr_t)ifnet_addrs, M_IFADDR);
101*43335Ssklower 		}
102*43335Ssklower 		ifnet_addrs = q;
103*43335Ssklower 	}
104*43335Ssklower 	/* XXX -- Temporary fix before changing 10 ethernet drivers */
105*43335Ssklower 	if (ifp->if_output == ether_output) {
106*43335Ssklower 		ifp->if_type = IFT_ETHER;
107*43335Ssklower 		ifp->if_addrlen = 6;
108*43335Ssklower 		ifp->if_hdrlen = 14;
109*43335Ssklower 	}
11041923Ssklower 	/*
11141923Ssklower 	 * create a Link Level name for this device
11241923Ssklower 	 */
11340792Ssklower 	sprint_d(workbuf, ifp->if_unit);
11440792Ssklower 	namelen = strlen(ifp->if_name);
11540792Ssklower 	unitlen = strlen(workbuf);
11640792Ssklower #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
11740792Ssklower 	socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
11840792Ssklower 			       unitlen + namelen + ifp->if_addrlen;
11940792Ssklower #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
12040792Ssklower 	socksize = ROUNDUP(socksize);
121*43335Ssklower 	if (socksize < sizeof(*sdl))
122*43335Ssklower 		socksize = sizeof(*sdl);
12340792Ssklower 	ifasize = sizeof(*ifa) + 2 * socksize;
12440792Ssklower 	ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
12540792Ssklower 	if (ifa == 0)
12640792Ssklower 		return;
127*43335Ssklower 	ifnet_addrs[if_index - 1] = ifa;
12840792Ssklower 	bzero((caddr_t)ifa, ifasize);
12940792Ssklower 	sdl = (struct sockaddr_dl *)(ifa + 1);
13040792Ssklower 	ifa->ifa_addr = (struct sockaddr *)sdl;
13140792Ssklower 	ifa->ifa_ifp = ifp;
13240792Ssklower 	sdl->sdl_len = socksize;
13340792Ssklower 	sdl->sdl_family = AF_LINK;
13440792Ssklower 	bcopy(ifp->if_name, sdl->sdl_data, namelen);
13540792Ssklower 	bcopy((caddr_t)workbuf, namelen + (caddr_t)sdl->sdl_data, unitlen);
13640792Ssklower 	sdl->sdl_nlen = (namelen += unitlen);
13740792Ssklower 	sdl->sdl_index = ifp->if_index;
13840792Ssklower 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
13940792Ssklower 	ifa->ifa_netmask = (struct sockaddr *)sdl;
14040792Ssklower 	sdl->sdl_len = socksize - ifp->if_addrlen;
14140792Ssklower 	while (namelen != 0)
14240792Ssklower 		sdl->sdl_data[--namelen] = 0xff;
14340792Ssklower 	ifa->ifa_next = ifp->if_addrlist;
14441923Ssklower 	ifa->ifa_rtrequest = link_rtrequest;
14540792Ssklower 	ifp->if_addrlist = ifa;
1465160Swnj }
1476333Ssam /*
1486333Ssam  * Locate an interface based on a complete address.
1496333Ssam  */
1504951Swnj /*ARGSUSED*/
15118544Skarels struct ifaddr *
15218544Skarels ifa_ifwithaddr(addr)
15337549Smckusick 	register struct sockaddr *addr;
1544944Swnj {
1554944Swnj 	register struct ifnet *ifp;
15618544Skarels 	register struct ifaddr *ifa;
1574944Swnj 
1586333Ssam #define	equal(a1, a2) \
15937549Smckusick   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
16018544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
16118544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
16237549Smckusick 		if (ifa->ifa_addr->sa_family != addr->sa_family)
1636333Ssam 			continue;
16437549Smckusick 		if (equal(addr, ifa->ifa_addr))
16518544Skarels 			return (ifa);
166*43335Ssklower 		if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
167*43335Ssklower 		    equal(ifa->ifa_broadaddr, addr))
16818544Skarels 			return (ifa);
1696333Ssam 	}
17018544Skarels 	return ((struct ifaddr *)0);
1714944Swnj }
17223933Ssklower /*
17323933Ssklower  * Locate the point to point interface with a given destination address.
17423933Ssklower  */
17523933Ssklower /*ARGSUSED*/
17623933Ssklower struct ifaddr *
17723933Ssklower ifa_ifwithdstaddr(addr)
17837549Smckusick 	register struct sockaddr *addr;
17923933Ssklower {
18023933Ssklower 	register struct ifnet *ifp;
18123933Ssklower 	register struct ifaddr *ifa;
1824944Swnj 
18323933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
18423933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
18523933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
18637549Smckusick 			if (ifa->ifa_addr->sa_family != addr->sa_family)
18723933Ssklower 				continue;
18837549Smckusick 			if (equal(addr, ifa->ifa_dstaddr))
18923933Ssklower 				return (ifa);
19023933Ssklower 	}
19123933Ssklower 	return ((struct ifaddr *)0);
19223933Ssklower }
19323933Ssklower 
1946333Ssam /*
1956333Ssam  * Find an interface on a specific network.  If many, choice
1966333Ssam  * is first found.
1976333Ssam  */
19818544Skarels struct ifaddr *
19918544Skarels ifa_ifwithnet(addr)
20037549Smckusick 	struct sockaddr *addr;
2014944Swnj {
2024944Swnj 	register struct ifnet *ifp;
20318544Skarels 	register struct ifaddr *ifa;
20437549Smckusick 	u_int af = addr->sa_family;
2054944Swnj 
2066619Ssam 	if (af >= AF_MAX)
2076619Ssam 		return (0);
208*43335Ssklower 	if (af == AF_LINK) {
209*43335Ssklower 	    register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
210*43335Ssklower 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
211*43335Ssklower 		return (ifnet_addrs[sdl->sdl_index - 1]);
212*43335Ssklower 	}
21318544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
21418544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
215*43335Ssklower 		register char *cp, *cp2, *cp3;
216*43335Ssklower 		register char *cplim;
21737549Smckusick 		if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
2186333Ssam 			continue;
21937549Smckusick 		cp = addr->sa_data;
22037549Smckusick 		cp2 = ifa->ifa_addr->sa_data;
22137549Smckusick 		cp3 = ifa->ifa_netmask->sa_data;
22237549Smckusick 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
22337549Smckusick 		for (; cp3 < cplim; cp3++)
22437549Smckusick 			if ((*cp++ ^ *cp2++) & *cp3)
22537549Smckusick 				break;
22637549Smckusick 		if (cp3 == cplim)
22718544Skarels 			return (ifa);
22837549Smckusick 	    }
22918544Skarels 	return ((struct ifaddr *)0);
2306333Ssam }
2316333Ssam 
2326333Ssam /*
2336333Ssam  * Find an interface using a specific address family
2346333Ssam  */
23518544Skarels struct ifaddr *
23618544Skarels ifa_ifwithaf(af)
2376333Ssam 	register int af;
2385083Swnj {
2396333Ssam 	register struct ifnet *ifp;
24018544Skarels 	register struct ifaddr *ifa;
2415083Swnj 
2426333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
24318544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
24437549Smckusick 		if (ifa->ifa_addr->sa_family == af)
24518544Skarels 			return (ifa);
24618544Skarels 	return ((struct ifaddr *)0);
2475083Swnj }
2485104Swnj 
249*43335Ssklower /*
250*43335Ssklower  * Find an interface address specific to an interface best matching
251*43335Ssklower  * a given address.
252*43335Ssklower  */
253*43335Ssklower struct ifaddr *
254*43335Ssklower ifaof_ifpforaddr(addr, ifp)
255*43335Ssklower 	struct sockaddr *addr;
256*43335Ssklower 	register struct ifnet *ifp;
257*43335Ssklower {
258*43335Ssklower 	register struct ifaddr *ifa;
259*43335Ssklower 	register char *cp, *cp2, *cp3;
260*43335Ssklower 	register char *cplim;
261*43335Ssklower 	struct ifaddr *ifa_maybe = 0;
262*43335Ssklower 	u_int af = addr->sa_family;
263*43335Ssklower 
264*43335Ssklower 	if (af >= AF_MAX)
265*43335Ssklower 		return (0);
266*43335Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
267*43335Ssklower 		if (ifa->ifa_addr->sa_family != af)
268*43335Ssklower 			continue;
269*43335Ssklower 		ifa_maybe = ifa;
270*43335Ssklower 		if (ifa->ifa_netmask == 0) {
271*43335Ssklower 			if (equal(addr, ifa->ifa_addr) ||
272*43335Ssklower 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
273*43335Ssklower 				return (ifa);
274*43335Ssklower 			continue;
275*43335Ssklower 		}
276*43335Ssklower 		cp = addr->sa_data;
277*43335Ssklower 		cp2 = ifa->ifa_addr->sa_data;
278*43335Ssklower 		cp3 = ifa->ifa_netmask->sa_data;
279*43335Ssklower 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
280*43335Ssklower 		for (; cp3 < cplim; cp3++)
281*43335Ssklower 			if ((*cp++ ^ *cp2++) & *cp3)
282*43335Ssklower 				break;
283*43335Ssklower 		if (cp3 == cplim)
284*43335Ssklower 			return (ifa);
285*43335Ssklower 	}
286*43335Ssklower 	return (ifa_maybe);
287*43335Ssklower }
28841923Ssklower #include "route.h"
2896333Ssam /*
29041923Ssklower  * Default action when installing a route with a Link Level gateway.
29141923Ssklower  * Lookup an appropriate real ifa to point to.
29241923Ssklower  * This should be moved to /sys/net/link.c eventually.
29341923Ssklower  */
29441923Ssklower link_rtrequest(cmd, rt, sa)
29541923Ssklower register struct rtentry *rt;
29641923Ssklower struct sockaddr *sa;
29741923Ssklower {
29841923Ssklower 	register struct ifaddr *ifa;
29941923Ssklower 	struct sockaddr *dst;
30041923Ssklower 	struct ifnet *ifp, *oldifnet = ifnet;
30141923Ssklower 
30241923Ssklower 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
30341923Ssklower 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
30441923Ssklower 		return;
305*43335Ssklower 	if (ifa = ifaof_ifpforaddr(dst, ifp)) {
30641923Ssklower 		rt->rt_ifa = ifa;
30741923Ssklower 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
30841923Ssklower 			ifa->ifa_rtrequest(cmd, rt, sa);
309*43335Ssklower 	}
31041923Ssklower }
31141923Ssklower 
31241923Ssklower /*
3136582Ssam  * Mark an interface down and notify protocols of
3146582Ssam  * the transition.
3159184Ssam  * NOTE: must be called at splnet or eqivalent.
3166582Ssam  */
3176582Ssam if_down(ifp)
3186582Ssam 	register struct ifnet *ifp;
3196582Ssam {
32018544Skarels 	register struct ifaddr *ifa;
3218173Sroot 
3226582Ssam 	ifp->if_flags &= ~IFF_UP;
32318544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
32437549Smckusick 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
32533984Skarels 	if_qflush(&ifp->if_snd);
3266582Ssam }
3277264Ssam 
3287264Ssam /*
32933984Skarels  * Flush an interface queue.
33033984Skarels  */
33133984Skarels if_qflush(ifq)
33233984Skarels 	register struct ifqueue *ifq;
33333984Skarels {
33433984Skarels 	register struct mbuf *m, *n;
33533984Skarels 
33633984Skarels 	n = ifq->ifq_head;
33733984Skarels 	while (m = n) {
33833984Skarels 		n = m->m_act;
33933984Skarels 		m_freem(m);
34033984Skarels 	}
34133984Skarels 	ifq->ifq_head = 0;
34233984Skarels 	ifq->ifq_tail = 0;
34333984Skarels 	ifq->ifq_len = 0;
34433984Skarels }
34533984Skarels 
34633984Skarels /*
3477264Ssam  * Handle interface watchdog timer routines.  Called
3487264Ssam  * from softclock, we decrement timers (if set) and
3497264Ssam  * call the appropriate interface routine on expiration.
3507264Ssam  */
3517264Ssam if_slowtimo()
3527264Ssam {
3537264Ssam 	register struct ifnet *ifp;
35437549Smckusick 	int s = splimp();
3557264Ssam 
3569184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
3579184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
3589184Ssam 			continue;
3599184Ssam 		if (ifp->if_watchdog)
3607264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
3619184Ssam 	}
36237549Smckusick 	splx(s);
3638692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
3647264Ssam }
36511576Ssam 
36611576Ssam /*
36713049Ssam  * Map interface name to
36813049Ssam  * interface structure pointer.
36911576Ssam  */
37013049Ssam struct ifnet *
37113049Ssam ifunit(name)
37213049Ssam 	register char *name;
37311576Ssam {
37413049Ssam 	register char *cp;
37511576Ssam 	register struct ifnet *ifp;
37613049Ssam 	int unit;
37736821Skarels 	unsigned len;
37836821Skarels 	char *ep, c;
37911576Ssam 
38013049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
38111576Ssam 		if (*cp >= '0' && *cp <= '9')
38211576Ssam 			break;
38313049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
38413049Ssam 		return ((struct ifnet *)0);
38536821Skarels 	/*
38636821Skarels 	 * Save first char of unit, and pointer to it,
38736821Skarels 	 * so we can put a null there to avoid matching
38836821Skarels 	 * initial substrings of interface names.
38936821Skarels 	 */
39036821Skarels 	len = cp - name + 1;
39136821Skarels 	c = *cp;
39236821Skarels 	ep = cp;
39336821Skarels 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
39436821Skarels 		unit = unit * 10 + *cp++ - '0';
39536821Skarels 	*ep = 0;
39611576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
39736821Skarels 		if (bcmp(ifp->if_name, name, len))
39811576Ssam 			continue;
39911576Ssam 		if (unit == ifp->if_unit)
40013049Ssam 			break;
40111576Ssam 	}
40236821Skarels 	*ep = c;
40313049Ssam 	return (ifp);
40413049Ssam }
40511576Ssam 
40613049Ssam /*
40713049Ssam  * Interface ioctls.
40813049Ssam  */
40918544Skarels ifioctl(so, cmd, data)
41018544Skarels 	struct socket *so;
41113049Ssam 	int cmd;
41213049Ssam 	caddr_t data;
41313049Ssam {
41413049Ssam 	register struct ifnet *ifp;
41513049Ssam 	register struct ifreq *ifr;
41637549Smckusick 	int error;
41713049Ssam 
41811576Ssam 	switch (cmd) {
41911576Ssam 
42013049Ssam 	case SIOCGIFCONF:
42137549Smckusick 	case OSIOCGIFCONF:
42213049Ssam 		return (ifconf(cmd, data));
42313049Ssam 
42425647Skarels #if defined(INET) && NETHER > 0
42516220Skarels 	case SIOCSARP:
42616220Skarels 	case SIOCDARP:
42737549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
42837549Smckusick 			return (error);
42916220Skarels 		/* FALL THROUGH */
43016220Skarels 	case SIOCGARP:
43137549Smckusick 	case OSIOCGARP:
43216220Skarels 		return (arpioctl(cmd, data));
43316220Skarels #endif
43413049Ssam 	}
43513049Ssam 	ifr = (struct ifreq *)data;
43613049Ssam 	ifp = ifunit(ifr->ifr_name);
43713049Ssam 	if (ifp == 0)
43813049Ssam 		return (ENXIO);
43913049Ssam 	switch (cmd) {
44013049Ssam 
44111576Ssam 	case SIOCGIFFLAGS:
44211576Ssam 		ifr->ifr_flags = ifp->if_flags;
44311576Ssam 		break;
44411576Ssam 
44526091Skarels 	case SIOCGIFMETRIC:
44626091Skarels 		ifr->ifr_metric = ifp->if_metric;
44726091Skarels 		break;
44826091Skarels 
44913053Ssam 	case SIOCSIFFLAGS:
45037549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
45137549Smckusick 			return (error);
45213053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
45313053Ssam 			int s = splimp();
45413053Ssam 			if_down(ifp);
45513053Ssam 			splx(s);
45613053Ssam 		}
45718544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
45818544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
45924773Skarels 		if (ifp->if_ioctl)
46024773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
46113053Ssam 		break;
46213053Ssam 
46326091Skarels 	case SIOCSIFMETRIC:
46437549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
46537549Smckusick 			return (error);
46626091Skarels 		ifp->if_metric = ifr->ifr_metric;
46726091Skarels 		break;
46826091Skarels 
46911576Ssam 	default:
47018544Skarels 		if (so->so_proto == 0)
47113049Ssam 			return (EOPNOTSUPP);
47237549Smckusick #ifndef COMPAT_43
47318544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
47418544Skarels 			cmd, data, ifp));
47537549Smckusick #else
47637549Smckusick 	    {
47741545Smckusick 		int ocmd = cmd;
47837549Smckusick 
47937549Smckusick 		switch (cmd) {
48037549Smckusick 
48137549Smckusick 		case SIOCSIFDSTADDR:
48237549Smckusick 		case SIOCSIFADDR:
48337549Smckusick 		case SIOCSIFBRDADDR:
48437549Smckusick 		case SIOCSIFNETMASK:
48537549Smckusick #if BYTE_ORDER != BIG_ENDIAN
48637549Smckusick 			if (ifr->ifr_addr.sa_family == 0 &&
48737549Smckusick 			    ifr->ifr_addr.sa_len < 16) {
48837549Smckusick 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
48937549Smckusick 				ifr->ifr_addr.sa_len = 16;
49037549Smckusick 			}
49137549Smckusick #else
49237549Smckusick 			if (ifr->ifr_addr.sa_len == 0)
49337549Smckusick 				ifr->ifr_addr.sa_len = 16;
49437549Smckusick #endif
49537549Smckusick 			break;
49637549Smckusick 
49737549Smckusick 		case OSIOCGIFADDR:
49837549Smckusick 			cmd = SIOCGIFADDR;
49937549Smckusick 			break;
50037549Smckusick 
50137549Smckusick 		case OSIOCGIFDSTADDR:
50237549Smckusick 			cmd = SIOCGIFDSTADDR;
50337549Smckusick 			break;
50437549Smckusick 
50537549Smckusick 		case OSIOCGIFBRDADDR:
50637549Smckusick 			cmd = SIOCGIFBRDADDR;
50737549Smckusick 			break;
50837549Smckusick 
50937549Smckusick 		case OSIOCGIFNETMASK:
51037549Smckusick 			cmd = SIOCGIFNETMASK;
51137549Smckusick 		}
51237549Smckusick 		error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
51337549Smckusick 							    cmd, data, ifp));
51437549Smckusick 		switch (ocmd) {
51537549Smckusick 
51637549Smckusick 		case OSIOCGIFADDR:
51737549Smckusick 		case OSIOCGIFDSTADDR:
51837549Smckusick 		case OSIOCGIFBRDADDR:
51937549Smckusick 		case OSIOCGIFNETMASK:
52037549Smckusick 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
52137549Smckusick 		}
52237549Smckusick 		return (error);
52337549Smckusick 
52437549Smckusick 	    }
52537549Smckusick #endif
52611576Ssam 	}
52711576Ssam 	return (0);
52811576Ssam }
52911576Ssam 
53011576Ssam /*
53111576Ssam  * Return interface configuration
53211576Ssam  * of system.  List may be used
53311576Ssam  * in later ioctl's (above) to get
53411576Ssam  * other information.
53511576Ssam  */
53612783Ssam /*ARGSUSED*/
53711576Ssam ifconf(cmd, data)
53811576Ssam 	int cmd;
53911576Ssam 	caddr_t data;
54011576Ssam {
54111576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
54211576Ssam 	register struct ifnet *ifp = ifnet;
54318544Skarels 	register struct ifaddr *ifa;
54411630Ssam 	register char *cp, *ep;
54511630Ssam 	struct ifreq ifr, *ifrp;
54611576Ssam 	int space = ifc->ifc_len, error = 0;
54711576Ssam 
54811630Ssam 	ifrp = ifc->ifc_req;
54911630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
55011576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
55111630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
55211630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
55311576Ssam 			;
55411630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
55518544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
55618544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
55718544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
55818544Skarels 			if (error)
55918544Skarels 				break;
56018544Skarels 			space -= sizeof (ifr), ifrp++;
56118544Skarels 		} else
56218544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
56337549Smckusick 			register struct sockaddr *sa = ifa->ifa_addr;
56437549Smckusick #ifdef COMPAT_43
56537549Smckusick 			if (cmd == OSIOCGIFCONF) {
56637549Smckusick 				struct osockaddr *osa =
56737549Smckusick 					 (struct osockaddr *)&ifr.ifr_addr;
56837549Smckusick 				ifr.ifr_addr = *sa;
56937549Smckusick 				osa->sa_family = sa->sa_family;
57037549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
57137549Smckusick 						sizeof (ifr));
57237549Smckusick 				ifrp++;
57337549Smckusick 			} else
57437549Smckusick #endif
57537549Smckusick 			if (sa->sa_len <= sizeof(*sa)) {
57637549Smckusick 				ifr.ifr_addr = *sa;
57737549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
57837549Smckusick 						sizeof (ifr));
57937549Smckusick 				ifrp++;
58037549Smckusick 			} else {
58137549Smckusick 				space -= sa->sa_len - sizeof(*sa);
58237549Smckusick 				if (space < sizeof (ifr))
58337549Smckusick 					break;
58437549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
58537549Smckusick 						sizeof (ifr.ifr_name));
58637549Smckusick 				if (error == 0)
58737549Smckusick 				    error = copyout((caddr_t)sa,
58837549Smckusick 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
58937549Smckusick 				ifrp = (struct ifreq *)
59037549Smckusick 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
59137549Smckusick 			}
59218544Skarels 			if (error)
59318544Skarels 				break;
59437549Smckusick 			space -= sizeof (ifr);
59518544Skarels 		}
59611576Ssam 	}
59711576Ssam 	ifc->ifc_len -= space;
59811576Ssam 	return (error);
59911576Ssam }
60040792Ssklower 
60140792Ssklower static sprint_d(cp, n)
60240792Ssklower register char *cp;
60340792Ssklower u_short n;
60440792Ssklower {
60540792Ssklower 	register int q, m;
60640792Ssklower 	do {
60740792Ssklower 	    if (n >= 10000) m = 10000;
60840792Ssklower 		else if (n >= 1000) m = 1000;
60940792Ssklower 		else if (n >= 100) m = 100;
61040792Ssklower 		else if (n >= 10) m = 10;
61140792Ssklower 		else m = 1;
61240792Ssklower 	    q = n / m;
61340792Ssklower 	    n -= m * q;
61440792Ssklower 	    if (q > 9) q = 10; /* For crays with more than 100K interfaces */
61540792Ssklower 	    *cp++ = "0123456789Z"[q];
61640792Ssklower 	} while (n > 0);
61740792Ssklower 	*cp++ = 0;
61840792Ssklower }
619