in.c revision 1.32 1 /* $NetBSD: in.c,v 1.32 1996/09/09 14:51:09 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)in.c 8.2 (Berkeley) 11/15/93
36 */
37
38 #include <sys/param.h>
39 #include <sys/ioctl.h>
40 #include <sys/errno.h>
41 #include <sys/malloc.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/systm.h>
45 #include <sys/proc.h>
46 #include <sys/queue.h>
47
48 #include <net/if.h>
49 #include <net/route.h>
50
51 #include <netinet/in_systm.h>
52 #include <netinet/in.h>
53 #include <netinet/ip.h>
54 #include <netinet/in_var.h>
55 #include <netinet/if_ether.h>
56 #include <netinet/ip_mroute.h>
57 #include <netinet/igmp_var.h>
58
59 #include "ether.h"
60
61 #ifdef INET
62
63 #ifndef SUBNETSARELOCAL
64 #define SUBNETSARELOCAL 1
65 #endif
66 int subnetsarelocal = SUBNETSARELOCAL;
67
68 #ifdef PACKET_FILTER
69 typedef LIST_HEAD(, packet_filter_hook) pfil_list_t;
70 pfil_list_t pfil_in_list;
71 pfil_list_t pfil_out_list;
72 pfil_list_t pfil_bad_list;
73 static int done_pfil_init;
74 #endif /* PACKET_FILTER */
75
76 /*
77 * Return 1 if an internet address is for a ``local'' host
78 * (one to which we have a connection). If subnetsarelocal
79 * is true, this includes other subnets of the local net.
80 * Otherwise, it includes only the directly-connected (sub)nets.
81 */
82 int
83 in_localaddr(in)
84 struct in_addr in;
85 {
86 register struct in_ifaddr *ia;
87
88 if (subnetsarelocal) {
89 for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
90 if ((in.s_addr & ia->ia_netmask) == ia->ia_net)
91 return (1);
92 } else {
93 for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
94 if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet)
95 return (1);
96 }
97 return (0);
98 }
99
100 /*
101 * Determine whether an IP address is in a reserved set of addresses
102 * that may not be forwarded, or whether datagrams to that destination
103 * may be forwarded.
104 */
105 int
106 in_canforward(in)
107 struct in_addr in;
108 {
109 register u_int32_t net;
110
111 if (IN_EXPERIMENTAL(in.s_addr) || IN_MULTICAST(in.s_addr))
112 return (0);
113 if (IN_CLASSA(in.s_addr)) {
114 net = in.s_addr & IN_CLASSA_NET;
115 if (net == 0 || net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
116 return (0);
117 }
118 return (1);
119 }
120
121 /*
122 * Trim a mask in a sockaddr
123 */
124 void
125 in_socktrim(ap)
126 struct sockaddr_in *ap;
127 {
128 register char *cplim = (char *) &ap->sin_addr;
129 register char *cp = (char *) (&ap->sin_addr + 1);
130
131 ap->sin_len = 0;
132 while (--cp >= cplim)
133 if (*cp) {
134 (ap)->sin_len = cp - (char *) (ap) + 1;
135 break;
136 }
137 }
138
139 int in_interfaces; /* number of external internet interfaces */
140
141 /*
142 * Generic internet control operations (ioctl's).
143 * Ifp is 0 if not an interface-specific ioctl.
144 */
145 /* ARGSUSED */
146 int
147 in_control(so, cmd, data, ifp, p)
148 struct socket *so;
149 u_long cmd;
150 caddr_t data;
151 register struct ifnet *ifp;
152 struct proc *p;
153 {
154 register struct ifreq *ifr = (struct ifreq *)data;
155 register struct in_ifaddr *ia = 0;
156 struct in_aliasreq *ifra = (struct in_aliasreq *)data;
157 struct sockaddr_in oldaddr;
158 int error, hostIsNew, maskIsNew;
159
160 /*
161 * Find address for this interface, if it exists.
162 */
163 if (ifp)
164 for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
165 if (ia->ia_ifp == ifp)
166 break;
167
168 switch (cmd) {
169
170 case SIOCAIFADDR:
171 case SIOCDIFADDR:
172 if (ifra->ifra_addr.sin_family == AF_INET)
173 for (; ia != 0; ia = ia->ia_list.tqe_next) {
174 if (ia->ia_ifp == ifp &&
175 in_hosteq(ia->ia_addr.sin_addr, ifra->ifra_addr.sin_addr))
176 break;
177 }
178 if (cmd == SIOCDIFADDR && ia == 0)
179 return (EADDRNOTAVAIL);
180 /* FALLTHROUGH */
181 case SIOCSIFADDR:
182 case SIOCSIFNETMASK:
183 case SIOCSIFDSTADDR:
184 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))
185 return (EPERM);
186
187 if (ifp == 0)
188 panic("in_control");
189 if (ia == 0) {
190 MALLOC(ia, struct in_ifaddr *, sizeof(*ia),
191 M_IFADDR, M_WAITOK);
192 if (ia == 0)
193 return (ENOBUFS);
194 bzero((caddr_t)ia, sizeof *ia);
195 TAILQ_INSERT_TAIL(&in_ifaddr, ia, ia_list);
196 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
197 ifa_list);
198 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
199 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
200 ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
201 ia->ia_sockmask.sin_len = 8;
202 if (ifp->if_flags & IFF_BROADCAST) {
203 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
204 ia->ia_broadaddr.sin_family = AF_INET;
205 }
206 ia->ia_ifp = ifp;
207 LIST_INIT(&ia->ia_multiaddrs);
208 if ((ifp->if_flags & IFF_LOOPBACK) == 0)
209 in_interfaces++;
210 }
211 break;
212
213 case SIOCSIFBRDADDR:
214 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))
215 return (EPERM);
216 /* FALLTHROUGH */
217
218 case SIOCGIFADDR:
219 case SIOCGIFNETMASK:
220 case SIOCGIFDSTADDR:
221 case SIOCGIFBRDADDR:
222 if (ia == 0)
223 return (EADDRNOTAVAIL);
224 break;
225 }
226 switch (cmd) {
227
228 case SIOCGIFADDR:
229 *satosin(&ifr->ifr_addr) = ia->ia_addr;
230 break;
231
232 case SIOCGIFBRDADDR:
233 if ((ifp->if_flags & IFF_BROADCAST) == 0)
234 return (EINVAL);
235 *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
236 break;
237
238 case SIOCGIFDSTADDR:
239 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
240 return (EINVAL);
241 *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
242 break;
243
244 case SIOCGIFNETMASK:
245 *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
246 break;
247
248 case SIOCSIFDSTADDR:
249 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
250 return (EINVAL);
251 oldaddr = ia->ia_dstaddr;
252 ia->ia_dstaddr = *satosin(&ifr->ifr_dstaddr);
253 if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
254 (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
255 ia->ia_dstaddr = oldaddr;
256 return (error);
257 }
258 if (ia->ia_flags & IFA_ROUTE) {
259 ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr);
260 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
261 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
262 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
263 }
264 break;
265
266 case SIOCSIFBRDADDR:
267 if ((ifp->if_flags & IFF_BROADCAST) == 0)
268 return (EINVAL);
269 ia->ia_broadaddr = *satosin(&ifr->ifr_broadaddr);
270 break;
271
272 case SIOCSIFADDR:
273 return (in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1));
274
275 case SIOCSIFNETMASK:
276 ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr =
277 ifra->ifra_addr.sin_addr.s_addr;
278 break;
279
280 case SIOCAIFADDR:
281 maskIsNew = 0;
282 hostIsNew = 1;
283 error = 0;
284 if (ia->ia_addr.sin_family == AF_INET) {
285 if (ifra->ifra_addr.sin_len == 0) {
286 ifra->ifra_addr = ia->ia_addr;
287 hostIsNew = 0;
288 } else if (in_hosteq(ia->ia_addr.sin_addr, ifra->ifra_addr.sin_addr))
289 hostIsNew = 0;
290 }
291 if (ifra->ifra_mask.sin_len) {
292 in_ifscrub(ifp, ia);
293 ia->ia_sockmask = ifra->ifra_mask;
294 ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
295 maskIsNew = 1;
296 }
297 if ((ifp->if_flags & IFF_POINTOPOINT) &&
298 (ifra->ifra_dstaddr.sin_family == AF_INET)) {
299 in_ifscrub(ifp, ia);
300 ia->ia_dstaddr = ifra->ifra_dstaddr;
301 maskIsNew = 1; /* We lie; but the effect's the same */
302 }
303 if (ifra->ifra_addr.sin_family == AF_INET &&
304 (hostIsNew || maskIsNew))
305 error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
306 if ((ifp->if_flags & IFF_BROADCAST) &&
307 (ifra->ifra_broadaddr.sin_family == AF_INET))
308 ia->ia_broadaddr = ifra->ifra_broadaddr;
309 return (error);
310
311 case SIOCDIFADDR:
312 in_ifscrub(ifp, ia);
313 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
314 TAILQ_REMOVE(&in_ifaddr, ia, ia_list);
315 IFAFREE((&ia->ia_ifa));
316 break;
317
318 #ifdef MROUTING
319 case SIOCGETVIFCNT:
320 case SIOCGETSGCNT:
321 return (mrt_ioctl(so, cmd, data));
322 #endif /* MROUTING */
323
324 default:
325 if (ifp == 0 || ifp->if_ioctl == 0)
326 return (EOPNOTSUPP);
327 return ((*ifp->if_ioctl)(ifp, cmd, data));
328 }
329 return (0);
330 }
331
332 /*
333 * Delete any existing route for an interface.
334 */
335 void
336 in_ifscrub(ifp, ia)
337 register struct ifnet *ifp;
338 register struct in_ifaddr *ia;
339 {
340
341 if ((ia->ia_flags & IFA_ROUTE) == 0)
342 return;
343 if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
344 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
345 else
346 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
347 ia->ia_flags &= ~IFA_ROUTE;
348 }
349
350 /*
351 * Initialize an interface's internet address
352 * and routing table entry.
353 */
354 int
355 in_ifinit(ifp, ia, sin, scrub)
356 register struct ifnet *ifp;
357 register struct in_ifaddr *ia;
358 struct sockaddr_in *sin;
359 int scrub;
360 {
361 register u_int32_t i = sin->sin_addr.s_addr;
362 struct sockaddr_in oldaddr;
363 int s = splimp(), flags = RTF_UP, error;
364
365 /*
366 * Set up new addresses.
367 */
368 oldaddr = ia->ia_addr;
369 ia->ia_addr = *sin;
370 /*
371 * Give the interface a chance to initialize
372 * if this is its first address,
373 * and to validate the address if necessary.
374 */
375 if (ifp->if_ioctl &&
376 (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)))
377 goto bad;
378 splx(s);
379 if (scrub) {
380 ia->ia_ifa.ifa_addr = sintosa(&oldaddr);
381 in_ifscrub(ifp, ia);
382 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
383 }
384 if (IN_CLASSA(i))
385 ia->ia_netmask = IN_CLASSA_NET;
386 else if (IN_CLASSB(i))
387 ia->ia_netmask = IN_CLASSB_NET;
388 else
389 ia->ia_netmask = IN_CLASSC_NET;
390 /*
391 * The subnet mask usually includes at least the standard network part,
392 * but may may be smaller in the case of supernetting.
393 * If it is set, we believe it.
394 */
395 if (ia->ia_subnetmask == 0) {
396 ia->ia_subnetmask = ia->ia_netmask;
397 ia->ia_sockmask.sin_addr.s_addr = ia->ia_subnetmask;
398 } else
399 ia->ia_netmask &= ia->ia_subnetmask;
400 ia->ia_net = i & ia->ia_netmask;
401 ia->ia_subnet = i & ia->ia_subnetmask;
402 in_socktrim(&ia->ia_sockmask);
403 /*
404 * Add route for the network.
405 */
406 ia->ia_ifa.ifa_metric = ifp->if_metric;
407 if (ifp->if_flags & IFF_BROADCAST) {
408 ia->ia_broadaddr.sin_addr.s_addr =
409 ia->ia_subnet | ~ia->ia_subnetmask;
410 ia->ia_netbroadcast.s_addr =
411 ia->ia_net | ~ia->ia_netmask;
412 } else if (ifp->if_flags & IFF_LOOPBACK) {
413 ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
414 flags |= RTF_HOST;
415 } else if (ifp->if_flags & IFF_POINTOPOINT) {
416 if (ia->ia_dstaddr.sin_family != AF_INET)
417 return (0);
418 flags |= RTF_HOST;
419 }
420 error = rtinit(&ia->ia_ifa, (int)RTM_ADD, flags);
421 if (!error)
422 ia->ia_flags |= IFA_ROUTE;
423 /*
424 * If the interface supports multicast, join the "all hosts"
425 * multicast group on that interface.
426 */
427 if (ifp->if_flags & IFF_MULTICAST) {
428 struct in_addr addr;
429
430 addr.s_addr = INADDR_ALLHOSTS_GROUP;
431 in_addmulti(&addr, ifp);
432 }
433 return (error);
434 bad:
435 splx(s);
436 ia->ia_addr = oldaddr;
437 return (error);
438 }
439
440 /*
441 * Return 1 if the address might be a local broadcast address.
442 */
443 int
444 in_broadcast(in, ifp)
445 struct in_addr in;
446 struct ifnet *ifp;
447 {
448 register struct ifaddr *ifa;
449
450 if (in.s_addr == INADDR_BROADCAST ||
451 in_nullhost(in))
452 return 1;
453 if ((ifp->if_flags & IFF_BROADCAST) == 0)
454 return 0;
455 /*
456 * Look through the list of addresses for a match
457 * with a broadcast address.
458 */
459 #define ia (ifatoia(ifa))
460 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
461 if (ifa->ifa_addr->sa_family == AF_INET &&
462 (in_hosteq(in, ia->ia_broadaddr.sin_addr) ||
463 in_hosteq(in, ia->ia_netbroadcast) ||
464 /*
465 * Check for old-style (host 0) broadcast.
466 */
467 in.s_addr == ia->ia_subnet ||
468 in.s_addr == ia->ia_net))
469 return 1;
470 return (0);
471 #undef ia
472 }
473
474 /*
475 * Add an address to the list of IP multicast addresses for a given interface.
476 */
477 struct in_multi *
478 in_addmulti(ap, ifp)
479 register struct in_addr *ap;
480 register struct ifnet *ifp;
481 {
482 register struct in_multi *inm;
483 struct ifreq ifr;
484 struct in_ifaddr *ia;
485 int s = splsoftnet();
486
487 /*
488 * See if address already in list.
489 */
490 IN_LOOKUP_MULTI(*ap, ifp, inm);
491 if (inm != NULL) {
492 /*
493 * Found it; just increment the reference count.
494 */
495 ++inm->inm_refcount;
496 } else {
497 /*
498 * New address; allocate a new multicast record
499 * and link it into the interface's multicast list.
500 */
501 inm = (struct in_multi *)malloc(sizeof(*inm),
502 M_IPMADDR, M_NOWAIT);
503 if (inm == NULL) {
504 splx(s);
505 return (NULL);
506 }
507 inm->inm_addr = *ap;
508 inm->inm_ifp = ifp;
509 inm->inm_refcount = 1;
510 IFP_TO_IA(ifp, ia);
511 if (ia == NULL) {
512 free(inm, M_IPMADDR);
513 splx(s);
514 return (NULL);
515 }
516 inm->inm_ia = ia;
517 LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_list);
518 /*
519 * Ask the network driver to update its multicast reception
520 * filter appropriately for the new address.
521 */
522 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
523 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
524 satosin(&ifr.ifr_addr)->sin_addr = *ap;
525 if ((ifp->if_ioctl == NULL) ||
526 (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
527 LIST_REMOVE(inm, inm_list);
528 free(inm, M_IPMADDR);
529 splx(s);
530 return (NULL);
531 }
532 /*
533 * Let IGMP know that we have joined a new IP multicast group.
534 */
535 igmp_joingroup(inm);
536 }
537 splx(s);
538 return (inm);
539 }
540
541 /*
542 * Delete a multicast address record.
543 */
544 void
545 in_delmulti(inm)
546 register struct in_multi *inm;
547 {
548 struct ifreq ifr;
549 int s = splsoftnet();
550
551 if (--inm->inm_refcount == 0) {
552 /*
553 * No remaining claims to this record; let IGMP know that
554 * we are leaving the multicast group.
555 */
556 igmp_leavegroup(inm);
557 /*
558 * Unlink from list.
559 */
560 LIST_REMOVE(inm, inm_list);
561 /*
562 * Notify the network driver to update its multicast reception
563 * filter.
564 */
565 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
566 satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
567 (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
568 (caddr_t)&ifr);
569 free(inm, M_IPMADDR);
570 }
571 splx(s);
572 }
573 #endif
574
575 #ifdef PACKET_FILTER
576 void pfil_init __P((void));
577 void pfil_list_add(pfil_list_t *,
578 int (*) __P((void *, int, struct ifnet *, int, struct mbuf **)), int);
579 void pfil_list_remove(struct packet_filter_hook *,
580 int (*) __P((void *, int, struct ifnet *, int, struct mbuf **)));
581
582 void
583 pfil_init()
584 {
585 LIST_INIT(&pfil_in_list);
586 LIST_INIT(&pfil_out_list);
587 LIST_INIT(&pfil_bad_list);
588 done_pfil_init = 1;
589 }
590
591 /*
592 * pfil_add_hook() adds a function to the packet filter hook. the
593 * flags are:
594 * PFIL_IN call me on incoming packets
595 * PFIL_OUT call me on outgoing packets
596 * PFIL_BAD call me when rejecting a packet (that was
597 * not already reject by in/out filters).
598 * PFIL_ALL call me on all of the above
599 * PFIL_WAITOK OK to call malloc with M_WAITOK.
600 */
601 void
602 pfil_add_hook(func, flags)
603 int (*func) __P((void *, int, struct ifnet *, int,
604 struct mbuf **));
605 int flags;
606 {
607
608 if (done_pfil_init == 0)
609 pfil_init();
610
611 if (flags & PFIL_IN)
612 pfil_list_add(&pfil_in_list, func, flags);
613 if (flags & PFIL_OUT)
614 pfil_list_add(&pfil_out_list, func, flags);
615 if (flags & PFIL_BAD)
616 pfil_list_add(&pfil_bad_list, func, flags);
617 }
618
619 void
620 pfil_list_add(list, func, flags)
621 pfil_list_t *list;
622 int (*func) __P((void *, int, struct ifnet *, int,
623 struct mbuf **));
624 int flags;
625 {
626 struct packet_filter_hook *pfh;
627
628 pfh = (struct packet_filter_hook *)malloc(sizeof(*pfh), M_IFADDR,
629 flags & PFIL_WAITOK ? M_WAITOK : M_NOWAIT);
630 if (pfh == NULL)
631 panic("no memory for packet filter hook");
632
633 pfh->pfil_func = func;
634 LIST_INSERT_HEAD(list, pfh, pfil_link);
635 }
636
637 /*
638 * pfil_remove_hook removes a specific function from the packet filter
639 * hook list.
640 */
641 void
642 pfil_remove_hook(func, flags)
643 int (*func) __P((void *, int, struct ifnet *, int,
644 struct mbuf **));
645 int flags;
646 {
647
648 if (done_pfil_init == 0)
649 pfil_init();
650
651 if (flags & PFIL_IN)
652 pfil_list_remove(pfil_in_list.lh_first, func);
653 if (flags & PFIL_OUT)
654 pfil_list_remove(pfil_out_list.lh_first, func);
655 if (flags & PFIL_BAD)
656 pfil_list_remove(pfil_bad_list.lh_first, func);
657 }
658
659 /*
660 * pfil_list_remove is an internal function that takes a function off the
661 * specified list.
662 */
663 void
664 pfil_list_remove(list, func)
665 struct packet_filter_hook *list;
666 int (*func) __P((void *, int, struct ifnet *, int,
667 struct mbuf **));
668 {
669 struct packet_filter_hook *pfh;
670
671 for (pfh = list; pfh; pfh = pfh->pfil_link.le_next)
672 if (pfh->pfil_func == func) {
673 LIST_REMOVE(pfh, pfil_link);
674 free(pfh, M_IFADDR);
675 return;
676 }
677 printf("pfil_list_remove: no function on list\n");
678 #ifdef DIAGNOSTIC
679 panic("pfil_list_remove");
680 #endif
681 }
682
683 struct packet_filter_hook *
684 pfil_hook_get(flag)
685 int flag;
686 {
687 if (done_pfil_init)
688 switch (flag) {
689 case PFIL_IN:
690 return (pfil_in_list.lh_first);
691 case PFIL_OUT:
692 return (pfil_out_list.lh_first);
693 case PFIL_BAD:
694 return (pfil_bad_list.lh_first);
695 }
696 return NULL;
697 }
698 #endif /* PACKET_FILTER */
699