xref: /original-bsd/sys/net/if.c (revision 13ec26c3)
1 /*
2  * Copyright (c) 1980, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if.c	7.19 (Berkeley) 05/12/92
8  */
9 
10 #include "param.h"
11 #include "mbuf.h"
12 #include "systm.h"
13 #include "proc.h"
14 #include "socket.h"
15 #include "socketvar.h"
16 #include "protosw.h"
17 #include "kernel.h"
18 #include "ioctl.h"
19 
20 #include "if.h"
21 #include "af.h"
22 #include "if_dl.h"
23 #include "if_types.h"
24 
25 #include "ether.h"
26 
27 int	ifqmaxlen = IFQ_MAXLEN;
28 
29 /*
30  * Network interface utility routines.
31  *
32  * Routines with ifa_ifwith* names take sockaddr *'s as
33  * parameters.
34  */
35 
36 ifinit()
37 {
38 	register struct ifnet *ifp;
39 
40 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
41 		if (ifp->if_snd.ifq_maxlen == 0)
42 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
43 	if_slowtimo();
44 }
45 
46 #ifdef vax
47 /*
48  * Call each interface on a Unibus reset.
49  */
50 ifubareset(uban)
51 	int uban;
52 {
53 	register struct ifnet *ifp;
54 
55 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
56 		if (ifp->if_reset)
57 			(*ifp->if_reset)(ifp->if_unit, uban);
58 }
59 #endif
60 
61 int if_index = 0;
62 struct ifaddr **ifnet_addrs;
63 static char *sprint_d();
64 
65 /*
66  * Attach an interface to the
67  * list of "active" interfaces.
68  */
69 void
70 if_attach(ifp)
71 	struct ifnet *ifp;
72 {
73 	unsigned socksize, ifasize;
74 	int namelen, unitlen, masklen;
75 	char workbuf[12], *unitname;
76 	register struct ifnet **p = &ifnet;
77 	register struct sockaddr_dl *sdl;
78 	register struct ifaddr *ifa;
79 	static int if_indexlim = 8;
80 	extern link_rtrequest(), ether_output();
81 
82 	while (*p)
83 		p = &((*p)->if_next);
84 	*p = ifp;
85 	ifp->if_index = ++if_index;
86 	if (ifnet_addrs == 0 || if_index >= if_indexlim) {
87 		unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
88 		struct ifaddr **q = (struct ifaddr **)
89 					malloc(n, M_IFADDR, M_WAITOK);
90 		if (ifnet_addrs) {
91 			bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
92 			free((caddr_t)ifnet_addrs, M_IFADDR);
93 		}
94 		ifnet_addrs = q;
95 	}
96 	/*
97 	 * create a Link Level name for this device
98 	 */
99 	unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
100 	namelen = strlen(ifp->if_name);
101 	unitlen = strlen(unitname);
102 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
103 	masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) +
104 			       unitlen + namelen;
105 	socksize = masklen + ifp->if_addrlen;
106 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
107 	socksize = ROUNDUP(socksize);
108 	if (socksize < sizeof(*sdl))
109 		socksize = sizeof(*sdl);
110 	ifasize = sizeof(*ifa) + 2 * socksize;
111 	if (ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK)) {
112 		bzero((caddr_t)ifa, ifasize);
113 		sdl = (struct sockaddr_dl *)(ifa + 1);
114 		sdl->sdl_len = socksize;
115 		sdl->sdl_family = AF_LINK;
116 		bcopy(ifp->if_name, sdl->sdl_data, namelen);
117 		bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
118 		sdl->sdl_nlen = (namelen += unitlen);
119 		sdl->sdl_index = ifp->if_index;
120 		sdl->sdl_type = ifp->if_type;
121 		ifnet_addrs[if_index - 1] = ifa;
122 		ifa->ifa_ifp = ifp;
123 		ifa->ifa_next = ifp->if_addrlist;
124 		ifa->ifa_rtrequest = link_rtrequest;
125 		ifp->if_addrlist = ifa;
126 		ifa->ifa_addr = (struct sockaddr *)sdl;
127 		sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
128 		ifa->ifa_netmask = (struct sockaddr *)sdl;
129 		sdl->sdl_len = masklen;
130 		while (namelen != 0)
131 			sdl->sdl_data[--namelen] = 0xff;
132 	}
133 	/* XXX -- Temporary fix before changing 10 ethernet drivers */
134 	if (ifp->if_output == ether_output)
135 		ether_ifattach(ifp);
136 }
137 /*
138  * Locate an interface based on a complete address.
139  */
140 /*ARGSUSED*/
141 struct ifaddr *
142 ifa_ifwithaddr(addr)
143 	register struct sockaddr *addr;
144 {
145 	register struct ifnet *ifp;
146 	register struct ifaddr *ifa;
147 
148 #define	equal(a1, a2) \
149   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
150 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
151 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
152 		if (ifa->ifa_addr->sa_family != addr->sa_family)
153 			continue;
154 		if (equal(addr, ifa->ifa_addr))
155 			return (ifa);
156 		if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
157 		    equal(ifa->ifa_broadaddr, addr))
158 			return (ifa);
159 	}
160 	return ((struct ifaddr *)0);
161 }
162 /*
163  * Locate the point to point interface with a given destination address.
164  */
165 /*ARGSUSED*/
166 struct ifaddr *
167 ifa_ifwithdstaddr(addr)
168 	register struct sockaddr *addr;
169 {
170 	register struct ifnet *ifp;
171 	register struct ifaddr *ifa;
172 
173 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
174 	    if (ifp->if_flags & IFF_POINTOPOINT)
175 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
176 			if (ifa->ifa_addr->sa_family != addr->sa_family)
177 				continue;
178 			if (equal(addr, ifa->ifa_dstaddr))
179 				return (ifa);
180 	}
181 	return ((struct ifaddr *)0);
182 }
183 
184 /*
185  * Find an interface on a specific network.  If many, choice
186  * is most specific found.
187  */
188 struct ifaddr *
189 ifa_ifwithnet(addr)
190 	struct sockaddr *addr;
191 {
192 	register struct ifnet *ifp;
193 	register struct ifaddr *ifa;
194 	struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
195 	u_int af = addr->sa_family;
196 	char *addr_data = addr->sa_data, *cplim;
197 
198 	if (af == AF_LINK) {
199 	    register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
200 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
201 		return (ifnet_addrs[sdl->sdl_index - 1]);
202 	}
203 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
204 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
205 		register char *cp, *cp2, *cp3;
206 
207 		if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
208 			next: continue;
209 		cp = addr_data;
210 		cp2 = ifa->ifa_addr->sa_data;
211 		cp3 = ifa->ifa_netmask->sa_data;
212 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
213 		while (cp3 < cplim)
214 			if ((*cp++ ^ *cp2++) & *cp3++)
215 				goto next;
216 		if (ifa_maybe == 0 ||
217 		    rn_refines(ifa->ifa_netmask, ifa_maybe->ifa_netmask))
218 			ifa_maybe = ifa;
219 	    }
220 	return (ifa_maybe);
221 }
222 
223 /*
224  * Find an interface using a specific address family
225  */
226 struct ifaddr *
227 ifa_ifwithaf(af)
228 	register int af;
229 {
230 	register struct ifnet *ifp;
231 	register struct ifaddr *ifa;
232 
233 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
234 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
235 		if (ifa->ifa_addr->sa_family == af)
236 			return (ifa);
237 	return ((struct ifaddr *)0);
238 }
239 
240 /*
241  * Find an interface address specific to an interface best matching
242  * a given address.
243  */
244 struct ifaddr *
245 ifaof_ifpforaddr(addr, ifp)
246 	struct sockaddr *addr;
247 	register struct ifnet *ifp;
248 {
249 	register struct ifaddr *ifa;
250 	register char *cp, *cp2, *cp3;
251 	register char *cplim;
252 	struct ifaddr *ifa_maybe = 0;
253 	u_int af = addr->sa_family;
254 
255 	if (af >= AF_MAX)
256 		return (0);
257 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
258 		if (ifa->ifa_addr->sa_family != af)
259 			continue;
260 		ifa_maybe = ifa;
261 		if (ifa->ifa_netmask == 0) {
262 			if (equal(addr, ifa->ifa_addr) ||
263 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
264 				return (ifa);
265 			continue;
266 		}
267 		cp = addr->sa_data;
268 		cp2 = ifa->ifa_addr->sa_data;
269 		cp3 = ifa->ifa_netmask->sa_data;
270 		cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
271 		for (; cp3 < cplim; cp3++)
272 			if ((*cp++ ^ *cp2++) & *cp3)
273 				break;
274 		if (cp3 == cplim)
275 			return (ifa);
276 	}
277 	return (ifa_maybe);
278 }
279 #include "route.h"
280 /*
281  * Default action when installing a route with a Link Level gateway.
282  * Lookup an appropriate real ifa to point to.
283  * This should be moved to /sys/net/link.c eventually.
284  */
285 link_rtrequest(cmd, rt, sa)
286 	int cmd;
287 	register struct rtentry *rt;
288 	struct sockaddr *sa;
289 {
290 	register struct ifaddr *ifa;
291 	struct sockaddr *dst;
292 	struct ifnet *ifp, *oldifnet = ifnet;
293 
294 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
295 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
296 		return;
297 	if (ifa = ifaof_ifpforaddr(dst, ifp)) {
298 		rt->rt_ifa = ifa;
299 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
300 			ifa->ifa_rtrequest(cmd, rt, sa);
301 	}
302 }
303 
304 /*
305  * Mark an interface down and notify protocols of
306  * the transition.
307  * NOTE: must be called at splnet or eqivalent.
308  */
309 if_down(ifp)
310 	register struct ifnet *ifp;
311 {
312 	register struct ifaddr *ifa;
313 
314 	ifp->if_flags &= ~IFF_UP;
315 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
316 		pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
317 	if_qflush(&ifp->if_snd);
318 	rt_ifmsg(ifp);
319 }
320 
321 /*
322  * Mark an interface up and notify protocols of
323  * the transition.
324  * NOTE: must be called at splnet or eqivalent.
325  */
326 if_up(ifp)
327 	register struct ifnet *ifp;
328 {
329 	register struct ifaddr *ifa;
330 
331 	ifp->if_flags |= IFF_UP;
332 #ifdef notyet
333 	/* this has no effect on IP, and will kill all iso connections XXX */
334 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
335 		pfctlinput(PRC_IFUP, ifa->ifa_addr);
336 #endif notyet
337 	rt_ifmsg(ifp);
338 }
339 
340 /*
341  * Flush an interface queue.
342  */
343 if_qflush(ifq)
344 	register struct ifqueue *ifq;
345 {
346 	register struct mbuf *m, *n;
347 
348 	n = ifq->ifq_head;
349 	while (m = n) {
350 		n = m->m_act;
351 		m_freem(m);
352 	}
353 	ifq->ifq_head = 0;
354 	ifq->ifq_tail = 0;
355 	ifq->ifq_len = 0;
356 }
357 
358 /*
359  * Handle interface watchdog timer routines.  Called
360  * from softclock, we decrement timers (if set) and
361  * call the appropriate interface routine on expiration.
362  */
363 if_slowtimo()
364 {
365 	register struct ifnet *ifp;
366 	int s = splimp();
367 
368 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
369 		if (ifp->if_timer == 0 || --ifp->if_timer)
370 			continue;
371 		if (ifp->if_watchdog)
372 			(*ifp->if_watchdog)(ifp->if_unit);
373 	}
374 	splx(s);
375 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
376 }
377 
378 /*
379  * Map interface name to
380  * interface structure pointer.
381  */
382 struct ifnet *
383 ifunit(name)
384 	register char *name;
385 {
386 	register char *cp;
387 	register struct ifnet *ifp;
388 	int unit;
389 	unsigned len;
390 	char *ep, c;
391 
392 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
393 		if (*cp >= '0' && *cp <= '9')
394 			break;
395 	if (*cp == '\0' || cp == name + IFNAMSIZ)
396 		return ((struct ifnet *)0);
397 	/*
398 	 * Save first char of unit, and pointer to it,
399 	 * so we can put a null there to avoid matching
400 	 * initial substrings of interface names.
401 	 */
402 	len = cp - name + 1;
403 	c = *cp;
404 	ep = cp;
405 	for (unit = 0; *cp >= '0' && *cp <= '9'; )
406 		unit = unit * 10 + *cp++ - '0';
407 	*ep = 0;
408 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
409 		if (bcmp(ifp->if_name, name, len))
410 			continue;
411 		if (unit == ifp->if_unit)
412 			break;
413 	}
414 	*ep = c;
415 	return (ifp);
416 }
417 
418 /*
419  * Interface ioctls.
420  */
421 ifioctl(so, cmd, data, p)
422 	struct socket *so;
423 	int cmd;
424 	caddr_t data;
425 	struct proc *p;
426 {
427 	register struct ifnet *ifp;
428 	register struct ifreq *ifr;
429 	int error;
430 
431 	switch (cmd) {
432 
433 	case SIOCGIFCONF:
434 	case OSIOCGIFCONF:
435 		return (ifconf(cmd, data));
436 
437 #if defined(INET) && NETHER > 0
438 	case SIOCSARP:
439 	case SIOCDARP:
440 		if (error = suser(p->p_ucred, &p->p_acflag))
441 			return (error);
442 		/* FALL THROUGH */
443 	case SIOCGARP:
444 	case OSIOCGARP:
445 		return (arpioctl(cmd, data));
446 #endif
447 	}
448 	ifr = (struct ifreq *)data;
449 	ifp = ifunit(ifr->ifr_name);
450 	if (ifp == 0)
451 		return (ENXIO);
452 	switch (cmd) {
453 
454 	case SIOCGIFFLAGS:
455 		ifr->ifr_flags = ifp->if_flags;
456 		break;
457 
458 	case SIOCGIFMETRIC:
459 		ifr->ifr_metric = ifp->if_metric;
460 		break;
461 
462 	case SIOCSIFFLAGS:
463 		if (error = suser(p->p_ucred, &p->p_acflag))
464 			return (error);
465 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
466 			int s = splimp();
467 			if_down(ifp);
468 			splx(s);
469 		}
470 		if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
471 			int s = splimp();
472 			if_up(ifp);
473 			splx(s);
474 		}
475 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
476 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
477 		if (ifp->if_ioctl)
478 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
479 		break;
480 
481 	case SIOCSIFMETRIC:
482 		if (error = suser(p->p_ucred, &p->p_acflag))
483 			return (error);
484 		ifp->if_metric = ifr->ifr_metric;
485 		break;
486 
487 	default:
488 		if (so->so_proto == 0)
489 			return (EOPNOTSUPP);
490 #ifndef COMPAT_43
491 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
492 			cmd, data, ifp));
493 #else
494 	    {
495 		int ocmd = cmd;
496 
497 		switch (cmd) {
498 
499 		case SIOCSIFDSTADDR:
500 		case SIOCSIFADDR:
501 		case SIOCSIFBRDADDR:
502 		case SIOCSIFNETMASK:
503 #if BYTE_ORDER != BIG_ENDIAN
504 			if (ifr->ifr_addr.sa_family == 0 &&
505 			    ifr->ifr_addr.sa_len < 16) {
506 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
507 				ifr->ifr_addr.sa_len = 16;
508 			}
509 #else
510 			if (ifr->ifr_addr.sa_len == 0)
511 				ifr->ifr_addr.sa_len = 16;
512 #endif
513 			break;
514 
515 		case OSIOCGIFADDR:
516 			cmd = SIOCGIFADDR;
517 			break;
518 
519 		case OSIOCGIFDSTADDR:
520 			cmd = SIOCGIFDSTADDR;
521 			break;
522 
523 		case OSIOCGIFBRDADDR:
524 			cmd = SIOCGIFBRDADDR;
525 			break;
526 
527 		case OSIOCGIFNETMASK:
528 			cmd = SIOCGIFNETMASK;
529 		}
530 		error =  ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
531 							    cmd, data, ifp));
532 		switch (ocmd) {
533 
534 		case OSIOCGIFADDR:
535 		case OSIOCGIFDSTADDR:
536 		case OSIOCGIFBRDADDR:
537 		case OSIOCGIFNETMASK:
538 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
539 		}
540 		return (error);
541 
542 	    }
543 #endif
544 	}
545 	return (0);
546 }
547 
548 /*
549  * Return interface configuration
550  * of system.  List may be used
551  * in later ioctl's (above) to get
552  * other information.
553  */
554 /*ARGSUSED*/
555 ifconf(cmd, data)
556 	int cmd;
557 	caddr_t data;
558 {
559 	register struct ifconf *ifc = (struct ifconf *)data;
560 	register struct ifnet *ifp = ifnet;
561 	register struct ifaddr *ifa;
562 	register char *cp, *ep;
563 	struct ifreq ifr, *ifrp;
564 	int space = ifc->ifc_len, error = 0;
565 
566 	ifrp = ifc->ifc_req;
567 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
568 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
569 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
570 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
571 			continue;
572 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
573 		if ((ifa = ifp->if_addrlist) == 0) {
574 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
575 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
576 			if (error)
577 				break;
578 			space -= sizeof (ifr), ifrp++;
579 		} else
580 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
581 			register struct sockaddr *sa = ifa->ifa_addr;
582 #ifdef COMPAT_43
583 			if (cmd == OSIOCGIFCONF) {
584 				struct osockaddr *osa =
585 					 (struct osockaddr *)&ifr.ifr_addr;
586 				ifr.ifr_addr = *sa;
587 				osa->sa_family = sa->sa_family;
588 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
589 						sizeof (ifr));
590 				ifrp++;
591 			} else
592 #endif
593 			if (sa->sa_len <= sizeof(*sa)) {
594 				ifr.ifr_addr = *sa;
595 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
596 						sizeof (ifr));
597 				ifrp++;
598 			} else {
599 				space -= sa->sa_len - sizeof(*sa);
600 				if (space < sizeof (ifr))
601 					break;
602 				error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
603 						sizeof (ifr.ifr_name));
604 				if (error == 0)
605 				    error = copyout((caddr_t)sa,
606 				      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
607 				ifrp = (struct ifreq *)
608 					(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
609 			}
610 			if (error)
611 				break;
612 			space -= sizeof (ifr);
613 		}
614 	}
615 	ifc->ifc_len -= space;
616 	return (error);
617 }
618 
619 static char *
620 sprint_d(n, buf, buflen)
621 	u_int n;
622 	char *buf;
623 	int buflen;
624 {
625 	register char *cp = buf + buflen - 1;
626 
627 	*cp = 0;
628 	do {
629 		cp--;
630 		*cp = "0123456789"[n % 10];
631 		n /= 10;
632 	} while (n != 0);
633 	return (cp);
634 }
635