MCLALLOC must be called at splimp
[unix-history] / usr / src / sys / net / if.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1980, 1986 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 7.1 (Berkeley) %G%
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
25int 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
34ifinit()
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 */
48ifubareset(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 */
63if_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*/
77struct ifaddr *
78ifa_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*/
102struct ifaddr *
103ifa_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 */
124struct ifaddr *
125ifa_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 */
150struct ifaddr *
151ifa_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 */
170if_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 */
185if_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 */
202struct ifnet *
203ifunit(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 */
228ifioctl(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*/
301ifconf(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}