source: rtems-libbsd/contrib/pf/rtems/freebsd/net/pf_table.c @ 9a8e3e0

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 9a8e3e0 was 9a8e3e0, checked in by Joel Sherrill <joel.sherrill@…>, on 03/08/12 at 14:17:55

Revert move of contrib until more sorted out

  • Property mode set to 100644
File size: 57.6 KB
Line 
1#include <rtems/freebsd/machine/rtems-bsd-config.h>
2
3/*      $OpenBSD: pf_table.c,v 1.68 2006/05/02 10:08:45 dhartmei Exp $  */
4
5/*
6 * Copyright (c) 2002 Cedric Berger
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 *    - Redistributions of source code must retain the above copyright
14 *      notice, this list of conditions and the following disclaimer.
15 *    - Redistributions in binary form must reproduce the above
16 *      copyright notice, this list of conditions and the following
17 *      disclaimer in the documentation and/or other materials provided
18 *      with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35#ifdef __FreeBSD__
36#include <rtems/freebsd/local/opt_inet.h>
37#include <rtems/freebsd/local/opt_inet6.h>
38
39#include <rtems/freebsd/sys/cdefs.h>
40__FBSDID("$FreeBSD$");
41#endif
42
43#include <rtems/freebsd/sys/param.h>
44#include <rtems/freebsd/sys/systm.h>
45#include <rtems/freebsd/sys/socket.h>
46#include <rtems/freebsd/sys/mbuf.h>
47#include <rtems/freebsd/sys/kernel.h>
48#include <rtems/freebsd/sys/lock.h>
49#include <rtems/freebsd/sys/rwlock.h>
50#ifdef __FreeBSD__
51#include <rtems/freebsd/sys/malloc.h>
52#endif
53
54#include <rtems/freebsd/net/if.h>
55#include <rtems/freebsd/net/route.h>
56#include <rtems/freebsd/netinet/in.h>
57#ifndef __FreeBSD__
58#include <rtems/freebsd/netinet/ip_ipsp.h>
59#endif
60
61#include <rtems/freebsd/net/pfvar.h>
62
63#define ACCEPT_FLAGS(oklist)                    \
64        do {                                    \
65                if ((flags & ~(oklist)) &       \
66                    PFR_FLAG_ALLMASK)           \
67                        return (EINVAL);        \
68        } while (0)
69
70#ifdef __FreeBSD__
71static inline int
72_copyin(const void *uaddr, void *kaddr, size_t len)
73{
74        int r;
75
76        PF_UNLOCK();
77        r = copyin(uaddr, kaddr, len);
78        PF_LOCK();
79
80        return (r);
81}
82
83static inline int
84_copyout(const void *uaddr, void *kaddr, size_t len)
85{
86        int r;
87
88        PF_UNLOCK();
89        r = copyout(uaddr, kaddr, len);
90        PF_LOCK();
91
92        return (r);
93}
94
95#define COPYIN(from, to, size)                  \
96        ((flags & PFR_FLAG_USERIOCTL) ?         \
97        _copyin((from), (to), (size)) :         \
98        (bcopy((from), (to), (size)), 0))
99
100#define COPYOUT(from, to, size)                 \
101        ((flags & PFR_FLAG_USERIOCTL) ?         \
102        _copyout((from), (to), (size)) :        \
103        (bcopy((from), (to), (size)), 0))
104
105#else
106
107#define COPYIN(from, to, size)                  \
108        ((flags & PFR_FLAG_USERIOCTL) ?         \
109        copyin((from), (to), (size)) :          \
110        (bcopy((from), (to), (size)), 0))
111
112#define COPYOUT(from, to, size)                 \
113        ((flags & PFR_FLAG_USERIOCTL) ?         \
114        copyout((from), (to), (size)) :         \
115        (bcopy((from), (to), (size)), 0))
116
117#endif
118
119#define FILLIN_SIN(sin, addr)                   \
120        do {                                    \
121                (sin).sin_len = sizeof(sin);    \
122                (sin).sin_family = AF_INET;     \
123                (sin).sin_addr = (addr);        \
124        } while (0)
125
126#define FILLIN_SIN6(sin6, addr)                 \
127        do {                                    \
128                (sin6).sin6_len = sizeof(sin6); \
129                (sin6).sin6_family = AF_INET6;  \
130                (sin6).sin6_addr = (addr);      \
131        } while (0)
132
133#define SWAP(type, a1, a2)                      \
134        do {                                    \
135                type tmp = a1;                  \
136                a1 = a2;                        \
137                a2 = tmp;                       \
138        } while (0)
139
140#define SUNION2PF(su, af) (((af)==AF_INET) ?    \
141    (struct pf_addr *)&(su)->sin.sin_addr :     \
142    (struct pf_addr *)&(su)->sin6.sin6_addr)
143
144#define AF_BITS(af)             (((af)==AF_INET)?32:128)
145#define ADDR_NETWORK(ad)        ((ad)->pfra_net < AF_BITS((ad)->pfra_af))
146#define KENTRY_NETWORK(ke)      ((ke)->pfrke_net < AF_BITS((ke)->pfrke_af))
147#define KENTRY_RNF_ROOT(ke) \
148                ((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0)
149
150#define NO_ADDRESSES            (-1)
151#define ENQUEUE_UNMARKED_ONLY   (1)
152#define INVERT_NEG_FLAG         (1)
153
154struct pfr_walktree {
155        enum pfrw_op {
156                PFRW_MARK,
157                PFRW_SWEEP,
158                PFRW_ENQUEUE,
159                PFRW_GET_ADDRS,
160                PFRW_GET_ASTATS,
161                PFRW_POOL_GET,
162                PFRW_DYNADDR_UPDATE
163        }        pfrw_op;
164        union {
165                struct pfr_addr         *pfrw1_addr;
166                struct pfr_astats       *pfrw1_astats;
167                struct pfr_kentryworkq  *pfrw1_workq;
168                struct pfr_kentry       *pfrw1_kentry;
169                struct pfi_dynaddr      *pfrw1_dyn;
170        }        pfrw_1;
171        int      pfrw_free;
172        int      pfrw_flags;
173};
174#define pfrw_addr       pfrw_1.pfrw1_addr
175#define pfrw_astats     pfrw_1.pfrw1_astats
176#define pfrw_workq      pfrw_1.pfrw1_workq
177#define pfrw_kentry     pfrw_1.pfrw1_kentry
178#define pfrw_dyn        pfrw_1.pfrw1_dyn
179#define pfrw_cnt        pfrw_free
180
181#define senderr(e)      do { rv = (e); goto _bad; } while (0)
182
183#ifdef __FreeBSD__
184uma_zone_t               pfr_ktable_pl;
185uma_zone_t               pfr_kentry_pl;
186uma_zone_t               pfr_kentry_pl2;
187#else
188struct pool              pfr_ktable_pl;
189struct pool              pfr_kentry_pl;
190struct pool              pfr_kentry_pl2;
191#endif
192struct sockaddr_in       pfr_sin;
193struct sockaddr_in6      pfr_sin6;
194union sockaddr_union     pfr_mask;
195struct pf_addr           pfr_ffaddr;
196
197void                     pfr_copyout_addr(struct pfr_addr *,
198                            struct pfr_kentry *ke);
199int                      pfr_validate_addr(struct pfr_addr *);
200void                     pfr_enqueue_addrs(struct pfr_ktable *,
201                            struct pfr_kentryworkq *, int *, int);
202void                     pfr_mark_addrs(struct pfr_ktable *);
203struct pfr_kentry       *pfr_lookup_addr(struct pfr_ktable *,
204                            struct pfr_addr *, int);
205struct pfr_kentry       *pfr_create_kentry(struct pfr_addr *, int);
206void                     pfr_destroy_kentries(struct pfr_kentryworkq *);
207void                     pfr_destroy_kentry(struct pfr_kentry *);
208void                     pfr_insert_kentries(struct pfr_ktable *,
209                            struct pfr_kentryworkq *, long);
210void                     pfr_remove_kentries(struct pfr_ktable *,
211                            struct pfr_kentryworkq *);
212void                     pfr_clstats_kentries(struct pfr_kentryworkq *, long,
213                            int);
214void                     pfr_reset_feedback(struct pfr_addr *, int, int);
215void                     pfr_prepare_network(union sockaddr_union *, int, int);
216int                      pfr_route_kentry(struct pfr_ktable *,
217                            struct pfr_kentry *);
218int                      pfr_unroute_kentry(struct pfr_ktable *,
219                            struct pfr_kentry *);
220int                      pfr_walktree(struct radix_node *, void *);
221int                      pfr_validate_table(struct pfr_table *, int, int);
222int                      pfr_fix_anchor(char *);
223void                     pfr_commit_ktable(struct pfr_ktable *, long);
224void                     pfr_insert_ktables(struct pfr_ktableworkq *);
225void                     pfr_insert_ktable(struct pfr_ktable *);
226void                     pfr_setflags_ktables(struct pfr_ktableworkq *);
227void                     pfr_setflags_ktable(struct pfr_ktable *, int);
228void                     pfr_clstats_ktables(struct pfr_ktableworkq *, long,
229                            int);
230void                     pfr_clstats_ktable(struct pfr_ktable *, long, int);
231struct pfr_ktable       *pfr_create_ktable(struct pfr_table *, long, int);
232void                     pfr_destroy_ktables(struct pfr_ktableworkq *, int);
233void                     pfr_destroy_ktable(struct pfr_ktable *, int);
234int                      pfr_ktable_compare(struct pfr_ktable *,
235                            struct pfr_ktable *);
236struct pfr_ktable       *pfr_lookup_table(struct pfr_table *);
237void                     pfr_clean_node_mask(struct pfr_ktable *,
238                            struct pfr_kentryworkq *);
239int                      pfr_table_count(struct pfr_table *, int);
240int                      pfr_skip_table(struct pfr_table *,
241                            struct pfr_ktable *, int);
242struct pfr_kentry       *pfr_kentry_byidx(struct pfr_ktable *, int, int);
243
244RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
245RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
246
247struct pfr_ktablehead    pfr_ktables;
248struct pfr_table         pfr_nulltable;
249int                      pfr_ktable_cnt;
250
251void
252pfr_initialize(void)
253{
254#ifndef __FreeBSD__
255        pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0,
256            "pfrktable", &pool_allocator_oldnointr);
257        pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0,
258            "pfrkentry", &pool_allocator_oldnointr);
259        pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0,
260            "pfrkentry2", NULL);
261#endif
262
263        pfr_sin.sin_len = sizeof(pfr_sin);
264        pfr_sin.sin_family = AF_INET;
265        pfr_sin6.sin6_len = sizeof(pfr_sin6);
266        pfr_sin6.sin6_family = AF_INET6;
267
268        memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr));
269}
270
271int
272pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
273{
274        struct pfr_ktable       *kt;
275        struct pfr_kentryworkq   workq;
276        int                      s;
277
278        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
279        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
280                return (EINVAL);
281        kt = pfr_lookup_table(tbl);
282        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
283                return (ESRCH);
284        if (kt->pfrkt_flags & PFR_TFLAG_CONST)
285                return (EPERM);
286        pfr_enqueue_addrs(kt, &workq, ndel, 0);
287
288        if (!(flags & PFR_FLAG_DUMMY)) {
289                s = 0;
290                if (flags & PFR_FLAG_ATOMIC)
291                        s = splsoftnet();
292                pfr_remove_kentries(kt, &workq);
293                if (flags & PFR_FLAG_ATOMIC)
294                        splx(s);
295                if (kt->pfrkt_cnt) {
296                        printf("pfr_clr_addrs: corruption detected (%d).\n",
297                            kt->pfrkt_cnt);
298                        kt->pfrkt_cnt = 0;
299                }
300        }
301        return (0);
302}
303
304int
305pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
306    int *nadd, int flags)
307{
308        struct pfr_ktable       *kt, *tmpkt;
309        struct pfr_kentryworkq   workq;
310        struct pfr_kentry       *p, *q;
311        struct pfr_addr          ad;
312        int                      i, rv, s = 0, xadd = 0;
313        long                     tzero = time_second;
314
315        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
316        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
317                return (EINVAL);
318        kt = pfr_lookup_table(tbl);
319        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
320                return (ESRCH);
321        if (kt->pfrkt_flags & PFR_TFLAG_CONST)
322                return (EPERM);
323        tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0);
324        if (tmpkt == NULL)
325                return (ENOMEM);
326        SLIST_INIT(&workq);
327        for (i = 0; i < size; i++) {
328                if (COPYIN(addr+i, &ad, sizeof(ad)))
329                        senderr(EFAULT);
330                if (pfr_validate_addr(&ad))
331                        senderr(EINVAL);
332                p = pfr_lookup_addr(kt, &ad, 1);
333                q = pfr_lookup_addr(tmpkt, &ad, 1);
334                if (flags & PFR_FLAG_FEEDBACK) {
335                        if (q != NULL)
336                                ad.pfra_fback = PFR_FB_DUPLICATE;
337                        else if (p == NULL)
338                                ad.pfra_fback = PFR_FB_ADDED;
339                        else if (p->pfrke_not != ad.pfra_not)
340                                ad.pfra_fback = PFR_FB_CONFLICT;
341                        else
342                                ad.pfra_fback = PFR_FB_NONE;
343                }
344                if (p == NULL && q == NULL) {
345                        p = pfr_create_kentry(&ad, 0);
346                        if (p == NULL)
347                                senderr(ENOMEM);
348                        if (pfr_route_kentry(tmpkt, p)) {
349                                pfr_destroy_kentry(p);
350                                ad.pfra_fback = PFR_FB_NONE;
351                        } else {
352                                SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
353                                xadd++;
354                        }
355                }
356                if (flags & PFR_FLAG_FEEDBACK) {
357                        if (COPYOUT(&ad, addr+i, sizeof(ad)))
358                                senderr(EFAULT);
359                }
360        }
361        pfr_clean_node_mask(tmpkt, &workq);
362        if (!(flags & PFR_FLAG_DUMMY)) {
363                if (flags & PFR_FLAG_ATOMIC)
364                        s = splsoftnet();
365                pfr_insert_kentries(kt, &workq, tzero);
366                if (flags & PFR_FLAG_ATOMIC)
367                        splx(s);
368        } else
369                pfr_destroy_kentries(&workq);
370        if (nadd != NULL)
371                *nadd = xadd;
372        pfr_destroy_ktable(tmpkt, 0);
373        return (0);
374_bad:
375        pfr_clean_node_mask(tmpkt, &workq);
376        pfr_destroy_kentries(&workq);
377        if (flags & PFR_FLAG_FEEDBACK)
378                pfr_reset_feedback(addr, size, flags);
379        pfr_destroy_ktable(tmpkt, 0);
380        return (rv);
381}
382
383int
384pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
385    int *ndel, int flags)
386{
387        struct pfr_ktable       *kt;
388        struct pfr_kentryworkq   workq;
389        struct pfr_kentry       *p;
390        struct pfr_addr          ad;
391        int                      i, rv, s = 0, xdel = 0, log = 1;
392
393        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
394        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
395                return (EINVAL);
396        kt = pfr_lookup_table(tbl);
397        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
398                return (ESRCH);
399        if (kt->pfrkt_flags & PFR_TFLAG_CONST)
400                return (EPERM);
401        /*
402         * there are two algorithms to choose from here.
403         * with:
404         *   n: number of addresses to delete
405         *   N: number of addresses in the table
406         *
407         * one is O(N) and is better for large 'n'
408         * one is O(n*LOG(N)) and is better for small 'n'
409         *
410         * following code try to decide which one is best.
411         */
412        for (i = kt->pfrkt_cnt; i > 0; i >>= 1)
413                log++;
414        if (size > kt->pfrkt_cnt/log) {
415                /* full table scan */
416                pfr_mark_addrs(kt);
417        } else {
418                /* iterate over addresses to delete */
419                for (i = 0; i < size; i++) {
420                        if (COPYIN(addr+i, &ad, sizeof(ad)))
421                                return (EFAULT);
422                        if (pfr_validate_addr(&ad))
423                                return (EINVAL);
424                        p = pfr_lookup_addr(kt, &ad, 1);
425                        if (p != NULL)
426                                p->pfrke_mark = 0;
427                }
428        }
429        SLIST_INIT(&workq);
430        for (i = 0; i < size; i++) {
431                if (COPYIN(addr+i, &ad, sizeof(ad)))
432                        senderr(EFAULT);
433                if (pfr_validate_addr(&ad))
434                        senderr(EINVAL);
435                p = pfr_lookup_addr(kt, &ad, 1);
436                if (flags & PFR_FLAG_FEEDBACK) {
437                        if (p == NULL)
438                                ad.pfra_fback = PFR_FB_NONE;
439                        else if (p->pfrke_not != ad.pfra_not)
440                                ad.pfra_fback = PFR_FB_CONFLICT;
441                        else if (p->pfrke_mark)
442                                ad.pfra_fback = PFR_FB_DUPLICATE;
443                        else
444                                ad.pfra_fback = PFR_FB_DELETED;
445                }
446                if (p != NULL && p->pfrke_not == ad.pfra_not &&
447                    !p->pfrke_mark) {
448                        p->pfrke_mark = 1;
449                        SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
450                        xdel++;
451                }
452                if (flags & PFR_FLAG_FEEDBACK)
453                        if (COPYOUT(&ad, addr+i, sizeof(ad)))
454                                senderr(EFAULT);
455        }
456        if (!(flags & PFR_FLAG_DUMMY)) {
457                if (flags & PFR_FLAG_ATOMIC)
458                        s = splsoftnet();
459                pfr_remove_kentries(kt, &workq);
460                if (flags & PFR_FLAG_ATOMIC)
461                        splx(s);
462        }
463        if (ndel != NULL)
464                *ndel = xdel;
465        return (0);
466_bad:
467        if (flags & PFR_FLAG_FEEDBACK)
468                pfr_reset_feedback(addr, size, flags);
469        return (rv);
470}
471
472int
473pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
474    int *size2, int *nadd, int *ndel, int *nchange, int flags,
475    u_int32_t ignore_pfrt_flags)
476{
477        struct pfr_ktable       *kt, *tmpkt;
478        struct pfr_kentryworkq   addq, delq, changeq;
479        struct pfr_kentry       *p, *q;
480        struct pfr_addr          ad;
481        int                      i, rv, s = 0, xadd = 0, xdel = 0, xchange = 0;
482        long                     tzero = time_second;
483
484        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
485        if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
486            PFR_FLAG_USERIOCTL))
487                return (EINVAL);
488        kt = pfr_lookup_table(tbl);
489        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
490                return (ESRCH);
491        if (kt->pfrkt_flags & PFR_TFLAG_CONST)
492                return (EPERM);
493        tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0);
494        if (tmpkt == NULL)
495                return (ENOMEM);
496        pfr_mark_addrs(kt);
497        SLIST_INIT(&addq);
498        SLIST_INIT(&delq);
499        SLIST_INIT(&changeq);
500        for (i = 0; i < size; i++) {
501                if (COPYIN(addr+i, &ad, sizeof(ad)))
502                        senderr(EFAULT);
503                if (pfr_validate_addr(&ad))
504                        senderr(EINVAL);
505                ad.pfra_fback = PFR_FB_NONE;
506                p = pfr_lookup_addr(kt, &ad, 1);
507                if (p != NULL) {
508                        if (p->pfrke_mark) {
509                                ad.pfra_fback = PFR_FB_DUPLICATE;
510                                goto _skip;
511                        }
512                        p->pfrke_mark = 1;
513                        if (p->pfrke_not != ad.pfra_not) {
514                                SLIST_INSERT_HEAD(&changeq, p, pfrke_workq);
515                                ad.pfra_fback = PFR_FB_CHANGED;
516                                xchange++;
517                        }
518                } else {
519                        q = pfr_lookup_addr(tmpkt, &ad, 1);
520                        if (q != NULL) {
521                                ad.pfra_fback = PFR_FB_DUPLICATE;
522                                goto _skip;
523                        }
524                        p = pfr_create_kentry(&ad, 0);
525                        if (p == NULL)
526                                senderr(ENOMEM);
527                        if (pfr_route_kentry(tmpkt, p)) {
528                                pfr_destroy_kentry(p);
529                                ad.pfra_fback = PFR_FB_NONE;
530                        } else {
531                                SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
532                                ad.pfra_fback = PFR_FB_ADDED;
533                                xadd++;
534                        }
535                }
536_skip:
537                if (flags & PFR_FLAG_FEEDBACK)
538                        if (COPYOUT(&ad, addr+i, sizeof(ad)))
539                                senderr(EFAULT);
540        }
541        pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
542        if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
543                if (*size2 < size+xdel) {
544                        *size2 = size+xdel;
545                        senderr(0);
546                }
547                i = 0;
548                SLIST_FOREACH(p, &delq, pfrke_workq) {
549                        pfr_copyout_addr(&ad, p);
550                        ad.pfra_fback = PFR_FB_DELETED;
551                        if (COPYOUT(&ad, addr+size+i, sizeof(ad)))
552                                senderr(EFAULT);
553                        i++;
554                }
555        }
556        pfr_clean_node_mask(tmpkt, &addq);
557        if (!(flags & PFR_FLAG_DUMMY)) {
558                if (flags & PFR_FLAG_ATOMIC)
559                        s = splsoftnet();
560                pfr_insert_kentries(kt, &addq, tzero);
561                pfr_remove_kentries(kt, &delq);
562                pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
563                if (flags & PFR_FLAG_ATOMIC)
564                        splx(s);
565        } else
566                pfr_destroy_kentries(&addq);
567        if (nadd != NULL)
568                *nadd = xadd;
569        if (ndel != NULL)
570                *ndel = xdel;
571        if (nchange != NULL)
572                *nchange = xchange;
573        if ((flags & PFR_FLAG_FEEDBACK) && size2)
574                *size2 = size+xdel;
575        pfr_destroy_ktable(tmpkt, 0);
576        return (0);
577_bad:
578        pfr_clean_node_mask(tmpkt, &addq);
579        pfr_destroy_kentries(&addq);
580        if (flags & PFR_FLAG_FEEDBACK)
581                pfr_reset_feedback(addr, size, flags);
582        pfr_destroy_ktable(tmpkt, 0);
583        return (rv);
584}
585
586int
587pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
588        int *nmatch, int flags)
589{
590        struct pfr_ktable       *kt;
591        struct pfr_kentry       *p;
592        struct pfr_addr          ad;
593        int                      i, xmatch = 0;
594
595        ACCEPT_FLAGS(PFR_FLAG_REPLACE);
596        if (pfr_validate_table(tbl, 0, 0))
597                return (EINVAL);
598        kt = pfr_lookup_table(tbl);
599        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
600                return (ESRCH);
601
602        for (i = 0; i < size; i++) {
603                if (COPYIN(addr+i, &ad, sizeof(ad)))
604                        return (EFAULT);
605                if (pfr_validate_addr(&ad))
606                        return (EINVAL);
607                if (ADDR_NETWORK(&ad))
608                        return (EINVAL);
609                p = pfr_lookup_addr(kt, &ad, 0);
610                if (flags & PFR_FLAG_REPLACE)
611                        pfr_copyout_addr(&ad, p);
612                ad.pfra_fback = (p == NULL) ? PFR_FB_NONE :
613                    (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH);
614                if (p != NULL && !p->pfrke_not)
615                        xmatch++;
616                if (COPYOUT(&ad, addr+i, sizeof(ad)))
617                        return (EFAULT);
618        }
619        if (nmatch != NULL)
620                *nmatch = xmatch;
621        return (0);
622}
623
624int
625pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
626        int flags)
627{
628        struct pfr_ktable       *kt;
629        struct pfr_walktree      w;
630        int                      rv;
631
632        ACCEPT_FLAGS(0);
633        if (pfr_validate_table(tbl, 0, 0))
634                return (EINVAL);
635        kt = pfr_lookup_table(tbl);
636        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
637                return (ESRCH);
638        if (kt->pfrkt_cnt > *size) {
639                *size = kt->pfrkt_cnt;
640                return (0);
641        }
642
643        bzero(&w, sizeof(w));
644        w.pfrw_op = PFRW_GET_ADDRS;
645        w.pfrw_addr = addr;
646        w.pfrw_free = kt->pfrkt_cnt;
647        w.pfrw_flags = flags;
648#ifdef __FreeBSD__
649        rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
650#else
651        rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
652#endif
653        if (!rv)
654#ifdef __FreeBSD__
655                rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
656                    &w);
657#else
658                rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
659#endif
660        if (rv)
661                return (rv);
662
663        if (w.pfrw_free) {
664                printf("pfr_get_addrs: corruption detected (%d).\n",
665                    w.pfrw_free);
666                return (ENOTTY);
667        }
668        *size = kt->pfrkt_cnt;
669        return (0);
670}
671
672int
673pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
674        int flags)
675{
676        struct pfr_ktable       *kt;
677        struct pfr_walktree      w;
678        struct pfr_kentryworkq   workq;
679        int                      rv, s = 0;
680        long                     tzero = time_second;
681
682        ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */
683        if (pfr_validate_table(tbl, 0, 0))
684                return (EINVAL);
685        kt = pfr_lookup_table(tbl);
686        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
687                return (ESRCH);
688        if (kt->pfrkt_cnt > *size) {
689                *size = kt->pfrkt_cnt;
690                return (0);
691        }
692
693        bzero(&w, sizeof(w));
694        w.pfrw_op = PFRW_GET_ASTATS;
695        w.pfrw_astats = addr;
696        w.pfrw_free = kt->pfrkt_cnt;
697        w.pfrw_flags = flags;
698        if (flags & PFR_FLAG_ATOMIC)
699                s = splsoftnet();
700#ifdef __FreeBSD__
701        rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
702#else
703        rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
704#endif
705        if (!rv)
706#ifdef __FreeBSD__
707                rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
708                    &w);
709#else
710                rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
711#endif
712        if (!rv && (flags & PFR_FLAG_CLSTATS)) {
713                pfr_enqueue_addrs(kt, &workq, NULL, 0);
714                pfr_clstats_kentries(&workq, tzero, 0);
715        }
716        if (flags & PFR_FLAG_ATOMIC)
717                splx(s);
718        if (rv)
719                return (rv);
720
721        if (w.pfrw_free) {
722                printf("pfr_get_astats: corruption detected (%d).\n",
723                    w.pfrw_free);
724                return (ENOTTY);
725        }
726        *size = kt->pfrkt_cnt;
727        return (0);
728}
729
730int
731pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
732    int *nzero, int flags)
733{
734        struct pfr_ktable       *kt;
735        struct pfr_kentryworkq   workq;
736        struct pfr_kentry       *p;
737        struct pfr_addr          ad;
738        int                      i, rv, s = 0, xzero = 0;
739
740        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
741        if (pfr_validate_table(tbl, 0, 0))
742                return (EINVAL);
743        kt = pfr_lookup_table(tbl);
744        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
745                return (ESRCH);
746        SLIST_INIT(&workq);
747        for (i = 0; i < size; i++) {
748                if (COPYIN(addr+i, &ad, sizeof(ad)))
749                        senderr(EFAULT);
750                if (pfr_validate_addr(&ad))
751                        senderr(EINVAL);
752                p = pfr_lookup_addr(kt, &ad, 1);
753                if (flags & PFR_FLAG_FEEDBACK) {
754                        ad.pfra_fback = (p != NULL) ?
755                            PFR_FB_CLEARED : PFR_FB_NONE;
756                        if (COPYOUT(&ad, addr+i, sizeof(ad)))
757                                senderr(EFAULT);
758                }
759                if (p != NULL) {
760                        SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
761                        xzero++;
762                }
763        }
764
765        if (!(flags & PFR_FLAG_DUMMY)) {
766                if (flags & PFR_FLAG_ATOMIC)
767                        s = splsoftnet();
768                pfr_clstats_kentries(&workq, 0, 0);
769                if (flags & PFR_FLAG_ATOMIC)
770                        splx(s);
771        }
772        if (nzero != NULL)
773                *nzero = xzero;
774        return (0);
775_bad:
776        if (flags & PFR_FLAG_FEEDBACK)
777                pfr_reset_feedback(addr, size, flags);
778        return (rv);
779}
780
781int
782pfr_validate_addr(struct pfr_addr *ad)
783{
784        int i;
785
786        switch (ad->pfra_af) {
787#ifdef INET
788        case AF_INET:
789                if (ad->pfra_net > 32)
790                        return (-1);
791                break;
792#endif /* INET */
793#ifdef INET6
794        case AF_INET6:
795                if (ad->pfra_net > 128)
796                        return (-1);
797                break;
798#endif /* INET6 */
799        default:
800                return (-1);
801        }
802        if (ad->pfra_net < 128 &&
803                (((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8))))
804                        return (-1);
805        for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++)
806                if (((caddr_t)ad)[i])
807                        return (-1);
808        if (ad->pfra_not && ad->pfra_not != 1)
809                return (-1);
810        if (ad->pfra_fback)
811                return (-1);
812        return (0);
813}
814
815void
816pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
817        int *naddr, int sweep)
818{
819        struct pfr_walktree     w;
820
821        SLIST_INIT(workq);
822        bzero(&w, sizeof(w));
823        w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
824        w.pfrw_workq = workq;
825        if (kt->pfrkt_ip4 != NULL)
826#ifdef __FreeBSD__
827                if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree,
828                    &w))
829#else
830                if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
831#endif
832                        printf("pfr_enqueue_addrs: IPv4 walktree failed.\n");
833        if (kt->pfrkt_ip6 != NULL)
834#ifdef __FreeBSD__
835                if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
836                    &w))
837#else
838                if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
839#endif
840                        printf("pfr_enqueue_addrs: IPv6 walktree failed.\n");
841        if (naddr != NULL)
842                *naddr = w.pfrw_cnt;
843}
844
845void
846pfr_mark_addrs(struct pfr_ktable *kt)
847{
848        struct pfr_walktree     w;
849
850        bzero(&w, sizeof(w));
851        w.pfrw_op = PFRW_MARK;
852#ifdef __FreeBSD__
853        if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
854#else
855        if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
856#endif
857                printf("pfr_mark_addrs: IPv4 walktree failed.\n");
858#ifdef __FreeBSD__
859        if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
860#else
861        if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
862#endif
863                printf("pfr_mark_addrs: IPv6 walktree failed.\n");
864}
865
866
867struct pfr_kentry *
868pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
869{
870        union sockaddr_union     sa, mask;
871        struct radix_node_head  *head = NULL;   /* make the compiler happy */
872        struct pfr_kentry       *ke;
873        int                      s;
874
875        bzero(&sa, sizeof(sa));
876        if (ad->pfra_af == AF_INET) {
877                FILLIN_SIN(sa.sin, ad->pfra_ip4addr);
878                head = kt->pfrkt_ip4;
879        } else if ( ad->pfra_af == AF_INET6 ) {
880                FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr);
881                head = kt->pfrkt_ip6;
882        }
883        if (ADDR_NETWORK(ad)) {
884                pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
885                s = splsoftnet(); /* rn_lookup makes use of globals */
886#ifdef __FreeBSD__
887                PF_ASSERT(MA_OWNED);
888#endif
889                ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
890                splx(s);
891                if (ke && KENTRY_RNF_ROOT(ke))
892                        ke = NULL;
893        } else {
894                ke = (struct pfr_kentry *)rn_match(&sa, head);
895                if (ke && KENTRY_RNF_ROOT(ke))
896                        ke = NULL;
897                if (exact && ke && KENTRY_NETWORK(ke))
898                        ke = NULL;
899        }
900        return (ke);
901}
902
903struct pfr_kentry *
904pfr_create_kentry(struct pfr_addr *ad, int intr)
905{
906        struct pfr_kentry       *ke;
907
908        if (intr)
909                ke = pool_get(&pfr_kentry_pl2, PR_NOWAIT);
910        else
911                ke = pool_get(&pfr_kentry_pl, PR_NOWAIT);
912        if (ke == NULL)
913                return (NULL);
914        bzero(ke, sizeof(*ke));
915
916        if (ad->pfra_af == AF_INET)
917                FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr);
918        else if (ad->pfra_af == AF_INET6)
919                FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr);
920        ke->pfrke_af = ad->pfra_af;
921        ke->pfrke_net = ad->pfra_net;
922        ke->pfrke_not = ad->pfra_not;
923        ke->pfrke_intrpool = intr;
924        return (ke);
925}
926
927void
928pfr_destroy_kentries(struct pfr_kentryworkq *workq)
929{
930        struct pfr_kentry       *p, *q;
931
932        for (p = SLIST_FIRST(workq); p != NULL; p = q) {
933                q = SLIST_NEXT(p, pfrke_workq);
934                pfr_destroy_kentry(p);
935        }
936}
937
938void
939pfr_destroy_kentry(struct pfr_kentry *ke)
940{
941        if (ke->pfrke_intrpool)
942                pool_put(&pfr_kentry_pl2, ke);
943        else
944                pool_put(&pfr_kentry_pl, ke);
945}
946
947void
948pfr_insert_kentries(struct pfr_ktable *kt,
949    struct pfr_kentryworkq *workq, long tzero)
950{
951        struct pfr_kentry       *p;
952        int                      rv, n = 0;
953
954        SLIST_FOREACH(p, workq, pfrke_workq) {
955                rv = pfr_route_kentry(kt, p);
956                if (rv) {
957                        printf("pfr_insert_kentries: cannot route entry "
958                            "(code=%d).\n", rv);
959                        break;
960                }
961                p->pfrke_tzero = tzero;
962                n++;
963        }
964        kt->pfrkt_cnt += n;
965}
966
967int
968pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero)
969{
970        struct pfr_kentry       *p;
971        int                      rv;
972
973        p = pfr_lookup_addr(kt, ad, 1);
974        if (p != NULL)
975                return (0);
976        p = pfr_create_kentry(ad, 1);
977        if (p == NULL)
978                return (EINVAL);
979
980        rv = pfr_route_kentry(kt, p);
981        if (rv)
982                return (rv);
983
984        p->pfrke_tzero = tzero;
985        kt->pfrkt_cnt++;
986
987        return (0);
988}
989
990void
991pfr_remove_kentries(struct pfr_ktable *kt,
992    struct pfr_kentryworkq *workq)
993{
994        struct pfr_kentry       *p;
995        int                      n = 0;
996
997        SLIST_FOREACH(p, workq, pfrke_workq) {
998                pfr_unroute_kentry(kt, p);
999                n++;
1000        }
1001        kt->pfrkt_cnt -= n;
1002        pfr_destroy_kentries(workq);
1003}
1004
1005void
1006pfr_clean_node_mask(struct pfr_ktable *kt,
1007    struct pfr_kentryworkq *workq)
1008{
1009        struct pfr_kentry       *p;
1010
1011        SLIST_FOREACH(p, workq, pfrke_workq)
1012                pfr_unroute_kentry(kt, p);
1013}
1014
1015void
1016pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange)
1017{
1018        struct pfr_kentry       *p;
1019        int                      s;
1020
1021        SLIST_FOREACH(p, workq, pfrke_workq) {
1022                s = splsoftnet();
1023                if (negchange)
1024                        p->pfrke_not = !p->pfrke_not;
1025                bzero(p->pfrke_packets, sizeof(p->pfrke_packets));
1026                bzero(p->pfrke_bytes, sizeof(p->pfrke_bytes));
1027                splx(s);
1028                p->pfrke_tzero = tzero;
1029        }
1030}
1031
1032void
1033pfr_reset_feedback(struct pfr_addr *addr, int size, int flags)
1034{
1035        struct pfr_addr ad;
1036        int             i;
1037
1038        for (i = 0; i < size; i++) {
1039                if (COPYIN(addr+i, &ad, sizeof(ad)))
1040                        break;
1041                ad.pfra_fback = PFR_FB_NONE;
1042                if (COPYOUT(&ad, addr+i, sizeof(ad)))
1043                        break;
1044        }
1045}
1046
1047void
1048pfr_prepare_network(union sockaddr_union *sa, int af, int net)
1049{
1050        int     i;
1051
1052        bzero(sa, sizeof(*sa));
1053        if (af == AF_INET) {
1054                sa->sin.sin_len = sizeof(sa->sin);
1055                sa->sin.sin_family = AF_INET;
1056                sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0;
1057        } else if (af == AF_INET6) {
1058                sa->sin6.sin6_len = sizeof(sa->sin6);
1059                sa->sin6.sin6_family = AF_INET6;
1060                for (i = 0; i < 4; i++) {
1061                        if (net <= 32) {
1062                                sa->sin6.sin6_addr.s6_addr32[i] =
1063                                    net ? htonl(-1 << (32-net)) : 0;
1064                                break;
1065                        }
1066                        sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF;
1067                        net -= 32;
1068                }
1069        }
1070}
1071
1072int
1073pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
1074{
1075        union sockaddr_union     mask;
1076        struct radix_node       *rn;
1077        struct radix_node_head  *head = NULL;   /* make the compiler happy */
1078        int                      s;
1079
1080        bzero(ke->pfrke_node, sizeof(ke->pfrke_node));
1081        if (ke->pfrke_af == AF_INET)
1082                head = kt->pfrkt_ip4;
1083        else if (ke->pfrke_af == AF_INET6)
1084                head = kt->pfrkt_ip6;
1085
1086        s = splsoftnet();
1087#ifdef __FreeBSD__
1088        PF_ASSERT(MA_OWNED);
1089#endif
1090        if (KENTRY_NETWORK(ke)) {
1091                pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
1092                rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node);
1093        } else
1094                rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node);
1095        splx(s);
1096
1097        return (rn == NULL ? -1 : 0);
1098}
1099
1100int
1101pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
1102{
1103        union sockaddr_union     mask;
1104        struct radix_node       *rn;
1105        struct radix_node_head  *head = NULL;   /* make the compiler happy */
1106        int                      s;
1107
1108        if (ke->pfrke_af == AF_INET)
1109                head = kt->pfrkt_ip4;
1110        else if (ke->pfrke_af == AF_INET6)
1111                head = kt->pfrkt_ip6;
1112
1113        s = splsoftnet();
1114#ifdef __FreeBSD__
1115        PF_ASSERT(MA_OWNED);
1116#endif
1117        if (KENTRY_NETWORK(ke)) {
1118                pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
1119#ifdef __FreeBSD__
1120                rn = rn_delete(&ke->pfrke_sa, &mask, head);
1121#else
1122                rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL);
1123#endif
1124        } else
1125#ifdef __FreeBSD__
1126                rn = rn_delete(&ke->pfrke_sa, NULL, head);
1127#else
1128                rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL);
1129#endif
1130        splx(s);
1131
1132        if (rn == NULL) {
1133                printf("pfr_unroute_kentry: delete failed.\n");
1134                return (-1);
1135        }
1136        return (0);
1137}
1138
1139void
1140pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke)
1141{
1142        bzero(ad, sizeof(*ad));
1143        if (ke == NULL)
1144                return;
1145        ad->pfra_af = ke->pfrke_af;
1146        ad->pfra_net = ke->pfrke_net;
1147        ad->pfra_not = ke->pfrke_not;
1148        if (ad->pfra_af == AF_INET)
1149                ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr;
1150        else if (ad->pfra_af == AF_INET6)
1151                ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr;
1152}
1153
1154int
1155pfr_walktree(struct radix_node *rn, void *arg)
1156{
1157        struct pfr_kentry       *ke = (struct pfr_kentry *)rn;
1158        struct pfr_walktree     *w = arg;
1159        int                      s, flags = w->pfrw_flags;
1160
1161        switch (w->pfrw_op) {
1162        case PFRW_MARK:
1163                ke->pfrke_mark = 0;
1164                break;
1165        case PFRW_SWEEP:
1166                if (ke->pfrke_mark)
1167                        break;
1168                /* FALLTHROUGH */
1169        case PFRW_ENQUEUE:
1170                SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq);
1171                w->pfrw_cnt++;
1172                break;
1173        case PFRW_GET_ADDRS:
1174                if (w->pfrw_free-- > 0) {
1175                        struct pfr_addr ad;
1176
1177                        pfr_copyout_addr(&ad, ke);
1178                        if (COPYOUT(&ad, w->pfrw_addr, sizeof(ad)))
1179                                return (EFAULT);
1180                        w->pfrw_addr++;
1181                }
1182                break;
1183        case PFRW_GET_ASTATS:
1184                if (w->pfrw_free-- > 0) {
1185                        struct pfr_astats as;
1186
1187                        pfr_copyout_addr(&as.pfras_a, ke);
1188
1189                        s = splsoftnet();
1190                        bcopy(ke->pfrke_packets, as.pfras_packets,
1191                            sizeof(as.pfras_packets));
1192                        bcopy(ke->pfrke_bytes, as.pfras_bytes,
1193                            sizeof(as.pfras_bytes));
1194                        splx(s);
1195                        as.pfras_tzero = ke->pfrke_tzero;
1196
1197                        if (COPYOUT(&as, w->pfrw_astats, sizeof(as)))
1198                                return (EFAULT);
1199                        w->pfrw_astats++;
1200                }
1201                break;
1202        case PFRW_POOL_GET:
1203                if (ke->pfrke_not)
1204                        break; /* negative entries are ignored */
1205                if (!w->pfrw_cnt--) {
1206                        w->pfrw_kentry = ke;
1207                        return (1); /* finish search */
1208                }
1209                break;
1210        case PFRW_DYNADDR_UPDATE:
1211                if (ke->pfrke_af == AF_INET) {
1212                        if (w->pfrw_dyn->pfid_acnt4++ > 0)
1213                                break;
1214                        pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net);
1215                        w->pfrw_dyn->pfid_addr4 = *SUNION2PF(
1216                            &ke->pfrke_sa, AF_INET);
1217                        w->pfrw_dyn->pfid_mask4 = *SUNION2PF(
1218                            &pfr_mask, AF_INET);
1219                } else if (ke->pfrke_af == AF_INET6){
1220                        if (w->pfrw_dyn->pfid_acnt6++ > 0)
1221                                break;
1222                        pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net);
1223                        w->pfrw_dyn->pfid_addr6 = *SUNION2PF(
1224                            &ke->pfrke_sa, AF_INET6);
1225                        w->pfrw_dyn->pfid_mask6 = *SUNION2PF(
1226                            &pfr_mask, AF_INET6);
1227                }
1228                break;
1229        }
1230        return (0);
1231}
1232
1233int
1234pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
1235{
1236        struct pfr_ktableworkq   workq;
1237        struct pfr_ktable       *p;
1238        int                      s = 0, xdel = 0;
1239
1240        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ALLRSETS);
1241        if (pfr_fix_anchor(filter->pfrt_anchor))
1242                return (EINVAL);
1243        if (pfr_table_count(filter, flags) < 0)
1244                return (ENOENT);
1245
1246        SLIST_INIT(&workq);
1247        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1248                if (pfr_skip_table(filter, p, flags))
1249                        continue;
1250                if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR))
1251                        continue;
1252                if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE))
1253                        continue;
1254                p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
1255                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1256                xdel++;
1257        }
1258        if (!(flags & PFR_FLAG_DUMMY)) {
1259                if (flags & PFR_FLAG_ATOMIC)
1260                        s = splsoftnet();
1261                pfr_setflags_ktables(&workq);
1262                if (flags & PFR_FLAG_ATOMIC)
1263                        splx(s);
1264        }
1265        if (ndel != NULL)
1266                *ndel = xdel;
1267        return (0);
1268}
1269
1270int
1271pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
1272{
1273        struct pfr_ktableworkq   addq, changeq;
1274        struct pfr_ktable       *p, *q, *r, key;
1275        int                      i, rv, s = 0, xadd = 0;
1276        long                     tzero = time_second;
1277
1278        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
1279        SLIST_INIT(&addq);
1280        SLIST_INIT(&changeq);
1281        for (i = 0; i < size; i++) {
1282                if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
1283                        senderr(EFAULT);
1284                if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK,
1285                    flags & PFR_FLAG_USERIOCTL))
1286                        senderr(EINVAL);
1287                key.pfrkt_flags |= PFR_TFLAG_ACTIVE;
1288                p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1289                if (p == NULL) {
1290                        p = pfr_create_ktable(&key.pfrkt_t, tzero, 1);
1291                        if (p == NULL)
1292                                senderr(ENOMEM);
1293                        SLIST_FOREACH(q, &addq, pfrkt_workq) {
1294                                if (!pfr_ktable_compare(p, q))
1295                                        goto _skip;
1296                        }
1297                        SLIST_INSERT_HEAD(&addq, p, pfrkt_workq);
1298                        xadd++;
1299                        if (!key.pfrkt_anchor[0])
1300                                goto _skip;
1301
1302                        /* find or create root table */
1303                        bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor));
1304                        r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1305                        if (r != NULL) {
1306                                p->pfrkt_root = r;
1307                                goto _skip;
1308                        }
1309                        SLIST_FOREACH(q, &addq, pfrkt_workq) {
1310                                if (!pfr_ktable_compare(&key, q)) {
1311                                        p->pfrkt_root = q;
1312                                        goto _skip;
1313                                }
1314                        }
1315                        key.pfrkt_flags = 0;
1316                        r = pfr_create_ktable(&key.pfrkt_t, 0, 1);
1317                        if (r == NULL)
1318                                senderr(ENOMEM);
1319                        SLIST_INSERT_HEAD(&addq, r, pfrkt_workq);
1320                        p->pfrkt_root = r;
1321                } else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1322                        SLIST_FOREACH(q, &changeq, pfrkt_workq)
1323                                if (!pfr_ktable_compare(&key, q))
1324                                        goto _skip;
1325                        p->pfrkt_nflags = (p->pfrkt_flags &
1326                            ~PFR_TFLAG_USRMASK) | key.pfrkt_flags;
1327                        SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
1328                        xadd++;
1329                }
1330_skip:
1331        ;
1332        }
1333        if (!(flags & PFR_FLAG_DUMMY)) {
1334                if (flags & PFR_FLAG_ATOMIC)
1335                        s = splsoftnet();
1336                pfr_insert_ktables(&addq);
1337                pfr_setflags_ktables(&changeq);
1338                if (flags & PFR_FLAG_ATOMIC)
1339                        splx(s);
1340        } else
1341                 pfr_destroy_ktables(&addq, 0);
1342        if (nadd != NULL)
1343                *nadd = xadd;
1344        return (0);
1345_bad:
1346        pfr_destroy_ktables(&addq, 0);
1347        return (rv);
1348}
1349
1350int
1351pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
1352{
1353        struct pfr_ktableworkq   workq;
1354        struct pfr_ktable       *p, *q, key;
1355        int                      i, s = 0, xdel = 0;
1356
1357        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
1358        SLIST_INIT(&workq);
1359        for (i = 0; i < size; i++) {
1360                if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
1361                        return (EFAULT);
1362                if (pfr_validate_table(&key.pfrkt_t, 0,
1363                    flags & PFR_FLAG_USERIOCTL))
1364                        return (EINVAL);
1365                p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1366                if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1367                        SLIST_FOREACH(q, &workq, pfrkt_workq)
1368                                if (!pfr_ktable_compare(p, q))
1369                                        goto _skip;
1370                        p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
1371                        SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1372                        xdel++;
1373                }
1374_skip:
1375        ;
1376        }
1377
1378        if (!(flags & PFR_FLAG_DUMMY)) {
1379                if (flags & PFR_FLAG_ATOMIC)
1380                        s = splsoftnet();
1381                pfr_setflags_ktables(&workq);
1382                if (flags & PFR_FLAG_ATOMIC)
1383                        splx(s);
1384        }
1385        if (ndel != NULL)
1386                *ndel = xdel;
1387        return (0);
1388}
1389
1390int
1391pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
1392        int flags)
1393{
1394        struct pfr_ktable       *p;
1395        int                      n, nn;
1396
1397        ACCEPT_FLAGS(PFR_FLAG_ALLRSETS);
1398        if (pfr_fix_anchor(filter->pfrt_anchor))
1399                return (EINVAL);
1400        n = nn = pfr_table_count(filter, flags);
1401        if (n < 0)
1402                return (ENOENT);
1403        if (n > *size) {
1404                *size = n;
1405                return (0);
1406        }
1407        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1408                if (pfr_skip_table(filter, p, flags))
1409                        continue;
1410                if (n-- <= 0)
1411                        continue;
1412                if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl)))
1413                        return (EFAULT);
1414        }
1415        if (n) {
1416                printf("pfr_get_tables: corruption detected (%d).\n", n);
1417                return (ENOTTY);
1418        }
1419        *size = nn;
1420        return (0);
1421}
1422
1423int
1424pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
1425        int flags)
1426{
1427        struct pfr_ktable       *p;
1428        struct pfr_ktableworkq   workq;
1429        int                      s = 0, n, nn;
1430        long                     tzero = time_second;
1431
1432        ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS);
1433                                        /* XXX PFR_FLAG_CLSTATS disabled */
1434        if (pfr_fix_anchor(filter->pfrt_anchor))
1435                return (EINVAL);
1436        n = nn = pfr_table_count(filter, flags);
1437        if (n < 0)
1438                return (ENOENT);
1439        if (n > *size) {
1440                *size = n;
1441                return (0);
1442        }
1443        SLIST_INIT(&workq);
1444        if (flags & PFR_FLAG_ATOMIC)
1445                s = splsoftnet();
1446        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1447                if (pfr_skip_table(filter, p, flags))
1448                        continue;
1449                if (n-- <= 0)
1450                        continue;
1451                if (!(flags & PFR_FLAG_ATOMIC))
1452                        s = splsoftnet();
1453                if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl))) {
1454                        if (!(flags & PFR_FLAG_ATOMIC))
1455                                splx(s);
1456                        return (EFAULT);
1457                }
1458                if (!(flags & PFR_FLAG_ATOMIC))
1459                        splx(s);
1460                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1461        }
1462        if (flags & PFR_FLAG_CLSTATS)
1463                pfr_clstats_ktables(&workq, tzero,
1464                    flags & PFR_FLAG_ADDRSTOO);
1465        if (flags & PFR_FLAG_ATOMIC)
1466                splx(s);
1467        if (n) {
1468                printf("pfr_get_tstats: corruption detected (%d).\n", n);
1469                return (ENOTTY);
1470        }
1471        *size = nn;
1472        return (0);
1473}
1474
1475int
1476pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
1477{
1478        struct pfr_ktableworkq   workq;
1479        struct pfr_ktable       *p, key;
1480        int                      i, s = 0, xzero = 0;
1481        long                     tzero = time_second;
1482
1483        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO);
1484        SLIST_INIT(&workq);
1485        for (i = 0; i < size; i++) {
1486                if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
1487                        return (EFAULT);
1488                if (pfr_validate_table(&key.pfrkt_t, 0, 0))
1489                        return (EINVAL);
1490                p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1491                if (p != NULL) {
1492                        SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1493                        xzero++;
1494                }
1495        }
1496        if (!(flags & PFR_FLAG_DUMMY)) {
1497                if (flags & PFR_FLAG_ATOMIC)
1498                        s = splsoftnet();
1499                pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO);
1500                if (flags & PFR_FLAG_ATOMIC)
1501                        splx(s);
1502        }
1503        if (nzero != NULL)
1504                *nzero = xzero;
1505        return (0);
1506}
1507
1508int
1509pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
1510        int *nchange, int *ndel, int flags)
1511{
1512        struct pfr_ktableworkq   workq;
1513        struct pfr_ktable       *p, *q, key;
1514        int                      i, s = 0, xchange = 0, xdel = 0;
1515
1516        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
1517        if ((setflag & ~PFR_TFLAG_USRMASK) ||
1518            (clrflag & ~PFR_TFLAG_USRMASK) ||
1519            (setflag & clrflag))
1520                return (EINVAL);
1521        SLIST_INIT(&workq);
1522        for (i = 0; i < size; i++) {
1523                if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
1524                        return (EFAULT);
1525                if (pfr_validate_table(&key.pfrkt_t, 0,
1526                    flags & PFR_FLAG_USERIOCTL))
1527                        return (EINVAL);
1528                p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1529                if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1530                        p->pfrkt_nflags = (p->pfrkt_flags | setflag) &
1531                            ~clrflag;
1532                        if (p->pfrkt_nflags == p->pfrkt_flags)
1533                                goto _skip;
1534                        SLIST_FOREACH(q, &workq, pfrkt_workq)
1535                                if (!pfr_ktable_compare(p, q))
1536                                        goto _skip;
1537                        SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1538                        if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) &&
1539                            (clrflag & PFR_TFLAG_PERSIST) &&
1540                            !(p->pfrkt_flags & PFR_TFLAG_REFERENCED))
1541                                xdel++;
1542                        else
1543                                xchange++;
1544                }
1545_skip:
1546        ;
1547        }
1548        if (!(flags & PFR_FLAG_DUMMY)) {
1549                if (flags & PFR_FLAG_ATOMIC)
1550                        s = splsoftnet();
1551                pfr_setflags_ktables(&workq);
1552                if (flags & PFR_FLAG_ATOMIC)
1553                        splx(s);
1554        }
1555        if (nchange != NULL)
1556                *nchange = xchange;
1557        if (ndel != NULL)
1558                *ndel = xdel;
1559        return (0);
1560}
1561
1562int
1563pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags)
1564{
1565        struct pfr_ktableworkq   workq;
1566        struct pfr_ktable       *p;
1567        struct pf_ruleset       *rs;
1568        int                      xdel = 0;
1569
1570        ACCEPT_FLAGS(PFR_FLAG_DUMMY);
1571        rs = pf_find_or_create_ruleset(trs->pfrt_anchor);
1572        if (rs == NULL)
1573                return (ENOMEM);
1574        SLIST_INIT(&workq);
1575        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1576                if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1577                    pfr_skip_table(trs, p, 0))
1578                        continue;
1579                p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
1580                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1581                xdel++;
1582        }
1583        if (!(flags & PFR_FLAG_DUMMY)) {
1584                pfr_setflags_ktables(&workq);
1585                if (ticket != NULL)
1586                        *ticket = ++rs->tticket;
1587                rs->topen = 1;
1588        } else
1589                pf_remove_if_empty_ruleset(rs);
1590        if (ndel != NULL)
1591                *ndel = xdel;
1592        return (0);
1593}
1594
1595int
1596pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
1597    int *nadd, int *naddr, u_int32_t ticket, int flags)
1598{
1599        struct pfr_ktableworkq   tableq;
1600        struct pfr_kentryworkq   addrq;
1601        struct pfr_ktable       *kt, *rt, *shadow, key;
1602        struct pfr_kentry       *p;
1603        struct pfr_addr          ad;
1604        struct pf_ruleset       *rs;
1605        int                      i, rv, xadd = 0, xaddr = 0;
1606
1607        ACCEPT_FLAGS(PFR_FLAG_DUMMY|PFR_FLAG_ADDRSTOO);
1608        if (size && !(flags & PFR_FLAG_ADDRSTOO))
1609                return (EINVAL);
1610        if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK,
1611            flags & PFR_FLAG_USERIOCTL))
1612                return (EINVAL);
1613        rs = pf_find_ruleset(tbl->pfrt_anchor);
1614        if (rs == NULL || !rs->topen || ticket != rs->tticket)
1615                return (EBUSY);
1616        tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
1617        SLIST_INIT(&tableq);
1618        kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl);
1619        if (kt == NULL) {
1620                kt = pfr_create_ktable(tbl, 0, 1);
1621                if (kt == NULL)
1622                        return (ENOMEM);
1623                SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq);
1624                xadd++;
1625                if (!tbl->pfrt_anchor[0])
1626                        goto _skip;
1627
1628                /* find or create root table */
1629                bzero(&key, sizeof(key));
1630                strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name));
1631                rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1632                if (rt != NULL) {
1633                        kt->pfrkt_root = rt;
1634                        goto _skip;
1635                }
1636                rt = pfr_create_ktable(&key.pfrkt_t, 0, 1);
1637                if (rt == NULL) {
1638                        pfr_destroy_ktables(&tableq, 0);
1639                        return (ENOMEM);
1640                }
1641                SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq);
1642                kt->pfrkt_root = rt;
1643        } else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE))
1644                xadd++;
1645_skip:
1646        shadow = pfr_create_ktable(tbl, 0, 0);
1647        if (shadow == NULL) {
1648                pfr_destroy_ktables(&tableq, 0);
1649                return (ENOMEM);
1650        }
1651        SLIST_INIT(&addrq);
1652        for (i = 0; i < size; i++) {
1653                if (COPYIN(addr+i, &ad, sizeof(ad)))
1654                        senderr(EFAULT);
1655                if (pfr_validate_addr(&ad))
1656                        senderr(EINVAL);
1657                if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
1658                        continue;
1659                p = pfr_create_kentry(&ad, 0);
1660                if (p == NULL)
1661                        senderr(ENOMEM);
1662                if (pfr_route_kentry(shadow, p)) {
1663                        pfr_destroy_kentry(p);
1664                        continue;
1665                }
1666                SLIST_INSERT_HEAD(&addrq, p, pfrke_workq);
1667                xaddr++;
1668        }
1669        if (!(flags & PFR_FLAG_DUMMY)) {
1670                if (kt->pfrkt_shadow != NULL)
1671                        pfr_destroy_ktable(kt->pfrkt_shadow, 1);
1672                kt->pfrkt_flags |= PFR_TFLAG_INACTIVE;
1673                pfr_insert_ktables(&tableq);
1674                shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ?
1675                    xaddr : NO_ADDRESSES;
1676                kt->pfrkt_shadow = shadow;
1677        } else {
1678                pfr_clean_node_mask(shadow, &addrq);
1679                pfr_destroy_ktable(shadow, 0);
1680                pfr_destroy_ktables(&tableq, 0);
1681                pfr_destroy_kentries(&addrq);
1682        }
1683        if (nadd != NULL)
1684                *nadd = xadd;
1685        if (naddr != NULL)
1686                *naddr = xaddr;
1687        return (0);
1688_bad:
1689        pfr_destroy_ktable(shadow, 0);
1690        pfr_destroy_ktables(&tableq, 0);
1691        pfr_destroy_kentries(&addrq);
1692        return (rv);
1693}
1694
1695int
1696pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags)
1697{
1698        struct pfr_ktableworkq   workq;
1699        struct pfr_ktable       *p;
1700        struct pf_ruleset       *rs;
1701        int                      xdel = 0;
1702
1703        ACCEPT_FLAGS(PFR_FLAG_DUMMY);
1704        rs = pf_find_ruleset(trs->pfrt_anchor);
1705        if (rs == NULL || !rs->topen || ticket != rs->tticket)
1706                return (0);
1707        SLIST_INIT(&workq);
1708        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1709                if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1710                    pfr_skip_table(trs, p, 0))
1711                        continue;
1712                p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
1713                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1714                xdel++;
1715        }
1716        if (!(flags & PFR_FLAG_DUMMY)) {
1717                pfr_setflags_ktables(&workq);
1718                rs->topen = 0;
1719                pf_remove_if_empty_ruleset(rs);
1720        }
1721        if (ndel != NULL)
1722                *ndel = xdel;
1723        return (0);
1724}
1725
1726int
1727pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
1728    int *nchange, int flags)
1729{
1730        struct pfr_ktable       *p, *q;
1731        struct pfr_ktableworkq   workq;
1732        struct pf_ruleset       *rs;
1733        int                      s = 0, xadd = 0, xchange = 0;
1734        long                     tzero = time_second;
1735
1736        ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
1737        rs = pf_find_ruleset(trs->pfrt_anchor);
1738        if (rs == NULL || !rs->topen || ticket != rs->tticket)
1739                return (EBUSY);
1740
1741        SLIST_INIT(&workq);
1742        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1743                if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1744                    pfr_skip_table(trs, p, 0))
1745                        continue;
1746                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1747                if (p->pfrkt_flags & PFR_TFLAG_ACTIVE)
1748                        xchange++;
1749                else
1750                        xadd++;
1751        }
1752
1753        if (!(flags & PFR_FLAG_DUMMY)) {
1754                if (flags & PFR_FLAG_ATOMIC)
1755                        s = splsoftnet();
1756                for (p = SLIST_FIRST(&workq); p != NULL; p = q) {
1757                        q = SLIST_NEXT(p, pfrkt_workq);
1758                        pfr_commit_ktable(p, tzero);
1759                }
1760                if (flags & PFR_FLAG_ATOMIC)
1761                        splx(s);
1762                rs->topen = 0;
1763                pf_remove_if_empty_ruleset(rs);
1764        }
1765        if (nadd != NULL)
1766                *nadd = xadd;
1767        if (nchange != NULL)
1768                *nchange = xchange;
1769
1770        return (0);
1771}
1772
1773void
1774pfr_commit_ktable(struct pfr_ktable *kt, long tzero)
1775{
1776        struct pfr_ktable       *shadow = kt->pfrkt_shadow;
1777        int                      nflags;
1778
1779        if (shadow->pfrkt_cnt == NO_ADDRESSES) {
1780                if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
1781                        pfr_clstats_ktable(kt, tzero, 1);
1782        } else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
1783                /* kt might contain addresses */
1784                struct pfr_kentryworkq   addrq, addq, changeq, delq, garbageq;
1785                struct pfr_kentry       *p, *q, *next;
1786                struct pfr_addr          ad;
1787
1788                pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
1789                pfr_mark_addrs(kt);
1790                SLIST_INIT(&addq);
1791                SLIST_INIT(&changeq);
1792                SLIST_INIT(&delq);
1793                SLIST_INIT(&garbageq);
1794                pfr_clean_node_mask(shadow, &addrq);
1795                for (p = SLIST_FIRST(&addrq); p != NULL; p = next) {
1796                        next = SLIST_NEXT(p, pfrke_workq);      /* XXX */
1797                        pfr_copyout_addr(&ad, p);
1798                        q = pfr_lookup_addr(kt, &ad, 1);
1799                        if (q != NULL) {
1800                                if (q->pfrke_not != p->pfrke_not)
1801                                        SLIST_INSERT_HEAD(&changeq, q,
1802                                            pfrke_workq);
1803                                q->pfrke_mark = 1;
1804                                SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq);
1805                        } else {
1806                                p->pfrke_tzero = tzero;
1807                                SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
1808                        }
1809                }
1810                pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY);
1811                pfr_insert_kentries(kt, &addq, tzero);
1812                pfr_remove_kentries(kt, &delq);
1813                pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
1814                pfr_destroy_kentries(&garbageq);
1815        } else {
1816                /* kt cannot contain addresses */
1817                SWAP(struct radix_node_head *, kt->pfrkt_ip4,
1818                    shadow->pfrkt_ip4);
1819                SWAP(struct radix_node_head *, kt->pfrkt_ip6,
1820                    shadow->pfrkt_ip6);
1821                SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt);
1822                pfr_clstats_ktable(kt, tzero, 1);
1823        }
1824        nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) |
1825            (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE)
1826                & ~PFR_TFLAG_INACTIVE;
1827        pfr_destroy_ktable(shadow, 0);
1828        kt->pfrkt_shadow = NULL;
1829        pfr_setflags_ktable(kt, nflags);
1830}
1831
1832int
1833pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved)
1834{
1835        int i;
1836
1837        if (!tbl->pfrt_name[0])
1838                return (-1);
1839        if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR))
1840                 return (-1);
1841        if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1])
1842                return (-1);
1843        for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++)
1844                if (tbl->pfrt_name[i])
1845                        return (-1);
1846        if (pfr_fix_anchor(tbl->pfrt_anchor))
1847                return (-1);
1848        if (tbl->pfrt_flags & ~allowedflags)
1849                return (-1);
1850        return (0);
1851}
1852
1853/*
1854 * Rewrite anchors referenced by tables to remove slashes
1855 * and check for validity.
1856 */
1857int
1858pfr_fix_anchor(char *anchor)
1859{
1860        size_t siz = MAXPATHLEN;
1861        int i;
1862
1863        if (anchor[0] == '/') {
1864                char *path;
1865                int off;
1866
1867                path = anchor;
1868                off = 1;
1869                while (*++path == '/')
1870                        off++;
1871                bcopy(path, anchor, siz - off);
1872                memset(anchor + siz - off, 0, off);
1873        }
1874        if (anchor[siz - 1])
1875                return (-1);
1876        for (i = strlen(anchor); i < siz; i++)
1877                if (anchor[i])
1878                        return (-1);
1879        return (0);
1880}
1881
1882int
1883pfr_table_count(struct pfr_table *filter, int flags)
1884{
1885        struct pf_ruleset *rs;
1886
1887        if (flags & PFR_FLAG_ALLRSETS)
1888                return (pfr_ktable_cnt);
1889        if (filter->pfrt_anchor[0]) {
1890                rs = pf_find_ruleset(filter->pfrt_anchor);
1891                return ((rs != NULL) ? rs->tables : -1);
1892        }
1893        return (pf_main_ruleset.tables);
1894}
1895
1896int
1897pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags)
1898{
1899        if (flags & PFR_FLAG_ALLRSETS)
1900                return (0);
1901        if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor))
1902                return (1);
1903        return (0);
1904}
1905
1906void
1907pfr_insert_ktables(struct pfr_ktableworkq *workq)
1908{
1909        struct pfr_ktable       *p;
1910
1911        SLIST_FOREACH(p, workq, pfrkt_workq)
1912                pfr_insert_ktable(p);
1913}
1914
1915void
1916pfr_insert_ktable(struct pfr_ktable *kt)
1917{
1918        RB_INSERT(pfr_ktablehead, &pfr_ktables, kt);
1919        pfr_ktable_cnt++;
1920        if (kt->pfrkt_root != NULL)
1921                if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++)
1922                        pfr_setflags_ktable(kt->pfrkt_root,
1923                            kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR);
1924}
1925
1926void
1927pfr_setflags_ktables(struct pfr_ktableworkq *workq)
1928{
1929        struct pfr_ktable       *p, *q;
1930
1931        for (p = SLIST_FIRST(workq); p; p = q) {
1932                q = SLIST_NEXT(p, pfrkt_workq);
1933                pfr_setflags_ktable(p, p->pfrkt_nflags);
1934        }
1935}
1936
1937void
1938pfr_setflags_ktable(struct pfr_ktable *kt, int newf)
1939{
1940        struct pfr_kentryworkq  addrq;
1941
1942        if (!(newf & PFR_TFLAG_REFERENCED) &&
1943            !(newf & PFR_TFLAG_PERSIST))
1944                newf &= ~PFR_TFLAG_ACTIVE;
1945        if (!(newf & PFR_TFLAG_ACTIVE))
1946                newf &= ~PFR_TFLAG_USRMASK;
1947        if (!(newf & PFR_TFLAG_SETMASK)) {
1948                RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt);
1949                if (kt->pfrkt_root != NULL)
1950                        if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR])
1951                                pfr_setflags_ktable(kt->pfrkt_root,
1952                                    kt->pfrkt_root->pfrkt_flags &
1953                                        ~PFR_TFLAG_REFDANCHOR);
1954                pfr_destroy_ktable(kt, 1);
1955                pfr_ktable_cnt--;
1956                return;
1957        }
1958        if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) {
1959                pfr_enqueue_addrs(kt, &addrq, NULL, 0);
1960                pfr_remove_kentries(kt, &addrq);
1961        }
1962        if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) {
1963                pfr_destroy_ktable(kt->pfrkt_shadow, 1);
1964                kt->pfrkt_shadow = NULL;
1965        }
1966        kt->pfrkt_flags = newf;
1967}
1968
1969void
1970pfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse)
1971{
1972        struct pfr_ktable       *p;
1973
1974        SLIST_FOREACH(p, workq, pfrkt_workq)
1975                pfr_clstats_ktable(p, tzero, recurse);
1976}
1977
1978void
1979pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse)
1980{
1981        struct pfr_kentryworkq   addrq;
1982        int                      s;
1983
1984        if (recurse) {
1985                pfr_enqueue_addrs(kt, &addrq, NULL, 0);
1986                pfr_clstats_kentries(&addrq, tzero, 0);
1987        }
1988        s = splsoftnet();
1989        bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets));
1990        bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes));
1991        kt->pfrkt_match = kt->pfrkt_nomatch = 0;
1992        splx(s);
1993        kt->pfrkt_tzero = tzero;
1994}
1995
1996struct pfr_ktable *
1997pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset)
1998{
1999        struct pfr_ktable       *kt;
2000        struct pf_ruleset       *rs;
2001
2002        kt = pool_get(&pfr_ktable_pl, PR_NOWAIT);
2003        if (kt == NULL)
2004                return (NULL);
2005        bzero(kt, sizeof(*kt));
2006        kt->pfrkt_t = *tbl;
2007
2008        if (attachruleset) {
2009                rs = pf_find_or_create_ruleset(tbl->pfrt_anchor);
2010                if (!rs) {
2011                        pfr_destroy_ktable(kt, 0);
2012                        return (NULL);
2013                }
2014                kt->pfrkt_rs = rs;
2015                rs->tables++;
2016        }
2017
2018        if (!rn_inithead((void **)&kt->pfrkt_ip4,
2019            offsetof(struct sockaddr_in, sin_addr) * 8) ||
2020            !rn_inithead((void **)&kt->pfrkt_ip6,
2021            offsetof(struct sockaddr_in6, sin6_addr) * 8)) {
2022                pfr_destroy_ktable(kt, 0);
2023                return (NULL);
2024        }
2025        kt->pfrkt_tzero = tzero;
2026
2027        return (kt);
2028}
2029
2030void
2031pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
2032{
2033        struct pfr_ktable       *p, *q;
2034
2035        for (p = SLIST_FIRST(workq); p; p = q) {
2036                q = SLIST_NEXT(p, pfrkt_workq);
2037                pfr_destroy_ktable(p, flushaddr);
2038        }
2039}
2040
2041void
2042pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
2043{
2044        struct pfr_kentryworkq   addrq;
2045
2046        if (flushaddr) {
2047                pfr_enqueue_addrs(kt, &addrq, NULL, 0);
2048                pfr_clean_node_mask(kt, &addrq);
2049                pfr_destroy_kentries(&addrq);
2050        }
2051#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
2052        if (kt->pfrkt_ip4 != NULL) {
2053                RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip4);
2054                free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
2055        }
2056        if (kt->pfrkt_ip6 != NULL) {
2057                RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip6);
2058                free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
2059        }
2060#else
2061        if (kt->pfrkt_ip4 != NULL)
2062                free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
2063        if (kt->pfrkt_ip6 != NULL)
2064                free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
2065#endif
2066        if (kt->pfrkt_shadow != NULL)
2067                pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
2068        if (kt->pfrkt_rs != NULL) {
2069                kt->pfrkt_rs->tables--;
2070                pf_remove_if_empty_ruleset(kt->pfrkt_rs);
2071        }
2072        pool_put(&pfr_ktable_pl, kt);
2073}
2074
2075int
2076pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
2077{
2078        int d;
2079
2080        if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE)))
2081                return (d);
2082        return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor));
2083}
2084
2085struct pfr_ktable *
2086pfr_lookup_table(struct pfr_table *tbl)
2087{
2088        /* struct pfr_ktable start like a struct pfr_table */
2089        return (RB_FIND(pfr_ktablehead, &pfr_ktables,
2090            (struct pfr_ktable *)tbl));
2091}
2092
2093int
2094pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
2095{
2096        struct pfr_kentry       *ke = NULL;
2097        int                      match;
2098
2099        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2100                kt = kt->pfrkt_root;
2101        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2102                return (0);
2103
2104        switch (af) {
2105#ifdef INET
2106        case AF_INET:
2107                pfr_sin.sin_addr.s_addr = a->addr32[0];
2108                ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
2109                if (ke && KENTRY_RNF_ROOT(ke))
2110                        ke = NULL;
2111                break;
2112#endif /* INET */
2113#ifdef INET6
2114        case AF_INET6:
2115                bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
2116                ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
2117                if (ke && KENTRY_RNF_ROOT(ke))
2118                        ke = NULL;
2119                break;
2120#endif /* INET6 */
2121        }
2122        match = (ke && !ke->pfrke_not);
2123        if (match)
2124                kt->pfrkt_match++;
2125        else
2126                kt->pfrkt_nomatch++;
2127        return (match);
2128}
2129
2130void
2131pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
2132    u_int64_t len, int dir_out, int op_pass, int notrule)
2133{
2134        struct pfr_kentry       *ke = NULL;
2135
2136        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2137                kt = kt->pfrkt_root;
2138        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2139                return;
2140
2141        switch (af) {
2142#ifdef INET
2143        case AF_INET:
2144                pfr_sin.sin_addr.s_addr = a->addr32[0];
2145                ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
2146                if (ke && KENTRY_RNF_ROOT(ke))
2147                        ke = NULL;
2148                break;
2149#endif /* INET */
2150#ifdef INET6
2151        case AF_INET6:
2152                bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
2153                ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
2154                if (ke && KENTRY_RNF_ROOT(ke))
2155                        ke = NULL;
2156                break;
2157#endif /* INET6 */
2158        default:
2159                ;
2160        }
2161        if ((ke == NULL || ke->pfrke_not) != notrule) {
2162                if (op_pass != PFR_OP_PASS)
2163                        printf("pfr_update_stats: assertion failed.\n");
2164                op_pass = PFR_OP_XPASS;
2165        }
2166        kt->pfrkt_packets[dir_out][op_pass]++;
2167        kt->pfrkt_bytes[dir_out][op_pass] += len;
2168        if (ke != NULL && op_pass != PFR_OP_XPASS) {
2169                ke->pfrke_packets[dir_out][op_pass]++;
2170                ke->pfrke_bytes[dir_out][op_pass] += len;
2171        }
2172}
2173
2174struct pfr_ktable *
2175pfr_attach_table(struct pf_ruleset *rs, char *name)
2176{
2177        struct pfr_ktable       *kt, *rt;
2178        struct pfr_table         tbl;
2179        struct pf_anchor        *ac = rs->anchor;
2180
2181        bzero(&tbl, sizeof(tbl));
2182        strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
2183        if (ac != NULL)
2184                strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
2185        kt = pfr_lookup_table(&tbl);
2186        if (kt == NULL) {
2187                kt = pfr_create_ktable(&tbl, time_second, 1);
2188                if (kt == NULL)
2189                        return (NULL);
2190                if (ac != NULL) {
2191                        bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor));
2192                        rt = pfr_lookup_table(&tbl);
2193                        if (rt == NULL) {
2194                                rt = pfr_create_ktable(&tbl, 0, 1);
2195                                if (rt == NULL) {
2196                                        pfr_destroy_ktable(kt, 0);
2197                                        return (NULL);
2198                                }
2199                                pfr_insert_ktable(rt);
2200                        }
2201                        kt->pfrkt_root = rt;
2202                }
2203                pfr_insert_ktable(kt);
2204        }
2205        if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++)
2206                pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED);
2207        return (kt);
2208}
2209
2210void
2211pfr_detach_table(struct pfr_ktable *kt)
2212{
2213        if (kt->pfrkt_refcnt[PFR_REFCNT_RULE] <= 0)
2214                printf("pfr_detach_table: refcount = %d.\n",
2215                    kt->pfrkt_refcnt[PFR_REFCNT_RULE]);
2216        else if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE])
2217                pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED);
2218}
2219
2220
2221int
2222pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
2223    struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af)
2224{
2225        struct pfr_kentry       *ke, *ke2 = NULL;
2226        struct pf_addr          *addr = NULL;
2227        union sockaddr_union     mask;
2228        int                      idx = -1, use_counter = 0;
2229
2230        if (af == AF_INET)
2231                addr = (struct pf_addr *)&pfr_sin.sin_addr;
2232        else if (af == AF_INET6)
2233                addr = (struct pf_addr *)&pfr_sin6.sin6_addr;
2234        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2235                kt = kt->pfrkt_root;
2236        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2237                return (-1);
2238
2239        if (pidx != NULL)
2240                idx = *pidx;
2241        if (counter != NULL && idx >= 0)
2242                use_counter = 1;
2243        if (idx < 0)
2244                idx = 0;
2245
2246_next_block:
2247        ke = pfr_kentry_byidx(kt, idx, af);
2248        if (ke == NULL)
2249                return (1);
2250        pfr_prepare_network(&pfr_mask, af, ke->pfrke_net);
2251        *raddr = SUNION2PF(&ke->pfrke_sa, af);
2252        *rmask = SUNION2PF(&pfr_mask, af);
2253
2254        if (use_counter) {
2255                /* is supplied address within block? */
2256                if (!PF_MATCHA(0, *raddr, *rmask, counter, af)) {
2257                        /* no, go to next block in table */
2258                        idx++;
2259                        use_counter = 0;
2260                        goto _next_block;
2261                }
2262                PF_ACPY(addr, counter, af);
2263        } else {
2264                /* use first address of block */
2265                PF_ACPY(addr, *raddr, af);
2266        }
2267
2268        if (!KENTRY_NETWORK(ke)) {
2269                /* this is a single IP address - no possible nested block */
2270                PF_ACPY(counter, addr, af);
2271                *pidx = idx;
2272                return (0);
2273        }
2274        for (;;) {
2275                /* we don't want to use a nested block */
2276                if (af == AF_INET)
2277                        ke2 = (struct pfr_kentry *)rn_match(&pfr_sin,
2278                            kt->pfrkt_ip4);
2279                else if (af == AF_INET6)
2280                        ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6,
2281                            kt->pfrkt_ip6);
2282                /* no need to check KENTRY_RNF_ROOT() here */
2283                if (ke2 == ke) {
2284                        /* lookup return the same block - perfect */
2285                        PF_ACPY(counter, addr, af);
2286                        *pidx = idx;
2287                        return (0);
2288                }
2289
2290                /* we need to increase the counter past the nested block */
2291                pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net);
2292                PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af);
2293                PF_AINC(addr, af);
2294                if (!PF_MATCHA(0, *raddr, *rmask, addr, af)) {
2295                        /* ok, we reached the end of our main block */
2296                        /* go to next block in table */
2297                        idx++;
2298                        use_counter = 0;
2299                        goto _next_block;
2300                }
2301        }
2302}
2303
2304struct pfr_kentry *
2305pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
2306{
2307        struct pfr_walktree     w;
2308
2309        bzero(&w, sizeof(w));
2310        w.pfrw_op = PFRW_POOL_GET;
2311        w.pfrw_cnt = idx;
2312
2313        switch (af) {
2314#ifdef INET
2315        case AF_INET:
2316#ifdef __FreeBSD__
2317                kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2318#else
2319                rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2320#endif
2321                return (w.pfrw_kentry);
2322#endif /* INET */
2323#ifdef INET6
2324        case AF_INET6:
2325#ifdef __FreeBSD__
2326                kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2327#else
2328                rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2329#endif
2330                return (w.pfrw_kentry);
2331#endif /* INET6 */
2332        default:
2333                return (NULL);
2334        }
2335}
2336
2337void
2338pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn)
2339{
2340        struct pfr_walktree     w;
2341        int                     s;
2342
2343        bzero(&w, sizeof(w));
2344        w.pfrw_op = PFRW_DYNADDR_UPDATE;
2345        w.pfrw_dyn = dyn;
2346
2347        s = splsoftnet();
2348        dyn->pfid_acnt4 = 0;
2349        dyn->pfid_acnt6 = 0;
2350        if (!dyn->pfid_af || dyn->pfid_af == AF_INET)
2351#ifdef __FreeBSD__
2352                kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2353#else
2354                rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2355#endif
2356        if (!dyn->pfid_af || dyn->pfid_af == AF_INET6)
2357#ifdef __FreeBSD__
2358                kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2359#else
2360                rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2361#endif
2362        splx(s);
2363}
Note: See TracBrowser for help on using the repository browser.