xref: /csrg-svn/sys/net/if.c (revision 41545)
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.10 (Berkeley) 05/10/90
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 "user.h"
27 #include "kernel.h"
28 #include "ioctl.h"
29 #include "errno.h"
30 
31 #include "if.h"
32 #include "af.h"
33 #include "if_dl.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 int if_index = 0;
72 /*
73  * Attach an interface to the
74  * list of "active" interfaces.
75  */
76 if_attach(ifp)
77 	struct ifnet *ifp;
78 {
79 	register struct ifnet **p = &ifnet;
80 	unsigned socksize, ifasize;
81 	int namelen, unitlen;
82 	char workbuf[16];
83 	register struct sockaddr_dl *sdl;
84 	register struct ifaddr *ifa;
85 
86 	while (*p)
87 		p = &((*p)->if_next);
88 	*p = ifp;
89 	ifp->if_index = ++if_index;
90 	/* create a link level name for this device */
91 	sprint_d(workbuf, ifp->if_unit);
92 	namelen = strlen(ifp->if_name);
93 	unitlen = strlen(workbuf);
94 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
95 	socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
96 			       unitlen + namelen + ifp->if_addrlen;
97 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
98 	socksize = ROUNDUP(socksize);
99 	ifasize = sizeof(*ifa) + 2 * socksize;
100 	ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
101 	if (ifa == 0)
102 		return;
103 	bzero((caddr_t)ifa, ifasize);
104 	sdl = (struct sockaddr_dl *)(ifa + 1);
105 	ifa->ifa_addr = (struct sockaddr *)sdl;
106 	ifa->ifa_ifp = ifp;
107 	sdl->sdl_len = socksize;
108 	sdl->sdl_family = AF_LINK;
109 	bcopy(ifp->if_name, sdl->sdl_data, namelen);
110 	bcopy((caddr_t)workbuf, namelen + (caddr_t)sdl->sdl_data, unitlen);
111 	sdl->sdl_nlen = (namelen += unitlen);
112 	sdl->sdl_index = ifp->if_index;
113 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
114 	ifa->ifa_netmask = (struct sockaddr *)sdl;
115 	sdl->sdl_len = socksize - ifp->if_addrlen;
116 	while (namelen != 0)
117 		sdl->sdl_data[--namelen] = 0xff;
118 	ifa->ifa_next = ifp->if_addrlist;
119 	ifp->if_addrlist = ifa;
120 }
121 
122 /*
123  * Locate an interface based on a complete address.
124  */
125 /*ARGSUSED*/
126 struct ifaddr *
127 ifa_ifwithaddr(addr)
128 	register struct sockaddr *addr;
129 {
130 	register struct ifnet *ifp;
131 	register struct ifaddr *ifa;
132 
133 #define	equal(a1, a2) \
134   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
135 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
136 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
137 		if (ifa->ifa_addr->sa_family != addr->sa_family)
138 			continue;
139 		if (equal(addr, ifa->ifa_addr))
140 			return (ifa);
141 		if ((ifp->if_flags & IFF_BROADCAST) &&
142 		    equal(&ifa->ifa_broadaddr, addr))
143 			return (ifa);
144 	}
145 	return ((struct ifaddr *)0);
146 }
147 /*
148  * Locate the point to point interface with a given destination address.
149  */
150 /*ARGSUSED*/
151 struct ifaddr *
152 ifa_ifwithdstaddr(addr)
153 	register struct sockaddr *addr;
154 {
155 	register struct ifnet *ifp;
156 	register struct ifaddr *ifa;
157 
158 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
159 	    if (ifp->if_flags & IFF_POINTOPOINT)
160 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
161 			if (ifa->ifa_addr->sa_family != addr->sa_family)
162 				continue;
163 			if (equal(addr, ifa->ifa_dstaddr))
164 				return (ifa);
165 	}
166 	return ((struct ifaddr *)0);
167 }
168 
169 /*
170  * Find an interface on a specific network.  If many, choice
171  * is first found.
172  */
173 struct ifaddr *
174 ifa_ifwithnet(addr)
175 	struct sockaddr *addr;
176 {
177 	register struct ifnet *ifp;
178 	register struct ifaddr *ifa;
179 	register char *cp, *cp2, *cp3;
180 	register char *cplim;
181 	u_int af = addr->sa_family;
182 
183 	if (af >= AF_MAX)
184 		return (0);
185 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
186 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
187 		if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
188 			continue;
189 		cp = addr->sa_data;
190 		cp2 = ifa->ifa_addr->sa_data;
191 		cp3 = ifa->ifa_netmask->sa_data;
192 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
193 		for (; cp3 < cplim; cp3++)
194 			if ((*cp++ ^ *cp2++) & *cp3)
195 				break;
196 		if (cp3 == cplim)
197 			return (ifa);
198 	    }
199 	return ((struct ifaddr *)0);
200 }
201 
202 #ifdef notdef
203 /*
204  * Find an interface using a specific address family
205  */
206 struct ifaddr *
207 ifa_ifwithaf(af)
208 	register int af;
209 {
210 	register struct ifnet *ifp;
211 	register struct ifaddr *ifa;
212 
213 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
214 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
215 		if (ifa->ifa_addr->sa_family == af)
216 			return (ifa);
217 	return ((struct ifaddr *)0);
218 }
219 #endif
220 
221 /*
222  * Mark an interface down and notify protocols of
223  * the transition.
224  * NOTE: must be called at splnet or eqivalent.
225  */
226 if_down(ifp)
227 	register struct ifnet *ifp;
228 {
229 	register struct ifaddr *ifa;
230 
231 	ifp->if_flags &= ~IFF_UP;
232 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
233 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
234 	if_qflush(&ifp->if_snd);
235 }
236 
237 /*
238  * Flush an interface queue.
239  */
240 if_qflush(ifq)
241 	register struct ifqueue *ifq;
242 {
243 	register struct mbuf *m, *n;
244 
245 	n = ifq->ifq_head;
246 	while (m = n) {
247 		n = m->m_act;
248 		m_freem(m);
249 	}
250 	ifq->ifq_head = 0;
251 	ifq->ifq_tail = 0;
252 	ifq->ifq_len = 0;
253 }
254 
255 /*
256  * Handle interface watchdog timer routines.  Called
257  * from softclock, we decrement timers (if set) and
258  * call the appropriate interface routine on expiration.
259  */
260 if_slowtimo()
261 {
262 	register struct ifnet *ifp;
263 	int s = splimp();
264 
265 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
266 		if (ifp->if_timer == 0 || --ifp->if_timer)
267 			continue;
268 		if (ifp->if_watchdog)
269 			(*ifp->if_watchdog)(ifp->if_unit);
270 	}
271 	splx(s);
272 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
273 }
274 
275 /*
276  * Map interface name to
277  * interface structure pointer.
278  */
279 struct ifnet *
280 ifunit(name)
281 	register char *name;
282 {
283 	register char *cp;
284 	register struct ifnet *ifp;
285 	int unit;
286 	unsigned len;
287 	char *ep, c;
288 
289 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
290 		if (*cp >= '0' && *cp <= '9')
291 			break;
292 	if (*cp == '\0' || cp == name + IFNAMSIZ)
293 		return ((struct ifnet *)0);
294 	/*
295 	 * Save first char of unit, and pointer to it,
296 	 * so we can put a null there to avoid matching
297 	 * initial substrings of interface names.
298 	 */
299 	len = cp - name + 1;
300 	c = *cp;
301 	ep = cp;
302 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
303 		unit = unit * 10 + *cp++ - '0';
304 	*ep = 0;
305 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
306 		if (bcmp(ifp->if_name, name, len))
307 			continue;
308 		if (unit == ifp->if_unit)
309 			break;
310 	}
311 	*ep = c;
312 	return (ifp);
313 }
314 
315 /*
316  * Interface ioctls.
317  */
318 ifioctl(so, cmd, data)
319 	struct socket *so;
320 	int cmd;
321 	caddr_t data;
322 {
323 	register struct ifnet *ifp;
324 	register struct ifreq *ifr;
325 	int error;
326 
327 	switch (cmd) {
328 
329 	case SIOCGIFCONF:
330 	case OSIOCGIFCONF:
331 		return (ifconf(cmd, data));
332 
333 #if defined(INET) && NETHER > 0
334 	case SIOCSARP:
335 	case SIOCDARP:
336 		if (error = suser(u.u_cred, &u.u_acflag))
337 			return (error);
338 		/* FALL THROUGH */
339 	case SIOCGARP:
340 	case OSIOCGARP:
341 		return (arpioctl(cmd, data));
342 #endif
343 	}
344 	ifr = (struct ifreq *)data;
345 	ifp = ifunit(ifr->ifr_name);
346 	if (ifp == 0)
347 		return (ENXIO);
348 	switch (cmd) {
349 
350 	case SIOCGIFFLAGS:
351 		ifr->ifr_flags = ifp->if_flags;
352 		break;
353 
354 	case SIOCGIFMETRIC:
355 		ifr->ifr_metric = ifp->if_metric;
356 		break;
357 
358 	case SIOCSIFFLAGS:
359 		if (error = suser(u.u_cred, &u.u_acflag))
360 			return (error);
361 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
362 			int s = splimp();
363 			if_down(ifp);
364 			splx(s);
365 		}
366 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
367 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
368 		if (ifp->if_ioctl)
369 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
370 		break;
371 
372 	case SIOCSIFMETRIC:
373 		if (error = suser(u.u_cred, &u.u_acflag))
374 			return (error);
375 		ifp->if_metric = ifr->ifr_metric;
376 		break;
377 
378 	default:
379 		if (so->so_proto == 0)
380 			return (EOPNOTSUPP);
381 #ifndef COMPAT_43
382 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
383 			cmd, data, ifp));
384 #else
385 	    {
386 		int ocmd = cmd;
387 
388 		switch (cmd) {
389 
390 		case SIOCSIFDSTADDR:
391 		case SIOCSIFADDR:
392 		case SIOCSIFBRDADDR:
393 		case SIOCSIFNETMASK:
394 #if BYTE_ORDER != BIG_ENDIAN
395 			if (ifr->ifr_addr.sa_family == 0 &&
396 			    ifr->ifr_addr.sa_len < 16) {
397 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
398 				ifr->ifr_addr.sa_len = 16;
399 			}
400 #else
401 			if (ifr->ifr_addr.sa_len == 0)
402 				ifr->ifr_addr.sa_len = 16;
403 #endif
404 			break;
405 
406 		case OSIOCGIFADDR:
407 			cmd = SIOCGIFADDR;
408 			break;
409 
410 		case OSIOCGIFDSTADDR:
411 			cmd = SIOCGIFDSTADDR;
412 			break;
413 
414 		case OSIOCGIFBRDADDR:
415 			cmd = SIOCGIFBRDADDR;
416 			break;
417 
418 		case OSIOCGIFNETMASK:
419 			cmd = SIOCGIFNETMASK;
420 		}
421 		error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
422 							    cmd, data, ifp));
423 		switch (ocmd) {
424 
425 		case OSIOCGIFADDR:
426 		case OSIOCGIFDSTADDR:
427 		case OSIOCGIFBRDADDR:
428 		case OSIOCGIFNETMASK:
429 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
430 		}
431 		return (error);
432 
433 	    }
434 #endif
435 	}
436 	return (0);
437 }
438 
439 /*
440  * Return interface configuration
441  * of system.  List may be used
442  * in later ioctl's (above) to get
443  * other information.
444  */
445 /*ARGSUSED*/
446 ifconf(cmd, data)
447 	int cmd;
448 	caddr_t data;
449 {
450 	register struct ifconf *ifc = (struct ifconf *)data;
451 	register struct ifnet *ifp = ifnet;
452 	register struct ifaddr *ifa;
453 	register char *cp, *ep;
454 	struct ifreq ifr, *ifrp;
455 	int space = ifc->ifc_len, error = 0;
456 
457 	ifrp = ifc->ifc_req;
458 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
459 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
460 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
461 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
462 			;
463 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
464 		if ((ifa = ifp->if_addrlist) == 0) {
465 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
466 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
467 			if (error)
468 				break;
469 			space -= sizeof (ifr), ifrp++;
470 		} else
471 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
472 			register struct sockaddr *sa = ifa->ifa_addr;
473 #ifdef COMPAT_43
474 			if (cmd == OSIOCGIFCONF) {
475 				struct osockaddr *osa =
476 					 (struct osockaddr *)&ifr.ifr_addr;
477 				ifr.ifr_addr = *sa;
478 				osa->sa_family = sa->sa_family;
479 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
480 						sizeof (ifr));
481 				ifrp++;
482 			} else
483 #endif
484 			if (sa->sa_len <= sizeof(*sa)) {
485 				ifr.ifr_addr = *sa;
486 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
487 						sizeof (ifr));
488 				ifrp++;
489 			} else {
490 				space -= sa->sa_len - sizeof(*sa);
491 				if (space < sizeof (ifr))
492 					break;
493 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
494 						sizeof (ifr.ifr_name));
495 				if (error == 0)
496 				    error = copyout((caddr_t)sa,
497 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
498 				ifrp = (struct ifreq *)
499 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
500 			}
501 			if (error)
502 				break;
503 			space -= sizeof (ifr);
504 		}
505 	}
506 	ifc->ifc_len -= space;
507 	return (error);
508 }
509 
510 static sprint_d(cp, n)
511 register char *cp;
512 u_short n;
513 {
514 	register int q, m;
515 	do {
516 	    if (n >= 10000) m = 10000;
517 		else if (n >= 1000) m = 1000;
518 		else if (n >= 100) m = 100;
519 		else if (n >= 10) m = 10;
520 		else m = 1;
521 	    q = n / m;
522 	    n -= m * q;
523 	    if (q > 9) q = 10; /* For crays with more than 100K interfaces */
524 	    *cp++ = "0123456789Z"[q];
525 	} while (n > 0);
526 	*cp++ = 0;
527 }
528