xref: /csrg-svn/sys/net/if.c (revision 23157)
1*23157Smckusick /*
2*23157Smckusick  * Copyright (c) 1980 Regents of the University of California.
3*23157Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*23157Smckusick  * specifies the terms and conditions for redistribution.
5*23157Smckusick  *
6*23157Smckusick  *	@(#)if.c	6.7 (Berkeley) 06/08/85
7*23157Smckusick  */
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 }
1014944Swnj 
1026333Ssam /*
1036333Ssam  * Find an interface on a specific network.  If many, choice
1046333Ssam  * is first found.
1056333Ssam  */
10618544Skarels struct ifaddr *
10718544Skarels ifa_ifwithnet(addr)
1086333Ssam 	register struct sockaddr *addr;
1094944Swnj {
1104944Swnj 	register struct ifnet *ifp;
11118544Skarels 	register struct ifaddr *ifa;
1128393Swnj 	register u_int af = addr->sa_family;
1136619Ssam 	register int (*netmatch)();
1144944Swnj 
1156619Ssam 	if (af >= AF_MAX)
1166619Ssam 		return (0);
1176619Ssam 	netmatch = afswitch[af].af_netmatch;
11818544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
11918544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
12018544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
1216333Ssam 			continue;
12218544Skarels 		if ((*netmatch)(&ifa->ifa_addr, addr))
12318544Skarels 			return (ifa);
1246333Ssam 	}
12518544Skarels 	return ((struct ifaddr *)0);
1266333Ssam }
1276333Ssam 
1286333Ssam /*
1296333Ssam  * Find an interface using a specific address family
1306333Ssam  */
13118544Skarels struct ifaddr *
13218544Skarels ifa_ifwithaf(af)
1336333Ssam 	register int af;
1345083Swnj {
1356333Ssam 	register struct ifnet *ifp;
13618544Skarels 	register struct ifaddr *ifa;
1375083Swnj 
1386333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
13918544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
14018544Skarels 		if (ifa->ifa_addr.sa_family == af)
14118544Skarels 			return (ifa);
14218544Skarels 	return ((struct ifaddr *)0);
1435083Swnj }
1445104Swnj 
1456333Ssam /*
1466582Ssam  * Mark an interface down and notify protocols of
1476582Ssam  * the transition.
1489184Ssam  * NOTE: must be called at splnet or eqivalent.
1496582Ssam  */
1506582Ssam if_down(ifp)
1516582Ssam 	register struct ifnet *ifp;
1526582Ssam {
15318544Skarels 	register struct ifaddr *ifa;
1548173Sroot 
1556582Ssam 	ifp->if_flags &= ~IFF_UP;
15618544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
15718544Skarels 		pfctlinput(PRC_IFDOWN, (caddr_t)&ifa->ifa_addr);
1586582Ssam }
1597264Ssam 
1607264Ssam /*
1617264Ssam  * Handle interface watchdog timer routines.  Called
1627264Ssam  * from softclock, we decrement timers (if set) and
1637264Ssam  * call the appropriate interface routine on expiration.
1647264Ssam  */
1657264Ssam if_slowtimo()
1667264Ssam {
1677264Ssam 	register struct ifnet *ifp;
1687264Ssam 
1699184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
1709184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
1719184Ssam 			continue;
1729184Ssam 		if (ifp->if_watchdog)
1737264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
1749184Ssam 	}
1758692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
1767264Ssam }
17711576Ssam 
17811576Ssam /*
17913049Ssam  * Map interface name to
18013049Ssam  * interface structure pointer.
18111576Ssam  */
18213049Ssam struct ifnet *
18313049Ssam ifunit(name)
18413049Ssam 	register char *name;
18511576Ssam {
18613049Ssam 	register char *cp;
18711576Ssam 	register struct ifnet *ifp;
18813049Ssam 	int unit;
18911576Ssam 
19013049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
19111576Ssam 		if (*cp >= '0' && *cp <= '9')
19211576Ssam 			break;
19313049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
19413049Ssam 		return ((struct ifnet *)0);
19516135Skarels 	unit = *cp - '0';
19611576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
19713049Ssam 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
19811576Ssam 			continue;
19911576Ssam 		if (unit == ifp->if_unit)
20013049Ssam 			break;
20111576Ssam 	}
20213049Ssam 	return (ifp);
20313049Ssam }
20411576Ssam 
20513049Ssam /*
20613049Ssam  * Interface ioctls.
20713049Ssam  */
20818544Skarels ifioctl(so, cmd, data)
20918544Skarels 	struct socket *so;
21013049Ssam 	int cmd;
21113049Ssam 	caddr_t data;
21213049Ssam {
21313049Ssam 	register struct ifnet *ifp;
21413049Ssam 	register struct ifreq *ifr;
21513049Ssam 
21611576Ssam 	switch (cmd) {
21711576Ssam 
21813049Ssam 	case SIOCGIFCONF:
21913049Ssam 		return (ifconf(cmd, data));
22013049Ssam 
22116220Skarels #if defined(INET) && NETHER > 0
22216220Skarels 	case SIOCSARP:
22316220Skarels 	case SIOCDARP:
22416220Skarels 		if (!suser())
22516220Skarels 			return (u.u_error);
22616220Skarels 		/* FALL THROUGH */
22716220Skarels 	case SIOCGARP:
22816220Skarels 		return (arpioctl(cmd, data));
22916220Skarels #endif
23013049Ssam 	}
23113049Ssam 	ifr = (struct ifreq *)data;
23213049Ssam 	ifp = ifunit(ifr->ifr_name);
23313049Ssam 	if (ifp == 0)
23413049Ssam 		return (ENXIO);
23513049Ssam 	switch (cmd) {
23613049Ssam 
23711576Ssam 	case SIOCGIFFLAGS:
23811576Ssam 		ifr->ifr_flags = ifp->if_flags;
23911576Ssam 		break;
24011576Ssam 
24113053Ssam 	case SIOCSIFFLAGS:
24213053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
24313053Ssam 			int s = splimp();
24413053Ssam 			if_down(ifp);
24513053Ssam 			splx(s);
24613053Ssam 		}
24718544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
24818544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
24913053Ssam 		break;
25013053Ssam 
25111576Ssam 	default:
25218544Skarels 		if (so->so_proto == 0)
25313049Ssam 			return (EOPNOTSUPP);
25418544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
25518544Skarels 			cmd, data, ifp));
25611576Ssam 	}
25711576Ssam 	return (0);
25811576Ssam }
25911576Ssam 
26011576Ssam /*
26111576Ssam  * Return interface configuration
26211576Ssam  * of system.  List may be used
26311576Ssam  * in later ioctl's (above) to get
26411576Ssam  * other information.
26511576Ssam  */
26612783Ssam /*ARGSUSED*/
26711576Ssam ifconf(cmd, data)
26811576Ssam 	int cmd;
26911576Ssam 	caddr_t data;
27011576Ssam {
27111576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
27211576Ssam 	register struct ifnet *ifp = ifnet;
27318544Skarels 	register struct ifaddr *ifa;
27411630Ssam 	register char *cp, *ep;
27511630Ssam 	struct ifreq ifr, *ifrp;
27611576Ssam 	int space = ifc->ifc_len, error = 0;
27711576Ssam 
27811630Ssam 	ifrp = ifc->ifc_req;
27911630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
28011576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
28111630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
28211630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
28311576Ssam 			;
28411630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
28518544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
28618544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
28718544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
28818544Skarels 			if (error)
28918544Skarels 				break;
29018544Skarels 			space -= sizeof (ifr), ifrp++;
29118544Skarels 		} else
29218544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
29318544Skarels 			ifr.ifr_addr = ifa->ifa_addr;
29418544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
29518544Skarels 			if (error)
29618544Skarels 				break;
29718544Skarels 			space -= sizeof (ifr), ifrp++;
29818544Skarels 		}
29911576Ssam 	}
30011576Ssam 	ifc->ifc_len -= space;
30111576Ssam 	return (error);
30211576Ssam }
303