xref: /original-bsd/sys/net/if.c (revision 38045c73)
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 this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  *
12  *	@(#)if.c	7.3 (Berkeley) 04/07/88
13  */
14 
15 #include "param.h"
16 #include "mbuf.h"
17 #include "systm.h"
18 #include "socket.h"
19 #include "socketvar.h"
20 #include "protosw.h"
21 #include "dir.h"
22 #include "user.h"
23 #include "kernel.h"
24 #include "ioctl.h"
25 #include "errno.h"
26 
27 #include "if.h"
28 #include "af.h"
29 
30 #include "ether.h"
31 
32 int	ifqmaxlen = IFQ_MAXLEN;
33 
34 /*
35  * Network interface utility routines.
36  *
37  * Routines with ifa_ifwith* names take sockaddr *'s as
38  * parameters.
39  */
40 
41 ifinit()
42 {
43 	register struct ifnet *ifp;
44 
45 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
46 		if (ifp->if_snd.ifq_maxlen == 0)
47 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
48 	if_slowtimo();
49 }
50 
51 #ifdef vax
52 /*
53  * Call each interface on a Unibus reset.
54  */
55 ifubareset(uban)
56 	int uban;
57 {
58 	register struct ifnet *ifp;
59 
60 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
61 		if (ifp->if_reset)
62 			(*ifp->if_reset)(ifp->if_unit, uban);
63 }
64 #endif
65 
66 /*
67  * Attach an interface to the
68  * list of "active" interfaces.
69  */
70 if_attach(ifp)
71 	struct ifnet *ifp;
72 {
73 	register struct ifnet **p = &ifnet;
74 
75 	while (*p)
76 		p = &((*p)->if_next);
77 	*p = ifp;
78 }
79 
80 /*
81  * Locate an interface based on a complete address.
82  */
83 /*ARGSUSED*/
84 struct ifaddr *
85 ifa_ifwithaddr(addr)
86 	struct sockaddr *addr;
87 {
88 	register struct ifnet *ifp;
89 	register struct ifaddr *ifa;
90 
91 #define	equal(a1, a2) \
92 	(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
93 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
94 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
95 		if (ifa->ifa_addr.sa_family != addr->sa_family)
96 			continue;
97 		if (equal(&ifa->ifa_addr, addr))
98 			return (ifa);
99 		if ((ifp->if_flags & IFF_BROADCAST) &&
100 		    equal(&ifa->ifa_broadaddr, addr))
101 			return (ifa);
102 	}
103 	return ((struct ifaddr *)0);
104 }
105 /*
106  * Locate the point to point interface with a given destination address.
107  */
108 /*ARGSUSED*/
109 struct ifaddr *
110 ifa_ifwithdstaddr(addr)
111 	struct sockaddr *addr;
112 {
113 	register struct ifnet *ifp;
114 	register struct ifaddr *ifa;
115 
116 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
117 	    if (ifp->if_flags & IFF_POINTOPOINT)
118 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
119 			if (ifa->ifa_addr.sa_family != addr->sa_family)
120 				continue;
121 			if (equal(&ifa->ifa_dstaddr, addr))
122 				return (ifa);
123 	}
124 	return ((struct ifaddr *)0);
125 }
126 
127 /*
128  * Find an interface on a specific network.  If many, choice
129  * is first found.
130  */
131 struct ifaddr *
132 ifa_ifwithnet(addr)
133 	register struct sockaddr *addr;
134 {
135 	register struct ifnet *ifp;
136 	register struct ifaddr *ifa;
137 	register u_int af = addr->sa_family;
138 	register int (*netmatch)();
139 
140 	if (af >= AF_MAX)
141 		return (0);
142 	netmatch = afswitch[af].af_netmatch;
143 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
144 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
145 		if (ifa->ifa_addr.sa_family != addr->sa_family)
146 			continue;
147 		if ((*netmatch)(&ifa->ifa_addr, addr))
148 			return (ifa);
149 	}
150 	return ((struct ifaddr *)0);
151 }
152 
153 #ifdef notdef
154 /*
155  * Find an interface using a specific address family
156  */
157 struct ifaddr *
158 ifa_ifwithaf(af)
159 	register int af;
160 {
161 	register struct ifnet *ifp;
162 	register struct ifaddr *ifa;
163 
164 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
165 	    for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
166 		if (ifa->ifa_addr.sa_family == af)
167 			return (ifa);
168 	return ((struct ifaddr *)0);
169 }
170 #endif
171 
172 /*
173  * Mark an interface down and notify protocols of
174  * the transition.
175  * NOTE: must be called at splnet or eqivalent.
176  */
177 if_down(ifp)
178 	register struct ifnet *ifp;
179 {
180 	register struct ifaddr *ifa;
181 
182 	ifp->if_flags &= ~IFF_UP;
183 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
184 		pfctlinput(PRC_IFDOWN, &ifa->ifa_addr);
185 	if_qflush(&ifp->if_snd);
186 }
187 
188 /*
189  * Flush an interface queue.
190  */
191 if_qflush(ifq)
192 	register struct ifqueue *ifq;
193 {
194 	register struct mbuf *m, *n;
195 
196 	n = ifq->ifq_head;
197 	while (m = n) {
198 		n = m->m_act;
199 		m_freem(m);
200 	}
201 	ifq->ifq_head = 0;
202 	ifq->ifq_tail = 0;
203 	ifq->ifq_len = 0;
204 }
205 
206 /*
207  * Handle interface watchdog timer routines.  Called
208  * from softclock, we decrement timers (if set) and
209  * call the appropriate interface routine on expiration.
210  */
211 if_slowtimo()
212 {
213 	register struct ifnet *ifp;
214 
215 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
216 		if (ifp->if_timer == 0 || --ifp->if_timer)
217 			continue;
218 		if (ifp->if_watchdog)
219 			(*ifp->if_watchdog)(ifp->if_unit);
220 	}
221 	timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
222 }
223 
224 /*
225  * Map interface name to
226  * interface structure pointer.
227  */
228 struct ifnet *
229 ifunit(name)
230 	register char *name;
231 {
232 	register char *cp;
233 	register struct ifnet *ifp;
234 	int unit;
235 
236 	for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
237 		if (*cp >= '0' && *cp <= '9')
238 			break;
239 	if (*cp == '\0' || cp == name + IFNAMSIZ)
240 		return ((struct ifnet *)0);
241 	unit = *cp - '0';
242 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
243 		if (bcmp(ifp->if_name, name, (unsigned)(cp - name)))
244 			continue;
245 		if (unit == ifp->if_unit)
246 			break;
247 	}
248 	return (ifp);
249 }
250 
251 /*
252  * Interface ioctls.
253  */
254 ifioctl(so, cmd, data)
255 	struct socket *so;
256 	int cmd;
257 	caddr_t data;
258 {
259 	register struct ifnet *ifp;
260 	register struct ifreq *ifr;
261 
262 	switch (cmd) {
263 
264 	case SIOCGIFCONF:
265 		return (ifconf(cmd, data));
266 
267 #if defined(INET) && NETHER > 0
268 	case SIOCSARP:
269 	case SIOCDARP:
270 		if (!suser())
271 			return (u.u_error);
272 		/* FALL THROUGH */
273 	case SIOCGARP:
274 		return (arpioctl(cmd, data));
275 #endif
276 	}
277 	ifr = (struct ifreq *)data;
278 	ifp = ifunit(ifr->ifr_name);
279 	if (ifp == 0)
280 		return (ENXIO);
281 	switch (cmd) {
282 
283 	case SIOCGIFFLAGS:
284 		ifr->ifr_flags = ifp->if_flags;
285 		break;
286 
287 	case SIOCGIFMETRIC:
288 		ifr->ifr_metric = ifp->if_metric;
289 		break;
290 
291 	case SIOCSIFFLAGS:
292 		if (!suser())
293 			return (u.u_error);
294 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
295 			int s = splimp();
296 			if_down(ifp);
297 			splx(s);
298 		}
299 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
300 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
301 		if (ifp->if_ioctl)
302 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
303 		break;
304 
305 	case SIOCSIFMETRIC:
306 		if (!suser())
307 			return (u.u_error);
308 		ifp->if_metric = ifr->ifr_metric;
309 		break;
310 
311 	default:
312 		if (so->so_proto == 0)
313 			return (EOPNOTSUPP);
314 		return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
315 			cmd, data, ifp));
316 	}
317 	return (0);
318 }
319 
320 /*
321  * Return interface configuration
322  * of system.  List may be used
323  * in later ioctl's (above) to get
324  * other information.
325  */
326 /*ARGSUSED*/
327 ifconf(cmd, data)
328 	int cmd;
329 	caddr_t data;
330 {
331 	register struct ifconf *ifc = (struct ifconf *)data;
332 	register struct ifnet *ifp = ifnet;
333 	register struct ifaddr *ifa;
334 	register char *cp, *ep;
335 	struct ifreq ifr, *ifrp;
336 	int space = ifc->ifc_len, error = 0;
337 
338 	ifrp = ifc->ifc_req;
339 	ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
340 	for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
341 		bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
342 		for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
343 			;
344 		*cp++ = '0' + ifp->if_unit; *cp = '\0';
345 		if ((ifa = ifp->if_addrlist) == 0) {
346 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
347 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
348 			if (error)
349 				break;
350 			space -= sizeof (ifr), ifrp++;
351 		} else
352 		    for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
353 			ifr.ifr_addr = ifa->ifa_addr;
354 			error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
355 			if (error)
356 				break;
357 			space -= sizeof (ifr), ifrp++;
358 		}
359 	}
360 	ifc->ifc_len -= space;
361 	return (error);
362 }
363