xref: /csrg-svn/sys/net/if.c (revision 23933)
123157Smckusick /*
223157Smckusick  * Copyright (c) 1980 Regents of the University of California.
323157Smckusick  * All rights reserved.  The Berkeley software License Agreement
423157Smckusick  * specifies the terms and conditions for redistribution.
523157Smckusick  *
6*23933Ssklower  *	@(#)if.c	6.8 (Berkeley) 07/18/85
723157Smckusick  */
84944Swnj 
917036Sbloom #include "param.h"
1017036Sbloom #include "systm.h"
1117036Sbloom #include "socket.h"
1218544Skarels #include "socketvar.h"
1317036Sbloom #include "protosw.h"
1417036Sbloom #include "dir.h"
1517036Sbloom #include "user.h"
1617036Sbloom #include "kernel.h"
1717036Sbloom #include "ioctl.h"
1817036Sbloom #include "errno.h"
1910872Ssam 
2017036Sbloom #include "if.h"
2117036Sbloom #include "af.h"
224944Swnj 
2316220Skarels #include "ether.h"
2416220Skarels 
256207Swnj int	ifqmaxlen = IFQ_MAXLEN;
266207Swnj 
276333Ssam /*
286333Ssam  * Network interface utility routines.
296333Ssam  *
3018544Skarels  * Routines with ifa_ifwith* names take sockaddr *'s as
3118544Skarels  * parameters.
326333Ssam  */
336333Ssam 
345206Swnj ifinit()
355206Swnj {
365206Swnj 	register struct ifnet *ifp;
375206Swnj 
385206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
396207Swnj 		if (ifp->if_init) {
406333Ssam 			(*ifp->if_init)(ifp->if_unit);
416207Swnj 			if (ifp->if_snd.ifq_maxlen == 0)
426207Swnj 				ifp->if_snd.ifq_maxlen = ifqmaxlen;
436207Swnj 		}
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 
626333Ssam /*
636333Ssam  * Attach an interface to the
646333Ssam  * list of "active" interfaces.
656333Ssam  */
665160Swnj if_attach(ifp)
675160Swnj 	struct ifnet *ifp;
685160Swnj {
695698Swnj 	register struct ifnet **p = &ifnet;
705160Swnj 
715698Swnj 	while (*p)
725698Swnj 		p = &((*p)->if_next);
735698Swnj 	*p = ifp;
745160Swnj }
755160Swnj 
766333Ssam /*
776333Ssam  * Locate an interface based on a complete address.
786333Ssam  */
794951Swnj /*ARGSUSED*/
8018544Skarels struct ifaddr *
8118544Skarels ifa_ifwithaddr(addr)
826333Ssam 	struct sockaddr *addr;
834944Swnj {
844944Swnj 	register struct ifnet *ifp;
8518544Skarels 	register struct ifaddr *ifa;
864944Swnj 
876333Ssam #define	equal(a1, a2) \
886333Ssam 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
8918544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
9018544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
9118544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
926333Ssam 			continue;
9318544Skarels 		if (equal(&ifa->ifa_addr, addr))
9418544Skarels 			return (ifa);
956333Ssam 		if ((ifp->if_flags & IFF_BROADCAST) &&
9618544Skarels 		    equal(&ifa->ifa_broadaddr, addr))
9718544Skarels 			return (ifa);
986333Ssam 	}
9918544Skarels 	return ((struct ifaddr *)0);
1004944Swnj }
101*23933Ssklower /*
102*23933Ssklower  * Locate the point to point interface with a given destination address.
103*23933Ssklower  */
104*23933Ssklower /*ARGSUSED*/
105*23933Ssklower struct ifaddr *
106*23933Ssklower ifa_ifwithdstaddr(addr)
107*23933Ssklower 	struct sockaddr *addr;
108*23933Ssklower {
109*23933Ssklower 	register struct ifnet *ifp;
110*23933Ssklower 	register struct ifaddr *ifa;
1114944Swnj 
112*23933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
113*23933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
114*23933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
115*23933Ssklower 			if (ifa->ifa_addr.sa_family != addr->sa_family)
116*23933Ssklower 				continue;
117*23933Ssklower 			if (equal(&ifa->ifa_dstaddr, addr))
118*23933Ssklower 				return (ifa);
119*23933Ssklower 	}
120*23933Ssklower 	return ((struct ifaddr *)0);
121*23933Ssklower }
122*23933Ssklower 
1236333Ssam /*
1246333Ssam  * Find an interface on a specific network.  If many, choice
1256333Ssam  * is first found.
1266333Ssam  */
12718544Skarels struct ifaddr *
12818544Skarels ifa_ifwithnet(addr)
1296333Ssam 	register struct sockaddr *addr;
1304944Swnj {
1314944Swnj 	register struct ifnet *ifp;
13218544Skarels 	register struct ifaddr *ifa;
1338393Swnj 	register u_int af = addr->sa_family;
1346619Ssam 	register int (*netmatch)();
1354944Swnj 
1366619Ssam 	if (af >= AF_MAX)
1376619Ssam 		return (0);
1386619Ssam 	netmatch = afswitch[af].af_netmatch;
13918544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
14018544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
14118544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
1426333Ssam 			continue;
14318544Skarels 		if ((*netmatch)(&ifa->ifa_addr, addr))
14418544Skarels 			return (ifa);
1456333Ssam 	}
14618544Skarels 	return ((struct ifaddr *)0);
1476333Ssam }
1486333Ssam 
1496333Ssam /*
1506333Ssam  * Find an interface using a specific address family
1516333Ssam  */
15218544Skarels struct ifaddr *
15318544Skarels ifa_ifwithaf(af)
1546333Ssam 	register int af;
1555083Swnj {
1566333Ssam 	register struct ifnet *ifp;
15718544Skarels 	register struct ifaddr *ifa;
1585083Swnj 
1596333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
16018544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
16118544Skarels 		if (ifa->ifa_addr.sa_family == af)
16218544Skarels 			return (ifa);
16318544Skarels 	return ((struct ifaddr *)0);
1645083Swnj }
1655104Swnj 
1666333Ssam /*
1676582Ssam  * Mark an interface down and notify protocols of
1686582Ssam  * the transition.
1699184Ssam  * NOTE: must be called at splnet or eqivalent.
1706582Ssam  */
1716582Ssam if_down(ifp)
1726582Ssam 	register struct ifnet *ifp;
1736582Ssam {
17418544Skarels 	register struct ifaddr *ifa;
1758173Sroot 
1766582Ssam 	ifp->if_flags &= ~IFF_UP;
17718544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
17818544Skarels 		pfctlinput(PRC_IFDOWN, (caddr_t)&ifa->ifa_addr);
1796582Ssam }
1807264Ssam 
1817264Ssam /*
1827264Ssam  * Handle interface watchdog timer routines.  Called
1837264Ssam  * from softclock, we decrement timers (if set) and
1847264Ssam  * call the appropriate interface routine on expiration.
1857264Ssam  */
1867264Ssam if_slowtimo()
1877264Ssam {
1887264Ssam 	register struct ifnet *ifp;
1897264Ssam 
1909184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
1919184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
1929184Ssam 			continue;
1939184Ssam 		if (ifp->if_watchdog)
1947264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
1959184Ssam 	}
1968692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
1977264Ssam }
19811576Ssam 
19911576Ssam /*
20013049Ssam  * Map interface name to
20113049Ssam  * interface structure pointer.
20211576Ssam  */
20313049Ssam struct ifnet *
20413049Ssam ifunit(name)
20513049Ssam 	register char *name;
20611576Ssam {
20713049Ssam 	register char *cp;
20811576Ssam 	register struct ifnet *ifp;
20913049Ssam 	int unit;
21011576Ssam 
21113049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
21211576Ssam 		if (*cp >= '0' && *cp <= '9')
21311576Ssam 			break;
21413049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
21513049Ssam 		return ((struct ifnet *)0);
21616135Skarels 	unit = *cp - '0';
21711576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
21813049Ssam 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
21911576Ssam 			continue;
22011576Ssam 		if (unit == ifp->if_unit)
22113049Ssam 			break;
22211576Ssam 	}
22313049Ssam 	return (ifp);
22413049Ssam }
22511576Ssam 
22613049Ssam /*
22713049Ssam  * Interface ioctls.
22813049Ssam  */
22918544Skarels ifioctl(so, cmd, data)
23018544Skarels 	struct socket *so;
23113049Ssam 	int cmd;
23213049Ssam 	caddr_t data;
23313049Ssam {
23413049Ssam 	register struct ifnet *ifp;
23513049Ssam 	register struct ifreq *ifr;
23613049Ssam 
23711576Ssam 	switch (cmd) {
23811576Ssam 
23913049Ssam 	case SIOCGIFCONF:
24013049Ssam 		return (ifconf(cmd, data));
24113049Ssam 
24216220Skarels #if defined(INET) && NETHER > 0
24316220Skarels 	case SIOCSARP:
24416220Skarels 	case SIOCDARP:
24516220Skarels 		if (!suser())
24616220Skarels 			return (u.u_error);
24716220Skarels 		/* FALL THROUGH */
24816220Skarels 	case SIOCGARP:
24916220Skarels 		return (arpioctl(cmd, data));
25016220Skarels #endif
25113049Ssam 	}
25213049Ssam 	ifr = (struct ifreq *)data;
25313049Ssam 	ifp = ifunit(ifr->ifr_name);
25413049Ssam 	if (ifp == 0)
25513049Ssam 		return (ENXIO);
25613049Ssam 	switch (cmd) {
25713049Ssam 
25811576Ssam 	case SIOCGIFFLAGS:
25911576Ssam 		ifr->ifr_flags = ifp->if_flags;
26011576Ssam 		break;
26111576Ssam 
26213053Ssam 	case SIOCSIFFLAGS:
26313053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
26413053Ssam 			int s = splimp();
26513053Ssam 			if_down(ifp);
26613053Ssam 			splx(s);
26713053Ssam 		}
26818544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
26918544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
27013053Ssam 		break;
27113053Ssam 
27211576Ssam 	default:
27318544Skarels 		if (so->so_proto == 0)
27413049Ssam 			return (EOPNOTSUPP);
27518544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
27618544Skarels 			cmd, data, ifp));
27711576Ssam 	}
27811576Ssam 	return (0);
27911576Ssam }
28011576Ssam 
28111576Ssam /*
28211576Ssam  * Return interface configuration
28311576Ssam  * of system.  List may be used
28411576Ssam  * in later ioctl's (above) to get
28511576Ssam  * other information.
28611576Ssam  */
28712783Ssam /*ARGSUSED*/
28811576Ssam ifconf(cmd, data)
28911576Ssam 	int cmd;
29011576Ssam 	caddr_t data;
29111576Ssam {
29211576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
29311576Ssam 	register struct ifnet *ifp = ifnet;
29418544Skarels 	register struct ifaddr *ifa;
29511630Ssam 	register char *cp, *ep;
29611630Ssam 	struct ifreq ifr, *ifrp;
29711576Ssam 	int space = ifc->ifc_len, error = 0;
29811576Ssam 
29911630Ssam 	ifrp = ifc->ifc_req;
30011630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
30111576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
30211630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
30311630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
30411576Ssam 			;
30511630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
30618544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
30718544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
30818544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
30918544Skarels 			if (error)
31018544Skarels 				break;
31118544Skarels 			space -= sizeof (ifr), ifrp++;
31218544Skarels 		} else
31318544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
31418544Skarels 			ifr.ifr_addr = ifa->ifa_addr;
31518544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
31618544Skarels 			if (error)
31718544Skarels 				break;
31818544Skarels 			space -= sizeof (ifr), ifrp++;
31918544Skarels 		}
32011576Ssam 	}
32111576Ssam 	ifc->ifc_len -= space;
32211576Ssam 	return (error);
32311576Ssam }
324