xref: /csrg-svn/sys/net/if.c (revision 26091)
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*26091Skarels  *	@(#)if.c	6.12 (Berkeley) 02/06/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 
1466333Ssam /*
1476333Ssam  * Find an interface using a specific address family
1486333Ssam  */
14918544Skarels struct ifaddr *
15018544Skarels ifa_ifwithaf(af)
1516333Ssam 	register int af;
1525083Swnj {
1536333Ssam 	register struct ifnet *ifp;
15418544Skarels 	register struct ifaddr *ifa;
1555083Swnj 
1566333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
15718544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
15818544Skarels 		if (ifa->ifa_addr.sa_family == af)
15918544Skarels 			return (ifa);
16018544Skarels 	return ((struct ifaddr *)0);
1615083Swnj }
1625104Swnj 
1636333Ssam /*
1646582Ssam  * Mark an interface down and notify protocols of
1656582Ssam  * the transition.
1669184Ssam  * NOTE: must be called at splnet or eqivalent.
1676582Ssam  */
1686582Ssam if_down(ifp)
1696582Ssam 	register struct ifnet *ifp;
1706582Ssam {
17118544Skarels 	register struct ifaddr *ifa;
1728173Sroot 
1736582Ssam 	ifp->if_flags &= ~IFF_UP;
17418544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
17524773Skarels 		pfctlinput(PRC_IFDOWN, &ifa->ifa_addr);
1766582Ssam }
1777264Ssam 
1787264Ssam /*
1797264Ssam  * Handle interface watchdog timer routines.  Called
1807264Ssam  * from softclock, we decrement timers (if set) and
1817264Ssam  * call the appropriate interface routine on expiration.
1827264Ssam  */
1837264Ssam if_slowtimo()
1847264Ssam {
1857264Ssam 	register struct ifnet *ifp;
1867264Ssam 
1879184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
1889184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
1899184Ssam 			continue;
1909184Ssam 		if (ifp->if_watchdog)
1917264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
1929184Ssam 	}
1938692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
1947264Ssam }
19511576Ssam 
19611576Ssam /*
19713049Ssam  * Map interface name to
19813049Ssam  * interface structure pointer.
19911576Ssam  */
20013049Ssam struct ifnet *
20113049Ssam ifunit(name)
20213049Ssam 	register char *name;
20311576Ssam {
20413049Ssam 	register char *cp;
20511576Ssam 	register struct ifnet *ifp;
20613049Ssam 	int unit;
20711576Ssam 
20813049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
20911576Ssam 		if (*cp >= '0' && *cp <= '9')
21011576Ssam 			break;
21113049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
21213049Ssam 		return ((struct ifnet *)0);
21316135Skarels 	unit = *cp - '0';
21411576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
21513049Ssam 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
21611576Ssam 			continue;
21711576Ssam 		if (unit == ifp->if_unit)
21813049Ssam 			break;
21911576Ssam 	}
22013049Ssam 	return (ifp);
22113049Ssam }
22211576Ssam 
22313049Ssam /*
22413049Ssam  * Interface ioctls.
22513049Ssam  */
22618544Skarels ifioctl(so, cmd, data)
22718544Skarels 	struct socket *so;
22813049Ssam 	int cmd;
22913049Ssam 	caddr_t data;
23013049Ssam {
23113049Ssam 	register struct ifnet *ifp;
23213049Ssam 	register struct ifreq *ifr;
23313049Ssam 
23411576Ssam 	switch (cmd) {
23511576Ssam 
23613049Ssam 	case SIOCGIFCONF:
23713049Ssam 		return (ifconf(cmd, data));
23813049Ssam 
23925647Skarels #if defined(INET) && NETHER > 0
24016220Skarels 	case SIOCSARP:
24116220Skarels 	case SIOCDARP:
24216220Skarels 		if (!suser())
24316220Skarels 			return (u.u_error);
24416220Skarels 		/* FALL THROUGH */
24516220Skarels 	case SIOCGARP:
24616220Skarels 		return (arpioctl(cmd, data));
24716220Skarels #endif
24813049Ssam 	}
24913049Ssam 	ifr = (struct ifreq *)data;
25013049Ssam 	ifp = ifunit(ifr->ifr_name);
25113049Ssam 	if (ifp == 0)
25213049Ssam 		return (ENXIO);
25313049Ssam 	switch (cmd) {
25413049Ssam 
25511576Ssam 	case SIOCGIFFLAGS:
25611576Ssam 		ifr->ifr_flags = ifp->if_flags;
25711576Ssam 		break;
25811576Ssam 
259*26091Skarels 	case SIOCGIFMETRIC:
260*26091Skarels 		ifr->ifr_metric = ifp->if_metric;
261*26091Skarels 		break;
262*26091Skarels 
26313053Ssam 	case SIOCSIFFLAGS:
26425565Sbloom 		if (!suser())
26525565Sbloom 			return (u.u_error);
26613053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
26713053Ssam 			int s = splimp();
26813053Ssam 			if_down(ifp);
26913053Ssam 			splx(s);
27013053Ssam 		}
27118544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
27218544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
27324773Skarels 		if (ifp->if_ioctl)
27424773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
27513053Ssam 		break;
27613053Ssam 
277*26091Skarels 	case SIOCSIFMETRIC:
278*26091Skarels 		if (!suser())
279*26091Skarels 			return (u.u_error);
280*26091Skarels 		ifp->if_metric = ifr->ifr_metric;
281*26091Skarels 		break;
282*26091Skarels 
28311576Ssam 	default:
28418544Skarels 		if (so->so_proto == 0)
28513049Ssam 			return (EOPNOTSUPP);
28618544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
28718544Skarels 			cmd, data, ifp));
28811576Ssam 	}
28911576Ssam 	return (0);
29011576Ssam }
29111576Ssam 
29211576Ssam /*
29311576Ssam  * Return interface configuration
29411576Ssam  * of system.  List may be used
29511576Ssam  * in later ioctl's (above) to get
29611576Ssam  * other information.
29711576Ssam  */
29812783Ssam /*ARGSUSED*/
29911576Ssam ifconf(cmd, data)
30011576Ssam 	int cmd;
30111576Ssam 	caddr_t data;
30211576Ssam {
30311576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
30411576Ssam 	register struct ifnet *ifp = ifnet;
30518544Skarels 	register struct ifaddr *ifa;
30611630Ssam 	register char *cp, *ep;
30711630Ssam 	struct ifreq ifr, *ifrp;
30811576Ssam 	int space = ifc->ifc_len, error = 0;
30911576Ssam 
31011630Ssam 	ifrp = ifc->ifc_req;
31111630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
31211576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
31311630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
31411630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
31511576Ssam 			;
31611630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
31718544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
31818544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
31918544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
32018544Skarels 			if (error)
32118544Skarels 				break;
32218544Skarels 			space -= sizeof (ifr), ifrp++;
32318544Skarels 		} else
32418544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
32518544Skarels 			ifr.ifr_addr = ifa->ifa_addr;
32618544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
32718544Skarels 			if (error)
32818544Skarels 				break;
32918544Skarels 			space -= sizeof (ifr), ifrp++;
33018544Skarels 		}
33111576Ssam 	}
33211576Ssam 	ifc->ifc_len -= space;
33311576Ssam 	return (error);
33411576Ssam }
335