kernel: Remove some unneeded NULL checks after kmalloc() with M_WAITOK.
[dragonfly.git] / sys / net / pf / pf_if.c
... / ...
CommitLineData
1/* $OpenBSD: pf_if.c,v 1.54 2008/06/14 16:55:28 mk Exp $ */
2
3/*
4 * Copyright 2005 Henning Brauer <henning@openbsd.org>
5 * Copyright 2005 Ryan McBride <mcbride@openbsd.org>
6 * Copyright (c) 2001 Daniel Hartmeier
7 * Copyright (c) 2003 Cedric Berger
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "opt_inet.h"
36#include "opt_inet6.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/eventhandler.h>
43#include <sys/filio.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/kernel.h>
47#include <sys/thread2.h>
48#include <sys/time.h>
49
50#include <net/if.h>
51#include <net/if_types.h>
52#include <net/route.h>
53
54#include <netinet/in.h>
55#include <netinet/in_var.h>
56#include <netinet/in_systm.h>
57#include <netinet/ip.h>
58#include <netinet/ip_var.h>
59
60#include <net/pf/pfvar.h>
61
62#ifdef INET6
63#include <netinet/ip6.h>
64#endif /* INET6 */
65
66struct pfi_kif *pfi_all = NULL;
67struct pfi_ifhead pfi_ifs;
68long pfi_update = 1;
69struct pfr_addr *pfi_buffer;
70int pfi_buffer_cnt;
71int pfi_buffer_max;
72
73eventhandler_tag pfi_clone_cookie = NULL;
74eventhandler_tag pfi_attach_cookie = NULL;
75eventhandler_tag pfi_detach_cookie = NULL;
76
77void pfi_kif_update(struct pfi_kif *);
78void pfi_dynaddr_update(struct pfi_dynaddr *dyn);
79void pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
80 int, int);
81void pfi_kifaddr_update(void *);
82void pfi_instance_add(struct ifnet *, int, int);
83void pfi_address_add(struct sockaddr *, int, int);
84int pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
85int pfi_skip_if(const char *, struct pfi_kif *);
86int pfi_unmask(void *);
87void pfi_kifaddr_update_event(void *, struct ifnet *,
88 enum ifaddr_event, struct ifaddr *);
89/*XXX jl void pfi_attach_clone_event(void *, struct if_clone *);*/
90void pfi_attach_ifnet_event(void *, struct ifnet *);
91void pfi_detach_ifnet_event(void *, struct ifnet *);
92
93RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
94RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
95
96#define PFI_BUFFER_MAX 0x10000
97MALLOC_DEFINE(PFI_MTYPE, "pf_if", "pf interface table");
98static MALLOC_DEFINE(M_PFIADDRPL, "pfiaddrpl", "pf interface address pool list");
99
100
101void
102pfi_initialize(void)
103{
104 struct ifnet *ifp;
105
106 if (pfi_all != NULL) /* already initialized */
107 return;
108
109 pfi_buffer_max = 64;
110 pfi_buffer = kmalloc(pfi_buffer_max * sizeof(*pfi_buffer),
111 PFI_MTYPE, M_WAITOK);
112
113 if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
114 panic("pfi_kif_get for pfi_all failed");
115
116 TAILQ_FOREACH(ifp, &ifnet, if_link) {
117 if (ifp->if_dunit != IF_DUNIT_NONE)
118 pfi_attach_ifnet(ifp);
119 }
120 pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_attach_event,
121 pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
122 pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_detach_event,
123 pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
124/* XXX jl pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event,
125 pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY); */
126
127 if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
128 panic("pfi_kif_get for pfi_all failed");
129}
130
131void
132pfi_cleanup(void)
133{
134 struct pfi_kif *p, key;
135 struct ifnet *ifp;
136
137 EVENTHANDLER_DEREGISTER(ifnet_attach_event, pfi_attach_cookie);
138 EVENTHANDLER_DEREGISTER(ifnet_detach_event, pfi_detach_cookie);
139 EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie);
140
141 /* release PFI_IFLAG_INSTANCE */
142 TAILQ_FOREACH(ifp, &ifnet, if_link) {
143 strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
144 p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
145 if (p != NULL)
146 pfi_detach_ifnet(ifp);
147 }
148
149 /* XXX clear all other interface group */
150 while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
151 RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
152
153 kfree(p, PFI_MTYPE);
154 }
155 kfree(pfi_buffer, PFI_MTYPE);
156 pfi_buffer = NULL;
157 pfi_all = NULL;
158}
159
160/*
161 * Wrapper functions for FreeBSD eventhandler
162 */
163void
164pfi_kifaddr_update_event(void *arg, struct ifnet *ifp,
165 enum ifaddr_event event __unused, struct ifaddr *ifa __unused)
166{
167 struct pfi_kif *p = arg;
168
169 /*
170 * Check to see if it is 'our' interface as we do not have per
171 * interface hooks and thus get an update for every interface.
172 */
173 if (p && p->pfik_ifp == ifp)
174 pfi_kifaddr_update(p);
175}
176
177/* XXX jl
178void
179pfi_attach_clone_event(void *arg __unused, struct if_clone *ifc)
180{
181 pfi_attach_clone(ifc);
182}
183*/
184
185void
186pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
187{
188 if (ifp->if_dunit != IF_DUNIT_NONE)
189 pfi_attach_ifnet(ifp);
190}
191
192void
193pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
194{
195 pfi_detach_ifnet(ifp);
196}
197
198struct pfi_kif *
199pfi_kif_get(const char *kif_name)
200{
201 struct pfi_kif *kif;
202 struct pfi_kif_cmp s;
203
204 bzero(&s, sizeof(s));
205 strlcpy(s.pfik_ifname, kif_name, sizeof(s.pfik_ifname));
206 if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL)
207 return (kif);
208
209 /* create new one */
210 if ((kif = kmalloc(sizeof(*kif), PFI_MTYPE, M_WAITOK)) == NULL)
211 return (NULL);
212
213 strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
214 kif->pfik_tzero = time_second;
215 TAILQ_INIT(&kif->pfik_dynaddrs);
216
217 RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
218 return (kif);
219}
220
221void
222pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
223{
224 switch (what) {
225 case PFI_KIF_REF_RULE:
226 kif->pfik_rules++;
227 break;
228 case PFI_KIF_REF_STATE:
229 kif->pfik_states++;
230 break;
231 default:
232 panic("pfi_kif_ref with unknown type");
233 }
234}
235
236void
237pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
238{
239 if (kif == NULL)
240 return;
241
242 switch (what) {
243 case PFI_KIF_REF_NONE:
244 break;
245 case PFI_KIF_REF_RULE:
246 if (kif->pfik_rules <= 0) {
247 kprintf("pfi_kif_unref: rules refcount <= 0\n");
248 return;
249 }
250 kif->pfik_rules--;
251 break;
252 case PFI_KIF_REF_STATE:
253 if (kif->pfik_states <= 0) {
254 kprintf("pfi_kif_unref: state refcount <= 0\n");
255 return;
256 }
257 kif->pfik_states--;
258 break;
259 default:
260 panic("pfi_kif_unref with unknown type");
261 }
262
263 if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
264 return;
265
266 if (kif->pfik_rules || kif->pfik_states)
267 return;
268
269 RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
270 kfree(kif, PFI_MTYPE);
271}
272
273int
274pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif)
275{
276 struct ifg_list *p;
277
278 if (rule_kif == NULL || rule_kif == packet_kif)
279 return (1);
280
281 if (rule_kif->pfik_group != NULL)
282 TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next)
283 if (p->ifgl_group == rule_kif->pfik_group)
284 return (1);
285
286 return (0);
287}
288
289void
290pfi_attach_ifnet(struct ifnet *ifp)
291{
292 struct pfi_kif *kif;
293
294 pfi_initialize();
295 crit_enter();
296 pfi_update++;
297 if ((kif = pfi_kif_get(ifp->if_xname)) == NULL)
298 panic("pfi_kif_get failed");
299
300 kif->pfik_ifp = ifp;
301 ifp->if_pf_kif = (caddr_t)kif;
302
303 pfi_kif_update(kif);
304
305 crit_exit();
306}
307
308void
309pfi_detach_ifnet(struct ifnet *ifp)
310{
311 struct pfi_kif *kif;
312
313 if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL)
314 return;
315
316 crit_enter();
317 pfi_update++;
318 pfi_kif_update(kif);
319
320 kif->pfik_ifp = NULL;
321 ifp->if_pf_kif = NULL;
322 pfi_kif_unref(kif, PFI_KIF_REF_NONE);
323 crit_exit();
324}
325
326void
327pfi_attach_ifgroup(struct ifg_group *ifg)
328{
329 struct pfi_kif *kif;
330
331 pfi_initialize();
332 crit_enter();
333 pfi_update++;
334 if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL)
335 panic("pfi_kif_get failed");
336
337 kif->pfik_group = ifg;
338 ifg->ifg_pf_kif = (caddr_t)kif;
339
340 crit_exit();
341}
342
343void
344pfi_detach_ifgroup(struct ifg_group *ifg)
345{
346 struct pfi_kif *kif;
347
348 if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL)
349 return;
350
351 crit_enter();
352 pfi_update++;
353
354 kif->pfik_group = NULL;
355 ifg->ifg_pf_kif = NULL;
356 pfi_kif_unref(kif, PFI_KIF_REF_NONE);
357 crit_exit();
358}
359
360void
361pfi_group_change(const char *group)
362{
363 struct pfi_kif *kif;
364
365 crit_enter();
366 pfi_update++;
367 if ((kif = pfi_kif_get(group)) == NULL)
368 panic("pfi_kif_get failed");
369
370 pfi_kif_update(kif);
371
372 crit_exit();
373}
374
375int
376pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
377{
378 switch (af) {
379#ifdef INET
380 case AF_INET:
381 switch (dyn->pfid_acnt4) {
382 case 0:
383 return (0);
384 case 1:
385 return (PF_MATCHA(0, &dyn->pfid_addr4,
386 &dyn->pfid_mask4, a, AF_INET));
387 default:
388 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
389 }
390 break;
391#endif /* INET */
392#ifdef INET6
393 case AF_INET6:
394 switch (dyn->pfid_acnt6) {
395 case 0:
396 return (0);
397 case 1:
398 return (PF_MATCHA(0, &dyn->pfid_addr6,
399 &dyn->pfid_mask6, a, AF_INET6));
400 default:
401 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
402 }
403 break;
404#endif /* INET6 */
405 default:
406 return (0);
407 }
408}
409
410int
411pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
412{
413 struct pfi_dynaddr *dyn;
414 char tblname[PF_TABLE_NAME_SIZE];
415 struct pf_ruleset *ruleset = NULL;
416 int rv = 0;
417
418 if (aw->type != PF_ADDR_DYNIFTL)
419 return (0);
420 if ((dyn = kmalloc(sizeof(struct pfi_dynaddr), M_PFIADDRPL, M_WAITOK|M_NULLOK|M_ZERO))
421 == NULL)
422 return (1);
423
424 crit_enter();
425 if (!strcmp(aw->v.ifname, "self"))
426 dyn->pfid_kif = pfi_kif_get(IFG_ALL);
427 else
428 dyn->pfid_kif = pfi_kif_get(aw->v.ifname);
429 if (dyn->pfid_kif == NULL) {
430 rv = 1;
431 goto _bad;
432 }
433 pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
434
435 dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
436 if (af == AF_INET && dyn->pfid_net == 32)
437 dyn->pfid_net = 128;
438 strlcpy(tblname, aw->v.ifname, sizeof(tblname));
439 if (aw->iflags & PFI_AFLAG_NETWORK)
440 strlcat(tblname, ":network", sizeof(tblname));
441 if (aw->iflags & PFI_AFLAG_BROADCAST)
442 strlcat(tblname, ":broadcast", sizeof(tblname));
443 if (aw->iflags & PFI_AFLAG_PEER)
444 strlcat(tblname, ":peer", sizeof(tblname));
445 if (aw->iflags & PFI_AFLAG_NOALIAS)
446 strlcat(tblname, ":0", sizeof(tblname));
447 if (dyn->pfid_net != 128)
448 ksnprintf(tblname + strlen(tblname),
449 sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
450 if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) {
451 rv = 1;
452 goto _bad;
453 }
454
455 if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) {
456 rv = 1;
457 goto _bad;
458 }
459
460 dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
461 dyn->pfid_iflags = aw->iflags;
462 dyn->pfid_af = af;
463
464 TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry);
465 aw->p.dyn = dyn;
466 pfi_kif_update(dyn->pfid_kif);
467 crit_exit();
468 return (0);
469
470_bad:
471 if (dyn->pfid_kt != NULL)
472 pfr_detach_table(dyn->pfid_kt);
473 if (ruleset != NULL)
474 pf_remove_if_empty_ruleset(ruleset);
475 if (dyn->pfid_kif != NULL)
476 pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
477 kfree(dyn, M_PFIADDRPL);
478 crit_exit();
479 return (rv);
480}
481
482void
483pfi_kif_update(struct pfi_kif *kif)
484{
485 struct ifg_list *ifgl;
486 struct pfi_dynaddr *p;
487
488 /* update all dynaddr */
489 TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry)
490 pfi_dynaddr_update(p);
491
492 /* again for all groups kif is member of */
493 if (kif->pfik_ifp != NULL)
494 TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next)
495 pfi_kif_update((struct pfi_kif *)
496 ifgl->ifgl_group->ifg_pf_kif);
497}
498
499void
500pfi_dynaddr_update(struct pfi_dynaddr *dyn)
501{
502 struct pfi_kif *kif;
503 struct pfr_ktable *kt;
504
505 if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL)
506 panic("pfi_dynaddr_update");
507
508 kif = dyn->pfid_kif;
509 kt = dyn->pfid_kt;
510
511 if (kt->pfrkt_larg != pfi_update) {
512 /* this table needs to be brought up-to-date */
513 pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
514 kt->pfrkt_larg = pfi_update;
515 }
516 pfr_dynaddr_update(kt, dyn);
517}
518
519void
520pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
521{
522 int e, size2 = 0;
523 struct ifg_member *ifgm;
524
525 pfi_buffer_cnt = 0;
526
527 if (kif->pfik_ifp != NULL)
528 pfi_instance_add(kif->pfik_ifp, net, flags);
529 else if (kif->pfik_group != NULL)
530 TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next)
531 pfi_instance_add(ifgm->ifgm_ifp, net, flags);
532
533 if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2,
534 NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK)))
535 kprintf("pfi_table_update: cannot set %d new addresses "
536 "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
537}
538
539void
540pfi_instance_add(struct ifnet *ifp, int net, int flags)
541{
542 struct ifaddr_container *ifac;
543 int got4 = 0, got6 = 0;
544 int net2, af;
545
546 if (ifp == NULL)
547 return;
548 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
549 struct ifaddr *ia = ifac->ifa;
550
551 if (ia->ifa_addr == NULL)
552 continue;
553 af = ia->ifa_addr->sa_family;
554 if (af != AF_INET && af != AF_INET6)
555 continue;
556 /*
557 * XXX: For point-to-point interfaces, (ifname:0) and IPv4,
558 * jump over address without a proper route to work
559 * around a problem with ppp not fully removing the
560 * address used during IPCP.
561 */
562 if ((ifp->if_flags & IFF_POINTOPOINT) &&
563 !(ia->ifa_flags & IFA_ROUTE) &&
564 (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET))
565 continue;
566 if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
567 continue;
568 if ((flags & PFI_AFLAG_BROADCAST) &&
569 !(ifp->if_flags & IFF_BROADCAST))
570 continue;
571 if ((flags & PFI_AFLAG_PEER) &&
572 !(ifp->if_flags & IFF_POINTOPOINT))
573 continue;
574 if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
575 IN6_IS_ADDR_LINKLOCAL(
576 &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
577 continue;
578 if (flags & PFI_AFLAG_NOALIAS) {
579 if (af == AF_INET && got4)
580 continue;
581 if (af == AF_INET6 && got6)
582 continue;
583 }
584 if (af == AF_INET)
585 got4 = 1;
586 else if (af == AF_INET6)
587 got6 = 1;
588 net2 = net;
589 if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
590 if (af == AF_INET)
591 net2 = pfi_unmask(&((struct sockaddr_in *)
592 ia->ifa_netmask)->sin_addr);
593 else if (af == AF_INET6)
594 net2 = pfi_unmask(&((struct sockaddr_in6 *)
595 ia->ifa_netmask)->sin6_addr);
596 }
597 if (af == AF_INET && net2 > 32)
598 net2 = 32;
599 if (flags & PFI_AFLAG_BROADCAST)
600 pfi_address_add(ia->ifa_broadaddr, af, net2);
601 else if (flags & PFI_AFLAG_PEER)
602 pfi_address_add(ia->ifa_dstaddr, af, net2);
603 else
604 pfi_address_add(ia->ifa_addr, af, net2);
605 }
606}
607
608void
609pfi_address_add(struct sockaddr *sa, int af, int net)
610{
611 struct pfr_addr *p;
612 int i;
613
614 if (pfi_buffer_cnt >= pfi_buffer_max) {
615 int new_max = pfi_buffer_max * 2;
616
617 if (new_max > PFI_BUFFER_MAX) {
618 kprintf("pfi_address_add: address buffer full (%d/%d)\n",
619 pfi_buffer_cnt, PFI_BUFFER_MAX);
620 return;
621 }
622 p = kmalloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, M_WAITOK);
623 memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
624 /* no need to zero buffer */
625 kfree(pfi_buffer, PFI_MTYPE);
626 pfi_buffer = p;
627 pfi_buffer_max = new_max;
628 }
629 if (af == AF_INET && net > 32)
630 net = 128;
631 p = pfi_buffer + pfi_buffer_cnt++;
632 bzero(p, sizeof(*p));
633 p->pfra_af = af;
634 p->pfra_net = net;
635 if (af == AF_INET)
636 p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
637 else if (af == AF_INET6) {
638 p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
639 if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr))
640 p->pfra_ip6addr.s6_addr16[1] = 0;
641 }
642 /* mask network address bits */
643 if (net < 128)
644 ((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
645 for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
646 ((caddr_t)p)[i] = 0;
647}
648
649void
650pfi_dynaddr_remove(struct pf_addr_wrap *aw)
651{
652 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
653 aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
654 return;
655
656 crit_enter();
657 TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
658 pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
659 aw->p.dyn->pfid_kif = NULL;
660 pfr_detach_table(aw->p.dyn->pfid_kt);
661 aw->p.dyn->pfid_kt = NULL;
662 kfree(aw->p.dyn, M_PFIADDRPL);
663 aw->p.dyn = NULL;
664 crit_exit();
665}
666
667void
668pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
669{
670 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
671 aw->p.dyn->pfid_kif == NULL)
672 return;
673 aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
674}
675
676void
677pfi_kifaddr_update(void *v)
678{
679 struct pfi_kif *kif = (struct pfi_kif *)v;
680
681 crit_enter();
682 pfi_update++;
683 pfi_kif_update(kif);
684 crit_exit();
685}
686
687int
688pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
689{
690 return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
691}
692
693void
694pfi_update_status(const char *name, struct pf_status *pfs)
695{
696 struct pfi_kif *p;
697 struct pfi_kif_cmp key;
698 struct ifg_member p_member, *ifgm;
699 TAILQ_HEAD(, ifg_member) ifg_members;
700 int i, j, k;
701
702 strlcpy(key.pfik_ifname, name, sizeof(key.pfik_ifname));
703 crit_enter();
704 p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key);
705 if (p == NULL) {
706 crit_exit();
707 return;
708 }
709 if (p->pfik_group != NULL) {
710 bcopy(&p->pfik_group->ifg_members, &ifg_members,
711 sizeof(ifg_members));
712 } else {
713 /* build a temporary list for p only */
714 bzero(&p_member, sizeof(p_member));
715 p_member.ifgm_ifp = p->pfik_ifp;
716 TAILQ_INIT(&ifg_members);
717 TAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next);
718 }
719 if (pfs) {
720 bzero(pfs->pcounters, sizeof(pfs->pcounters));
721 bzero(pfs->bcounters, sizeof(pfs->bcounters));
722 }
723 TAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) {
724 if (ifgm->ifgm_ifp == NULL)
725 continue;
726 p = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif;
727
728 /* just clear statistics */
729 if (pfs == NULL) {
730 bzero(p->pfik_packets, sizeof(p->pfik_packets));
731 bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
732 p->pfik_tzero = time_second;
733 continue;
734 }
735 for (i = 0; i < 2; i++)
736 for (j = 0; j < 2; j++)
737 for (k = 0; k < 2; k++) {
738 pfs->pcounters[i][j][k] +=
739 p->pfik_packets[i][j][k];
740 pfs->bcounters[i][j] +=
741 p->pfik_bytes[i][j][k];
742 }
743 }
744 crit_exit();
745}
746
747int
748pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
749{
750 struct pfi_kif *p, *nextp;
751 int n = 0;
752
753 crit_enter();
754 for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) {
755 nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
756 if (pfi_skip_if(name, p))
757 continue;
758 if (*size > n++) {
759 if (!p->pfik_tzero)
760 p->pfik_tzero = time_second;
761 pfi_kif_ref(p, PFI_KIF_REF_RULE);
762 if (copyout(p, buf++, sizeof(*buf))) {
763 pfi_kif_unref(p, PFI_KIF_REF_RULE);
764 crit_exit();
765 return (EFAULT);
766 }
767 nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
768 pfi_kif_unref(p, PFI_KIF_REF_RULE);
769 }
770 }
771 crit_exit();
772 *size = n;
773 return (0);
774}
775
776int
777pfi_skip_if(const char *filter, struct pfi_kif *p)
778{
779 int n;
780
781 if (filter == NULL || !*filter)
782 return (0);
783 if (!strcmp(p->pfik_name, filter))
784 return (0); /* exact match */
785 n = strlen(filter);
786 if (n < 1 || n >= IFNAMSIZ)
787 return (1); /* sanity check */
788 if (filter[n-1] >= '0' && filter[n-1] <= '9')
789 return (1); /* only do exact match in that case */
790 if (strncmp(p->pfik_name, filter, n))
791 return (1); /* prefix doesn't match */
792 return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
793}
794
795int
796pfi_set_flags(const char *name, int flags)
797{
798 struct pfi_kif *p;
799
800 crit_enter();
801 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
802 if (pfi_skip_if(name, p))
803 continue;
804 p->pfik_flags |= flags;
805 }
806 crit_exit();
807 return (0);
808}
809
810int
811pfi_clear_flags(const char *name, int flags)
812{
813 struct pfi_kif *p;
814
815 crit_enter();
816 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
817 if (pfi_skip_if(name, p))
818 continue;
819 p->pfik_flags &= ~flags;
820 }
821 crit_exit();
822 return (0);
823}
824
825/* from pf_print_state.c */
826int
827pfi_unmask(void *addr)
828{
829 struct pf_addr *m = addr;
830 int i = 31, j = 0, b = 0;
831 u_int32_t tmp;
832
833 while (j < 4 && m->addr32[j] == 0xffffffff) {
834 b += 32;
835 j++;
836 }
837 if (j < 4) {
838 tmp = ntohl(m->addr32[j]);
839 for (i = 31; tmp & (1 << i); --i)
840 b++;
841 }
842 return (b);
843}
844