xref: /csrg-svn/sys/net/if.c (revision 28942)
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*28942Skarels  *	@(#)if.c	6.13 (Berkeley) 06/02/86
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)
3924773Skarels 		if (ifp->if_snd.ifq_maxlen == 0)
4024773Skarels 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
418173Sroot 	if_slowtimo();
425206Swnj }
435206Swnj 
4413049Ssam #ifdef vax
456333Ssam /*
466333Ssam  * Call each interface on a Unibus reset.
476333Ssam  */
485206Swnj ifubareset(uban)
495206Swnj 	int uban;
505206Swnj {
515206Swnj 	register struct ifnet *ifp;
525206Swnj 
535206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
548974Sroot 		if (ifp->if_reset)
5515116Ssam 			(*ifp->if_reset)(ifp->if_unit, uban);
565206Swnj }
578393Swnj #endif
585206Swnj 
596333Ssam /*
606333Ssam  * Attach an interface to the
616333Ssam  * list of "active" interfaces.
626333Ssam  */
635160Swnj if_attach(ifp)
645160Swnj 	struct ifnet *ifp;
655160Swnj {
665698Swnj 	register struct ifnet **p = &ifnet;
675160Swnj 
685698Swnj 	while (*p)
695698Swnj 		p = &((*p)->if_next);
705698Swnj 	*p = ifp;
715160Swnj }
725160Swnj 
736333Ssam /*
746333Ssam  * Locate an interface based on a complete address.
756333Ssam  */
764951Swnj /*ARGSUSED*/
7718544Skarels struct ifaddr *
7818544Skarels ifa_ifwithaddr(addr)
796333Ssam 	struct sockaddr *addr;
804944Swnj {
814944Swnj 	register struct ifnet *ifp;
8218544Skarels 	register struct ifaddr *ifa;
834944Swnj 
846333Ssam #define	equal(a1, a2) \
856333Ssam 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
8618544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
8718544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
8818544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
896333Ssam 			continue;
9018544Skarels 		if (equal(&ifa->ifa_addr, addr))
9118544Skarels 			return (ifa);
926333Ssam 		if ((ifp->if_flags & IFF_BROADCAST) &&
9318544Skarels 		    equal(&ifa->ifa_broadaddr, addr))
9418544Skarels 			return (ifa);
956333Ssam 	}
9618544Skarels 	return ((struct ifaddr *)0);
974944Swnj }
9823933Ssklower /*
9923933Ssklower  * Locate the point to point interface with a given destination address.
10023933Ssklower  */
10123933Ssklower /*ARGSUSED*/
10223933Ssklower struct ifaddr *
10323933Ssklower ifa_ifwithdstaddr(addr)
10423933Ssklower 	struct sockaddr *addr;
10523933Ssklower {
10623933Ssklower 	register struct ifnet *ifp;
10723933Ssklower 	register struct ifaddr *ifa;
1084944Swnj 
10923933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
11023933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
11123933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
11223933Ssklower 			if (ifa->ifa_addr.sa_family != addr->sa_family)
11323933Ssklower 				continue;
11423933Ssklower 			if (equal(&ifa->ifa_dstaddr, addr))
11523933Ssklower 				return (ifa);
11623933Ssklower 	}
11723933Ssklower 	return ((struct ifaddr *)0);
11823933Ssklower }
11923933Ssklower 
1206333Ssam /*
1216333Ssam  * Find an interface on a specific network.  If many, choice
1226333Ssam  * is first found.
1236333Ssam  */
12418544Skarels struct ifaddr *
12518544Skarels ifa_ifwithnet(addr)
1266333Ssam 	register struct sockaddr *addr;
1274944Swnj {
1284944Swnj 	register struct ifnet *ifp;
12918544Skarels 	register struct ifaddr *ifa;
1308393Swnj 	register u_int af = addr->sa_family;
1316619Ssam 	register int (*netmatch)();
1324944Swnj 
1336619Ssam 	if (af >= AF_MAX)
1346619Ssam 		return (0);
1356619Ssam 	netmatch = afswitch[af].af_netmatch;
13618544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
13718544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
13818544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
1396333Ssam 			continue;
14018544Skarels 		if ((*netmatch)(&ifa->ifa_addr, addr))
14118544Skarels 			return (ifa);
1426333Ssam 	}
14318544Skarels 	return ((struct ifaddr *)0);
1446333Ssam }
1456333Ssam 
146*28942Skarels #ifdef notdef
1476333Ssam /*
1486333Ssam  * Find an interface using a specific address family
1496333Ssam  */
15018544Skarels struct ifaddr *
15118544Skarels ifa_ifwithaf(af)
1526333Ssam 	register int af;
1535083Swnj {
1546333Ssam 	register struct ifnet *ifp;
15518544Skarels 	register struct ifaddr *ifa;
1565083Swnj 
1576333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
15818544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
15918544Skarels 		if (ifa->ifa_addr.sa_family == af)
16018544Skarels 			return (ifa);
16118544Skarels 	return ((struct ifaddr *)0);
1625083Swnj }
163*28942Skarels #endif
1645104Swnj 
1656333Ssam /*
1666582Ssam  * Mark an interface down and notify protocols of
1676582Ssam  * the transition.
1689184Ssam  * NOTE: must be called at splnet or eqivalent.
1696582Ssam  */
1706582Ssam if_down(ifp)
1716582Ssam 	register struct ifnet *ifp;
1726582Ssam {
17318544Skarels 	register struct ifaddr *ifa;
1748173Sroot 
1756582Ssam 	ifp->if_flags &= ~IFF_UP;
17618544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
17724773Skarels 		pfctlinput(PRC_IFDOWN, &ifa->ifa_addr);
1786582Ssam }
1797264Ssam 
1807264Ssam /*
1817264Ssam  * Handle interface watchdog timer routines.  Called
1827264Ssam  * from softclock, we decrement timers (if set) and
1837264Ssam  * call the appropriate interface routine on expiration.
1847264Ssam  */
1857264Ssam if_slowtimo()
1867264Ssam {
1877264Ssam 	register struct ifnet *ifp;
1887264Ssam 
1899184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
1909184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
1919184Ssam 			continue;
1929184Ssam 		if (ifp->if_watchdog)
1937264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
1949184Ssam 	}
1958692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
1967264Ssam }
19711576Ssam 
19811576Ssam /*
19913049Ssam  * Map interface name to
20013049Ssam  * interface structure pointer.
20111576Ssam  */
20213049Ssam struct ifnet *
20313049Ssam ifunit(name)
20413049Ssam 	register char *name;
20511576Ssam {
20613049Ssam 	register char *cp;
20711576Ssam 	register struct ifnet *ifp;
20813049Ssam 	int unit;
20911576Ssam 
21013049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
21111576Ssam 		if (*cp >= '0' && *cp <= '9')
21211576Ssam 			break;
21313049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
21413049Ssam 		return ((struct ifnet *)0);
21516135Skarels 	unit = *cp - '0';
21611576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
21713049Ssam 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
21811576Ssam 			continue;
21911576Ssam 		if (unit == ifp->if_unit)
22013049Ssam 			break;
22111576Ssam 	}
22213049Ssam 	return (ifp);
22313049Ssam }
22411576Ssam 
22513049Ssam /*
22613049Ssam  * Interface ioctls.
22713049Ssam  */
22818544Skarels ifioctl(so, cmd, data)
22918544Skarels 	struct socket *so;
23013049Ssam 	int cmd;
23113049Ssam 	caddr_t data;
23213049Ssam {
23313049Ssam 	register struct ifnet *ifp;
23413049Ssam 	register struct ifreq *ifr;
23513049Ssam 
23611576Ssam 	switch (cmd) {
23711576Ssam 
23813049Ssam 	case SIOCGIFCONF:
23913049Ssam 		return (ifconf(cmd, data));
24013049Ssam 
24125647Skarels #if defined(INET) && NETHER > 0
24216220Skarels 	case SIOCSARP:
24316220Skarels 	case SIOCDARP:
24416220Skarels 		if (!suser())
24516220Skarels 			return (u.u_error);
24616220Skarels 		/* FALL THROUGH */
24716220Skarels 	case SIOCGARP:
24816220Skarels 		return (arpioctl(cmd, data));
24916220Skarels #endif
25013049Ssam 	}
25113049Ssam 	ifr = (struct ifreq *)data;
25213049Ssam 	ifp = ifunit(ifr->ifr_name);
25313049Ssam 	if (ifp == 0)
25413049Ssam 		return (ENXIO);
25513049Ssam 	switch (cmd) {
25613049Ssam 
25711576Ssam 	case SIOCGIFFLAGS:
25811576Ssam 		ifr->ifr_flags = ifp->if_flags;
25911576Ssam 		break;
26011576Ssam 
26126091Skarels 	case SIOCGIFMETRIC:
26226091Skarels 		ifr->ifr_metric = ifp->if_metric;
26326091Skarels 		break;
26426091Skarels 
26513053Ssam 	case SIOCSIFFLAGS:
26625565Sbloom 		if (!suser())
26725565Sbloom 			return (u.u_error);
26813053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
26913053Ssam 			int s = splimp();
27013053Ssam 			if_down(ifp);
27113053Ssam 			splx(s);
27213053Ssam 		}
27318544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
27418544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
27524773Skarels 		if (ifp->if_ioctl)
27624773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
27713053Ssam 		break;
27813053Ssam 
27926091Skarels 	case SIOCSIFMETRIC:
28026091Skarels 		if (!suser())
28126091Skarels 			return (u.u_error);
28226091Skarels 		ifp->if_metric = ifr->ifr_metric;
28326091Skarels 		break;
28426091Skarels 
28511576Ssam 	default:
28618544Skarels 		if (so->so_proto == 0)
28713049Ssam 			return (EOPNOTSUPP);
28818544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
28918544Skarels 			cmd, data, ifp));
29011576Ssam 	}
29111576Ssam 	return (0);
29211576Ssam }
29311576Ssam 
29411576Ssam /*
29511576Ssam  * Return interface configuration
29611576Ssam  * of system.  List may be used
29711576Ssam  * in later ioctl's (above) to get
29811576Ssam  * other information.
29911576Ssam  */
30012783Ssam /*ARGSUSED*/
30111576Ssam ifconf(cmd, data)
30211576Ssam 	int cmd;
30311576Ssam 	caddr_t data;
30411576Ssam {
30511576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
30611576Ssam 	register struct ifnet *ifp = ifnet;
30718544Skarels 	register struct ifaddr *ifa;
30811630Ssam 	register char *cp, *ep;
30911630Ssam 	struct ifreq ifr, *ifrp;
31011576Ssam 	int space = ifc->ifc_len, error = 0;
31111576Ssam 
31211630Ssam 	ifrp = ifc->ifc_req;
31311630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
31411576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
31511630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
31611630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
31711576Ssam 			;
31811630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
31918544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
32018544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
32118544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
32218544Skarels 			if (error)
32318544Skarels 				break;
32418544Skarels 			space -= sizeof (ifr), ifrp++;
32518544Skarels 		} else
32618544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
32718544Skarels 			ifr.ifr_addr = ifa->ifa_addr;
32818544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
32918544Skarels 			if (error)
33018544Skarels 				break;
33118544Skarels 			space -= sizeof (ifr), ifrp++;
33218544Skarels 		}
33311576Ssam 	}
33411576Ssam 	ifc->ifc_len -= space;
33511576Ssam 	return (error);
33611576Ssam }
337