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