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