xref: /csrg-svn/sys/net/if.c (revision 36822)
1 /*
2  * Copyright (c) 1980, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)if.c	7.6.1.1 (Berkeley) 02/17/89
18  */
19 
20 #include "param.h"
21 #include "mbuf.h"
22 #include "systm.h"
23 #include "socket.h"
24 #include "socketvar.h"
25 #include "protosw.h"
26 #include "dir.h"
27 #include "user.h"
28 #include "kernel.h"
29 #include "ioctl.h"
30 #include "errno.h"
31 
32 #include "if.h"
33 #include "af.h"
34 
35 #include "ether.h"
36 
37 int	ifqmaxlen = IFQ_MAXLEN;
38 
39 /*
40  * Network interface utility routines.
41  *
42  * Routines with ifa_ifwith* names take sockaddr *'s as
43  * parameters.
44  */
45 
46 ifinit()
47 {
48 	register struct ifnet *ifp;
49 
50 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
51 		if (ifp->if_snd.ifq_maxlen == 0)
52 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
53 	if_slowtimo();
54 }
55 
56 #ifdef vax
57 /*
58  * Call each interface on a Unibus reset.
59  */
60 ifubareset(uban)
61 	int uban;
62 {
63 	register struct ifnet *ifp;
64 
65 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
66 		if (ifp->if_reset)
67 			(*ifp->if_reset)(ifp->if_unit, uban);
68 }
69 #endif
70 
71 /*
72  * Attach an interface to the
73  * list of "active" interfaces.
74  */
75 if_attach(ifp)
76 	struct ifnet *ifp;
77 {
78 	register struct ifnet **p = &ifnet;
79 
80 	while (*p)
81 		p = &((*p)->if_next);
82 	*p = ifp;
83 }
84 
85 /*
86  * Locate an interface based on a complete address.
87  */
88 /*ARGSUSED*/
89 struct ifaddr *
90 ifa_ifwithaddr(addr)
91 	struct sockaddr *addr;
92 {
93 	register struct ifnet *ifp;
94 	register struct ifaddr *ifa;
95 
96 #define	equal(a1, a2) \
97 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
98 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
99 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
100 		if (ifa->ifa_addr.sa_family != addr->sa_family)
101 			continue;
102 		if (equal(&ifa->ifa_addr, addr))
103 			return (ifa);
104 		if ((ifp->if_flags & IFF_BROADCAST) &&
105 		    equal(&ifa->ifa_broadaddr, addr))
106 			return (ifa);
107 	}
108 	return ((struct ifaddr *)0);
109 }
110 /*
111  * Locate the point to point interface with a given destination address.
112  */
113 /*ARGSUSED*/
114 struct ifaddr *
115 ifa_ifwithdstaddr(addr)
116 	struct sockaddr *addr;
117 {
118 	register struct ifnet *ifp;
119 	register struct ifaddr *ifa;
120 
121 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
122 	    if (ifp->if_flags & IFF_POINTOPOINT)
123 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
124 			if (ifa->ifa_addr.sa_family != addr->sa_family)
125 				continue;
126 			if (equal(&ifa->ifa_dstaddr, addr))
127 				return (ifa);
128 	}
129 	return ((struct ifaddr *)0);
130 }
131 
132 /*
133  * Find an interface on a specific network.  If many, choice
134  * is first found.
135  */
136 struct ifaddr *
137 ifa_ifwithnet(addr)
138 	register struct sockaddr *addr;
139 {
140 	register struct ifnet *ifp;
141 	register struct ifaddr *ifa;
142 	register u_int af = addr->sa_family;
143 	register int (*netmatch)();
144 
145 	if (af >= AF_MAX)
146 		return (0);
147 	netmatch = afswitch[af].af_netmatch;
148 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
149 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
150 		if (ifa->ifa_addr.sa_family != addr->sa_family)
151 			continue;
152 		if ((*netmatch)(&ifa->ifa_addr, addr))
153 			return (ifa);
154 	}
155 	return ((struct ifaddr *)0);
156 }
157 
158 #ifdef notdef
159 /*
160  * Find an interface using a specific address family
161  */
162 struct ifaddr *
163 ifa_ifwithaf(af)
164 	register int af;
165 {
166 	register struct ifnet *ifp;
167 	register struct ifaddr *ifa;
168 
169 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
170 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
171 		if (ifa->ifa_addr.sa_family == af)
172 			return (ifa);
173 	return ((struct ifaddr *)0);
174 }
175 #endif
176 
177 /*
178  * Mark an interface down and notify protocols of
179  * the transition.
180  * NOTE: must be called at splnet or eqivalent.
181  */
182 if_down(ifp)
183 	register struct ifnet *ifp;
184 {
185 	register struct ifaddr *ifa;
186 
187 	ifp->if_flags &= ~IFF_UP;
188 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
189 		pfctlinput(PRC_IFDOWN, &ifa->ifa_addr);
190 	if_qflush(&ifp->if_snd);
191 }
192 
193 /*
194  * Flush an interface queue.
195  */
196 if_qflush(ifq)
197 	register struct ifqueue *ifq;
198 {
199 	register struct mbuf *m, *n;
200 
201 	n = ifq->ifq_head;
202 	while (m = n) {
203 		n = m->m_act;
204 		m_freem(m);
205 	}
206 	ifq->ifq_head = 0;
207 	ifq->ifq_tail = 0;
208 	ifq->ifq_len = 0;
209 }
210 
211 /*
212  * Handle interface watchdog timer routines.  Called
213  * from softclock, we decrement timers (if set) and
214  * call the appropriate interface routine on expiration.
215  */
216 if_slowtimo()
217 {
218 	register struct ifnet *ifp;
219 
220 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
221 		if (ifp->if_timer == 0 || --ifp->if_timer)
222 			continue;
223 		if (ifp->if_watchdog)
224 			(*ifp->if_watchdog)(ifp->if_unit);
225 	}
226 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
227 }
228 
229 /*
230  * Map interface name to
231  * interface structure pointer.
232  */
233 struct ifnet *
234 ifunit(name)
235 	register char *name;
236 {
237 	register char *cp;
238 	register struct ifnet *ifp;
239 	int unit;
240 	unsigned len;
241 	char *ep, c;
242 
243 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
244 		if (*cp >= '0' && *cp <= '9')
245 			break;
246 	if (*cp == '\0' || cp == name + IFNAMSIZ)
247 		return ((struct ifnet *)0);
248 	/*
249 	 * Save first char of unit, and pointer to it,
250 	 * so we can put a null there to avoid matching
251 	 * initial substrings of interface names.
252 	 */
253 	len = cp - name + 1;
254 	c = *cp;
255 	ep = cp;
256 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
257 		unit = unit * 10 + *cp++ - '0';
258 	*ep = 0;
259 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
260 		if (bcmp(ifp->if_name, name, len))
261 			continue;
262 		if (unit == ifp->if_unit)
263 			break;
264 	}
265 	*ep = c;
266 	return (ifp);
267 }
268 
269 /*
270  * Interface ioctls.
271  */
272 ifioctl(so, cmd, data)
273 	struct socket *so;
274 	int cmd;
275 	caddr_t data;
276 {
277 	register struct ifnet *ifp;
278 	register struct ifreq *ifr;
279 
280 	switch (cmd) {
281 
282 	case SIOCGIFCONF:
283 		return (ifconf(cmd, data));
284 
285 #if defined(INET) && NETHER > 0
286 	case SIOCSARP:
287 	case SIOCDARP:
288 		if (!suser())
289 			return (u.u_error);
290 		/* FALL THROUGH */
291 	case SIOCGARP:
292 		return (arpioctl(cmd, data));
293 #endif
294 	}
295 	ifr = (struct ifreq *)data;
296 	ifp = ifunit(ifr->ifr_name);
297 	if (ifp == 0)
298 		return (ENXIO);
299 	switch (cmd) {
300 
301 	case SIOCGIFFLAGS:
302 		ifr->ifr_flags = ifp->if_flags;
303 		break;
304 
305 	case SIOCGIFMETRIC:
306 		ifr->ifr_metric = ifp->if_metric;
307 		break;
308 
309 	case SIOCSIFFLAGS:
310 		if (!suser())
311 			return (u.u_error);
312 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
313 			int s = splimp();
314 			if_down(ifp);
315 			splx(s);
316 		}
317 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
318 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
319 		if (ifp->if_ioctl)
320 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
321 		break;
322 
323 	case SIOCSIFMETRIC:
324 		if (!suser())
325 			return (u.u_error);
326 		ifp->if_metric = ifr->ifr_metric;
327 		break;
328 
329 	default:
330 		if (so->so_proto == 0)
331 			return (EOPNOTSUPP);
332 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
333 			cmd, data, ifp));
334 	}
335 	return (0);
336 }
337 
338 /*
339  * Return interface configuration
340  * of system.  List may be used
341  * in later ioctl's (above) to get
342  * other information.
343  */
344 /*ARGSUSED*/
345 ifconf(cmd, data)
346 	int cmd;
347 	caddr_t data;
348 {
349 	register struct ifconf *ifc = (struct ifconf *)data;
350 	register struct ifnet *ifp = ifnet;
351 	register struct ifaddr *ifa;
352 	register char *cp, *ep;
353 	struct ifreq ifr, *ifrp;
354 	int space = ifc->ifc_len, error = 0;
355 
356 	ifrp = ifc->ifc_req;
357 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
358 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
359 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
360 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
361 			;
362 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
363 		if ((ifa = ifp->if_addrlist) == 0) {
364 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
365 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
366 			if (error)
367 				break;
368 			space -= sizeof (ifr), ifrp++;
369 		} else
370 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
371 			ifr.ifr_addr = ifa->ifa_addr;
372 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
373 			if (error)
374 				break;
375 			space -= sizeof (ifr), ifrp++;
376 		}
377 	}
378 	ifc->ifc_len -= space;
379 	return (error);
380 }
381