Fix from Mostyn Lewis for this:
[unix-history] / sys / net / if.c
CommitLineData
15637ed4
RG
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, 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 *
70c5ff60 33 * from: @(#)if.c 7.14 (Berkeley) 4/20/91
54f02f52 34 * $Id: if.c,v 1.8 1994/05/02 19:10:20 wollman Exp $
15637ed4
RG
35 */
36
37#include "param.h"
38#include "mbuf.h"
39#include "systm.h"
40#include "socket.h"
41#include "socketvar.h"
42#include "protosw.h"
43#include "proc.h"
44#include "kernel.h"
45#include "ioctl.h"
46
47#include "if.h"
15637ed4
RG
48#include "if_dl.h"
49#include "if_types.h"
50
51#include "ether.h"
52
53int ifqmaxlen = IFQ_MAXLEN;
8ace4366
GW
54struct ifqueue rawintrq; /* raw packet input queue */
55struct ifnet *ifnet; /* list of configured interfaces */
15637ed4 56
4c45483e
GW
57static void link_rtrequest(int, struct rtentry *, struct sockaddr *);
58static void if_qflush(struct ifqueue *);
59static void if_slowtimo(caddr_t, int);
60
15637ed4
RG
61/*
62 * Network interface utility routines.
63 *
64 * Routines with ifa_ifwith* names take sockaddr *'s as
65 * parameters.
66 */
67
4c45483e 68void
15637ed4
RG
69ifinit()
70{
71 register struct ifnet *ifp;
72
73 for (ifp = ifnet; ifp; ifp = ifp->if_next)
74 if (ifp->if_snd.ifq_maxlen == 0)
75 ifp->if_snd.ifq_maxlen = ifqmaxlen;
4c45483e 76 if_slowtimo((caddr_t)0, 0);
15637ed4
RG
77}
78
79#ifdef vax
80/*
81 * Call each interface on a Unibus reset.
82 */
83ifubareset(uban)
84 int uban;
85{
86 register struct ifnet *ifp;
87
88 for (ifp = ifnet; ifp; ifp = ifp->if_next)
89 if (ifp->if_reset)
90 (*ifp->if_reset)(ifp->if_unit, uban);
91}
92#endif
93
94int if_index = 0;
95struct ifaddr **ifnet_addrs;
96static char *sprint_d();
97
98/*
99 * Attach an interface to the
100 * list of "active" interfaces.
101 */
4c45483e 102void
15637ed4
RG
103if_attach(ifp)
104 struct ifnet *ifp;
105{
106 unsigned socksize, ifasize;
107 int namelen, unitlen;
108 char workbuf[12], *unitname;
109 register struct ifnet **p = &ifnet;
110 register struct sockaddr_dl *sdl;
111 register struct ifaddr *ifa;
112 static int if_indexlim = 8;
15637ed4
RG
113
114 while (*p)
115 p = &((*p)->if_next);
116 *p = ifp;
117 ifp->if_index = ++if_index;
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 if (ifnet_addrs) {
123 bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
124 free((caddr_t)ifnet_addrs, M_IFADDR);
125 }
126 ifnet_addrs = q;
127 }
4c45483e 128
15637ed4
RG
129 /*
130 * create a Link Level name for this device
131 */
132 unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
133 namelen = strlen(ifp->if_name);
134 unitlen = strlen(unitname);
135#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
136 socksize = _offsetof(struct sockaddr_dl, sdl_data[0]) +
137 unitlen + namelen + ifp->if_addrlen;
138#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
139 socksize = ROUNDUP(socksize);
140 if (socksize < sizeof(*sdl))
141 socksize = sizeof(*sdl);
142 ifasize = sizeof(*ifa) + 2 * socksize;
143 ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
144 if (ifa == 0)
145 return;
146 ifnet_addrs[if_index - 1] = ifa;
147 bzero((caddr_t)ifa, ifasize);
148 sdl = (struct sockaddr_dl *)(ifa + 1);
149 ifa->ifa_addr = (struct sockaddr *)sdl;
150 ifa->ifa_ifp = ifp;
151 sdl->sdl_len = socksize;
152 sdl->sdl_family = AF_LINK;
153 bcopy(ifp->if_name, sdl->sdl_data, namelen);
154 bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
155 sdl->sdl_nlen = (namelen += unitlen);
156 sdl->sdl_index = ifp->if_index;
157 sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
158 ifa->ifa_netmask = (struct sockaddr *)sdl;
159 sdl->sdl_len = socksize - ifp->if_addrlen;
160 while (namelen != 0)
161 sdl->sdl_data[--namelen] = 0xff;
162 ifa->ifa_next = ifp->if_addrlist;
163 ifa->ifa_rtrequest = link_rtrequest;
164 ifp->if_addrlist = ifa;
165}
166/*
167 * Locate an interface based on a complete address.
168 */
169/*ARGSUSED*/
170struct ifaddr *
171ifa_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*/
195struct ifaddr *
196ifa_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;
54f02f52 207 if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
15637ed4
RG
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 first found.
216 */
217struct ifaddr *
218ifa_ifwithnet(addr)
219 struct sockaddr *addr;
220{
221 register struct ifnet *ifp;
222 register struct ifaddr *ifa;
223 u_int af = addr->sa_family;
224
225 if (af >= AF_MAX)
226 return (0);
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 register char *cplim;
236 if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
237 continue;
238 cp = addr->sa_data;
239 cp2 = ifa->ifa_addr->sa_data;
240 cp3 = ifa->ifa_netmask->sa_data;
241 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
242 for (; cp3 < cplim; cp3++)
243 if ((*cp++ ^ *cp2++) & *cp3)
244 break;
245 if (cp3 == cplim)
246 return (ifa);
247 }
248 return ((struct ifaddr *)0);
249}
250
251/*
252 * Find an interface using a specific address family
253 */
254struct ifaddr *
255ifa_ifwithaf(af)
256 register int af;
257{
258 register struct ifnet *ifp;
259 register struct ifaddr *ifa;
260
261 for (ifp = ifnet; ifp; ifp = ifp->if_next)
262 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
263 if (ifa->ifa_addr->sa_family == af)
264 return (ifa);
265 return ((struct ifaddr *)0);
266}
267
268/*
269 * Find an interface address specific to an interface best matching
270 * a given address.
271 */
272struct ifaddr *
273ifaof_ifpforaddr(addr, ifp)
274 struct sockaddr *addr;
275 register struct ifnet *ifp;
276{
277 register struct ifaddr *ifa;
278 register char *cp, *cp2, *cp3;
279 register char *cplim;
280 struct ifaddr *ifa_maybe = 0;
281 u_int af = addr->sa_family;
282
283 if (af >= AF_MAX)
284 return (0);
285 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
286 if (ifa->ifa_addr->sa_family != af)
287 continue;
288 ifa_maybe = ifa;
289 if (ifa->ifa_netmask == 0) {
290 if (equal(addr, ifa->ifa_addr) ||
291 (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
292 return (ifa);
293 continue;
294 }
295 cp = addr->sa_data;
296 cp2 = ifa->ifa_addr->sa_data;
297 cp3 = ifa->ifa_netmask->sa_data;
298 cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
299 for (; cp3 < cplim; cp3++)
300 if ((*cp++ ^ *cp2++) & *cp3)
301 break;
302 if (cp3 == cplim)
303 return (ifa);
304 }
305 return (ifa_maybe);
306}
307#include "route.h"
308/*
309 * Default action when installing a route with a Link Level gateway.
310 * Lookup an appropriate real ifa to point to.
311 * This should be moved to /sys/net/link.c eventually.
312 */
4c45483e 313void
15637ed4 314link_rtrequest(cmd, rt, sa)
4c45483e
GW
315 int cmd;
316 register struct rtentry *rt;
317 struct sockaddr *sa;
15637ed4
RG
318{
319 register struct ifaddr *ifa;
320 struct sockaddr *dst;
321 struct ifnet *ifp, *oldifnet = ifnet;
322
323 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
324 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
325 return;
326 if (ifa = ifaof_ifpforaddr(dst, ifp)) {
327 rt->rt_ifa = ifa;
328 if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
329 ifa->ifa_rtrequest(cmd, rt, sa);
330 }
331}
332
333/*
334 * Mark an interface down and notify protocols of
335 * the transition.
336 * NOTE: must be called at splnet or eqivalent.
337 */
4c45483e 338void
15637ed4
RG
339if_down(ifp)
340 register struct ifnet *ifp;
341{
342 register struct ifaddr *ifa;
343
344 ifp->if_flags &= ~IFF_UP;
345 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
346 pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
347 if_qflush(&ifp->if_snd);
348}
349
350/*
351 * Flush an interface queue.
352 */
4c45483e 353static void
15637ed4
RG
354if_qflush(ifq)
355 register struct ifqueue *ifq;
356{
357 register struct mbuf *m, *n;
358
359 n = ifq->ifq_head;
360 while (m = n) {
361 n = m->m_act;
362 m_freem(m);
363 }
364 ifq->ifq_head = 0;
365 ifq->ifq_tail = 0;
366 ifq->ifq_len = 0;
367}
368
369/*
370 * Handle interface watchdog timer routines. Called
371 * from softclock, we decrement timers (if set) and
372 * call the appropriate interface routine on expiration.
373 */
4c45483e
GW
374static void
375if_slowtimo(caddr_t dummy1, int dummy2)
15637ed4
RG
376{
377 register struct ifnet *ifp;
378 int s = splimp();
379
380 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
381 if (ifp->if_timer == 0 || --ifp->if_timer)
382 continue;
383 if (ifp->if_watchdog)
384 (*ifp->if_watchdog)(ifp->if_unit);
385 }
386 splx(s);
387 timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
388}
389
390/*
391 * Map interface name to
392 * interface structure pointer.
393 */
394struct ifnet *
395ifunit(name)
396 register char *name;
397{
398 register char *cp;
399 register struct ifnet *ifp;
400 int unit;
401 unsigned len;
402 char *ep, c;
403
404 for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
405 if (*cp >= '0' && *cp <= '9')
406 break;
407 if (*cp == '\0' || cp == name + IFNAMSIZ)
408 return ((struct ifnet *)0);
409 /*
410 * Save first char of unit, and pointer to it,
411 * so we can put a null there to avoid matching
412 * initial substrings of interface names.
413 */
414 len = cp - name + 1;
415 c = *cp;
416 ep = cp;
417 for (unit = 0; *cp >= '0' && *cp <= '9'; )
418 unit = unit * 10 + *cp++ - '0';
419 *ep = 0;
420 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
421 if (bcmp(ifp->if_name, name, len))
422 continue;
423 if (unit == ifp->if_unit)
424 break;
425 }
426 *ep = c;
427 return (ifp);
428}
429
430/*
431 * Interface ioctls.
432 */
4c45483e 433int
15637ed4
RG
434ifioctl(so, cmd, data, p)
435 struct socket *so;
436 int cmd;
437 caddr_t data;
438 struct proc *p;
439{
440 register struct ifnet *ifp;
441 register struct ifreq *ifr;
442 int error;
443
444 switch (cmd) {
445
446 case SIOCGIFCONF:
447 case OSIOCGIFCONF:
448 return (ifconf(cmd, data));
449
450#if defined(INET) && NETHER > 0
451 case SIOCSARP:
452 case SIOCDARP:
453 if (error = suser(p->p_ucred, &p->p_acflag))
454 return (error);
455 /* FALL THROUGH */
456 case SIOCGARP:
457 case OSIOCGARP:
458 return (arpioctl(cmd, data));
459#endif
460 }
461 ifr = (struct ifreq *)data;
462 ifp = ifunit(ifr->ifr_name);
463 if (ifp == 0)
464 return (ENXIO);
465 switch (cmd) {
466
467 case SIOCGIFFLAGS:
468 ifr->ifr_flags = ifp->if_flags;
469 break;
470
471 case SIOCGIFMETRIC:
472 ifr->ifr_metric = ifp->if_metric;
473 break;
474
475 case SIOCSIFFLAGS:
476 if (error = suser(p->p_ucred, &p->p_acflag))
477 return (error);
478 if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
479 int s = splimp();
480 if_down(ifp);
481 splx(s);
482 }
483 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
484 (ifr->ifr_flags &~ IFF_CANTCHANGE);
485 if (ifp->if_ioctl)
486 (void) (*ifp->if_ioctl)(ifp, cmd, data);
487 break;
488
489 case SIOCSIFMETRIC:
490 if (error = suser(p->p_ucred, &p->p_acflag))
491 return (error);
492 ifp->if_metric = ifr->ifr_metric;
493 break;
494
8b3438a6
RG
495 case SIOCSIFMTU:
496 case SIOCGIFMTU:
497 case SIOCSIFASYNCMAP:
498 case SIOCGIFASYNCMAP:
499 if (!ifp->if_ioctl)
500 return (EOPNOTSUPP);
501 return ((*ifp->if_ioctl)(ifp, cmd, data));
502 break;
503
15637ed4
RG
504 default:
505 if (so->so_proto == 0)
506 return (EOPNOTSUPP);
507#ifndef COMPAT_43
508 return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
acfa932d
GW
509 (struct mbuf *)cmd, (struct mbuf *)data,
510 (struct mbuf *)ifp, (struct mbuf *)0));
15637ed4
RG
511#else
512 {
513 int ocmd = cmd;
514
515 switch (cmd) {
516
517 case SIOCSIFDSTADDR:
518 case SIOCSIFADDR:
519 case SIOCSIFBRDADDR:
520 case SIOCSIFNETMASK:
521#if BYTE_ORDER != BIG_ENDIAN
522 if (ifr->ifr_addr.sa_family == 0 &&
523 ifr->ifr_addr.sa_len < 16) {
524 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
525 ifr->ifr_addr.sa_len = 16;
526 }
527#else
528 if (ifr->ifr_addr.sa_len == 0)
529 ifr->ifr_addr.sa_len = 16;
530#endif
531 break;
532
533 case OSIOCGIFADDR:
534 cmd = SIOCGIFADDR;
535 break;
536
537 case OSIOCGIFDSTADDR:
538 cmd = SIOCGIFDSTADDR;
539 break;
540
541 case OSIOCGIFBRDADDR:
542 cmd = SIOCGIFBRDADDR;
543 break;
544
545 case OSIOCGIFNETMASK:
546 cmd = SIOCGIFNETMASK;
547 }
548 error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
fde1aeb2
GW
549 (struct mbuf *)cmd,
550 (struct mbuf *)data,
551 (struct mbuf *)ifp,
552 (struct mbuf *)0));
15637ed4
RG
553 switch (ocmd) {
554
555 case OSIOCGIFADDR:
556 case OSIOCGIFDSTADDR:
557 case OSIOCGIFBRDADDR:
558 case OSIOCGIFNETMASK:
559 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
560 }
561 return (error);
562
563 }
564#endif
565 }
566 return (0);
567}
568
569/*
570 * Return interface configuration
571 * of system. List may be used
572 * in later ioctl's (above) to get
573 * other information.
574 */
575/*ARGSUSED*/
4c45483e 576int
15637ed4
RG
577ifconf(cmd, data)
578 int cmd;
579 caddr_t data;
580{
581 register struct ifconf *ifc = (struct ifconf *)data;
582 register struct ifnet *ifp = ifnet;
583 register struct ifaddr *ifa;
584 register char *cp, *ep;
585 struct ifreq ifr, *ifrp;
586 int space = ifc->ifc_len, error = 0;
587
588 ifrp = ifc->ifc_req;
589 ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
590 for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
591 bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
592 for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
593 ;
594 *cp++ = '0' + ifp->if_unit; *cp = '\0';
595 if ((ifa = ifp->if_addrlist) == 0) {
596 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
597 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
598 if (error)
599 break;
600 space -= sizeof (ifr), ifrp++;
601 } else
602 for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
603 register struct sockaddr *sa = ifa->ifa_addr;
604#ifdef COMPAT_43
605 if (cmd == OSIOCGIFCONF) {
606 struct osockaddr *osa =
607 (struct osockaddr *)&ifr.ifr_addr;
608 ifr.ifr_addr = *sa;
609 osa->sa_family = sa->sa_family;
610 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
611 sizeof (ifr));
612 ifrp++;
613 } else
614#endif
615 if (sa->sa_len <= sizeof(*sa)) {
616 ifr.ifr_addr = *sa;
617 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
618 sizeof (ifr));
619 ifrp++;
620 } else {
621 space -= sa->sa_len - sizeof(*sa);
622 if (space < sizeof (ifr))
623 break;
624 error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
625 sizeof (ifr.ifr_name));
626 if (error == 0)
627 error = copyout((caddr_t)sa,
628 (caddr_t)&ifrp->ifr_addr, sa->sa_len);
629 ifrp = (struct ifreq *)
630 (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
631 }
632 if (error)
633 break;
634 space -= sizeof (ifr);
635 }
636 }
637 ifc->ifc_len -= space;
638 return (error);
639}
640
641static char *
642sprint_d(n, buf, buflen)
643 u_int n;
644 char *buf;
645 int buflen;
646{
647 register char *cp = buf + buflen - 1;
648
649 *cp = 0;
650 do {
651 cp--;
652 *cp = "0123456789"[n % 10];
653 n /= 10;
654 } while (n != 0);
655 return (cp);
656}
fde1aeb2
GW
657
658/*
659 * Set/clear promiscuous mode on interface ifp based on the truth value
660 * of pswitch. The calls are reference counted so that only the first
661 * "on" request actually has an effect, as does the final "off" request.
662 * Results are undefined if the "off" and "on" requests are not matched.
663 */
664int
665ifpromisc(ifp, pswitch)
666 struct ifnet *ifp;
667 int pswitch;
668{
669 struct ifreq ifr;
670 /*
671 * If the device is not configured up, we cannot put it in
672 * promiscuous mode.
673 */
674 if ((ifp->if_flags & IFF_UP) == 0)
675 return (ENETDOWN);
676
677 if (pswitch) {
678 if (ifp->if_pcount++ != 0)
679 return (0);
680 ifp->if_flags |= IFF_PROMISC;
681 } else {
682 if (--ifp->if_pcount > 0)
683 return (0);
684 ifp->if_flags &= ~IFF_PROMISC;
685 }
686 ifr.ifr_flags = ifp->if_flags;
687 return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
688}