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