xref: /csrg-svn/sys/net/if.c (revision 60346)
123157Smckusick /*
229061Smckusick  * Copyright (c) 1980, 1986 Regents of the University of California.
333183Sbostic  * All rights reserved.
423157Smckusick  *
544463Sbostic  * %sccs.include.redist.c%
633183Sbostic  *
7*60346Storek  *	@(#)if.c	7.26 (Berkeley) 05/24/93
823157Smckusick  */
94944Swnj 
1056529Sbostic #include <sys/param.h>
1156529Sbostic #include <sys/mbuf.h>
1256529Sbostic #include <sys/systm.h>
1356529Sbostic #include <sys/proc.h>
1456529Sbostic #include <sys/socket.h>
1556529Sbostic #include <sys/socketvar.h>
1656529Sbostic #include <sys/protosw.h>
1756529Sbostic #include <sys/kernel.h>
1856529Sbostic #include <sys/ioctl.h>
1910872Ssam 
2056529Sbostic #include <net/if.h>
2156529Sbostic #include <net/af.h>
2256529Sbostic #include <net/if_dl.h>
2356529Sbostic #include <net/if_types.h>
244944Swnj 
2516220Skarels #include "ether.h"
2616220Skarels 
276207Swnj int	ifqmaxlen = IFQ_MAXLEN;
2854768Storek void	if_slowtimo __P((void *arg));
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;
4454768Storek 	if_slowtimo(0);
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;
6448453Skarels static char *sprint_d();
6548453Skarels 
666333Ssam /*
676333Ssam  * Attach an interface to the
686333Ssam  * list of "active" interfaces.
696333Ssam  */
7052265Storek void
715160Swnj if_attach(ifp)
725160Swnj 	struct ifnet *ifp;
735160Swnj {
7440792Ssklower 	unsigned socksize, ifasize;
7554718Ssklower 	int namelen, unitlen, masklen, ether_output();
7648453Skarels 	char workbuf[12], *unitname;
7743335Ssklower 	register struct ifnet **p = &ifnet;
7840792Ssklower 	register struct sockaddr_dl *sdl;
7940792Ssklower 	register struct ifaddr *ifa;
8043335Ssklower 	static int if_indexlim = 8;
8154718Ssklower 	extern void link_rtrequest();
825160Swnj 
835698Swnj 	while (*p)
845698Swnj 		p = &((*p)->if_next);
855698Swnj 	*p = ifp;
8640792Ssklower 	ifp->if_index = ++if_index;
8743335Ssklower 	if (ifnet_addrs == 0 || if_index >= if_indexlim) {
8843335Ssklower 		unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
8943335Ssklower 		struct ifaddr **q = (struct ifaddr **)
9043335Ssklower 					malloc(n, M_IFADDR, M_WAITOK);
9143335Ssklower 		if (ifnet_addrs) {
9243335Ssklower 			bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
9343335Ssklower 			free((caddr_t)ifnet_addrs, M_IFADDR);
9443335Ssklower 		}
9543335Ssklower 		ifnet_addrs = q;
9643335Ssklower 	}
9741923Ssklower 	/*
9841923Ssklower 	 * create a Link Level name for this device
9941923Ssklower 	 */
10048453Skarels 	unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
10140792Ssklower 	namelen = strlen(ifp->if_name);
10248453Skarels 	unitlen = strlen(unitname);
10340792Ssklower #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
10452562Ssklower 	masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) +
10552562Ssklower 			       unitlen + namelen;
10652562Ssklower 	socksize = masklen + ifp->if_addrlen;
10740792Ssklower #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
10840792Ssklower 	socksize = ROUNDUP(socksize);
10943335Ssklower 	if (socksize < sizeof(*sdl))
11043335Ssklower 		socksize = sizeof(*sdl);
11140792Ssklower 	ifasize = sizeof(*ifa) + 2 * socksize;
11252562Ssklower 	if (ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK)) {
11352562Ssklower 		bzero((caddr_t)ifa, ifasize);
11452562Ssklower 		sdl = (struct sockaddr_dl *)(ifa + 1);
11552562Ssklower 		sdl->sdl_len = socksize;
11652562Ssklower 		sdl->sdl_family = AF_LINK;
11752562Ssklower 		bcopy(ifp->if_name, sdl->sdl_data, namelen);
11852562Ssklower 		bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
11952562Ssklower 		sdl->sdl_nlen = (namelen += unitlen);
12052562Ssklower 		sdl->sdl_index = ifp->if_index;
12152562Ssklower 		sdl->sdl_type = ifp->if_type;
12252562Ssklower 		ifnet_addrs[if_index - 1] = ifa;
12352562Ssklower 		ifa->ifa_ifp = ifp;
12452562Ssklower 		ifa->ifa_next = ifp->if_addrlist;
12552562Ssklower 		ifa->ifa_rtrequest = link_rtrequest;
12652562Ssklower 		ifp->if_addrlist = ifa;
12752562Ssklower 		ifa->ifa_addr = (struct sockaddr *)sdl;
12852562Ssklower 		sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
12952562Ssklower 		ifa->ifa_netmask = (struct sockaddr *)sdl;
13052562Ssklower 		sdl->sdl_len = masklen;
13152562Ssklower 		while (namelen != 0)
13252562Ssklower 			sdl->sdl_data[--namelen] = 0xff;
13352562Ssklower 	}
13452562Ssklower 	/* XXX -- Temporary fix before changing 10 ethernet drivers */
13552562Ssklower 	if (ifp->if_output == ether_output)
13652562Ssklower 		ether_ifattach(ifp);
1375160Swnj }
1386333Ssam /*
1396333Ssam  * Locate an interface based on a complete address.
1406333Ssam  */
1414951Swnj /*ARGSUSED*/
14218544Skarels struct ifaddr *
14318544Skarels ifa_ifwithaddr(addr)
14437549Smckusick 	register struct sockaddr *addr;
1454944Swnj {
1464944Swnj 	register struct ifnet *ifp;
14718544Skarels 	register struct ifaddr *ifa;
1484944Swnj 
1496333Ssam #define	equal(a1, a2) \
15037549Smckusick   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
15118544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
15218544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
15337549Smckusick 		if (ifa->ifa_addr->sa_family != addr->sa_family)
1546333Ssam 			continue;
15537549Smckusick 		if (equal(addr, ifa->ifa_addr))
15618544Skarels 			return (ifa);
15743335Ssklower 		if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
15843335Ssklower 		    equal(ifa->ifa_broadaddr, addr))
15918544Skarels 			return (ifa);
1606333Ssam 	}
16118544Skarels 	return ((struct ifaddr *)0);
1624944Swnj }
16323933Ssklower /*
16423933Ssklower  * Locate the point to point interface with a given destination address.
16523933Ssklower  */
16623933Ssklower /*ARGSUSED*/
16723933Ssklower struct ifaddr *
16823933Ssklower ifa_ifwithdstaddr(addr)
16937549Smckusick 	register struct sockaddr *addr;
17023933Ssklower {
17123933Ssklower 	register struct ifnet *ifp;
17223933Ssklower 	register struct ifaddr *ifa;
1734944Swnj 
17423933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
17523933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
17623933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
17737549Smckusick 			if (ifa->ifa_addr->sa_family != addr->sa_family)
17823933Ssklower 				continue;
17937549Smckusick 			if (equal(addr, ifa->ifa_dstaddr))
18023933Ssklower 				return (ifa);
18123933Ssklower 	}
18223933Ssklower 	return ((struct ifaddr *)0);
18323933Ssklower }
18423933Ssklower 
1856333Ssam /*
1866333Ssam  * Find an interface on a specific network.  If many, choice
18753454Ssklower  * is most specific found.
1886333Ssam  */
18918544Skarels struct ifaddr *
19018544Skarels ifa_ifwithnet(addr)
19137549Smckusick 	struct sockaddr *addr;
1924944Swnj {
1934944Swnj 	register struct ifnet *ifp;
19418544Skarels 	register struct ifaddr *ifa;
19553454Ssklower 	struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
19637549Smckusick 	u_int af = addr->sa_family;
19753454Ssklower 	char *addr_data = addr->sa_data, *cplim;
1984944Swnj 
19943335Ssklower 	if (af == AF_LINK) {
20043335Ssklower 	    register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
20143335Ssklower 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
20243335Ssklower 		return (ifnet_addrs[sdl->sdl_index - 1]);
20343335Ssklower 	}
20418544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
20518544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
20643335Ssklower 		register char *cp, *cp2, *cp3;
20753454Ssklower 
20837549Smckusick 		if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
20953454Ssklower 			next: continue;
21053454Ssklower 		cp = addr_data;
21137549Smckusick 		cp2 = ifa->ifa_addr->sa_data;
21237549Smckusick 		cp3 = ifa->ifa_netmask->sa_data;
21337549Smckusick 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
21453454Ssklower 		while (cp3 < cplim)
21553454Ssklower 			if ((*cp++ ^ *cp2++) & *cp3++)
21653454Ssklower 				goto next;
21753454Ssklower 		if (ifa_maybe == 0 ||
21853454Ssklower 		    rn_refines(ifa->ifa_netmask, ifa_maybe->ifa_netmask))
21953454Ssklower 			ifa_maybe = ifa;
22037549Smckusick 	    }
22153454Ssklower 	return (ifa_maybe);
2226333Ssam }
2236333Ssam 
2246333Ssam /*
2256333Ssam  * Find an interface using a specific address family
2266333Ssam  */
22718544Skarels struct ifaddr *
22818544Skarels ifa_ifwithaf(af)
2296333Ssam 	register int af;
2305083Swnj {
2316333Ssam 	register struct ifnet *ifp;
23218544Skarels 	register struct ifaddr *ifa;
2335083Swnj 
2346333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
23518544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
23637549Smckusick 		if (ifa->ifa_addr->sa_family == af)
23718544Skarels 			return (ifa);
23818544Skarels 	return ((struct ifaddr *)0);
2395083Swnj }
2405104Swnj 
24143335Ssklower /*
24243335Ssklower  * Find an interface address specific to an interface best matching
24343335Ssklower  * a given address.
24443335Ssklower  */
24543335Ssklower struct ifaddr *
24643335Ssklower ifaof_ifpforaddr(addr, ifp)
24743335Ssklower 	struct sockaddr *addr;
24843335Ssklower 	register struct ifnet *ifp;
24943335Ssklower {
25043335Ssklower 	register struct ifaddr *ifa;
25143335Ssklower 	register char *cp, *cp2, *cp3;
25243335Ssklower 	register char *cplim;
25343335Ssklower 	struct ifaddr *ifa_maybe = 0;
25443335Ssklower 	u_int af = addr->sa_family;
25543335Ssklower 
25643335Ssklower 	if (af >= AF_MAX)
25743335Ssklower 		return (0);
25843335Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
25943335Ssklower 		if (ifa->ifa_addr->sa_family != af)
26043335Ssklower 			continue;
26143335Ssklower 		ifa_maybe = ifa;
26243335Ssklower 		if (ifa->ifa_netmask == 0) {
26343335Ssklower 			if (equal(addr, ifa->ifa_addr) ||
26443335Ssklower 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
26543335Ssklower 				return (ifa);
26643335Ssklower 			continue;
26743335Ssklower 		}
26843335Ssklower 		cp = addr->sa_data;
26943335Ssklower 		cp2 = ifa->ifa_addr->sa_data;
27043335Ssklower 		cp3 = ifa->ifa_netmask->sa_data;
27143335Ssklower 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
27243335Ssklower 		for (; cp3 < cplim; cp3++)
27343335Ssklower 			if ((*cp++ ^ *cp2++) & *cp3)
27443335Ssklower 				break;
27543335Ssklower 		if (cp3 == cplim)
27643335Ssklower 			return (ifa);
27743335Ssklower 	}
27843335Ssklower 	return (ifa_maybe);
27943335Ssklower }
28056529Sbostic 
28156529Sbostic #include <net/route.h>
28256529Sbostic 
2836333Ssam /*
28441923Ssklower  * Default action when installing a route with a Link Level gateway.
28541923Ssklower  * Lookup an appropriate real ifa to point to.
28641923Ssklower  * This should be moved to /sys/net/link.c eventually.
28741923Ssklower  */
28854718Ssklower void
28941923Ssklower link_rtrequest(cmd, rt, sa)
29052265Storek 	int cmd;
29152265Storek 	register struct rtentry *rt;
29252265Storek 	struct sockaddr *sa;
29341923Ssklower {
29441923Ssklower 	register struct ifaddr *ifa;
29541923Ssklower 	struct sockaddr *dst;
29641923Ssklower 	struct ifnet *ifp, *oldifnet = ifnet;
29741923Ssklower 
29841923Ssklower 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
29941923Ssklower 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
30041923Ssklower 		return;
30143335Ssklower 	if (ifa = ifaof_ifpforaddr(dst, ifp)) {
30259063Ssklower 		IFAFREE(rt->rt_ifa);
30341923Ssklower 		rt->rt_ifa = ifa;
30459063Ssklower 		ifa->ifa_refcnt++;
30541923Ssklower 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
30641923Ssklower 			ifa->ifa_rtrequest(cmd, rt, sa);
30743335Ssklower 	}
30841923Ssklower }
30941923Ssklower 
31041923Ssklower /*
3116582Ssam  * Mark an interface down and notify protocols of
3126582Ssam  * the transition.
3139184Ssam  * NOTE: must be called at splnet or eqivalent.
3146582Ssam  */
3156582Ssam if_down(ifp)
3166582Ssam 	register struct ifnet *ifp;
3176582Ssam {
31818544Skarels 	register struct ifaddr *ifa;
3198173Sroot 
3206582Ssam 	ifp->if_flags &= ~IFF_UP;
32118544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
32237549Smckusick 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
32333984Skarels 	if_qflush(&ifp->if_snd);
32452562Ssklower 	rt_ifmsg(ifp);
3256582Ssam }
3267264Ssam 
3277264Ssam /*
32852562Ssklower  * Mark an interface up and notify protocols of
32952562Ssklower  * the transition.
33052562Ssklower  * NOTE: must be called at splnet or eqivalent.
33152562Ssklower  */
33252562Ssklower if_up(ifp)
33352562Ssklower 	register struct ifnet *ifp;
33452562Ssklower {
33552562Ssklower 	register struct ifaddr *ifa;
33652562Ssklower 
33752562Ssklower 	ifp->if_flags |= IFF_UP;
33852562Ssklower #ifdef notyet
33952562Ssklower 	/* this has no effect on IP, and will kill all iso connections XXX */
34052562Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
34152562Ssklower 		pfctlinput(PRC_IFUP, ifa->ifa_addr);
342*60346Storek #endif
34352562Ssklower 	rt_ifmsg(ifp);
34452562Ssklower }
34552562Ssklower 
34652562Ssklower /*
34733984Skarels  * Flush an interface queue.
34833984Skarels  */
34933984Skarels if_qflush(ifq)
35033984Skarels 	register struct ifqueue *ifq;
35133984Skarels {
35233984Skarels 	register struct mbuf *m, *n;
35333984Skarels 
35433984Skarels 	n = ifq->ifq_head;
35533984Skarels 	while (m = n) {
35633984Skarels 		n = m->m_act;
35733984Skarels 		m_freem(m);
35833984Skarels 	}
35933984Skarels 	ifq->ifq_head = 0;
36033984Skarels 	ifq->ifq_tail = 0;
36133984Skarels 	ifq->ifq_len = 0;
36233984Skarels }
36333984Skarels 
36433984Skarels /*
3657264Ssam  * Handle interface watchdog timer routines.  Called
3667264Ssam  * from softclock, we decrement timers (if set) and
3677264Ssam  * call the appropriate interface routine on expiration.
3687264Ssam  */
36954768Storek void
37054768Storek if_slowtimo(arg)
37154768Storek 	void *arg;
3727264Ssam {
3737264Ssam 	register struct ifnet *ifp;
37437549Smckusick 	int s = splimp();
3757264Ssam 
3769184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
3779184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
3789184Ssam 			continue;
3799184Ssam 		if (ifp->if_watchdog)
3807264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
3819184Ssam 	}
38237549Smckusick 	splx(s);
38354768Storek 	timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
3847264Ssam }
38511576Ssam 
38611576Ssam /*
38713049Ssam  * Map interface name to
38813049Ssam  * interface structure pointer.
38911576Ssam  */
39013049Ssam struct ifnet *
39113049Ssam ifunit(name)
39213049Ssam 	register char *name;
39311576Ssam {
39413049Ssam 	register char *cp;
39511576Ssam 	register struct ifnet *ifp;
39613049Ssam 	int unit;
39736821Skarels 	unsigned len;
39836821Skarels 	char *ep, c;
39911576Ssam 
40013049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
40111576Ssam 		if (*cp >= '0' && *cp <= '9')
40211576Ssam 			break;
40313049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
40413049Ssam 		return ((struct ifnet *)0);
40536821Skarels 	/*
40636821Skarels 	 * Save first char of unit, and pointer to it,
40736821Skarels 	 * so we can put a null there to avoid matching
40836821Skarels 	 * initial substrings of interface names.
40936821Skarels 	 */
41036821Skarels 	len = cp - name + 1;
41136821Skarels 	c = *cp;
41236821Skarels 	ep = cp;
41336821Skarels 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
41436821Skarels 		unit = unit * 10 + *cp++ - '0';
41536821Skarels 	*ep = 0;
41611576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
41736821Skarels 		if (bcmp(ifp->if_name, name, len))
41811576Ssam 			continue;
41911576Ssam 		if (unit == ifp->if_unit)
42013049Ssam 			break;
42111576Ssam 	}
42236821Skarels 	*ep = c;
42313049Ssam 	return (ifp);
42413049Ssam }
42511576Ssam 
42613049Ssam /*
42713049Ssam  * Interface ioctls.
42813049Ssam  */
42948453Skarels ifioctl(so, cmd, data, p)
43018544Skarels 	struct socket *so;
43113049Ssam 	int cmd;
43213049Ssam 	caddr_t data;
43348453Skarels 	struct proc *p;
43413049Ssam {
43513049Ssam 	register struct ifnet *ifp;
43613049Ssam 	register struct ifreq *ifr;
43737549Smckusick 	int error;
43813049Ssam 
43911576Ssam 	switch (cmd) {
44011576Ssam 
44113049Ssam 	case SIOCGIFCONF:
44237549Smckusick 	case OSIOCGIFCONF:
44313049Ssam 		return (ifconf(cmd, data));
44413049Ssam 
44525647Skarels #if defined(INET) && NETHER > 0
44616220Skarels 	case SIOCSARP:
44716220Skarels 	case SIOCDARP:
44848453Skarels 		if (error = suser(p->p_ucred, &p->p_acflag))
44937549Smckusick 			return (error);
45016220Skarels 		/* FALL THROUGH */
45116220Skarels 	case SIOCGARP:
45237549Smckusick 	case OSIOCGARP:
45316220Skarels 		return (arpioctl(cmd, data));
45416220Skarels #endif
45513049Ssam 	}
45613049Ssam 	ifr = (struct ifreq *)data;
45713049Ssam 	ifp = ifunit(ifr->ifr_name);
45813049Ssam 	if (ifp == 0)
45913049Ssam 		return (ENXIO);
46013049Ssam 	switch (cmd) {
46113049Ssam 
46211576Ssam 	case SIOCGIFFLAGS:
46311576Ssam 		ifr->ifr_flags = ifp->if_flags;
46411576Ssam 		break;
46511576Ssam 
46626091Skarels 	case SIOCGIFMETRIC:
46726091Skarels 		ifr->ifr_metric = ifp->if_metric;
46826091Skarels 		break;
46926091Skarels 
47013053Ssam 	case SIOCSIFFLAGS:
47148453Skarels 		if (error = suser(p->p_ucred, &p->p_acflag))
47237549Smckusick 			return (error);
47313053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
47413053Ssam 			int s = splimp();
47513053Ssam 			if_down(ifp);
47613053Ssam 			splx(s);
47713053Ssam 		}
47852562Ssklower 		if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
47952562Ssklower 			int s = splimp();
48052562Ssklower 			if_up(ifp);
48152562Ssklower 			splx(s);
48252562Ssklower 		}
48318544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
48418544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
48524773Skarels 		if (ifp->if_ioctl)
48624773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
48713053Ssam 		break;
48813053Ssam 
48926091Skarels 	case SIOCSIFMETRIC:
49048453Skarels 		if (error = suser(p->p_ucred, &p->p_acflag))
49137549Smckusick 			return (error);
49226091Skarels 		ifp->if_metric = ifr->ifr_metric;
49326091Skarels 		break;
49426091Skarels 
49554718Ssklower 	case SIOCADDMULTI:
49654718Ssklower 	case SIOCDELMULTI:
49754718Ssklower 		if (error = suser(p->p_ucred, &p->p_acflag))
49854718Ssklower 			return (error);
49958027Storek 		if (ifp->if_ioctl == NULL)
50054718Ssklower 			return (EOPNOTSUPP);
50154718Ssklower 		return ((*ifp->if_ioctl)(ifp, cmd, data));
50254718Ssklower 
50311576Ssam 	default:
50418544Skarels 		if (so->so_proto == 0)
50513049Ssam 			return (EOPNOTSUPP);
50637549Smckusick #ifndef COMPAT_43
50718544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
50818544Skarels 			cmd, data, ifp));
50937549Smckusick #else
51037549Smckusick 	    {
51141545Smckusick 		int ocmd = cmd;
51237549Smckusick 
51337549Smckusick 		switch (cmd) {
51437549Smckusick 
51537549Smckusick 		case SIOCSIFDSTADDR:
51637549Smckusick 		case SIOCSIFADDR:
51737549Smckusick 		case SIOCSIFBRDADDR:
51837549Smckusick 		case SIOCSIFNETMASK:
51937549Smckusick #if BYTE_ORDER != BIG_ENDIAN
52037549Smckusick 			if (ifr->ifr_addr.sa_family == 0 &&
52137549Smckusick 			    ifr->ifr_addr.sa_len < 16) {
52237549Smckusick 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
52337549Smckusick 				ifr->ifr_addr.sa_len = 16;
52437549Smckusick 			}
52537549Smckusick #else
52637549Smckusick 			if (ifr->ifr_addr.sa_len == 0)
52737549Smckusick 				ifr->ifr_addr.sa_len = 16;
52837549Smckusick #endif
52937549Smckusick 			break;
53037549Smckusick 
53137549Smckusick 		case OSIOCGIFADDR:
53237549Smckusick 			cmd = SIOCGIFADDR;
53337549Smckusick 			break;
53437549Smckusick 
53537549Smckusick 		case OSIOCGIFDSTADDR:
53637549Smckusick 			cmd = SIOCGIFDSTADDR;
53737549Smckusick 			break;
53837549Smckusick 
53937549Smckusick 		case OSIOCGIFBRDADDR:
54037549Smckusick 			cmd = SIOCGIFBRDADDR;
54137549Smckusick 			break;
54237549Smckusick 
54337549Smckusick 		case OSIOCGIFNETMASK:
54437549Smckusick 			cmd = SIOCGIFNETMASK;
54537549Smckusick 		}
54637549Smckusick 		error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
54737549Smckusick 							    cmd, data, ifp));
54837549Smckusick 		switch (ocmd) {
54937549Smckusick 
55037549Smckusick 		case OSIOCGIFADDR:
55137549Smckusick 		case OSIOCGIFDSTADDR:
55237549Smckusick 		case OSIOCGIFBRDADDR:
55337549Smckusick 		case OSIOCGIFNETMASK:
55437549Smckusick 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
55537549Smckusick 		}
55637549Smckusick 		return (error);
55737549Smckusick 
55837549Smckusick 	    }
55937549Smckusick #endif
56011576Ssam 	}
56111576Ssam 	return (0);
56211576Ssam }
56311576Ssam 
56411576Ssam /*
56511576Ssam  * Return interface configuration
56611576Ssam  * of system.  List may be used
56711576Ssam  * in later ioctl's (above) to get
56811576Ssam  * other information.
56911576Ssam  */
57012783Ssam /*ARGSUSED*/
57111576Ssam ifconf(cmd, data)
57211576Ssam 	int cmd;
57311576Ssam 	caddr_t data;
57411576Ssam {
57511576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
57611576Ssam 	register struct ifnet *ifp = ifnet;
57718544Skarels 	register struct ifaddr *ifa;
57811630Ssam 	register char *cp, *ep;
57911630Ssam 	struct ifreq ifr, *ifrp;
58011576Ssam 	int space = ifc->ifc_len, error = 0;
58111576Ssam 
58211630Ssam 	ifrp = ifc->ifc_req;
58311630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
58411576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
58511630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
58611630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
58752914Storek 			continue;
58811630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
58918544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
59018544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
59118544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
59218544Skarels 			if (error)
59318544Skarels 				break;
59418544Skarels 			space -= sizeof (ifr), ifrp++;
59518544Skarels 		} else
59618544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
59737549Smckusick 			register struct sockaddr *sa = ifa->ifa_addr;
59837549Smckusick #ifdef COMPAT_43
59937549Smckusick 			if (cmd == OSIOCGIFCONF) {
60037549Smckusick 				struct osockaddr *osa =
60137549Smckusick 					 (struct osockaddr *)&ifr.ifr_addr;
60237549Smckusick 				ifr.ifr_addr = *sa;
60337549Smckusick 				osa->sa_family = sa->sa_family;
60437549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
60537549Smckusick 						sizeof (ifr));
60637549Smckusick 				ifrp++;
60737549Smckusick 			} else
60837549Smckusick #endif
60937549Smckusick 			if (sa->sa_len <= sizeof(*sa)) {
61037549Smckusick 				ifr.ifr_addr = *sa;
61137549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
61237549Smckusick 						sizeof (ifr));
61337549Smckusick 				ifrp++;
61437549Smckusick 			} else {
61537549Smckusick 				space -= sa->sa_len - sizeof(*sa);
61637549Smckusick 				if (space < sizeof (ifr))
61737549Smckusick 					break;
61837549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
61937549Smckusick 						sizeof (ifr.ifr_name));
62037549Smckusick 				if (error == 0)
62137549Smckusick 				    error = copyout((caddr_t)sa,
62237549Smckusick 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
62337549Smckusick 				ifrp = (struct ifreq *)
62437549Smckusick 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
62537549Smckusick 			}
62618544Skarels 			if (error)
62718544Skarels 				break;
62837549Smckusick 			space -= sizeof (ifr);
62918544Skarels 		}
63011576Ssam 	}
63111576Ssam 	ifc->ifc_len -= space;
63211576Ssam 	return (error);
63311576Ssam }
63440792Ssklower 
63548453Skarels static char *
63648453Skarels sprint_d(n, buf, buflen)
63748453Skarels 	u_int n;
63848453Skarels 	char *buf;
63948453Skarels 	int buflen;
64040792Ssklower {
64148453Skarels 	register char *cp = buf + buflen - 1;
64248453Skarels 
64348453Skarels 	*cp = 0;
64440792Ssklower 	do {
64548453Skarels 		cp--;
64648453Skarels 		*cp = "0123456789"[n % 10];
64748453Skarels 		n /= 10;
64848453Skarels 	} while (n != 0);
64948453Skarels 	return (cp);
65040792Ssklower }
651