source: rtems-libbsd/freebsd/sys/contrib/pf/net/pf_table.c @ 66659ff

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 66659ff was 66659ff, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/13 at 15:20:21

Update to FreeBSD 9.2

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