xref: /csrg-svn/sys/net/if.c (revision 33984)
123157Smckusick /*
229061Smckusick  * Copyright (c) 1980, 1986 Regents of the University of California.
333183Sbostic  * All rights reserved.
423157Smckusick  *
533183Sbostic  * Redistribution and use in source and binary forms are permitted
633183Sbostic  * provided that this notice is preserved and that due credit is given
733183Sbostic  * to the University of California at Berkeley. The name of the University
833183Sbostic  * may not be used to endorse or promote products derived from this
933183Sbostic  * software without specific prior written permission. This software
1033183Sbostic  * is provided ``as is'' without express or implied warranty.
1133183Sbostic  *
12*33984Skarels  *	@(#)if.c	7.3 (Berkeley) 04/07/88
1323157Smckusick  */
144944Swnj 
1517036Sbloom #include "param.h"
16*33984Skarels #include "mbuf.h"
1717036Sbloom #include "systm.h"
1817036Sbloom #include "socket.h"
1918544Skarels #include "socketvar.h"
2017036Sbloom #include "protosw.h"
2117036Sbloom #include "dir.h"
2217036Sbloom #include "user.h"
2317036Sbloom #include "kernel.h"
2417036Sbloom #include "ioctl.h"
2517036Sbloom #include "errno.h"
2610872Ssam 
2717036Sbloom #include "if.h"
2817036Sbloom #include "af.h"
294944Swnj 
3016220Skarels #include "ether.h"
3116220Skarels 
326207Swnj int	ifqmaxlen = IFQ_MAXLEN;
336207Swnj 
346333Ssam /*
356333Ssam  * Network interface utility routines.
366333Ssam  *
3718544Skarels  * Routines with ifa_ifwith* names take sockaddr *'s as
3818544Skarels  * parameters.
396333Ssam  */
406333Ssam 
415206Swnj ifinit()
425206Swnj {
435206Swnj 	register struct ifnet *ifp;
445206Swnj 
455206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
4624773Skarels 		if (ifp->if_snd.ifq_maxlen == 0)
4724773Skarels 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
488173Sroot 	if_slowtimo();
495206Swnj }
505206Swnj 
5113049Ssam #ifdef vax
526333Ssam /*
536333Ssam  * Call each interface on a Unibus reset.
546333Ssam  */
555206Swnj ifubareset(uban)
565206Swnj 	int uban;
575206Swnj {
585206Swnj 	register struct ifnet *ifp;
595206Swnj 
605206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
618974Sroot 		if (ifp->if_reset)
6215116Ssam 			(*ifp->if_reset)(ifp->if_unit, uban);
635206Swnj }
648393Swnj #endif
655206Swnj 
666333Ssam /*
676333Ssam  * Attach an interface to the
686333Ssam  * list of "active" interfaces.
696333Ssam  */
705160Swnj if_attach(ifp)
715160Swnj 	struct ifnet *ifp;
725160Swnj {
735698Swnj 	register struct ifnet **p = &ifnet;
745160Swnj 
755698Swnj 	while (*p)
765698Swnj 		p = &((*p)->if_next);
775698Swnj 	*p = ifp;
785160Swnj }
795160Swnj 
806333Ssam /*
816333Ssam  * Locate an interface based on a complete address.
826333Ssam  */
834951Swnj /*ARGSUSED*/
8418544Skarels struct ifaddr *
8518544Skarels ifa_ifwithaddr(addr)
866333Ssam 	struct sockaddr *addr;
874944Swnj {
884944Swnj 	register struct ifnet *ifp;
8918544Skarels 	register struct ifaddr *ifa;
904944Swnj 
916333Ssam #define	equal(a1, a2) \
926333Ssam 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
9318544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
9418544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
9518544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
966333Ssam 			continue;
9718544Skarels 		if (equal(&ifa->ifa_addr, addr))
9818544Skarels 			return (ifa);
996333Ssam 		if ((ifp->if_flags & IFF_BROADCAST) &&
10018544Skarels 		    equal(&ifa->ifa_broadaddr, addr))
10118544Skarels 			return (ifa);
1026333Ssam 	}
10318544Skarels 	return ((struct ifaddr *)0);
1044944Swnj }
10523933Ssklower /*
10623933Ssklower  * Locate the point to point interface with a given destination address.
10723933Ssklower  */
10823933Ssklower /*ARGSUSED*/
10923933Ssklower struct ifaddr *
11023933Ssklower ifa_ifwithdstaddr(addr)
11123933Ssklower 	struct sockaddr *addr;
11223933Ssklower {
11323933Ssklower 	register struct ifnet *ifp;
11423933Ssklower 	register struct ifaddr *ifa;
1154944Swnj 
11623933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
11723933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
11823933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
11923933Ssklower 			if (ifa->ifa_addr.sa_family != addr->sa_family)
12023933Ssklower 				continue;
12123933Ssklower 			if (equal(&ifa->ifa_dstaddr, addr))
12223933Ssklower 				return (ifa);
12323933Ssklower 	}
12423933Ssklower 	return ((struct ifaddr *)0);
12523933Ssklower }
12623933Ssklower 
1276333Ssam /*
1286333Ssam  * Find an interface on a specific network.  If many, choice
1296333Ssam  * is first found.
1306333Ssam  */
13118544Skarels struct ifaddr *
13218544Skarels ifa_ifwithnet(addr)
1336333Ssam 	register struct sockaddr *addr;
1344944Swnj {
1354944Swnj 	register struct ifnet *ifp;
13618544Skarels 	register struct ifaddr *ifa;
1378393Swnj 	register u_int af = addr->sa_family;
1386619Ssam 	register int (*netmatch)();
1394944Swnj 
1406619Ssam 	if (af >= AF_MAX)
1416619Ssam 		return (0);
1426619Ssam 	netmatch = afswitch[af].af_netmatch;
14318544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
14418544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
14518544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
1466333Ssam 			continue;
14718544Skarels 		if ((*netmatch)(&ifa->ifa_addr, addr))
14818544Skarels 			return (ifa);
1496333Ssam 	}
15018544Skarels 	return ((struct ifaddr *)0);
1516333Ssam }
1526333Ssam 
15328942Skarels #ifdef notdef
1546333Ssam /*
1556333Ssam  * Find an interface using a specific address family
1566333Ssam  */
15718544Skarels struct ifaddr *
15818544Skarels ifa_ifwithaf(af)
1596333Ssam 	register int af;
1605083Swnj {
1616333Ssam 	register struct ifnet *ifp;
16218544Skarels 	register struct ifaddr *ifa;
1635083Swnj 
1646333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
16518544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
16618544Skarels 		if (ifa->ifa_addr.sa_family == af)
16718544Skarels 			return (ifa);
16818544Skarels 	return ((struct ifaddr *)0);
1695083Swnj }
17028942Skarels #endif
1715104Swnj 
1726333Ssam /*
1736582Ssam  * Mark an interface down and notify protocols of
1746582Ssam  * the transition.
1759184Ssam  * NOTE: must be called at splnet or eqivalent.
1766582Ssam  */
1776582Ssam if_down(ifp)
1786582Ssam 	register struct ifnet *ifp;
1796582Ssam {
18018544Skarels 	register struct ifaddr *ifa;
1818173Sroot 
1826582Ssam 	ifp->if_flags &= ~IFF_UP;
18318544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
18424773Skarels 		pfctlinput(PRC_IFDOWN, &ifa->ifa_addr);
185*33984Skarels 	if_qflush(&ifp->if_snd);
1866582Ssam }
1877264Ssam 
1887264Ssam /*
189*33984Skarels  * Flush an interface queue.
190*33984Skarels  */
191*33984Skarels if_qflush(ifq)
192*33984Skarels 	register struct ifqueue *ifq;
193*33984Skarels {
194*33984Skarels 	register struct mbuf *m, *n;
195*33984Skarels 
196*33984Skarels 	n = ifq->ifq_head;
197*33984Skarels 	while (m = n) {
198*33984Skarels 		n = m->m_act;
199*33984Skarels 		m_freem(m);
200*33984Skarels 	}
201*33984Skarels 	ifq->ifq_head = 0;
202*33984Skarels 	ifq->ifq_tail = 0;
203*33984Skarels 	ifq->ifq_len = 0;
204*33984Skarels }
205*33984Skarels 
206*33984Skarels /*
2077264Ssam  * Handle interface watchdog timer routines.  Called
2087264Ssam  * from softclock, we decrement timers (if set) and
2097264Ssam  * call the appropriate interface routine on expiration.
2107264Ssam  */
2117264Ssam if_slowtimo()
2127264Ssam {
2137264Ssam 	register struct ifnet *ifp;
2147264Ssam 
2159184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
2169184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
2179184Ssam 			continue;
2189184Ssam 		if (ifp->if_watchdog)
2197264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
2209184Ssam 	}
2218692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
2227264Ssam }
22311576Ssam 
22411576Ssam /*
22513049Ssam  * Map interface name to
22613049Ssam  * interface structure pointer.
22711576Ssam  */
22813049Ssam struct ifnet *
22913049Ssam ifunit(name)
23013049Ssam 	register char *name;
23111576Ssam {
23213049Ssam 	register char *cp;
23311576Ssam 	register struct ifnet *ifp;
23413049Ssam 	int unit;
23511576Ssam 
23613049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
23711576Ssam 		if (*cp >= '0' && *cp <= '9')
23811576Ssam 			break;
23913049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
24013049Ssam 		return ((struct ifnet *)0);
24116135Skarels 	unit = *cp - '0';
24211576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
24313049Ssam 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
24411576Ssam 			continue;
24511576Ssam 		if (unit == ifp->if_unit)
24613049Ssam 			break;
24711576Ssam 	}
24813049Ssam 	return (ifp);
24913049Ssam }
25011576Ssam 
25113049Ssam /*
25213049Ssam  * Interface ioctls.
25313049Ssam  */
25418544Skarels ifioctl(so, cmd, data)
25518544Skarels 	struct socket *so;
25613049Ssam 	int cmd;
25713049Ssam 	caddr_t data;
25813049Ssam {
25913049Ssam 	register struct ifnet *ifp;
26013049Ssam 	register struct ifreq *ifr;
26113049Ssam 
26211576Ssam 	switch (cmd) {
26311576Ssam 
26413049Ssam 	case SIOCGIFCONF:
26513049Ssam 		return (ifconf(cmd, data));
26613049Ssam 
26725647Skarels #if defined(INET) && NETHER > 0
26816220Skarels 	case SIOCSARP:
26916220Skarels 	case SIOCDARP:
27016220Skarels 		if (!suser())
27116220Skarels 			return (u.u_error);
27216220Skarels 		/* FALL THROUGH */
27316220Skarels 	case SIOCGARP:
27416220Skarels 		return (arpioctl(cmd, data));
27516220Skarels #endif
27613049Ssam 	}
27713049Ssam 	ifr = (struct ifreq *)data;
27813049Ssam 	ifp = ifunit(ifr->ifr_name);
27913049Ssam 	if (ifp == 0)
28013049Ssam 		return (ENXIO);
28113049Ssam 	switch (cmd) {
28213049Ssam 
28311576Ssam 	case SIOCGIFFLAGS:
28411576Ssam 		ifr->ifr_flags = ifp->if_flags;
28511576Ssam 		break;
28611576Ssam 
28726091Skarels 	case SIOCGIFMETRIC:
28826091Skarels 		ifr->ifr_metric = ifp->if_metric;
28926091Skarels 		break;
29026091Skarels 
29113053Ssam 	case SIOCSIFFLAGS:
29225565Sbloom 		if (!suser())
29325565Sbloom 			return (u.u_error);
29413053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
29513053Ssam 			int s = splimp();
29613053Ssam 			if_down(ifp);
29713053Ssam 			splx(s);
29813053Ssam 		}
29918544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
30018544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
30124773Skarels 		if (ifp->if_ioctl)
30224773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
30313053Ssam 		break;
30413053Ssam 
30526091Skarels 	case SIOCSIFMETRIC:
30626091Skarels 		if (!suser())
30726091Skarels 			return (u.u_error);
30826091Skarels 		ifp->if_metric = ifr->ifr_metric;
30926091Skarels 		break;
31026091Skarels 
31111576Ssam 	default:
31218544Skarels 		if (so->so_proto == 0)
31313049Ssam 			return (EOPNOTSUPP);
31418544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
31518544Skarels 			cmd, data, ifp));
31611576Ssam 	}
31711576Ssam 	return (0);
31811576Ssam }
31911576Ssam 
32011576Ssam /*
32111576Ssam  * Return interface configuration
32211576Ssam  * of system.  List may be used
32311576Ssam  * in later ioctl's (above) to get
32411576Ssam  * other information.
32511576Ssam  */
32612783Ssam /*ARGSUSED*/
32711576Ssam ifconf(cmd, data)
32811576Ssam 	int cmd;
32911576Ssam 	caddr_t data;
33011576Ssam {
33111576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
33211576Ssam 	register struct ifnet *ifp = ifnet;
33318544Skarels 	register struct ifaddr *ifa;
33411630Ssam 	register char *cp, *ep;
33511630Ssam 	struct ifreq ifr, *ifrp;
33611576Ssam 	int space = ifc->ifc_len, error = 0;
33711576Ssam 
33811630Ssam 	ifrp = ifc->ifc_req;
33911630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
34011576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
34111630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
34211630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
34311576Ssam 			;
34411630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
34518544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
34618544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
34718544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
34818544Skarels 			if (error)
34918544Skarels 				break;
35018544Skarels 			space -= sizeof (ifr), ifrp++;
35118544Skarels 		} else
35218544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
35318544Skarels 			ifr.ifr_addr = ifa->ifa_addr;
35418544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
35518544Skarels 			if (error)
35618544Skarels 				break;
35718544Skarels 			space -= sizeof (ifr), ifrp++;
35818544Skarels 		}
35911576Ssam 	}
36011576Ssam 	ifc->ifc_len -= space;
36111576Ssam 	return (error);
36211576Ssam }
363