xref: /csrg-svn/sys/net/if.c (revision 23933)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)if.c	6.8 (Berkeley) 07/18/85
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "socket.h"
12 #include "socketvar.h"
13 #include "protosw.h"
14 #include "dir.h"
15 #include "user.h"
16 #include "kernel.h"
17 #include "ioctl.h"
18 #include "errno.h"
19 
20 #include "if.h"
21 #include "af.h"
22 
23 #include "ether.h"
24 
25 int	ifqmaxlen = IFQ_MAXLEN;
26 
27 /*
28  * Network interface utility routines.
29  *
30  * Routines with ifa_ifwith* names take sockaddr *'s as
31  * parameters.
32  */
33 
34 ifinit()
35 {
36 	register struct ifnet *ifp;
37 
38 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
39 		if (ifp->if_init) {
40 			(*ifp->if_init)(ifp->if_unit);
41 			if (ifp->if_snd.ifq_maxlen == 0)
42 				ifp->if_snd.ifq_maxlen = ifqmaxlen;
43 		}
44 	if_slowtimo();
45 }
46 
47 #ifdef vax
48 /*
49  * Call each interface on a Unibus reset.
50  */
51 ifubareset(uban)
52 	int uban;
53 {
54 	register struct ifnet *ifp;
55 
56 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
57 		if (ifp->if_reset)
58 			(*ifp->if_reset)(ifp->if_unit, uban);
59 }
60 #endif
61 
62 /*
63  * Attach an interface to the
64  * list of "active" interfaces.
65  */
66 if_attach(ifp)
67 	struct ifnet *ifp;
68 {
69 	register struct ifnet **p = &ifnet;
70 
71 	while (*p)
72 		p = &((*p)->if_next);
73 	*p = ifp;
74 }
75 
76 /*
77  * Locate an interface based on a complete address.
78  */
79 /*ARGSUSED*/
80 struct ifaddr *
81 ifa_ifwithaddr(addr)
82 	struct sockaddr *addr;
83 {
84 	register struct ifnet *ifp;
85 	register struct ifaddr *ifa;
86 
87 #define	equal(a1, a2) \
88 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
89 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
90 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
91 		if (ifa->ifa_addr.sa_family != addr->sa_family)
92 			continue;
93 		if (equal(&ifa->ifa_addr, addr))
94 			return (ifa);
95 		if ((ifp->if_flags & IFF_BROADCAST) &&
96 		    equal(&ifa->ifa_broadaddr, addr))
97 			return (ifa);
98 	}
99 	return ((struct ifaddr *)0);
100 }
101 /*
102  * Locate the point to point interface with a given destination address.
103  */
104 /*ARGSUSED*/
105 struct ifaddr *
106 ifa_ifwithdstaddr(addr)
107 	struct sockaddr *addr;
108 {
109 	register struct ifnet *ifp;
110 	register struct ifaddr *ifa;
111 
112 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
113 	    if (ifp->if_flags & IFF_POINTOPOINT)
114 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
115 			if (ifa->ifa_addr.sa_family != addr->sa_family)
116 				continue;
117 			if (equal(&ifa->ifa_dstaddr, addr))
118 				return (ifa);
119 	}
120 	return ((struct ifaddr *)0);
121 }
122 
123 /*
124  * Find an interface on a specific network.  If many, choice
125  * is first found.
126  */
127 struct ifaddr *
128 ifa_ifwithnet(addr)
129 	register struct sockaddr *addr;
130 {
131 	register struct ifnet *ifp;
132 	register struct ifaddr *ifa;
133 	register u_int af = addr->sa_family;
134 	register int (*netmatch)();
135 
136 	if (af >= AF_MAX)
137 		return (0);
138 	netmatch = afswitch[af].af_netmatch;
139 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
140 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
141 		if (ifa->ifa_addr.sa_family != addr->sa_family)
142 			continue;
143 		if ((*netmatch)(&ifa->ifa_addr, addr))
144 			return (ifa);
145 	}
146 	return ((struct ifaddr *)0);
147 }
148 
149 /*
150  * Find an interface using a specific address family
151  */
152 struct ifaddr *
153 ifa_ifwithaf(af)
154 	register int af;
155 {
156 	register struct ifnet *ifp;
157 	register struct ifaddr *ifa;
158 
159 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
160 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
161 		if (ifa->ifa_addr.sa_family == af)
162 			return (ifa);
163 	return ((struct ifaddr *)0);
164 }
165 
166 /*
167  * Mark an interface down and notify protocols of
168  * the transition.
169  * NOTE: must be called at splnet or eqivalent.
170  */
171 if_down(ifp)
172 	register struct ifnet *ifp;
173 {
174 	register struct ifaddr *ifa;
175 
176 	ifp->if_flags &= ~IFF_UP;
177 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
178 		pfctlinput(PRC_IFDOWN, (caddr_t)&ifa->ifa_addr);
179 }
180 
181 /*
182  * Handle interface watchdog timer routines.  Called
183  * from softclock, we decrement timers (if set) and
184  * call the appropriate interface routine on expiration.
185  */
186 if_slowtimo()
187 {
188 	register struct ifnet *ifp;
189 
190 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
191 		if (ifp->if_timer == 0 || --ifp->if_timer)
192 			continue;
193 		if (ifp->if_watchdog)
194 			(*ifp->if_watchdog)(ifp->if_unit);
195 	}
196 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
197 }
198 
199 /*
200  * Map interface name to
201  * interface structure pointer.
202  */
203 struct ifnet *
204 ifunit(name)
205 	register char *name;
206 {
207 	register char *cp;
208 	register struct ifnet *ifp;
209 	int unit;
210 
211 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
212 		if (*cp >= '0' && *cp <= '9')
213 			break;
214 	if (*cp == '\0' || cp == name + IFNAMSIZ)
215 		return ((struct ifnet *)0);
216 	unit = *cp - '0';
217 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
218 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
219 			continue;
220 		if (unit == ifp->if_unit)
221 			break;
222 	}
223 	return (ifp);
224 }
225 
226 /*
227  * Interface ioctls.
228  */
229 ifioctl(so, cmd, data)
230 	struct socket *so;
231 	int cmd;
232 	caddr_t data;
233 {
234 	register struct ifnet *ifp;
235 	register struct ifreq *ifr;
236 
237 	switch (cmd) {
238 
239 	case SIOCGIFCONF:
240 		return (ifconf(cmd, data));
241 
242 #if defined(INET) && NETHER > 0
243 	case SIOCSARP:
244 	case SIOCDARP:
245 		if (!suser())
246 			return (u.u_error);
247 		/* FALL THROUGH */
248 	case SIOCGARP:
249 		return (arpioctl(cmd, data));
250 #endif
251 	}
252 	ifr = (struct ifreq *)data;
253 	ifp = ifunit(ifr->ifr_name);
254 	if (ifp == 0)
255 		return (ENXIO);
256 	switch (cmd) {
257 
258 	case SIOCGIFFLAGS:
259 		ifr->ifr_flags = ifp->if_flags;
260 		break;
261 
262 	case SIOCSIFFLAGS:
263 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
264 			int s = splimp();
265 			if_down(ifp);
266 			splx(s);
267 		}
268 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
269 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
270 		break;
271 
272 	default:
273 		if (so->so_proto == 0)
274 			return (EOPNOTSUPP);
275 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
276 			cmd, data, ifp));
277 	}
278 	return (0);
279 }
280 
281 /*
282  * Return interface configuration
283  * of system.  List may be used
284  * in later ioctl's (above) to get
285  * other information.
286  */
287 /*ARGSUSED*/
288 ifconf(cmd, data)
289 	int cmd;
290 	caddr_t data;
291 {
292 	register struct ifconf *ifc = (struct ifconf *)data;
293 	register struct ifnet *ifp = ifnet;
294 	register struct ifaddr *ifa;
295 	register char *cp, *ep;
296 	struct ifreq ifr, *ifrp;
297 	int space = ifc->ifc_len, error = 0;
298 
299 	ifrp = ifc->ifc_req;
300 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
301 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
302 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
303 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
304 			;
305 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
306 		if ((ifa = ifp->if_addrlist) == 0) {
307 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
308 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
309 			if (error)
310 				break;
311 			space -= sizeof (ifr), ifrp++;
312 		} else
313 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
314 			ifr.ifr_addr = ifa->ifa_addr;
315 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
316 			if (error)
317 				break;
318 			space -= sizeof (ifr), ifrp++;
319 		}
320 	}
321 	ifc->ifc_len -= space;
322 	return (error);
323 }
324