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