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