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