xref: /csrg-svn/sys/net/if.c (revision 34844)
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
6*34844Sbostic  * provided that the above copyright notice and this paragraph are
7*34844Sbostic  * duplicated in all such forms and that any documentation,
8*34844Sbostic  * advertising materials, and other materials related to such
9*34844Sbostic  * distribution and use acknowledge that the software was developed
10*34844Sbostic  * by the University of California, Berkeley.  The name of the
11*34844Sbostic  * University may not be used to endorse or promote products derived
12*34844Sbostic  * from this software without specific prior written permission.
13*34844Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*34844Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*34844Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633183Sbostic  *
17*34844Sbostic  *	@(#)if.c	7.4 (Berkeley) 06/27/88
1823157Smckusick  */
194944Swnj 
2017036Sbloom #include "param.h"
2133984Skarels #include "mbuf.h"
2217036Sbloom #include "systm.h"
2317036Sbloom #include "socket.h"
2418544Skarels #include "socketvar.h"
2517036Sbloom #include "protosw.h"
2617036Sbloom #include "dir.h"
2717036Sbloom #include "user.h"
2817036Sbloom #include "kernel.h"
2917036Sbloom #include "ioctl.h"
3017036Sbloom #include "errno.h"
3110872Ssam 
3217036Sbloom #include "if.h"
3317036Sbloom #include "af.h"
344944Swnj 
3516220Skarels #include "ether.h"
3616220Skarels 
376207Swnj int	ifqmaxlen = IFQ_MAXLEN;
386207Swnj 
396333Ssam /*
406333Ssam  * Network interface utility routines.
416333Ssam  *
4218544Skarels  * Routines with ifa_ifwith* names take sockaddr *'s as
4318544Skarels  * parameters.
446333Ssam  */
456333Ssam 
465206Swnj ifinit()
475206Swnj {
485206Swnj 	register struct ifnet *ifp;
495206Swnj 
505206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
5124773Skarels 		if (ifp->if_snd.ifq_maxlen == 0)
5224773Skarels 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
538173Sroot 	if_slowtimo();
545206Swnj }
555206Swnj 
5613049Ssam #ifdef vax
576333Ssam /*
586333Ssam  * Call each interface on a Unibus reset.
596333Ssam  */
605206Swnj ifubareset(uban)
615206Swnj 	int uban;
625206Swnj {
635206Swnj 	register struct ifnet *ifp;
645206Swnj 
655206Swnj 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
668974Sroot 		if (ifp->if_reset)
6715116Ssam 			(*ifp->if_reset)(ifp->if_unit, uban);
685206Swnj }
698393Swnj #endif
705206Swnj 
716333Ssam /*
726333Ssam  * Attach an interface to the
736333Ssam  * list of "active" interfaces.
746333Ssam  */
755160Swnj if_attach(ifp)
765160Swnj 	struct ifnet *ifp;
775160Swnj {
785698Swnj 	register struct ifnet **p = &ifnet;
795160Swnj 
805698Swnj 	while (*p)
815698Swnj 		p = &((*p)->if_next);
825698Swnj 	*p = ifp;
835160Swnj }
845160Swnj 
856333Ssam /*
866333Ssam  * Locate an interface based on a complete address.
876333Ssam  */
884951Swnj /*ARGSUSED*/
8918544Skarels struct ifaddr *
9018544Skarels ifa_ifwithaddr(addr)
916333Ssam 	struct sockaddr *addr;
924944Swnj {
934944Swnj 	register struct ifnet *ifp;
9418544Skarels 	register struct ifaddr *ifa;
954944Swnj 
966333Ssam #define	equal(a1, a2) \
976333Ssam 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
9818544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
9918544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
10018544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
1016333Ssam 			continue;
10218544Skarels 		if (equal(&ifa->ifa_addr, addr))
10318544Skarels 			return (ifa);
1046333Ssam 		if ((ifp->if_flags & IFF_BROADCAST) &&
10518544Skarels 		    equal(&ifa->ifa_broadaddr, addr))
10618544Skarels 			return (ifa);
1076333Ssam 	}
10818544Skarels 	return ((struct ifaddr *)0);
1094944Swnj }
11023933Ssklower /*
11123933Ssklower  * Locate the point to point interface with a given destination address.
11223933Ssklower  */
11323933Ssklower /*ARGSUSED*/
11423933Ssklower struct ifaddr *
11523933Ssklower ifa_ifwithdstaddr(addr)
11623933Ssklower 	struct sockaddr *addr;
11723933Ssklower {
11823933Ssklower 	register struct ifnet *ifp;
11923933Ssklower 	register struct ifaddr *ifa;
1204944Swnj 
12123933Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
12223933Ssklower 	    if (ifp->if_flags & IFF_POINTOPOINT)
12323933Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
12423933Ssklower 			if (ifa->ifa_addr.sa_family != addr->sa_family)
12523933Ssklower 				continue;
12623933Ssklower 			if (equal(&ifa->ifa_dstaddr, addr))
12723933Ssklower 				return (ifa);
12823933Ssklower 	}
12923933Ssklower 	return ((struct ifaddr *)0);
13023933Ssklower }
13123933Ssklower 
1326333Ssam /*
1336333Ssam  * Find an interface on a specific network.  If many, choice
1346333Ssam  * is first found.
1356333Ssam  */
13618544Skarels struct ifaddr *
13718544Skarels ifa_ifwithnet(addr)
1386333Ssam 	register struct sockaddr *addr;
1394944Swnj {
1404944Swnj 	register struct ifnet *ifp;
14118544Skarels 	register struct ifaddr *ifa;
1428393Swnj 	register u_int af = addr->sa_family;
1436619Ssam 	register int (*netmatch)();
1444944Swnj 
1456619Ssam 	if (af >= AF_MAX)
1466619Ssam 		return (0);
1476619Ssam 	netmatch = afswitch[af].af_netmatch;
14818544Skarels 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
14918544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
15018544Skarels 		if (ifa->ifa_addr.sa_family != addr->sa_family)
1516333Ssam 			continue;
15218544Skarels 		if ((*netmatch)(&ifa->ifa_addr, addr))
15318544Skarels 			return (ifa);
1546333Ssam 	}
15518544Skarels 	return ((struct ifaddr *)0);
1566333Ssam }
1576333Ssam 
15828942Skarels #ifdef notdef
1596333Ssam /*
1606333Ssam  * Find an interface using a specific address family
1616333Ssam  */
16218544Skarels struct ifaddr *
16318544Skarels ifa_ifwithaf(af)
1646333Ssam 	register int af;
1655083Swnj {
1666333Ssam 	register struct ifnet *ifp;
16718544Skarels 	register struct ifaddr *ifa;
1685083Swnj 
1696333Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
17018544Skarels 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
17118544Skarels 		if (ifa->ifa_addr.sa_family == af)
17218544Skarels 			return (ifa);
17318544Skarels 	return ((struct ifaddr *)0);
1745083Swnj }
17528942Skarels #endif
1765104Swnj 
1776333Ssam /*
1786582Ssam  * Mark an interface down and notify protocols of
1796582Ssam  * the transition.
1809184Ssam  * NOTE: must be called at splnet or eqivalent.
1816582Ssam  */
1826582Ssam if_down(ifp)
1836582Ssam 	register struct ifnet *ifp;
1846582Ssam {
18518544Skarels 	register struct ifaddr *ifa;
1868173Sroot 
1876582Ssam 	ifp->if_flags &= ~IFF_UP;
18818544Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
18924773Skarels 		pfctlinput(PRC_IFDOWN, &ifa->ifa_addr);
19033984Skarels 	if_qflush(&ifp->if_snd);
1916582Ssam }
1927264Ssam 
1937264Ssam /*
19433984Skarels  * Flush an interface queue.
19533984Skarels  */
19633984Skarels if_qflush(ifq)
19733984Skarels 	register struct ifqueue *ifq;
19833984Skarels {
19933984Skarels 	register struct mbuf *m, *n;
20033984Skarels 
20133984Skarels 	n = ifq->ifq_head;
20233984Skarels 	while (m = n) {
20333984Skarels 		n = m->m_act;
20433984Skarels 		m_freem(m);
20533984Skarels 	}
20633984Skarels 	ifq->ifq_head = 0;
20733984Skarels 	ifq->ifq_tail = 0;
20833984Skarels 	ifq->ifq_len = 0;
20933984Skarels }
21033984Skarels 
21133984Skarels /*
2127264Ssam  * Handle interface watchdog timer routines.  Called
2137264Ssam  * from softclock, we decrement timers (if set) and
2147264Ssam  * call the appropriate interface routine on expiration.
2157264Ssam  */
2167264Ssam if_slowtimo()
2177264Ssam {
2187264Ssam 	register struct ifnet *ifp;
2197264Ssam 
2209184Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
2219184Ssam 		if (ifp->if_timer == 0 || --ifp->if_timer)
2229184Ssam 			continue;
2239184Ssam 		if (ifp->if_watchdog)
2247264Ssam 			(*ifp->if_watchdog)(ifp->if_unit);
2259184Ssam 	}
2268692Sroot 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
2277264Ssam }
22811576Ssam 
22911576Ssam /*
23013049Ssam  * Map interface name to
23113049Ssam  * interface structure pointer.
23211576Ssam  */
23313049Ssam struct ifnet *
23413049Ssam ifunit(name)
23513049Ssam 	register char *name;
23611576Ssam {
23713049Ssam 	register char *cp;
23811576Ssam 	register struct ifnet *ifp;
23913049Ssam 	int unit;
24011576Ssam 
24113049Ssam 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
24211576Ssam 		if (*cp >= '0' && *cp <= '9')
24311576Ssam 			break;
24413049Ssam 	if (*cp == '\0' || cp == name + IFNAMSIZ)
24513049Ssam 		return ((struct ifnet *)0);
24616135Skarels 	unit = *cp - '0';
24711576Ssam 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
24813049Ssam 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
24911576Ssam 			continue;
25011576Ssam 		if (unit == ifp->if_unit)
25113049Ssam 			break;
25211576Ssam 	}
25313049Ssam 	return (ifp);
25413049Ssam }
25511576Ssam 
25613049Ssam /*
25713049Ssam  * Interface ioctls.
25813049Ssam  */
25918544Skarels ifioctl(so, cmd, data)
26018544Skarels 	struct socket *so;
26113049Ssam 	int cmd;
26213049Ssam 	caddr_t data;
26313049Ssam {
26413049Ssam 	register struct ifnet *ifp;
26513049Ssam 	register struct ifreq *ifr;
26613049Ssam 
26711576Ssam 	switch (cmd) {
26811576Ssam 
26913049Ssam 	case SIOCGIFCONF:
27013049Ssam 		return (ifconf(cmd, data));
27113049Ssam 
27225647Skarels #if defined(INET) && NETHER > 0
27316220Skarels 	case SIOCSARP:
27416220Skarels 	case SIOCDARP:
27516220Skarels 		if (!suser())
27616220Skarels 			return (u.u_error);
27716220Skarels 		/* FALL THROUGH */
27816220Skarels 	case SIOCGARP:
27916220Skarels 		return (arpioctl(cmd, data));
28016220Skarels #endif
28113049Ssam 	}
28213049Ssam 	ifr = (struct ifreq *)data;
28313049Ssam 	ifp = ifunit(ifr->ifr_name);
28413049Ssam 	if (ifp == 0)
28513049Ssam 		return (ENXIO);
28613049Ssam 	switch (cmd) {
28713049Ssam 
28811576Ssam 	case SIOCGIFFLAGS:
28911576Ssam 		ifr->ifr_flags = ifp->if_flags;
29011576Ssam 		break;
29111576Ssam 
29226091Skarels 	case SIOCGIFMETRIC:
29326091Skarels 		ifr->ifr_metric = ifp->if_metric;
29426091Skarels 		break;
29526091Skarels 
29613053Ssam 	case SIOCSIFFLAGS:
29725565Sbloom 		if (!suser())
29825565Sbloom 			return (u.u_error);
29913053Ssam 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
30013053Ssam 			int s = splimp();
30113053Ssam 			if_down(ifp);
30213053Ssam 			splx(s);
30313053Ssam 		}
30418544Skarels 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
30518544Skarels 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
30624773Skarels 		if (ifp->if_ioctl)
30724773Skarels 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
30813053Ssam 		break;
30913053Ssam 
31026091Skarels 	case SIOCSIFMETRIC:
31126091Skarels 		if (!suser())
31226091Skarels 			return (u.u_error);
31326091Skarels 		ifp->if_metric = ifr->ifr_metric;
31426091Skarels 		break;
31526091Skarels 
31611576Ssam 	default:
31718544Skarels 		if (so->so_proto == 0)
31813049Ssam 			return (EOPNOTSUPP);
31918544Skarels 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
32018544Skarels 			cmd, data, ifp));
32111576Ssam 	}
32211576Ssam 	return (0);
32311576Ssam }
32411576Ssam 
32511576Ssam /*
32611576Ssam  * Return interface configuration
32711576Ssam  * of system.  List may be used
32811576Ssam  * in later ioctl's (above) to get
32911576Ssam  * other information.
33011576Ssam  */
33112783Ssam /*ARGSUSED*/
33211576Ssam ifconf(cmd, data)
33311576Ssam 	int cmd;
33411576Ssam 	caddr_t data;
33511576Ssam {
33611576Ssam 	register struct ifconf *ifc = (struct ifconf *)data;
33711576Ssam 	register struct ifnet *ifp = ifnet;
33818544Skarels 	register struct ifaddr *ifa;
33911630Ssam 	register char *cp, *ep;
34011630Ssam 	struct ifreq ifr, *ifrp;
34111576Ssam 	int space = ifc->ifc_len, error = 0;
34211576Ssam 
34311630Ssam 	ifrp = ifc->ifc_req;
34411630Ssam 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
34511576Ssam 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
34611630Ssam 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
34711630Ssam 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
34811576Ssam 			;
34911630Ssam 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
35018544Skarels 		if ((ifa = ifp->if_addrlist) == 0) {
35118544Skarels 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
35218544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
35318544Skarels 			if (error)
35418544Skarels 				break;
35518544Skarels 			space -= sizeof (ifr), ifrp++;
35618544Skarels 		} else
35718544Skarels 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
35818544Skarels 			ifr.ifr_addr = ifa->ifa_addr;
35918544Skarels 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
36018544Skarels 			if (error)
36118544Skarels 				break;
36218544Skarels 			space -= sizeof (ifr), ifrp++;
36318544Skarels 		}
36411576Ssam 	}
36511576Ssam 	ifc->ifc_len -= space;
36611576Ssam 	return (error);
36711576Ssam }
368