1 | /* |
---|
2 | * Copyright (c) 1980, 1986, 1993 |
---|
3 | * The Regents of the University of California. All rights reserved. |
---|
4 | * |
---|
5 | * Redistribution and use in source and binary forms, with or without |
---|
6 | * modification, are permitted provided that the following conditions |
---|
7 | * are met: |
---|
8 | * 1. Redistributions of source code must retain the above copyright |
---|
9 | * notice, this list of conditions and the following disclaimer. |
---|
10 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer in the |
---|
12 | * documentation and/or other materials provided with the distribution. |
---|
13 | * 4. Neither the name of the University nor the names of its contributors |
---|
14 | * may be used to endorse or promote products derived from this software |
---|
15 | * without specific prior written permission. |
---|
16 | * |
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
27 | * SUCH DAMAGE. |
---|
28 | * |
---|
29 | * @(#)if.c 8.5 (Berkeley) 1/9/95 |
---|
30 | * $FreeBSD: src/sys/net/if.c,v 1.226 2005/04/15 01:51:26 cperciva Exp $ |
---|
31 | */ |
---|
32 | |
---|
33 | /* |
---|
34 | * $Id$ |
---|
35 | */ |
---|
36 | |
---|
37 | #include <sys/param.h> |
---|
38 | #include <sys/queue.h> |
---|
39 | #include <sys/mbuf.h> |
---|
40 | #include <sys/systm.h> |
---|
41 | #include <sys/proc.h> |
---|
42 | #include <sys/socket.h> |
---|
43 | #include <sys/socketvar.h> |
---|
44 | #include <sys/protosw.h> |
---|
45 | #include <sys/kernel.h> |
---|
46 | #include <sys/ioctl.h> |
---|
47 | #include <sys/errno.h> |
---|
48 | #include <sys/syslog.h> |
---|
49 | #include <sys/sysctl.h> |
---|
50 | |
---|
51 | #include <net/if.h> |
---|
52 | #include <net/if_dl.h> |
---|
53 | #include <net/if_types.h> |
---|
54 | #include <net/if_var.h> |
---|
55 | #include <net/radix.h> |
---|
56 | |
---|
57 | /* |
---|
58 | * System initialization |
---|
59 | */ |
---|
60 | |
---|
61 | static int ifconf(u_long, caddr_t); |
---|
62 | void ifinit(void *); |
---|
63 | static void if_qflush(struct ifqueue *); |
---|
64 | static void if_slowtimo(void *); |
---|
65 | static void link_rtrequest(int, struct rtentry *, struct sockaddr *); |
---|
66 | |
---|
67 | SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL) |
---|
68 | |
---|
69 | |
---|
70 | int ifqmaxlen = IFQ_MAXLEN; |
---|
71 | struct ifnet *ifnet; |
---|
72 | |
---|
73 | /* |
---|
74 | * Network interface utility routines. |
---|
75 | * |
---|
76 | * Routines with ifa_ifwith* names take sockaddr *'s as |
---|
77 | * parameters. |
---|
78 | * |
---|
79 | * This routine assumes that it will be called at splimp() or higher. |
---|
80 | */ |
---|
81 | /* ARGSUSED*/ |
---|
82 | void |
---|
83 | ifinit(void *dummy) |
---|
84 | { |
---|
85 | struct ifnet *ifp; |
---|
86 | |
---|
87 | for (ifp = ifnet; ifp; ifp = ifp->if_next) |
---|
88 | if (ifp->if_snd.ifq_maxlen == 0) |
---|
89 | ifp->if_snd.ifq_maxlen = ifqmaxlen; |
---|
90 | if_slowtimo(0); |
---|
91 | } |
---|
92 | |
---|
93 | int if_index = 0; |
---|
94 | struct ifaddr **ifnet_addrs; |
---|
95 | |
---|
96 | |
---|
97 | /* |
---|
98 | * Attach an interface to the |
---|
99 | * list of "active" interfaces. |
---|
100 | */ |
---|
101 | void |
---|
102 | if_attach(struct ifnet *ifp) |
---|
103 | { |
---|
104 | unsigned socksize, ifasize; |
---|
105 | int namelen, masklen; |
---|
106 | char workbuf[64]; |
---|
107 | struct ifnet **p = &ifnet; |
---|
108 | struct sockaddr_dl *sdl; |
---|
109 | struct ifaddr *ifa; |
---|
110 | static int if_indexlim = 8; |
---|
111 | |
---|
112 | |
---|
113 | while (*p) |
---|
114 | p = &((*p)->if_next); |
---|
115 | *p = ifp; |
---|
116 | ifp->if_index = ++if_index; |
---|
117 | microtime(&ifp->if_lastchange); |
---|
118 | if (ifnet_addrs == 0 || if_index >= if_indexlim) { |
---|
119 | unsigned n = (if_indexlim <<= 1) * sizeof(ifa); |
---|
120 | struct ifaddr **q = (struct ifaddr **) |
---|
121 | malloc(n, M_IFADDR, M_WAITOK); |
---|
122 | bzero((caddr_t)q, n); |
---|
123 | if (ifnet_addrs) { |
---|
124 | bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); |
---|
125 | free((caddr_t)ifnet_addrs, M_IFADDR); |
---|
126 | } |
---|
127 | ifnet_addrs = q; |
---|
128 | } |
---|
129 | /* |
---|
130 | * create a Link Level name for this device |
---|
131 | */ |
---|
132 | namelen = sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); |
---|
133 | #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) |
---|
134 | masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; |
---|
135 | socksize = masklen + ifp->if_addrlen; |
---|
136 | #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) |
---|
137 | socksize = ROUNDUP(socksize); |
---|
138 | if (socksize < sizeof(*sdl)) |
---|
139 | socksize = sizeof(*sdl); |
---|
140 | ifasize = sizeof(*ifa) + 2 * socksize; |
---|
141 | ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); |
---|
142 | if (ifa) { |
---|
143 | bzero((caddr_t)ifa, ifasize); |
---|
144 | sdl = (struct sockaddr_dl *)(ifa + 1); |
---|
145 | sdl->sdl_len = socksize; |
---|
146 | sdl->sdl_family = AF_LINK; |
---|
147 | bcopy(workbuf, sdl->sdl_data, namelen); |
---|
148 | sdl->sdl_nlen = namelen; |
---|
149 | sdl->sdl_index = ifp->if_index; |
---|
150 | sdl->sdl_type = ifp->if_type; |
---|
151 | ifnet_addrs[if_index - 1] = ifa; |
---|
152 | ifa->ifa_ifp = ifp; |
---|
153 | ifa->ifa_next = ifp->if_addrlist; |
---|
154 | ifa->ifa_rtrequest = link_rtrequest; |
---|
155 | ifp->if_addrlist = ifa; |
---|
156 | ifa->ifa_addr = (struct sockaddr *)sdl; |
---|
157 | |
---|
158 | sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); |
---|
159 | ifa->ifa_netmask = (struct sockaddr *)sdl; |
---|
160 | sdl->sdl_len = masklen; |
---|
161 | while (namelen != 0) |
---|
162 | sdl->sdl_data[--namelen] = 0xff; |
---|
163 | } |
---|
164 | } |
---|
165 | /* |
---|
166 | * Locate an interface based on a complete address. |
---|
167 | */ |
---|
168 | /*ARGSUSED*/ |
---|
169 | struct ifaddr * |
---|
170 | ifa_ifwithaddr(struct sockaddr *addr) |
---|
171 | { |
---|
172 | struct ifnet *ifp; |
---|
173 | struct ifaddr *ifa; |
---|
174 | |
---|
175 | #define equal(a1, a2) \ |
---|
176 | (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) |
---|
177 | for (ifp = ifnet; ifp; ifp = ifp->if_next) |
---|
178 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { |
---|
179 | if (ifa->ifa_addr->sa_family != addr->sa_family) |
---|
180 | continue; |
---|
181 | if (equal(addr, ifa->ifa_addr)) |
---|
182 | return (ifa); |
---|
183 | if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && |
---|
184 | equal(ifa->ifa_broadaddr, addr)) |
---|
185 | return (ifa); |
---|
186 | } |
---|
187 | return ((struct ifaddr *)0); |
---|
188 | } |
---|
189 | /* |
---|
190 | * Locate the point to point interface with a given destination address. |
---|
191 | */ |
---|
192 | /*ARGSUSED*/ |
---|
193 | struct ifaddr * |
---|
194 | ifa_ifwithdstaddr(struct sockaddr *addr) |
---|
195 | { |
---|
196 | struct ifnet *ifp; |
---|
197 | struct ifaddr *ifa; |
---|
198 | |
---|
199 | for (ifp = ifnet; ifp; ifp = ifp->if_next) |
---|
200 | if (ifp->if_flags & IFF_POINTOPOINT) |
---|
201 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { |
---|
202 | if (ifa->ifa_addr->sa_family != addr->sa_family) |
---|
203 | continue; |
---|
204 | if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) |
---|
205 | return (ifa); |
---|
206 | } |
---|
207 | return ((struct ifaddr *)0); |
---|
208 | } |
---|
209 | |
---|
210 | /* |
---|
211 | * Find an interface on a specific network. If many, choice |
---|
212 | * is most specific found. |
---|
213 | */ |
---|
214 | struct ifaddr * |
---|
215 | ifa_ifwithnet(struct sockaddr *addr) |
---|
216 | { |
---|
217 | struct ifnet *ifp; |
---|
218 | struct ifaddr *ifa; |
---|
219 | struct ifaddr *ifa_maybe = (struct ifaddr *) 0; |
---|
220 | u_int af = addr->sa_family; |
---|
221 | char *addr_data = addr->sa_data, *cplim; |
---|
222 | |
---|
223 | if (af == AF_LINK) { |
---|
224 | struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; |
---|
225 | if (sdl->sdl_index && sdl->sdl_index <= if_index) |
---|
226 | return (ifnet_addrs[sdl->sdl_index - 1]); |
---|
227 | } |
---|
228 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { |
---|
229 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { |
---|
230 | char *cp, *cp2, *cp3; |
---|
231 | |
---|
232 | if (ifa->ifa_addr->sa_family != af) |
---|
233 | next: continue; |
---|
234 | if (ifp->if_flags & IFF_POINTOPOINT) { |
---|
235 | if (ifa->ifa_dstaddr != 0 |
---|
236 | && equal(addr, ifa->ifa_dstaddr)) |
---|
237 | return (ifa); |
---|
238 | } else { |
---|
239 | /* |
---|
240 | * if we have a special address handler, |
---|
241 | * then use it instead of the generic one. |
---|
242 | */ |
---|
243 | if (ifa->ifa_claim_addr) { |
---|
244 | if ((*ifa->ifa_claim_addr)(ifa, addr)) { |
---|
245 | return (ifa); |
---|
246 | } else { |
---|
247 | continue; |
---|
248 | } |
---|
249 | } |
---|
250 | |
---|
251 | /* |
---|
252 | * Scan all the bits in the ifa's address. |
---|
253 | * If a bit dissagrees with what we are |
---|
254 | * looking for, mask it with the netmask |
---|
255 | * to see if it really matters. |
---|
256 | * (A byte at a time) |
---|
257 | */ |
---|
258 | if (ifa->ifa_netmask == 0) |
---|
259 | continue; |
---|
260 | cp = addr_data; |
---|
261 | cp2 = ifa->ifa_addr->sa_data; |
---|
262 | cp3 = ifa->ifa_netmask->sa_data; |
---|
263 | cplim = ifa->ifa_netmask->sa_len |
---|
264 | + (char *)ifa->ifa_netmask; |
---|
265 | while (cp3 < cplim) |
---|
266 | if ((*cp++ ^ *cp2++) & *cp3++) |
---|
267 | goto next; /* next address! */ |
---|
268 | /* |
---|
269 | * If the netmask of what we just found |
---|
270 | * is more specific than what we had before |
---|
271 | * (if we had one) then remember the new one |
---|
272 | * before continuing to search |
---|
273 | * for an even better one. |
---|
274 | */ |
---|
275 | if (ifa_maybe == 0 || |
---|
276 | rn_refines((caddr_t)ifa->ifa_netmask, |
---|
277 | (caddr_t)ifa_maybe->ifa_netmask)) |
---|
278 | ifa_maybe = ifa; |
---|
279 | } |
---|
280 | } |
---|
281 | } |
---|
282 | return (ifa_maybe); |
---|
283 | } |
---|
284 | |
---|
285 | /* |
---|
286 | * Find an interface address specific to an interface best matching |
---|
287 | * a given address. |
---|
288 | */ |
---|
289 | struct ifaddr * |
---|
290 | ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp) |
---|
291 | { |
---|
292 | struct ifaddr *ifa; |
---|
293 | char *cp, *cp2, *cp3; |
---|
294 | char *cplim; |
---|
295 | struct ifaddr *ifa_maybe = 0; |
---|
296 | u_int af = addr->sa_family; |
---|
297 | |
---|
298 | if (af >= AF_MAX) |
---|
299 | return (0); |
---|
300 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { |
---|
301 | if (ifa->ifa_addr->sa_family != af) |
---|
302 | continue; |
---|
303 | if (ifa_maybe == 0) |
---|
304 | ifa_maybe = ifa; |
---|
305 | if (ifa->ifa_netmask == 0) { |
---|
306 | if (equal(addr, ifa->ifa_addr) || |
---|
307 | (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) |
---|
308 | return (ifa); |
---|
309 | continue; |
---|
310 | } |
---|
311 | if (ifp->if_flags & IFF_POINTOPOINT) { |
---|
312 | if (equal(addr, ifa->ifa_dstaddr)) |
---|
313 | return (ifa); |
---|
314 | } else { |
---|
315 | cp = addr->sa_data; |
---|
316 | cp2 = ifa->ifa_addr->sa_data; |
---|
317 | cp3 = ifa->ifa_netmask->sa_data; |
---|
318 | cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; |
---|
319 | for (; cp3 < cplim; cp3++) |
---|
320 | if ((*cp++ ^ *cp2++) & *cp3) |
---|
321 | break; |
---|
322 | if (cp3 == cplim) |
---|
323 | return (ifa); |
---|
324 | } |
---|
325 | } |
---|
326 | return (ifa_maybe); |
---|
327 | } |
---|
328 | |
---|
329 | #include <net/route.h> |
---|
330 | |
---|
331 | /* |
---|
332 | * Default action when installing a route with a Link Level gateway. |
---|
333 | * Lookup an appropriate real ifa to point to. |
---|
334 | * This should be moved to /sys/net/link.c eventually. |
---|
335 | */ |
---|
336 | static void |
---|
337 | link_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa) |
---|
338 | { |
---|
339 | struct ifaddr *ifa; |
---|
340 | struct sockaddr *dst; |
---|
341 | struct ifnet *ifp; |
---|
342 | |
---|
343 | if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || |
---|
344 | ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) |
---|
345 | return; |
---|
346 | ifa = ifaof_ifpforaddr(dst, ifp); |
---|
347 | if (ifa) { |
---|
348 | IFAFREE(rt->rt_ifa); |
---|
349 | rt->rt_ifa = ifa; |
---|
350 | ifa->ifa_refcnt++; |
---|
351 | if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) |
---|
352 | ifa->ifa_rtrequest(cmd, rt, sa); |
---|
353 | } |
---|
354 | } |
---|
355 | |
---|
356 | /* |
---|
357 | * Mark an interface down and notify protocols of |
---|
358 | * the transition. |
---|
359 | * NOTE: must be called at splnet or eqivalent. |
---|
360 | */ |
---|
361 | void |
---|
362 | if_down(struct ifnet *ifp) |
---|
363 | { |
---|
364 | struct ifaddr *ifa; |
---|
365 | |
---|
366 | ifp->if_flags &= ~IFF_UP; |
---|
367 | microtime(&ifp->if_lastchange); |
---|
368 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) |
---|
369 | pfctlinput(PRC_IFDOWN, ifa->ifa_addr); |
---|
370 | if_qflush(&ifp->if_snd); |
---|
371 | rt_ifmsg(ifp); |
---|
372 | } |
---|
373 | |
---|
374 | /* |
---|
375 | * Mark an interface up and notify protocols of |
---|
376 | * the transition. |
---|
377 | * NOTE: must be called at splnet or eqivalent. |
---|
378 | */ |
---|
379 | void |
---|
380 | if_up(struct ifnet *ifp) |
---|
381 | { |
---|
382 | |
---|
383 | ifp->if_flags |= IFF_UP; |
---|
384 | microtime(&ifp->if_lastchange); |
---|
385 | #ifdef notyet |
---|
386 | struct ifaddr *ifa; |
---|
387 | /* this has no effect on IP, and will kill all iso connections XXX */ |
---|
388 | for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) |
---|
389 | pfctlinput(PRC_IFUP, ifa->ifa_addr); |
---|
390 | #endif |
---|
391 | rt_ifmsg(ifp); |
---|
392 | } |
---|
393 | |
---|
394 | /* |
---|
395 | * Flush an interface queue. |
---|
396 | */ |
---|
397 | static void |
---|
398 | if_qflush(struct ifqueue *ifq) |
---|
399 | { |
---|
400 | struct mbuf *m, *n; |
---|
401 | |
---|
402 | n = ifq->ifq_head; |
---|
403 | while ((m = n) != 0) { |
---|
404 | n = m->m_act; |
---|
405 | m_freem(m); |
---|
406 | } |
---|
407 | ifq->ifq_head = 0; |
---|
408 | ifq->ifq_tail = 0; |
---|
409 | ifq->ifq_len = 0; |
---|
410 | } |
---|
411 | |
---|
412 | /* |
---|
413 | * Handle interface watchdog timer routines. Called |
---|
414 | * from softclock, we decrement timers (if set) and |
---|
415 | * call the appropriate interface routine on expiration. |
---|
416 | */ |
---|
417 | static void |
---|
418 | if_slowtimo(void *arg) |
---|
419 | { |
---|
420 | struct ifnet *ifp; |
---|
421 | int s = splimp(); |
---|
422 | |
---|
423 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { |
---|
424 | if (ifp->if_timer == 0 || --ifp->if_timer) |
---|
425 | continue; |
---|
426 | if (ifp->if_watchdog) |
---|
427 | (*ifp->if_watchdog)(ifp); |
---|
428 | } |
---|
429 | splx(s); |
---|
430 | timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); |
---|
431 | } |
---|
432 | |
---|
433 | /* |
---|
434 | * Map interface name to |
---|
435 | * interface structure pointer. |
---|
436 | */ |
---|
437 | struct ifnet * |
---|
438 | ifunit(char *name) |
---|
439 | { |
---|
440 | char *cp; |
---|
441 | struct ifnet *ifp; |
---|
442 | int unit; |
---|
443 | unsigned len; |
---|
444 | char *ep, c; |
---|
445 | |
---|
446 | for (cp = name; cp < name + IFNAMSIZ && *cp; cp++) |
---|
447 | if (*cp >= '0' && *cp <= '9') |
---|
448 | break; |
---|
449 | if (*cp == '\0' || cp == name + IFNAMSIZ) |
---|
450 | return ((struct ifnet *)0); |
---|
451 | /* |
---|
452 | * Save first char of unit, and pointer to it, |
---|
453 | * so we can put a null there to avoid matching |
---|
454 | * initial substrings of interface names. |
---|
455 | */ |
---|
456 | len = cp - name + 1; |
---|
457 | c = *cp; |
---|
458 | ep = cp; |
---|
459 | for (unit = 0; *cp >= '0' && *cp <= '9'; ) |
---|
460 | unit = unit * 10 + *cp++ - '0'; |
---|
461 | if (*cp != '\0') |
---|
462 | return 0; /* no trailing garbage allowed */ |
---|
463 | *ep = 0; |
---|
464 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { |
---|
465 | if (bcmp(ifp->if_name, name, len)) |
---|
466 | continue; |
---|
467 | if (unit == ifp->if_unit) |
---|
468 | break; |
---|
469 | } |
---|
470 | *ep = c; |
---|
471 | return (ifp); |
---|
472 | } |
---|
473 | |
---|
474 | /* |
---|
475 | * Interface ioctls. |
---|
476 | */ |
---|
477 | int |
---|
478 | ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) |
---|
479 | { |
---|
480 | struct ifnet *ifp; |
---|
481 | struct ifreq *ifr; |
---|
482 | int error; |
---|
483 | |
---|
484 | switch (cmd) { |
---|
485 | |
---|
486 | case SIOCGIFCONF: |
---|
487 | case OSIOCGIFCONF: |
---|
488 | return (ifconf(cmd, data)); |
---|
489 | } |
---|
490 | ifr = (struct ifreq *)data; |
---|
491 | ifp = ifunit(ifr->ifr_name); |
---|
492 | if (ifp == 0) |
---|
493 | return (ENXIO); |
---|
494 | switch (cmd) { |
---|
495 | |
---|
496 | case SIOCGIFFLAGS: |
---|
497 | ifr->ifr_flags = ifp->if_flags; |
---|
498 | break; |
---|
499 | |
---|
500 | case SIOCGIFMETRIC: |
---|
501 | ifr->ifr_metric = ifp->if_metric; |
---|
502 | break; |
---|
503 | |
---|
504 | case SIOCGIFMTU: |
---|
505 | ifr->ifr_mtu = ifp->if_mtu; |
---|
506 | break; |
---|
507 | |
---|
508 | case SIOCGIFPHYS: |
---|
509 | ifr->ifr_phys = ifp->if_physical; |
---|
510 | break; |
---|
511 | |
---|
512 | case SIOCSIFFLAGS: |
---|
513 | error = suser(p->p_ucred, &p->p_acflag); |
---|
514 | if (error) |
---|
515 | return (error); |
---|
516 | if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { |
---|
517 | int s = splimp(); |
---|
518 | if_down(ifp); |
---|
519 | splx(s); |
---|
520 | } |
---|
521 | if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { |
---|
522 | int s = splimp(); |
---|
523 | if_up(ifp); |
---|
524 | splx(s); |
---|
525 | } |
---|
526 | ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | |
---|
527 | (ifr->ifr_flags &~ IFF_CANTCHANGE); |
---|
528 | if (ifp->if_ioctl) |
---|
529 | (void) (*ifp->if_ioctl)(ifp, cmd, data); |
---|
530 | microtime(&ifp->if_lastchange); |
---|
531 | break; |
---|
532 | |
---|
533 | case SIOCSIFMETRIC: |
---|
534 | error = suser(p->p_ucred, &p->p_acflag); |
---|
535 | if (error) |
---|
536 | return (error); |
---|
537 | ifp->if_metric = ifr->ifr_metric; |
---|
538 | microtime(&ifp->if_lastchange); |
---|
539 | break; |
---|
540 | |
---|
541 | case SIOCSIFPHYS: |
---|
542 | error = suser(p->p_ucred, &p->p_acflag); |
---|
543 | if (error) |
---|
544 | return error; |
---|
545 | if (!ifp->if_ioctl) |
---|
546 | return EOPNOTSUPP; |
---|
547 | error = (*ifp->if_ioctl)(ifp, cmd, data); |
---|
548 | if (error == 0) |
---|
549 | microtime(&ifp->if_lastchange); |
---|
550 | return(error); |
---|
551 | |
---|
552 | case SIOCSIFMTU: |
---|
553 | error = suser(p->p_ucred, &p->p_acflag); |
---|
554 | if (error) |
---|
555 | return (error); |
---|
556 | if (ifp->if_ioctl == NULL) |
---|
557 | return (EOPNOTSUPP); |
---|
558 | /* |
---|
559 | * 72 was chosen below because it is the size of a TCP/IP |
---|
560 | * header (40) + the minimum mss (32). |
---|
561 | */ |
---|
562 | if (ifr->ifr_mtu < 72 || ifr->ifr_mtu > 65535) |
---|
563 | return (EINVAL); |
---|
564 | error = (*ifp->if_ioctl)(ifp, cmd, data); |
---|
565 | if (error == 0) |
---|
566 | microtime(&ifp->if_lastchange); |
---|
567 | return(error); |
---|
568 | |
---|
569 | case SIOCADDMULTI: |
---|
570 | case SIOCDELMULTI: |
---|
571 | error = suser(p->p_ucred, &p->p_acflag); |
---|
572 | if (error) |
---|
573 | return (error); |
---|
574 | if (ifp->if_ioctl == NULL) |
---|
575 | return (EOPNOTSUPP); |
---|
576 | error = (*ifp->if_ioctl)(ifp, cmd, data); |
---|
577 | if (error == 0 ) |
---|
578 | microtime(&ifp->if_lastchange); |
---|
579 | return(error); |
---|
580 | |
---|
581 | case SIOCSIFMEDIA: |
---|
582 | error = suser(p->p_ucred, &p->p_acflag); |
---|
583 | if (error) |
---|
584 | return (error); |
---|
585 | if (ifp->if_ioctl == NULL) |
---|
586 | return (EOPNOTSUPP); |
---|
587 | error = (*ifp->if_ioctl)(ifp, cmd, data); |
---|
588 | if (error == 0) |
---|
589 | microtime(&ifp->if_lastchange); |
---|
590 | return error; |
---|
591 | |
---|
592 | case SIOCGIFMEDIA: |
---|
593 | if (ifp->if_ioctl == NULL) |
---|
594 | return (EOPNOTSUPP); |
---|
595 | return ((*ifp->if_ioctl)(ifp, cmd, data)); |
---|
596 | |
---|
597 | default: |
---|
598 | if (so->so_proto == 0) |
---|
599 | return (EOPNOTSUPP); |
---|
600 | #ifndef COMPAT_43 |
---|
601 | return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, |
---|
602 | data, |
---|
603 | ifp)); |
---|
604 | #else |
---|
605 | { |
---|
606 | int ocmd = cmd; |
---|
607 | |
---|
608 | switch (cmd) { |
---|
609 | |
---|
610 | case SIOCSIFDSTADDR: |
---|
611 | case SIOCSIFADDR: |
---|
612 | case SIOCSIFBRDADDR: |
---|
613 | case SIOCSIFNETMASK: |
---|
614 | #if BYTE_ORDER != BIG_ENDIAN |
---|
615 | if (ifr->ifr_addr.sa_family == 0 && |
---|
616 | ifr->ifr_addr.sa_len < 16) { |
---|
617 | ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; |
---|
618 | ifr->ifr_addr.sa_len = 16; |
---|
619 | } |
---|
620 | #else |
---|
621 | if (ifr->ifr_addr.sa_len == 0) |
---|
622 | ifr->ifr_addr.sa_len = 16; |
---|
623 | #endif |
---|
624 | break; |
---|
625 | |
---|
626 | case OSIOCGIFADDR: |
---|
627 | cmd = SIOCGIFADDR; |
---|
628 | break; |
---|
629 | |
---|
630 | case OSIOCGIFDSTADDR: |
---|
631 | cmd = SIOCGIFDSTADDR; |
---|
632 | break; |
---|
633 | |
---|
634 | case OSIOCGIFBRDADDR: |
---|
635 | cmd = SIOCGIFBRDADDR; |
---|
636 | break; |
---|
637 | |
---|
638 | case OSIOCGIFNETMASK: |
---|
639 | cmd = SIOCGIFNETMASK; |
---|
640 | } |
---|
641 | error = ((*so->so_proto->pr_usrreqs->pru_control)(so, |
---|
642 | cmd, |
---|
643 | data, |
---|
644 | ifp)); |
---|
645 | switch (ocmd) { |
---|
646 | |
---|
647 | case OSIOCGIFADDR: |
---|
648 | case OSIOCGIFDSTADDR: |
---|
649 | case OSIOCGIFBRDADDR: |
---|
650 | case OSIOCGIFNETMASK: |
---|
651 | *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; |
---|
652 | } |
---|
653 | return (error); |
---|
654 | |
---|
655 | } |
---|
656 | #endif |
---|
657 | |
---|
658 | /* |
---|
659 | * RTEMS additions for setting/getting `tap' function |
---|
660 | */ |
---|
661 | case SIOCSIFTAP: |
---|
662 | ifp->if_tap = ifr->ifr_tap; |
---|
663 | return 0; |
---|
664 | |
---|
665 | case SIOCGIFTAP: |
---|
666 | ifr->ifr_tap = ifp->if_tap; |
---|
667 | return 0; |
---|
668 | } |
---|
669 | return (0); |
---|
670 | } |
---|
671 | |
---|
672 | /* |
---|
673 | * Set/clear promiscuous mode on interface ifp based on the truth value |
---|
674 | * of pswitch. The calls are reference counted so that only the first |
---|
675 | * "on" request actually has an effect, as does the final "off" request. |
---|
676 | * Results are undefined if the "off" and "on" requests are not matched. |
---|
677 | */ |
---|
678 | int |
---|
679 | ifpromisc(struct ifnet *ifp, int pswitch) |
---|
680 | { |
---|
681 | struct ifreq ifr; |
---|
682 | |
---|
683 | if (pswitch) { |
---|
684 | /* |
---|
685 | * If the device is not configured up, we cannot put it in |
---|
686 | * promiscuous mode. |
---|
687 | */ |
---|
688 | if ((ifp->if_flags & IFF_UP) == 0) |
---|
689 | return (ENETDOWN); |
---|
690 | if (ifp->if_pcount++ != 0) |
---|
691 | return (0); |
---|
692 | ifp->if_flags |= IFF_PROMISC; |
---|
693 | log(LOG_INFO, "%s%d: promiscuous mode enabled\n", |
---|
694 | ifp->if_name, ifp->if_unit); |
---|
695 | } else { |
---|
696 | if (--ifp->if_pcount > 0) |
---|
697 | return (0); |
---|
698 | ifp->if_flags &= ~IFF_PROMISC; |
---|
699 | } |
---|
700 | ifr.ifr_flags = ifp->if_flags; |
---|
701 | return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); |
---|
702 | } |
---|
703 | |
---|
704 | /* |
---|
705 | * Return interface configuration |
---|
706 | * of system. List may be used |
---|
707 | * in later ioctl's (above) to get |
---|
708 | * other information. |
---|
709 | */ |
---|
710 | /*ARGSUSED*/ |
---|
711 | static int |
---|
712 | ifconf(u_long cmd, caddr_t data) |
---|
713 | { |
---|
714 | struct ifconf *ifc = (struct ifconf *)data; |
---|
715 | struct ifnet *ifp = ifnet; |
---|
716 | struct ifaddr *ifa; |
---|
717 | struct ifreq ifr, *ifrp; |
---|
718 | int space = ifc->ifc_len, error = 0; |
---|
719 | |
---|
720 | ifrp = ifc->ifc_req; |
---|
721 | for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { |
---|
722 | char workbuf[64]; |
---|
723 | int ifnlen; |
---|
724 | |
---|
725 | ifnlen = sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); |
---|
726 | if(ifnlen + 1 > sizeof ifr.ifr_name) { |
---|
727 | error = ENAMETOOLONG; |
---|
728 | } else { |
---|
729 | strcpy(ifr.ifr_name, workbuf); |
---|
730 | } |
---|
731 | |
---|
732 | if ((ifa = ifp->if_addrlist) == 0) { |
---|
733 | bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); |
---|
734 | error = copyout((caddr_t)&ifr, (caddr_t)ifrp, |
---|
735 | sizeof (ifr)); |
---|
736 | if (error) |
---|
737 | break; |
---|
738 | space -= sizeof (ifr), ifrp++; |
---|
739 | } else |
---|
740 | for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) { |
---|
741 | struct sockaddr *sa = ifa->ifa_addr; |
---|
742 | #ifdef COMPAT_43 |
---|
743 | if (cmd == OSIOCGIFCONF) { |
---|
744 | struct osockaddr *osa = |
---|
745 | (struct osockaddr *)&ifr.ifr_addr; |
---|
746 | ifr.ifr_addr = *sa; |
---|
747 | osa->sa_family = sa->sa_family; |
---|
748 | error = copyout((caddr_t)&ifr, (caddr_t)ifrp, |
---|
749 | sizeof (ifr)); |
---|
750 | ifrp++; |
---|
751 | } else |
---|
752 | #endif |
---|
753 | if (sa->sa_len <= sizeof(*sa)) { |
---|
754 | ifr.ifr_addr = *sa; |
---|
755 | error = copyout((caddr_t)&ifr, (caddr_t)ifrp, |
---|
756 | sizeof (ifr)); |
---|
757 | ifrp++; |
---|
758 | } else { |
---|
759 | space -= sa->sa_len - sizeof(*sa); |
---|
760 | if (space < sizeof (ifr)) |
---|
761 | break; |
---|
762 | error = copyout((caddr_t)&ifr, (caddr_t)ifrp, |
---|
763 | sizeof (ifr.ifr_name)); |
---|
764 | if (error == 0) |
---|
765 | error = copyout((caddr_t)sa, |
---|
766 | (caddr_t)&ifrp->ifr_addr, sa->sa_len); |
---|
767 | ifrp = (struct ifreq *) |
---|
768 | (sa->sa_len + (caddr_t)&ifrp->ifr_addr); |
---|
769 | } |
---|
770 | if (error) |
---|
771 | break; |
---|
772 | space -= sizeof (ifr); |
---|
773 | } |
---|
774 | } |
---|
775 | ifc->ifc_len -= space; |
---|
776 | return (error); |
---|
777 | } |
---|
778 | |
---|
779 | SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); |
---|
780 | SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); |
---|