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