xref: /csrg-svn/sys/net/if.c (revision 33183)
123157Smckusick /*
229061Smckusick  * Copyright (c) 1980, 1986 Regents of the University of California.
3*33183Sbostic  * All rights reserved.
423157Smckusick  *
5*33183Sbostic  * Redistribution and use in source and binary forms are permitted
6*33183Sbostic  * provided that this notice is preserved and that due credit is given
7*33183Sbostic  * to the University of California at Berkeley. The name of the University
8*33183Sbostic  * may not be used to endorse or promote products derived from this
9*33183Sbostic  * software without specific prior written permission. This software
10*33183Sbostic  * is provided ``as is'' without express or implied warranty.
11*33183Sbostic  *
12*33183Sbostic  *	@(#)if.c	7.2 (Berkeley) 12/30/87
1323157Smckusick  */
144944Swnj 
1517036Sbloom #include "param.h"
1617036Sbloom #include "systm.h"
1717036Sbloom #include "socket.h"
1818544Skarels #include "socketvar.h"
1917036Sbloom #include "protosw.h"
2017036Sbloom #include "dir.h"
2117036Sbloom #include "user.h"
2217036Sbloom #include "kernel.h"
2317036Sbloom #include "ioctl.h"
2417036Sbloom #include "errno.h"
2510872Ssam 
2617036Sbloom #include "if.h"
2717036Sbloom #include "af.h"
284944Swnj 
2916220Skarels #include "ether.h"
3016220Skarels 
316207Swnj int	ifqmaxlen = IFQ_MAXLEN;
326207Swnj 
336333Ssam /*
346333Ssam  * Network interface utility routines.
356333Ssam  *
3618544Skarels  * Routines with ifa_ifwith* names take sockaddr *'s as
3718544Skarels  * parameters.
386333Ssam  */
396333Ssam 
405206Swnj ifinit()
415206Swnj {
425206Swnj 	register struct ifnet *ifp;
435206Swnj 
445206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
4524773Skarels 		if (ifp->if_snd.ifq_maxlen == 0)
4624773Skarels 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
478173Sroot 	if_slowtimo();
485206Swnj }
495206Swnj 
5013049Ssam #ifdef vax
516333Ssam /*
526333Ssam  * Call each interface on a Unibus reset.
536333Ssam  */
545206Swnj ifubareset(uban)
555206Swnj 	int uban;
565206Swnj {
575206Swnj 	register struct ifnet *ifp;
585206Swnj 
595206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
608974Sroot 		if (ifp->if_reset)
6115116Ssam 			(*ifp->if_reset)(ifp->if_unit, uban);
625206Swnj }
638393Swnj #endif
645206Swnj 
656333Ssam /*
666333Ssam  * Attach an interface to the
676333Ssam  * list of "active" interfaces.
686333Ssam  */
695160Swnj if_attach(ifp)
705160Swnj 	struct ifnet *ifp;
715160Swnj {
725698Swnj 	register struct ifnet **p = &ifnet;
735160Swnj 
745698Swnj 	while (*p)
755698Swnj 		p = &((*p)->if_next);
765698Swnj 	*p = ifp;
775160Swnj }
785160Swnj 
796333Ssam /*
806333Ssam  * Locate an interface based on a complete address.
816333Ssam  */
824951Swnj /*ARGSUSED*/
8318544Skarels struct ifaddr *
8418544Skarels ifa_ifwithaddr(addr)
856333Ssam 	struct sockaddr *addr;
864944Swnj {
874944Swnj 	register struct ifnet *ifp;
8818544Skarels 	register struct ifaddr *ifa;
894944Swnj 
906333Ssam #define	equal(a1, a2) \
916333Ssam 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
9218544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
9318544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
9418544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
956333Ssam 			continue;
9618544Skarels 		if (equal(&ifa->ifa_addr, addr))
9718544Skarels 			return (ifa);
986333Ssam 		if ((ifp->if_flags & IFF_BROADCAST) &&
9918544Skarels 		    equal(&ifa->ifa_broadaddr, addr))
10018544Skarels 			return (ifa);
1016333Ssam 	}
10218544Skarels 	return ((struct ifaddr *)0);
1034944Swnj }
10423933Ssklower /*
10523933Ssklower  * Locate the point to point interface with a given destination address.
10623933Ssklower  */
10723933Ssklower /*ARGSUSED*/
10823933Ssklower struct ifaddr *
10923933Ssklower ifa_ifwithdstaddr(addr)
11023933Ssklower 	struct sockaddr *addr;
11123933Ssklower {
11223933Ssklower 	register struct ifnet *ifp;
11323933Ssklower 	register struct ifaddr *ifa;
1144944Swnj 
11523933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
11623933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
11723933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
11823933Ssklower 			if (ifa->ifa_addr.sa_family != addr->sa_family)
11923933Ssklower 				continue;
12023933Ssklower 			if (equal(&ifa->ifa_dstaddr, addr))
12123933Ssklower 				return (ifa);
12223933Ssklower 	}
12323933Ssklower 	return ((struct ifaddr *)0);
12423933Ssklower }
12523933Ssklower 
1266333Ssam /*
1276333Ssam  * Find an interface on a specific network.  If many, choice
1286333Ssam  * is first found.
1296333Ssam  */
13018544Skarels struct ifaddr *
13118544Skarels ifa_ifwithnet(addr)
1326333Ssam 	register struct sockaddr *addr;
1334944Swnj {
1344944Swnj 	register struct ifnet *ifp;
13518544Skarels 	register struct ifaddr *ifa;
1368393Swnj 	register u_int af = addr->sa_family;
1376619Ssam 	register int (*netmatch)();
1384944Swnj 
1396619Ssam 	if (af >= AF_MAX)
1406619Ssam 		return (0);
1416619Ssam 	netmatch = afswitch[af].af_netmatch;
14218544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
14318544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
14418544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
1456333Ssam 			continue;
14618544Skarels 		if ((*netmatch)(&ifa->ifa_addr, addr))
14718544Skarels 			return (ifa);
1486333Ssam 	}
14918544Skarels 	return ((struct ifaddr *)0);
1506333Ssam }
1516333Ssam 
15228942Skarels #ifdef notdef
1536333Ssam /*
1546333Ssam  * Find an interface using a specific address family
1556333Ssam  */
15618544Skarels struct ifaddr *
15718544Skarels ifa_ifwithaf(af)
1586333Ssam 	register int af;
1595083Swnj {
1606333Ssam 	register struct ifnet *ifp;
16118544Skarels 	register struct ifaddr *ifa;
1625083Swnj 
1636333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
16418544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
16518544Skarels 		if (ifa->ifa_addr.sa_family == af)
16618544Skarels 			return (ifa);
16718544Skarels 	return ((struct ifaddr *)0);
1685083Swnj }
16928942Skarels #endif
1705104Swnj 
1716333Ssam /*
1726582Ssam  * Mark an interface down and notify protocols of
1736582Ssam  * the transition.
1749184Ssam  * NOTE: must be called at splnet or eqivalent.
1756582Ssam  */
1766582Ssam if_down(ifp)
1776582Ssam 	register struct ifnet *ifp;
1786582Ssam {
17918544Skarels 	register struct ifaddr *ifa;
1808173Sroot 
1816582Ssam 	ifp->if_flags &= ~IFF_UP;
18218544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
18324773Skarels 		pfctlinput(PRC_IFDOWN, &ifa->ifa_addr);
1846582Ssam }
1857264Ssam 
1867264Ssam /*
1877264Ssam  * Handle interface watchdog timer routines.  Called
1887264Ssam  * from softclock, we decrement timers (if set) and
1897264Ssam  * call the appropriate interface routine on expiration.
1907264Ssam  */
1917264Ssam if_slowtimo()
1927264Ssam {
1937264Ssam 	register struct ifnet *ifp;
1947264Ssam 
1959184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
1969184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
1979184Ssam 			continue;
1989184Ssam 		if (ifp->if_watchdog)
1997264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
2009184Ssam 	}
2018692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
2027264Ssam }
20311576Ssam 
20411576Ssam /*
20513049Ssam  * Map interface name to
20613049Ssam  * interface structure pointer.
20711576Ssam  */
20813049Ssam struct ifnet *
20913049Ssam ifunit(name)
21013049Ssam 	register char *name;
21111576Ssam {
21213049Ssam 	register char *cp;
21311576Ssam 	register struct ifnet *ifp;
21413049Ssam 	int unit;
21511576Ssam 
21613049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
21711576Ssam 		if (*cp >= '0' && *cp <= '9')
21811576Ssam 			break;
21913049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
22013049Ssam 		return ((struct ifnet *)0);
22116135Skarels 	unit = *cp - '0';
22211576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
22313049Ssam 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
22411576Ssam 			continue;
22511576Ssam 		if (unit == ifp->if_unit)
22613049Ssam 			break;
22711576Ssam 	}
22813049Ssam 	return (ifp);
22913049Ssam }
23011576Ssam 
23113049Ssam /*
23213049Ssam  * Interface ioctls.
23313049Ssam  */
23418544Skarels ifioctl(so, cmd, data)
23518544Skarels 	struct socket *so;
23613049Ssam 	int cmd;
23713049Ssam 	caddr_t data;
23813049Ssam {
23913049Ssam 	register struct ifnet *ifp;
24013049Ssam 	register struct ifreq *ifr;
24113049Ssam 
24211576Ssam 	switch (cmd) {
24311576Ssam 
24413049Ssam 	case SIOCGIFCONF:
24513049Ssam 		return (ifconf(cmd, data));
24613049Ssam 
24725647Skarels #if defined(INET) && NETHER > 0
24816220Skarels 	case SIOCSARP:
24916220Skarels 	case SIOCDARP:
25016220Skarels 		if (!suser())
25116220Skarels 			return (u.u_error);
25216220Skarels 		/* FALL THROUGH */
25316220Skarels 	case SIOCGARP:
25416220Skarels 		return (arpioctl(cmd, data));
25516220Skarels #endif
25613049Ssam 	}
25713049Ssam 	ifr = (struct ifreq *)data;
25813049Ssam 	ifp = ifunit(ifr->ifr_name);
25913049Ssam 	if (ifp == 0)
26013049Ssam 		return (ENXIO);
26113049Ssam 	switch (cmd) {
26213049Ssam 
26311576Ssam 	case SIOCGIFFLAGS:
26411576Ssam 		ifr->ifr_flags = ifp->if_flags;
26511576Ssam 		break;
26611576Ssam 
26726091Skarels 	case SIOCGIFMETRIC:
26826091Skarels 		ifr->ifr_metric = ifp->if_metric;
26926091Skarels 		break;
27026091Skarels 
27113053Ssam 	case SIOCSIFFLAGS:
27225565Sbloom 		if (!suser())
27325565Sbloom 			return (u.u_error);
27413053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
27513053Ssam 			int s = splimp();
27613053Ssam 			if_down(ifp);
27713053Ssam 			splx(s);
27813053Ssam 		}
27918544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
28018544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
28124773Skarels 		if (ifp->if_ioctl)
28224773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
28313053Ssam 		break;
28413053Ssam 
28526091Skarels 	case SIOCSIFMETRIC:
28626091Skarels 		if (!suser())
28726091Skarels 			return (u.u_error);
28826091Skarels 		ifp->if_metric = ifr->ifr_metric;
28926091Skarels 		break;
29026091Skarels 
29111576Ssam 	default:
29218544Skarels 		if (so->so_proto == 0)
29313049Ssam 			return (EOPNOTSUPP);
29418544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
29518544Skarels 			cmd, data, ifp));
29611576Ssam 	}
29711576Ssam 	return (0);
29811576Ssam }
29911576Ssam 
30011576Ssam /*
30111576Ssam  * Return interface configuration
30211576Ssam  * of system.  List may be used
30311576Ssam  * in later ioctl's (above) to get
30411576Ssam  * other information.
30511576Ssam  */
30612783Ssam /*ARGSUSED*/
30711576Ssam ifconf(cmd, data)
30811576Ssam 	int cmd;
30911576Ssam 	caddr_t data;
31011576Ssam {
31111576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
31211576Ssam 	register struct ifnet *ifp = ifnet;
31318544Skarels 	register struct ifaddr *ifa;
31411630Ssam 	register char *cp, *ep;
31511630Ssam 	struct ifreq ifr, *ifrp;
31611576Ssam 	int space = ifc->ifc_len, error = 0;
31711576Ssam 
31811630Ssam 	ifrp = ifc->ifc_req;
31911630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
32011576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
32111630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
32211630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
32311576Ssam 			;
32411630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
32518544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
32618544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
32718544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
32818544Skarels 			if (error)
32918544Skarels 				break;
33018544Skarels 			space -= sizeof (ifr), ifrp++;
33118544Skarels 		} else
33218544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
33318544Skarels 			ifr.ifr_addr = ifa->ifa_addr;
33418544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
33518544Skarels 			if (error)
33618544Skarels 				break;
33718544Skarels 			space -= sizeof (ifr), ifrp++;
33818544Skarels 		}
33911576Ssam 	}
34011576Ssam 	ifc->ifc_len -= space;
34111576Ssam 	return (error);
34211576Ssam }
343