xref: /csrg-svn/sys/net/if.c (revision 41545)
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*41545Smckusick  *	@(#)if.c	7.10 (Berkeley) 05/10/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"
344944Swnj 
3516220Skarels #include "ether.h"
3616220Skarels 
376207Swnj int	ifqmaxlen = IFQ_MAXLEN;
386207Swnj 
396333Ssam /*
406333Ssam  * Network interface utility routines.
416333Ssam  *
4218544Skarels  * Routines with ifa_ifwith* names take sockaddr *'s as
4318544Skarels  * parameters.
446333Ssam  */
456333Ssam 
465206Swnj ifinit()
475206Swnj {
485206Swnj 	register struct ifnet *ifp;
495206Swnj 
505206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
5124773Skarels 		if (ifp->if_snd.ifq_maxlen == 0)
5224773Skarels 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
538173Sroot 	if_slowtimo();
545206Swnj }
555206Swnj 
5613049Ssam #ifdef vax
576333Ssam /*
586333Ssam  * Call each interface on a Unibus reset.
596333Ssam  */
605206Swnj ifubareset(uban)
615206Swnj 	int uban;
625206Swnj {
635206Swnj 	register struct ifnet *ifp;
645206Swnj 
655206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
668974Sroot 		if (ifp->if_reset)
6715116Ssam 			(*ifp->if_reset)(ifp->if_unit, uban);
685206Swnj }
698393Swnj #endif
705206Swnj 
7140792Ssklower int if_index = 0;
726333Ssam /*
736333Ssam  * Attach an interface to the
746333Ssam  * list of "active" interfaces.
756333Ssam  */
765160Swnj if_attach(ifp)
775160Swnj 	struct ifnet *ifp;
785160Swnj {
795698Swnj 	register struct ifnet **p = &ifnet;
8040792Ssklower 	unsigned socksize, ifasize;
8140792Ssklower 	int namelen, unitlen;
8240792Ssklower 	char workbuf[16];
8340792Ssklower 	register struct sockaddr_dl *sdl;
8440792Ssklower 	register struct ifaddr *ifa;
855160Swnj 
865698Swnj 	while (*p)
875698Swnj 		p = &((*p)->if_next);
885698Swnj 	*p = ifp;
8940792Ssklower 	ifp->if_index = ++if_index;
9040792Ssklower 	/* create a link level name for this device */
9140792Ssklower 	sprint_d(workbuf, ifp->if_unit);
9240792Ssklower 	namelen = strlen(ifp->if_name);
9340792Ssklower 	unitlen = strlen(workbuf);
9440792Ssklower #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
9540792Ssklower 	socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
9640792Ssklower 			       unitlen + namelen + ifp->if_addrlen;
9740792Ssklower #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
9840792Ssklower 	socksize = ROUNDUP(socksize);
9940792Ssklower 	ifasize = sizeof(*ifa) + 2 * socksize;
10040792Ssklower 	ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
10140792Ssklower 	if (ifa == 0)
10240792Ssklower 		return;
10340792Ssklower 	bzero((caddr_t)ifa, ifasize);
10440792Ssklower 	sdl = (struct sockaddr_dl *)(ifa + 1);
10540792Ssklower 	ifa->ifa_addr = (struct sockaddr *)sdl;
10640792Ssklower 	ifa->ifa_ifp = ifp;
10740792Ssklower 	sdl->sdl_len = socksize;
10840792Ssklower 	sdl->sdl_family = AF_LINK;
10940792Ssklower 	bcopy(ifp->if_name, sdl->sdl_data, namelen);
11040792Ssklower 	bcopy((caddr_t)workbuf, namelen + (caddr_t)sdl->sdl_data, unitlen);
11140792Ssklower 	sdl->sdl_nlen = (namelen += unitlen);
11240792Ssklower 	sdl->sdl_index = ifp->if_index;
11340792Ssklower 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
11440792Ssklower 	ifa->ifa_netmask = (struct sockaddr *)sdl;
11540792Ssklower 	sdl->sdl_len = socksize - ifp->if_addrlen;
11640792Ssklower 	while (namelen != 0)
11740792Ssklower 		sdl->sdl_data[--namelen] = 0xff;
11840792Ssklower 	ifa->ifa_next = ifp->if_addrlist;
11940792Ssklower 	ifp->if_addrlist = ifa;
1205160Swnj }
1215160Swnj 
1226333Ssam /*
1236333Ssam  * Locate an interface based on a complete address.
1246333Ssam  */
1254951Swnj /*ARGSUSED*/
12618544Skarels struct ifaddr *
12718544Skarels ifa_ifwithaddr(addr)
12837549Smckusick 	register struct sockaddr *addr;
1294944Swnj {
1304944Swnj 	register struct ifnet *ifp;
13118544Skarels 	register struct ifaddr *ifa;
1324944Swnj 
1336333Ssam #define	equal(a1, a2) \
13437549Smckusick   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
13518544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
13618544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
13737549Smckusick 		if (ifa->ifa_addr->sa_family != addr->sa_family)
1386333Ssam 			continue;
13937549Smckusick 		if (equal(addr, ifa->ifa_addr))
14018544Skarels 			return (ifa);
1416333Ssam 		if ((ifp->if_flags & IFF_BROADCAST) &&
14218544Skarels 		    equal(&ifa->ifa_broadaddr, addr))
14318544Skarels 			return (ifa);
1446333Ssam 	}
14518544Skarels 	return ((struct ifaddr *)0);
1464944Swnj }
14723933Ssklower /*
14823933Ssklower  * Locate the point to point interface with a given destination address.
14923933Ssklower  */
15023933Ssklower /*ARGSUSED*/
15123933Ssklower struct ifaddr *
15223933Ssklower ifa_ifwithdstaddr(addr)
15337549Smckusick 	register struct sockaddr *addr;
15423933Ssklower {
15523933Ssklower 	register struct ifnet *ifp;
15623933Ssklower 	register struct ifaddr *ifa;
1574944Swnj 
15823933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
15923933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
16023933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
16137549Smckusick 			if (ifa->ifa_addr->sa_family != addr->sa_family)
16223933Ssklower 				continue;
16337549Smckusick 			if (equal(addr, ifa->ifa_dstaddr))
16423933Ssklower 				return (ifa);
16523933Ssklower 	}
16623933Ssklower 	return ((struct ifaddr *)0);
16723933Ssklower }
16823933Ssklower 
1696333Ssam /*
1706333Ssam  * Find an interface on a specific network.  If many, choice
1716333Ssam  * is first found.
1726333Ssam  */
17318544Skarels struct ifaddr *
17418544Skarels ifa_ifwithnet(addr)
17537549Smckusick 	struct sockaddr *addr;
1764944Swnj {
1774944Swnj 	register struct ifnet *ifp;
17818544Skarels 	register struct ifaddr *ifa;
17937549Smckusick 	register char *cp, *cp2, *cp3;
18037549Smckusick 	register char *cplim;
18137549Smckusick 	u_int af = addr->sa_family;
1824944Swnj 
1836619Ssam 	if (af >= AF_MAX)
1846619Ssam 		return (0);
18518544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
18618544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
18737549Smckusick 		if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
1886333Ssam 			continue;
18937549Smckusick 		cp = addr->sa_data;
19037549Smckusick 		cp2 = ifa->ifa_addr->sa_data;
19137549Smckusick 		cp3 = ifa->ifa_netmask->sa_data;
19237549Smckusick 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
19337549Smckusick 		for (; cp3 < cplim; cp3++)
19437549Smckusick 			if ((*cp++ ^ *cp2++) & *cp3)
19537549Smckusick 				break;
19637549Smckusick 		if (cp3 == cplim)
19718544Skarels 			return (ifa);
19837549Smckusick 	    }
19918544Skarels 	return ((struct ifaddr *)0);
2006333Ssam }
2016333Ssam 
20228942Skarels #ifdef notdef
2036333Ssam /*
2046333Ssam  * Find an interface using a specific address family
2056333Ssam  */
20618544Skarels struct ifaddr *
20718544Skarels ifa_ifwithaf(af)
2086333Ssam 	register int af;
2095083Swnj {
2106333Ssam 	register struct ifnet *ifp;
21118544Skarels 	register struct ifaddr *ifa;
2125083Swnj 
2136333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
21418544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
21537549Smckusick 		if (ifa->ifa_addr->sa_family == af)
21618544Skarels 			return (ifa);
21718544Skarels 	return ((struct ifaddr *)0);
2185083Swnj }
21928942Skarels #endif
2205104Swnj 
2216333Ssam /*
2226582Ssam  * Mark an interface down and notify protocols of
2236582Ssam  * the transition.
2249184Ssam  * NOTE: must be called at splnet or eqivalent.
2256582Ssam  */
2266582Ssam if_down(ifp)
2276582Ssam 	register struct ifnet *ifp;
2286582Ssam {
22918544Skarels 	register struct ifaddr *ifa;
2308173Sroot 
2316582Ssam 	ifp->if_flags &= ~IFF_UP;
23218544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
23337549Smckusick 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
23433984Skarels 	if_qflush(&ifp->if_snd);
2356582Ssam }
2367264Ssam 
2377264Ssam /*
23833984Skarels  * Flush an interface queue.
23933984Skarels  */
24033984Skarels if_qflush(ifq)
24133984Skarels 	register struct ifqueue *ifq;
24233984Skarels {
24333984Skarels 	register struct mbuf *m, *n;
24433984Skarels 
24533984Skarels 	n = ifq->ifq_head;
24633984Skarels 	while (m = n) {
24733984Skarels 		n = m->m_act;
24833984Skarels 		m_freem(m);
24933984Skarels 	}
25033984Skarels 	ifq->ifq_head = 0;
25133984Skarels 	ifq->ifq_tail = 0;
25233984Skarels 	ifq->ifq_len = 0;
25333984Skarels }
25433984Skarels 
25533984Skarels /*
2567264Ssam  * Handle interface watchdog timer routines.  Called
2577264Ssam  * from softclock, we decrement timers (if set) and
2587264Ssam  * call the appropriate interface routine on expiration.
2597264Ssam  */
2607264Ssam if_slowtimo()
2617264Ssam {
2627264Ssam 	register struct ifnet *ifp;
26337549Smckusick 	int s = splimp();
2647264Ssam 
2659184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
2669184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
2679184Ssam 			continue;
2689184Ssam 		if (ifp->if_watchdog)
2697264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
2709184Ssam 	}
27137549Smckusick 	splx(s);
2728692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
2737264Ssam }
27411576Ssam 
27511576Ssam /*
27613049Ssam  * Map interface name to
27713049Ssam  * interface structure pointer.
27811576Ssam  */
27913049Ssam struct ifnet *
28013049Ssam ifunit(name)
28113049Ssam 	register char *name;
28211576Ssam {
28313049Ssam 	register char *cp;
28411576Ssam 	register struct ifnet *ifp;
28513049Ssam 	int unit;
28636821Skarels 	unsigned len;
28736821Skarels 	char *ep, c;
28811576Ssam 
28913049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
29011576Ssam 		if (*cp >= '0' && *cp <= '9')
29111576Ssam 			break;
29213049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
29313049Ssam 		return ((struct ifnet *)0);
29436821Skarels 	/*
29536821Skarels 	 * Save first char of unit, and pointer to it,
29636821Skarels 	 * so we can put a null there to avoid matching
29736821Skarels 	 * initial substrings of interface names.
29836821Skarels 	 */
29936821Skarels 	len = cp - name + 1;
30036821Skarels 	c = *cp;
30136821Skarels 	ep = cp;
30236821Skarels 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
30336821Skarels 		unit = unit * 10 + *cp++ - '0';
30436821Skarels 	*ep = 0;
30511576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
30636821Skarels 		if (bcmp(ifp->if_name, name, len))
30711576Ssam 			continue;
30811576Ssam 		if (unit == ifp->if_unit)
30913049Ssam 			break;
31011576Ssam 	}
31136821Skarels 	*ep = c;
31213049Ssam 	return (ifp);
31313049Ssam }
31411576Ssam 
31513049Ssam /*
31613049Ssam  * Interface ioctls.
31713049Ssam  */
31818544Skarels ifioctl(so, cmd, data)
31918544Skarels 	struct socket *so;
32013049Ssam 	int cmd;
32113049Ssam 	caddr_t data;
32213049Ssam {
32313049Ssam 	register struct ifnet *ifp;
32413049Ssam 	register struct ifreq *ifr;
32537549Smckusick 	int error;
32613049Ssam 
32711576Ssam 	switch (cmd) {
32811576Ssam 
32913049Ssam 	case SIOCGIFCONF:
33037549Smckusick 	case OSIOCGIFCONF:
33113049Ssam 		return (ifconf(cmd, data));
33213049Ssam 
33325647Skarels #if defined(INET) && NETHER > 0
33416220Skarels 	case SIOCSARP:
33516220Skarels 	case SIOCDARP:
33637549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
33737549Smckusick 			return (error);
33816220Skarels 		/* FALL THROUGH */
33916220Skarels 	case SIOCGARP:
34037549Smckusick 	case OSIOCGARP:
34116220Skarels 		return (arpioctl(cmd, data));
34216220Skarels #endif
34313049Ssam 	}
34413049Ssam 	ifr = (struct ifreq *)data;
34513049Ssam 	ifp = ifunit(ifr->ifr_name);
34613049Ssam 	if (ifp == 0)
34713049Ssam 		return (ENXIO);
34813049Ssam 	switch (cmd) {
34913049Ssam 
35011576Ssam 	case SIOCGIFFLAGS:
35111576Ssam 		ifr->ifr_flags = ifp->if_flags;
35211576Ssam 		break;
35311576Ssam 
35426091Skarels 	case SIOCGIFMETRIC:
35526091Skarels 		ifr->ifr_metric = ifp->if_metric;
35626091Skarels 		break;
35726091Skarels 
35813053Ssam 	case SIOCSIFFLAGS:
35937549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
36037549Smckusick 			return (error);
36113053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
36213053Ssam 			int s = splimp();
36313053Ssam 			if_down(ifp);
36413053Ssam 			splx(s);
36513053Ssam 		}
36618544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
36718544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
36824773Skarels 		if (ifp->if_ioctl)
36924773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
37013053Ssam 		break;
37113053Ssam 
37226091Skarels 	case SIOCSIFMETRIC:
37337549Smckusick 		if (error = suser(u.u_cred, &u.u_acflag))
37437549Smckusick 			return (error);
37526091Skarels 		ifp->if_metric = ifr->ifr_metric;
37626091Skarels 		break;
37726091Skarels 
37811576Ssam 	default:
37918544Skarels 		if (so->so_proto == 0)
38013049Ssam 			return (EOPNOTSUPP);
38137549Smckusick #ifndef COMPAT_43
38218544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
38318544Skarels 			cmd, data, ifp));
38437549Smckusick #else
38537549Smckusick 	    {
386*41545Smckusick 		int ocmd = cmd;
38737549Smckusick 
38837549Smckusick 		switch (cmd) {
38937549Smckusick 
39037549Smckusick 		case SIOCSIFDSTADDR:
39137549Smckusick 		case SIOCSIFADDR:
39237549Smckusick 		case SIOCSIFBRDADDR:
39337549Smckusick 		case SIOCSIFNETMASK:
39437549Smckusick #if BYTE_ORDER != BIG_ENDIAN
39537549Smckusick 			if (ifr->ifr_addr.sa_family == 0 &&
39637549Smckusick 			    ifr->ifr_addr.sa_len < 16) {
39737549Smckusick 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
39837549Smckusick 				ifr->ifr_addr.sa_len = 16;
39937549Smckusick 			}
40037549Smckusick #else
40137549Smckusick 			if (ifr->ifr_addr.sa_len == 0)
40237549Smckusick 				ifr->ifr_addr.sa_len = 16;
40337549Smckusick #endif
40437549Smckusick 			break;
40537549Smckusick 
40637549Smckusick 		case OSIOCGIFADDR:
40737549Smckusick 			cmd = SIOCGIFADDR;
40837549Smckusick 			break;
40937549Smckusick 
41037549Smckusick 		case OSIOCGIFDSTADDR:
41137549Smckusick 			cmd = SIOCGIFDSTADDR;
41237549Smckusick 			break;
41337549Smckusick 
41437549Smckusick 		case OSIOCGIFBRDADDR:
41537549Smckusick 			cmd = SIOCGIFBRDADDR;
41637549Smckusick 			break;
41737549Smckusick 
41837549Smckusick 		case OSIOCGIFNETMASK:
41937549Smckusick 			cmd = SIOCGIFNETMASK;
42037549Smckusick 		}
42137549Smckusick 		error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
42237549Smckusick 							    cmd, data, ifp));
42337549Smckusick 		switch (ocmd) {
42437549Smckusick 
42537549Smckusick 		case OSIOCGIFADDR:
42637549Smckusick 		case OSIOCGIFDSTADDR:
42737549Smckusick 		case OSIOCGIFBRDADDR:
42837549Smckusick 		case OSIOCGIFNETMASK:
42937549Smckusick 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
43037549Smckusick 		}
43137549Smckusick 		return (error);
43237549Smckusick 
43337549Smckusick 	    }
43437549Smckusick #endif
43511576Ssam 	}
43611576Ssam 	return (0);
43711576Ssam }
43811576Ssam 
43911576Ssam /*
44011576Ssam  * Return interface configuration
44111576Ssam  * of system.  List may be used
44211576Ssam  * in later ioctl's (above) to get
44311576Ssam  * other information.
44411576Ssam  */
44512783Ssam /*ARGSUSED*/
44611576Ssam ifconf(cmd, data)
44711576Ssam 	int cmd;
44811576Ssam 	caddr_t data;
44911576Ssam {
45011576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
45111576Ssam 	register struct ifnet *ifp = ifnet;
45218544Skarels 	register struct ifaddr *ifa;
45311630Ssam 	register char *cp, *ep;
45411630Ssam 	struct ifreq ifr, *ifrp;
45511576Ssam 	int space = ifc->ifc_len, error = 0;
45611576Ssam 
45711630Ssam 	ifrp = ifc->ifc_req;
45811630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
45911576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
46011630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
46111630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
46211576Ssam 			;
46311630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
46418544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
46518544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
46618544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
46718544Skarels 			if (error)
46818544Skarels 				break;
46918544Skarels 			space -= sizeof (ifr), ifrp++;
47018544Skarels 		} else
47118544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
47237549Smckusick 			register struct sockaddr *sa = ifa->ifa_addr;
47337549Smckusick #ifdef COMPAT_43
47437549Smckusick 			if (cmd == OSIOCGIFCONF) {
47537549Smckusick 				struct osockaddr *osa =
47637549Smckusick 					 (struct osockaddr *)&ifr.ifr_addr;
47737549Smckusick 				ifr.ifr_addr = *sa;
47837549Smckusick 				osa->sa_family = sa->sa_family;
47937549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
48037549Smckusick 						sizeof (ifr));
48137549Smckusick 				ifrp++;
48237549Smckusick 			} else
48337549Smckusick #endif
48437549Smckusick 			if (sa->sa_len <= sizeof(*sa)) {
48537549Smckusick 				ifr.ifr_addr = *sa;
48637549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
48737549Smckusick 						sizeof (ifr));
48837549Smckusick 				ifrp++;
48937549Smckusick 			} else {
49037549Smckusick 				space -= sa->sa_len - sizeof(*sa);
49137549Smckusick 				if (space < sizeof (ifr))
49237549Smckusick 					break;
49337549Smckusick 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
49437549Smckusick 						sizeof (ifr.ifr_name));
49537549Smckusick 				if (error == 0)
49637549Smckusick 				    error = copyout((caddr_t)sa,
49737549Smckusick 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
49837549Smckusick 				ifrp = (struct ifreq *)
49937549Smckusick 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
50037549Smckusick 			}
50118544Skarels 			if (error)
50218544Skarels 				break;
50337549Smckusick 			space -= sizeof (ifr);
50418544Skarels 		}
50511576Ssam 	}
50611576Ssam 	ifc->ifc_len -= space;
50711576Ssam 	return (error);
50811576Ssam }
50940792Ssklower 
51040792Ssklower static sprint_d(cp, n)
51140792Ssklower register char *cp;
51240792Ssklower u_short n;
51340792Ssklower {
51440792Ssklower 	register int q, m;
51540792Ssklower 	do {
51640792Ssklower 	    if (n >= 10000) m = 10000;
51740792Ssklower 		else if (n >= 1000) m = 1000;
51840792Ssklower 		else if (n >= 100) m = 100;
51940792Ssklower 		else if (n >= 10) m = 10;
52040792Ssklower 		else m = 1;
52140792Ssklower 	    q = n / m;
52240792Ssklower 	    n -= m * q;
52340792Ssklower 	    if (q > 9) q = 10; /* For crays with more than 100K interfaces */
52440792Ssklower 	    *cp++ = "0123456789Z"[q];
52540792Ssklower 	} while (n > 0);
52640792Ssklower 	*cp++ = 0;
52740792Ssklower }
528