xref: /csrg-svn/sys/net/if.c (revision 37549)
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.7 (Berkeley) 04/26/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 	register 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), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 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(addr, ifa->ifa_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 	register 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(addr, ifa->ifa_dstaddr))
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 	struct sockaddr *addr;
139 {
140 	register struct ifnet *ifp;
141 	register struct ifaddr *ifa;
142 	register char *cp, *cp2, *cp3;
143 	register char *cplim;
144 	u_int af = addr->sa_family;
145 
146 	if (af >= AF_MAX)
147 		return (0);
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 != af || ifa->ifa_netmask == 0)
151 			continue;
152 		cp = addr->sa_data;
153 		cp2 = ifa->ifa_addr->sa_data;
154 		cp3 = ifa->ifa_netmask->sa_data;
155 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
156 		for (; cp3 < cplim; cp3++)
157 			if ((*cp++ ^ *cp2++) & *cp3)
158 				break;
159 		if (cp3 == cplim)
160 			return (ifa);
161 	    }
162 	return ((struct ifaddr *)0);
163 }
164 
165 #ifdef notdef
166 /*
167  * Find an interface using a specific address family
168  */
169 struct ifaddr *
170 ifa_ifwithaf(af)
171 	register int af;
172 {
173 	register struct ifnet *ifp;
174 	register struct ifaddr *ifa;
175 
176 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
177 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
178 		if (ifa->ifa_addr->sa_family == af)
179 			return (ifa);
180 	return ((struct ifaddr *)0);
181 }
182 #endif
183 
184 /*
185  * Mark an interface down and notify protocols of
186  * the transition.
187  * NOTE: must be called at splnet or eqivalent.
188  */
189 if_down(ifp)
190 	register struct ifnet *ifp;
191 {
192 	register struct ifaddr *ifa;
193 
194 	ifp->if_flags &= ~IFF_UP;
195 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
196 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
197 	if_qflush(&ifp->if_snd);
198 }
199 
200 /*
201  * Flush an interface queue.
202  */
203 if_qflush(ifq)
204 	register struct ifqueue *ifq;
205 {
206 	register struct mbuf *m, *n;
207 
208 	n = ifq->ifq_head;
209 	while (m = n) {
210 		n = m->m_act;
211 		m_freem(m);
212 	}
213 	ifq->ifq_head = 0;
214 	ifq->ifq_tail = 0;
215 	ifq->ifq_len = 0;
216 }
217 
218 /*
219  * Handle interface watchdog timer routines.  Called
220  * from softclock, we decrement timers (if set) and
221  * call the appropriate interface routine on expiration.
222  */
223 if_slowtimo()
224 {
225 	register struct ifnet *ifp;
226 	int s = splimp();
227 
228 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
229 		if (ifp->if_timer == 0 || --ifp->if_timer)
230 			continue;
231 		if (ifp->if_watchdog)
232 			(*ifp->if_watchdog)(ifp->if_unit);
233 	}
234 	splx(s);
235 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
236 }
237 
238 /*
239  * Map interface name to
240  * interface structure pointer.
241  */
242 struct ifnet *
243 ifunit(name)
244 	register char *name;
245 {
246 	register char *cp;
247 	register struct ifnet *ifp;
248 	int unit;
249 	unsigned len;
250 	char *ep, c;
251 
252 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
253 		if (*cp >= '0' && *cp <= '9')
254 			break;
255 	if (*cp == '\0' || cp == name + IFNAMSIZ)
256 		return ((struct ifnet *)0);
257 	/*
258 	 * Save first char of unit, and pointer to it,
259 	 * so we can put a null there to avoid matching
260 	 * initial substrings of interface names.
261 	 */
262 	len = cp - name + 1;
263 	c = *cp;
264 	ep = cp;
265 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
266 		unit = unit * 10 + *cp++ - '0';
267 	*ep = 0;
268 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
269 		if (bcmp(ifp->if_name, name, len))
270 			continue;
271 		if (unit == ifp->if_unit)
272 			break;
273 	}
274 	*ep = c;
275 	return (ifp);
276 }
277 
278 /*
279  * Interface ioctls.
280  */
281 ifioctl(so, cmd, data)
282 	struct socket *so;
283 	int cmd;
284 	caddr_t data;
285 {
286 	register struct ifnet *ifp;
287 	register struct ifreq *ifr;
288 	int error;
289 
290 	switch (cmd) {
291 
292 	case SIOCGIFCONF:
293 	case OSIOCGIFCONF:
294 		return (ifconf(cmd, data));
295 
296 #if defined(INET) && NETHER > 0
297 	case SIOCSARP:
298 	case SIOCDARP:
299 		if (error = suser(u.u_cred, &u.u_acflag))
300 			return (error);
301 		/* FALL THROUGH */
302 	case SIOCGARP:
303 	case OSIOCGARP:
304 		return (arpioctl(cmd, data));
305 #endif
306 	}
307 	ifr = (struct ifreq *)data;
308 	ifp = ifunit(ifr->ifr_name);
309 	if (ifp == 0)
310 		return (ENXIO);
311 	switch (cmd) {
312 
313 	case SIOCGIFFLAGS:
314 		ifr->ifr_flags = ifp->if_flags;
315 		break;
316 
317 	case SIOCGIFMETRIC:
318 		ifr->ifr_metric = ifp->if_metric;
319 		break;
320 
321 	case SIOCSIFFLAGS:
322 		if (error = suser(u.u_cred, &u.u_acflag))
323 			return (error);
324 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
325 			int s = splimp();
326 			if_down(ifp);
327 			splx(s);
328 		}
329 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
330 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
331 		if (ifp->if_ioctl)
332 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
333 		break;
334 
335 	case SIOCSIFMETRIC:
336 		if (error = suser(u.u_cred, &u.u_acflag))
337 			return (error);
338 		ifp->if_metric = ifr->ifr_metric;
339 		break;
340 
341 	default:
342 		if (so->so_proto == 0)
343 			return (EOPNOTSUPP);
344 #ifndef COMPAT_43
345 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
346 			cmd, data, ifp));
347 #else
348 	    {
349 		int error, ocmd = cmd;
350 
351 		switch (cmd) {
352 
353 		case SIOCSIFDSTADDR:
354 		case SIOCSIFADDR:
355 		case SIOCSIFBRDADDR:
356 		case SIOCSIFNETMASK:
357 #if BYTE_ORDER != BIG_ENDIAN
358 			if (ifr->ifr_addr.sa_family == 0 &&
359 			    ifr->ifr_addr.sa_len < 16) {
360 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
361 				ifr->ifr_addr.sa_len = 16;
362 			}
363 #else
364 			if (ifr->ifr_addr.sa_len == 0)
365 				ifr->ifr_addr.sa_len = 16;
366 #endif
367 			break;
368 
369 		case OSIOCGIFADDR:
370 			cmd = SIOCGIFADDR;
371 			break;
372 
373 		case OSIOCGIFDSTADDR:
374 			cmd = SIOCGIFDSTADDR;
375 			break;
376 
377 		case OSIOCGIFBRDADDR:
378 			cmd = SIOCGIFBRDADDR;
379 			break;
380 
381 		case OSIOCGIFNETMASK:
382 			cmd = SIOCGIFNETMASK;
383 		}
384 		error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
385 							    cmd, data, ifp));
386 		switch (ocmd) {
387 
388 		case OSIOCGIFADDR:
389 		case OSIOCGIFDSTADDR:
390 		case OSIOCGIFBRDADDR:
391 		case OSIOCGIFNETMASK:
392 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
393 		}
394 		return (error);
395 
396 	    }
397 #endif
398 	}
399 	return (0);
400 }
401 
402 /*
403  * Return interface configuration
404  * of system.  List may be used
405  * in later ioctl's (above) to get
406  * other information.
407  */
408 /*ARGSUSED*/
409 ifconf(cmd, data)
410 	int cmd;
411 	caddr_t data;
412 {
413 	register struct ifconf *ifc = (struct ifconf *)data;
414 	register struct ifnet *ifp = ifnet;
415 	register struct ifaddr *ifa;
416 	register char *cp, *ep;
417 	struct ifreq ifr, *ifrp;
418 	int space = ifc->ifc_len, error = 0;
419 
420 	ifrp = ifc->ifc_req;
421 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
422 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
423 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
424 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
425 			;
426 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
427 		if ((ifa = ifp->if_addrlist) == 0) {
428 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
429 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
430 			if (error)
431 				break;
432 			space -= sizeof (ifr), ifrp++;
433 		} else
434 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
435 			register struct sockaddr *sa = ifa->ifa_addr;
436 #ifdef COMPAT_43
437 			if (cmd == OSIOCGIFCONF) {
438 				struct osockaddr *osa =
439 					 (struct osockaddr *)&ifr.ifr_addr;
440 				ifr.ifr_addr = *sa;
441 				osa->sa_family = sa->sa_family;
442 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
443 						sizeof (ifr));
444 				ifrp++;
445 			} else
446 #endif
447 			if (sa->sa_len <= sizeof(*sa)) {
448 				ifr.ifr_addr = *sa;
449 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
450 						sizeof (ifr));
451 				ifrp++;
452 			} else {
453 				space -= sa->sa_len - sizeof(*sa);
454 				if (space < sizeof (ifr))
455 					break;
456 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
457 						sizeof (ifr.ifr_name));
458 				if (error == 0)
459 				    error = copyout((caddr_t)sa,
460 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
461 				ifrp = (struct ifreq *)
462 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
463 			}
464 			if (error)
465 				break;
466 			space -= sizeof (ifr);
467 		}
468 	}
469 	ifc->ifc_len -= space;
470 	return (error);
471 }
472