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