xref: /dragonfly/sys/net/pf/pf_ioctl.c (revision b272101acc636ac635f83d03265ef6a44a3ba51a)
1 /*        $OpenBSD: pf_ioctl.c,v 1.209 2008/06/29 08:42:15 mcbride Exp $ */
2 /*add $OpenBSD: pf_ioctl.c,v 1.212 2009/02/15 20:42:33 mbalmer Exp $ */
3 
4 /*
5  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
6  *
7  * Copyright (c) 2001 Daniel Hartmeier
8  * Copyright (c) 2002,2003 Henning Brauer
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  *    - Redistributions of source code must retain the above copyright
16  *      notice, this list of conditions and the following disclaimer.
17  *    - Redistributions in binary form must reproduce the above
18  *      copyright notice, this list of conditions and the following
19  *      disclaimer in the documentation and/or other materials provided
20  *      with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Effort sponsored in part by the Defense Advanced Research Projects
36  * Agency (DARPA) and Air Force Research Laboratory, Air Force
37  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
38  *
39  */
40 
41 #include "opt_inet.h"
42 #include "opt_inet6.h"
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/conf.h>
47 #include <sys/device.h>
48 #include <sys/mbuf.h>
49 #include <sys/filio.h>
50 #include <sys/fcntl.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/kernel.h>
54 #include <sys/kthread.h>
55 #include <sys/time.h>
56 #include <sys/proc.h>
57 #include <sys/malloc.h>
58 #include <sys/module.h>
59 #include <sys/lock.h>
60 
61 #include <sys/thread2.h>
62 
63 #include <net/if.h>
64 #include <net/if_types.h>
65 #include <net/route.h>
66 
67 #include <netinet/in.h>
68 #include <netinet/in_var.h>
69 #include <netinet/in_systm.h>
70 #include <netinet/ip.h>
71 #include <netinet/ip_var.h>
72 #include <netinet/ip_icmp.h>
73 
74 #include <net/pf/pfvar.h>
75 #include <sys/md5.h>
76 
77 #include <net/pf/if_pflog.h>
78 #include <net/pf/if_pfsync.h>
79 
80 #ifdef INET6
81 #include <netinet/ip6.h>
82 #include <netinet/in_pcb.h>
83 #endif /* INET6 */
84 
85 #ifdef ALTQ
86 #include <net/altq/altq.h>
87 #endif
88 
89 #include <machine/limits.h>
90 #include <net/pfil.h>
91 
92 u_int rt_numfibs = RT_NUMFIBS;
93 
94 void                           pfattach(void);
95 struct pf_pool                *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
96                                   u_int8_t, u_int8_t, u_int8_t);
97 
98 void                           pf_mv_pool(struct pf_palist *, struct pf_palist *);
99 void                           pf_empty_pool(struct pf_palist *);
100 #ifdef ALTQ
101 int                            pf_begin_altq(u_int32_t *);
102 int                            pf_rollback_altq(u_int32_t);
103 int                            pf_commit_altq(u_int32_t);
104 int                            pf_enable_altq(struct pf_altq *);
105 int                            pf_disable_altq(struct pf_altq *);
106 #endif /* ALTQ */
107 int                            pf_begin_rules(u_int32_t *, int, const char *);
108 int                            pf_rollback_rules(u_int32_t, int, char *);
109 int                            pf_setup_pfsync_matching(struct pf_ruleset *);
110 void                           pf_hash_rule(MD5_CTX *, struct pf_rule *);
111 void                           pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
112 int                            pf_commit_rules(u_int32_t, int, char *);
113 int                            pf_addr_setup(struct pf_ruleset *,
114                                   struct pf_addr_wrap *, sa_family_t);
115 void                           pf_addr_copyout(struct pf_addr_wrap *);
116 
117 struct pf_rule                 pf_default_rule;
118 struct lock                    pf_consistency_lock;
119 struct lock                    pf_global_statetbl_lock;
120 #ifdef ALTQ
121 static int                     pf_altq_running;
122 #endif
123 
124 #define   TAGID_MAX  50000
125 TAILQ_HEAD(pf_tags, pf_tagname)         pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
126                                         pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids);
127 
128 #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
129 #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
130 #endif
131 u_int16_t            tagname2tag(struct pf_tags *, char *);
132 void                           tag2tagname(struct pf_tags *, u_int16_t, char *);
133 void                           tag_unref(struct pf_tags *, u_int16_t);
134 int                            pf_rtlabel_add(struct pf_addr_wrap *);
135 void                           pf_rtlabel_remove(struct pf_addr_wrap *);
136 void                           pf_rtlabel_copyout(struct pf_addr_wrap *);
137 
138 #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) kprintf x
139 
140 static cdev_t       pf_dev;
141 
142 static MALLOC_DEFINE(M_PFRULEPL, "pfrulepl", "pf rule pool list");
143 static MALLOC_DEFINE(M_PFALTQPL, "pfaltqpl", "pf altq pool list");
144 static MALLOC_DEFINE(M_PFPOOLADDRPL, "pfpooladdrpl", "pf pool address pool list");
145 static MALLOC_DEFINE(M_PFFRENTPL, "pffrent", "pf frent pool list");
146 
147 MALLOC_DEFINE(M_PF,             "pf", "pf general");
148 
149 
150 /*
151  * XXX - These are new and need to be checked when moveing to a new version
152  */
153 static void                    pf_clear_states(void);
154 static int                     pf_clear_tables(void);
155 static void                    pf_clear_srcnodes(void);
156 /*
157  * XXX - These are new and need to be checked when moveing to a new version
158  */
159 
160 /*
161  * Wrapper functions for pfil(9) hooks
162  */
163 static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
164                     int dir);
165 static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
166                     int dir);
167 #ifdef INET6
168 static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
169                     int dir);
170 static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
171                     int dir);
172 #endif
173 
174 static int                     hook_pf(void);
175 static int                     dehook_pf(void);
176 static int                     shutdown_pf(void);
177 static int                     pf_load(void);
178 static int                     pf_unload(void);
179 
180 d_open_t  pfopen;
181 d_close_t pfclose;
182 d_ioctl_t pfioctl;
183 
184 static struct dev_ops pf_ops = {            /* XXX convert to port model */
185           { PF_NAME, 73, 0 },
186           .d_open = pfopen,
187           .d_close =          pfclose,
188           .d_ioctl =          pfioctl
189 };
190 
191 static volatile int pf_pfil_hooked = 0;
192 int pf_end_threads = 0;
193 
194 int debug_pfugidhack = 0;
195 SYSCTL_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW, &debug_pfugidhack, 0,
196           "Enable/disable pf user/group rules mpsafe hack");
197 
198 void
pfattach(void)199 pfattach(void)
200 {
201           u_int32_t *my_timeout = pf_default_rule.timeout;
202           int nn;
203 
204           if (!rn_inithead(&pf_maskhead, NULL, 0)) {
205                     kprintf("pf mask radix tree create failed\n");
206                     return;
207           }
208           kmalloc_create(&pf_state_pl, "pf state pool list");
209           kmalloc_raise_limit(pf_state_pl, 0);
210           kmalloc_create(&pf_frent_pl, "pf fragment pool list");
211           kmalloc_raise_limit(pf_frent_pl, 0);
212           kmalloc_create(&pf_cent_pl, "pf cent pool list");
213           kmalloc_raise_limit(pf_cent_pl, 0);
214 
215           /*
216            * Allocate pcpu array.
217            *
218            * NOTE: The state table also has a global element which we index
219            *         at [ncpus], so it needs one extra slot.
220            */
221           tree_src_tracking = kmalloc(sizeof(*tree_src_tracking) * ncpus,
222                                         M_PF, M_WAITOK | M_ZERO);
223           tree_id = kmalloc(sizeof(*tree_id) * ncpus,
224                                         M_PF, M_WAITOK | M_ZERO);
225           state_list = kmalloc(sizeof(*state_list) * ncpus,
226                                         M_PF, M_WAITOK | M_ZERO);
227           pf_counters = kmalloc(sizeof(*pf_counters) * ncpus,
228                                         M_PF, M_WAITOK | M_ZERO);
229           pf_statetbl = kmalloc(sizeof(*pf_statetbl) * (ncpus + 1),
230                                         M_PF, M_WAITOK | M_ZERO);
231           purge_cur = kmalloc(sizeof(*purge_cur) * ncpus,
232                                         M_PF, M_WAITOK | M_ZERO);
233 
234           pfr_initialize();
235           pfi_initialize();
236           pf_osfp_initialize();
237 
238           pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl;
239           pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
240           pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl;
241           pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
242           if (ctob(physmem) <= 100*1024*1024)
243                     pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
244                         PFR_KENTRY_HIWAT_SMALL;
245 
246           for (nn = 0; nn < ncpus; ++nn) {
247                     RB_INIT(&tree_src_tracking[nn]);
248                     RB_INIT(&tree_id[nn]);
249           }
250           RB_INIT(&pf_anchors);
251           pf_init_ruleset(&pf_main_ruleset);
252           TAILQ_INIT(&pf_altqs[0]);
253           TAILQ_INIT(&pf_altqs[1]);
254           TAILQ_INIT(&pf_pabuf);
255           pf_altqs_active = &pf_altqs[0];
256           pf_altqs_inactive = &pf_altqs[1];
257           for (nn = 0; nn < ncpus; ++nn)
258                     TAILQ_INIT(&state_list[nn]);
259 
260           /* default rule should never be garbage collected */
261           pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
262           pf_default_rule.action = PF_PASS;
263           pf_default_rule.nr = (uint32_t)(-1);
264           pf_default_rule.rtableid = -1;
265 
266           /* initialize default timeouts */
267           my_timeout[PFTM_TCP_FIRST_PACKET] = 120;          /* First TCP packet */
268           my_timeout[PFTM_TCP_OPENING] = 30;                /* No response yet */
269           my_timeout[PFTM_TCP_ESTABLISHED] = 24*60*60;      /* Established */
270           my_timeout[PFTM_TCP_CLOSING] = 15 * 60;           /* Half closed */
271           my_timeout[PFTM_TCP_FIN_WAIT] = 45;               /* Got both FINs */
272           my_timeout[PFTM_TCP_CLOSED] = 90;                 /* Got a RST */
273           my_timeout[PFTM_UDP_FIRST_PACKET] = 60;           /* First UDP packet */
274           my_timeout[PFTM_UDP_SINGLE] = 30;                 /* Unidirectional */
275           my_timeout[PFTM_UDP_MULTIPLE] = 60;               /* Bidirectional */
276           my_timeout[PFTM_ICMP_FIRST_PACKET] = 20;          /* First ICMP packet */
277           my_timeout[PFTM_ICMP_ERROR_REPLY] = 10;           /* Got error response */
278           my_timeout[PFTM_OTHER_FIRST_PACKET] = 60;         /* First packet */
279           my_timeout[PFTM_OTHER_SINGLE] = 30;               /* Unidirectional */
280           my_timeout[PFTM_OTHER_MULTIPLE] = 60;             /* Bidirectional */
281           my_timeout[PFTM_FRAG] = 30;                       /* Fragment expire */
282           my_timeout[PFTM_INTERVAL] = 10;                             /* Expire interval */
283           my_timeout[PFTM_SRC_NODE] = 0;                              /* Source Tracking */
284           my_timeout[PFTM_TS_DIFF] = 30;                              /* Allowed TS diff */
285           my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
286           my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
287 
288           pf_normalize_init();
289           bzero(&pf_status, sizeof(pf_status));
290           pf_status.debug = PF_DEBUG_URGENT;
291           /* XXX do our best to avoid a conflict */
292           pf_status.hostid = karc4random();
293 
294           if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge"))
295                     panic("pfpurge thread");
296 }
297 
298 int
pfopen(struct dev_open_args * ap)299 pfopen(struct dev_open_args *ap)
300 {
301           lwkt_gettoken(&pf_token);
302           cdev_t dev = ap->a_head.a_dev;
303           if (minor(dev) >= 1) {
304                     lwkt_reltoken(&pf_token);
305                     return (ENXIO);
306           }
307           lwkt_reltoken(&pf_token);
308           return (0);
309 }
310 
311 int
pfclose(struct dev_close_args * ap)312 pfclose(struct dev_close_args *ap)
313 {
314           lwkt_gettoken(&pf_token);
315           cdev_t dev = ap->a_head.a_dev;
316           if (minor(dev) >= 1) {
317                     lwkt_reltoken(&pf_token);
318                     return (ENXIO);
319           }
320           lwkt_reltoken(&pf_token);
321           return (0);
322 }
323 
324 struct pf_pool *
pf_get_pool(char * anchor,u_int32_t ticket,u_int8_t rule_action,u_int32_t rule_number,u_int8_t r_last,u_int8_t active,u_int8_t check_ticket)325 pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
326     u_int32_t rule_number, u_int8_t r_last, u_int8_t active,
327     u_int8_t check_ticket)
328 {
329           struct pf_ruleset   *ruleset;
330           struct pf_rule                *rule;
331           int                            rs_num;
332 
333           ruleset = pf_find_ruleset(anchor);
334           if (ruleset == NULL)
335                     return (NULL);
336           rs_num = pf_get_ruleset_number(rule_action);
337           if (rs_num >= PF_RULESET_MAX)
338                     return (NULL);
339           if (active) {
340                     if (check_ticket && ticket !=
341                         ruleset->rules[rs_num].active.ticket)
342                               return (NULL);
343                     if (r_last)
344                               rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
345                                   pf_rulequeue);
346                     else
347                               rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
348           } else {
349                     if (check_ticket && ticket !=
350                         ruleset->rules[rs_num].inactive.ticket)
351                               return (NULL);
352                     if (r_last)
353                               rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
354                                   pf_rulequeue);
355                     else
356                               rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
357           }
358           if (!r_last) {
359                     while ((rule != NULL) && (rule->nr != rule_number))
360                               rule = TAILQ_NEXT(rule, entries);
361           }
362           if (rule == NULL)
363                     return (NULL);
364 
365           return (&rule->rpool);
366 }
367 
368 void
pf_mv_pool(struct pf_palist * poola,struct pf_palist * poolb)369 pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
370 {
371           struct pf_pooladdr  *mv_pool_pa;
372 
373           while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
374                     TAILQ_REMOVE(poola, mv_pool_pa, entries);
375                     TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
376           }
377 }
378 
379 void
pf_empty_pool(struct pf_palist * poola)380 pf_empty_pool(struct pf_palist *poola)
381 {
382           struct pf_pooladdr  *empty_pool_pa;
383 
384           while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
385                     pfi_dynaddr_remove(&empty_pool_pa->addr);
386                     pf_tbladdr_remove(&empty_pool_pa->addr);
387                     pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
388                     TAILQ_REMOVE(poola, empty_pool_pa, entries);
389                     kfree(empty_pool_pa, M_PFPOOLADDRPL);
390           }
391 }
392 
393 void
pf_rm_rule(struct pf_rulequeue * rulequeue,struct pf_rule * rule)394 pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
395 {
396           if (rulequeue != NULL) {
397                     if (rule->states_cur <= 0) {
398                               /*
399                                * XXX - we need to remove the table *before* detaching
400                                * the rule to make sure the table code does not delete
401                                * the anchor under our feet.
402                                */
403                               pf_tbladdr_remove(&rule->src.addr);
404                               pf_tbladdr_remove(&rule->dst.addr);
405                               if (rule->overload_tbl)
406                                         pfr_detach_table(rule->overload_tbl);
407                     }
408                     TAILQ_REMOVE(rulequeue, rule, entries);
409                     rule->entries.tqe_prev = NULL;
410                     rule->nr = -1;
411           }
412 
413           if (rule->states_cur > 0 || rule->src_nodes > 0 ||
414               rule->entries.tqe_prev != NULL)
415                     return;
416           pf_tag_unref(rule->tag);
417           pf_tag_unref(rule->match_tag);
418 #ifdef ALTQ
419           if (rule->pqid != rule->qid)
420                     pf_qid_unref(rule->pqid);
421           pf_qid_unref(rule->qid);
422 #endif
423           pf_rtlabel_remove(&rule->src.addr);
424           pf_rtlabel_remove(&rule->dst.addr);
425           pfi_dynaddr_remove(&rule->src.addr);
426           pfi_dynaddr_remove(&rule->dst.addr);
427           if (rulequeue == NULL) {
428                     pf_tbladdr_remove(&rule->src.addr);
429                     pf_tbladdr_remove(&rule->dst.addr);
430                     if (rule->overload_tbl)
431                               pfr_detach_table(rule->overload_tbl);
432           }
433           pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
434           pf_anchor_remove(rule);
435           pf_empty_pool(&rule->rpool.list);
436           kfree(rule, M_PFRULEPL);
437 }
438 
439 u_int16_t
tagname2tag(struct pf_tags * head,char * tagname)440 tagname2tag(struct pf_tags *head, char *tagname)
441 {
442           struct pf_tagname   *tag, *p = NULL;
443           u_int16_t            new_tagid = 1;
444 
445           TAILQ_FOREACH(tag, head, entries)
446                     if (strcmp(tagname, tag->name) == 0) {
447                               tag->ref++;
448                               return (tag->tag);
449                     }
450 
451           /*
452            * to avoid fragmentation, we do a linear search from the beginning
453            * and take the first free slot we find. if there is none or the list
454            * is empty, append a new entry at the end.
455            */
456 
457           /* new entry */
458           if (!TAILQ_EMPTY(head))
459                     for (p = TAILQ_FIRST(head); p != NULL &&
460                         p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
461                               new_tagid = p->tag + 1;
462 
463           if (new_tagid > TAGID_MAX)
464                     return (0);
465 
466           /* allocate and fill new struct pf_tagname */
467           tag = kmalloc(sizeof(*tag), M_TEMP, M_WAITOK);
468           strlcpy(tag->name, tagname, sizeof(tag->name));
469           tag->tag = new_tagid;
470           tag->ref++;
471 
472           if (p != NULL)      /* insert new entry before p */
473                     TAILQ_INSERT_BEFORE(p, tag, entries);
474           else      /* either list empty or no free slot in between */
475                     TAILQ_INSERT_TAIL(head, tag, entries);
476 
477           return (tag->tag);
478 }
479 
480 void
tag2tagname(struct pf_tags * head,u_int16_t tagid,char * p)481 tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
482 {
483           struct pf_tagname   *tag;
484 
485           TAILQ_FOREACH(tag, head, entries)
486                     if (tag->tag == tagid) {
487                               strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
488                               return;
489                     }
490 }
491 
492 void
tag_unref(struct pf_tags * head,u_int16_t tag)493 tag_unref(struct pf_tags *head, u_int16_t tag)
494 {
495           struct pf_tagname   *p, *next;
496 
497           if (tag == 0)
498                     return;
499 
500           for (p = TAILQ_FIRST(head); p != NULL; p = next) {
501                     next = TAILQ_NEXT(p, entries);
502                     if (tag == p->tag) {
503                               if (--p->ref == 0) {
504                                         TAILQ_REMOVE(head, p, entries);
505                                         kfree(p, M_TEMP);
506                               }
507                               break;
508                     }
509           }
510 }
511 
512 u_int16_t
pf_tagname2tag(char * tagname)513 pf_tagname2tag(char *tagname)
514 {
515           return (tagname2tag(&pf_tags, tagname));
516 }
517 
518 void
pf_tag2tagname(u_int16_t tagid,char * p)519 pf_tag2tagname(u_int16_t tagid, char *p)
520 {
521           tag2tagname(&pf_tags, tagid, p);
522 }
523 
524 void
pf_tag_ref(u_int16_t tag)525 pf_tag_ref(u_int16_t tag)
526 {
527           struct pf_tagname *t;
528 
529           TAILQ_FOREACH(t, &pf_tags, entries)
530                     if (t->tag == tag)
531                               break;
532           if (t != NULL)
533                     t->ref++;
534 }
535 
536 void
pf_tag_unref(u_int16_t tag)537 pf_tag_unref(u_int16_t tag)
538 {
539           tag_unref(&pf_tags, tag);
540 }
541 
542 int
pf_rtlabel_add(struct pf_addr_wrap * a)543 pf_rtlabel_add(struct pf_addr_wrap *a)
544 {
545           return (0);
546 }
547 
548 void
pf_rtlabel_remove(struct pf_addr_wrap * a)549 pf_rtlabel_remove(struct pf_addr_wrap *a)
550 {
551 }
552 
553 void
pf_rtlabel_copyout(struct pf_addr_wrap * a)554 pf_rtlabel_copyout(struct pf_addr_wrap *a)
555 {
556           if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel)
557                     strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname));
558 }
559 
560 #ifdef ALTQ
561 u_int32_t
pf_qname2qid(char * qname)562 pf_qname2qid(char *qname)
563 {
564           return ((u_int32_t)tagname2tag(&pf_qids, qname));
565 }
566 
567 void
pf_qid2qname(u_int32_t qid,char * p)568 pf_qid2qname(u_int32_t qid, char *p)
569 {
570           tag2tagname(&pf_qids, (u_int16_t)qid, p);
571 }
572 
573 void
pf_qid_unref(u_int32_t qid)574 pf_qid_unref(u_int32_t qid)
575 {
576           tag_unref(&pf_qids, (u_int16_t)qid);
577 }
578 
579 int
pf_begin_altq(u_int32_t * ticket)580 pf_begin_altq(u_int32_t *ticket)
581 {
582           struct pf_altq      *altq;
583           int                  error = 0;
584 
585           /* Purge the old altq list */
586           while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
587                     TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
588                     if (altq->qname[0] == 0) {
589                               /* detach and destroy the discipline */
590                               error = altq_remove(altq);
591                     } else
592                               pf_qid_unref(altq->qid);
593                     kfree(altq, M_PFALTQPL);
594           }
595           if (error)
596                     return (error);
597           *ticket = ++ticket_altqs_inactive;
598           altqs_inactive_open = 1;
599           return (0);
600 }
601 
602 int
pf_rollback_altq(u_int32_t ticket)603 pf_rollback_altq(u_int32_t ticket)
604 {
605           struct pf_altq      *altq;
606           int                  error = 0;
607 
608           if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
609                     return (0);
610           /* Purge the old altq list */
611           while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
612                     TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
613                     if (altq->qname[0] == 0) {
614                               /* detach and destroy the discipline */
615                               error = altq_remove(altq);
616                     } else
617                               pf_qid_unref(altq->qid);
618                     kfree(altq, M_PFALTQPL);
619           }
620           altqs_inactive_open = 0;
621           return (error);
622 }
623 
624 int
pf_commit_altq(u_int32_t ticket)625 pf_commit_altq(u_int32_t ticket)
626 {
627           struct pf_altqqueue *old_altqs;
628           struct pf_altq                *altq;
629           int                            err, error = 0;
630 
631           if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
632                     return (EBUSY);
633 
634           /* swap altqs, keep the old. */
635           crit_enter();
636           old_altqs = pf_altqs_active;
637           pf_altqs_active = pf_altqs_inactive;
638           pf_altqs_inactive = old_altqs;
639           ticket_altqs_active = ticket_altqs_inactive;
640 
641           /* Attach new disciplines */
642           TAILQ_FOREACH(altq, pf_altqs_active, entries) {
643                     if (altq->qname[0] == 0) {
644                               /* attach the discipline */
645                               error = altq_pfattach(altq);
646                               if (error) {
647                                         crit_exit();
648                                         return (error);
649                               }
650                     }
651           }
652 
653           /* Purge the old altq list */
654           while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
655                     TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
656                     if (altq->qname[0] == 0) {
657                               /* detach and destroy the discipline */
658                               if (pf_altq_running)
659                                         error = pf_disable_altq(altq);
660                               err = altq_pfdetach(altq);
661                               if (err != 0 && error == 0)
662                                         error = err;
663                               err = altq_remove(altq);
664                               if (err != 0 && error == 0)
665                                         error = err;
666                     } else
667                               pf_qid_unref(altq->qid);
668                     kfree(altq, M_PFALTQPL);
669           }
670           crit_exit();
671 
672           altqs_inactive_open = 0;
673           return (error);
674 }
675 
676 int
pf_enable_altq(struct pf_altq * altq)677 pf_enable_altq(struct pf_altq *altq)
678 {
679           struct ifnet                  *ifp;
680           struct tb_profile    tb;
681           int                            error = 0;
682 
683           ifnet_lock();
684 
685           if ((ifp = ifunit(altq->ifname)) == NULL) {
686                     ifnet_unlock();
687                     return (EINVAL);
688           }
689 
690           if (ifp->if_snd.altq_type != ALTQT_NONE)
691                     error = altq_enable(&ifp->if_snd);
692 
693           /* set tokenbucket regulator */
694           if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
695                     tb.rate = altq->ifbandwidth;
696                     tb.depth = altq->tbrsize;
697                     crit_enter();
698                     error = tbr_set(&ifp->if_snd, &tb);
699                     crit_exit();
700           }
701 
702           ifnet_unlock();
703           return (error);
704 }
705 
706 int
pf_disable_altq(struct pf_altq * altq)707 pf_disable_altq(struct pf_altq *altq)
708 {
709           struct ifnet                  *ifp;
710           struct tb_profile    tb;
711           int                            error;
712 
713           ifnet_lock();
714 
715           if ((ifp = ifunit(altq->ifname)) == NULL) {
716                     ifnet_unlock();
717                     return (EINVAL);
718           }
719 
720           /*
721            * when the discipline is no longer referenced, it was overridden
722            * by a new one.  if so, just return.
723            */
724           if (altq->altq_disc != ifp->if_snd.altq_disc) {
725                     ifnet_unlock();
726                     return (0);
727           }
728 
729           error = altq_disable(&ifp->if_snd);
730 
731           if (error == 0) {
732                     /* clear tokenbucket regulator */
733                     tb.rate = 0;
734                     crit_enter();
735                     error = tbr_set(&ifp->if_snd, &tb);
736                     crit_exit();
737           }
738 
739           ifnet_unlock();
740           return (error);
741 }
742 #endif /* ALTQ */
743 
744 int
pf_begin_rules(u_int32_t * ticket,int rs_num,const char * anchor)745 pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
746 {
747           struct pf_ruleset   *rs;
748           struct pf_rule                *rule;
749 
750           if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
751                     return (EINVAL);
752           rs = pf_find_or_create_ruleset(anchor);
753           if (rs == NULL)
754                     return (EINVAL);
755           while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
756                     pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
757                     rs->rules[rs_num].inactive.rcount--;
758           }
759           *ticket = ++rs->rules[rs_num].inactive.ticket;
760           rs->rules[rs_num].inactive.open = 1;
761           return (0);
762 }
763 
764 int
pf_rollback_rules(u_int32_t ticket,int rs_num,char * anchor)765 pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
766 {
767           struct pf_ruleset   *rs;
768           struct pf_rule                *rule;
769 
770           if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
771                     return (EINVAL);
772           rs = pf_find_ruleset(anchor);
773           if (rs == NULL || !rs->rules[rs_num].inactive.open ||
774               rs->rules[rs_num].inactive.ticket != ticket)
775                     return (0);
776           while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
777                     pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
778                     rs->rules[rs_num].inactive.rcount--;
779           }
780           rs->rules[rs_num].inactive.open = 0;
781           return (0);
782 }
783 
784 #define PF_MD5_UPD(st, elm)                                                     \
785                     MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
786 
787 #define PF_MD5_UPD_STR(st, elm)                                                           \
788                     MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
789 
790 #define PF_MD5_UPD_HTONL(st, elm, stor) do {                                    \
791                     (stor) = htonl((st)->elm);                                  \
792                     MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
793 } while (0)
794 
795 #define PF_MD5_UPD_HTONS(st, elm, stor) do {                                    \
796                     (stor) = htons((st)->elm);                                  \
797                     MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
798 } while (0)
799 
800 void
pf_hash_rule_addr(MD5_CTX * ctx,struct pf_rule_addr * pfr)801 pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
802 {
803           PF_MD5_UPD(pfr, addr.type);
804           switch (pfr->addr.type) {
805                     case PF_ADDR_DYNIFTL:
806                               PF_MD5_UPD(pfr, addr.v.ifname);
807                               PF_MD5_UPD(pfr, addr.iflags);
808                               break;
809                     case PF_ADDR_TABLE:
810                               PF_MD5_UPD(pfr, addr.v.tblname);
811                               break;
812                     case PF_ADDR_ADDRMASK:
813                               /* XXX ignore af? */
814                               PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
815                               PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
816                               break;
817                     case PF_ADDR_RTLABEL:
818                               PF_MD5_UPD(pfr, addr.v.rtlabelname);
819                               break;
820           }
821 
822           PF_MD5_UPD(pfr, port[0]);
823           PF_MD5_UPD(pfr, port[1]);
824           PF_MD5_UPD(pfr, neg);
825           PF_MD5_UPD(pfr, port_op);
826 }
827 
828 void
pf_hash_rule(MD5_CTX * ctx,struct pf_rule * rule)829 pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
830 {
831           u_int16_t x;
832           u_int32_t y;
833 
834           pf_hash_rule_addr(ctx, &rule->src);
835           pf_hash_rule_addr(ctx, &rule->dst);
836           PF_MD5_UPD_STR(rule, label);
837           PF_MD5_UPD_STR(rule, ifname);
838           PF_MD5_UPD_STR(rule, match_tagname);
839           PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
840           PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
841           PF_MD5_UPD_HTONL(rule, prob, y);
842           PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
843           PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
844           PF_MD5_UPD(rule, uid.op);
845           PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
846           PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
847           PF_MD5_UPD(rule, gid.op);
848           PF_MD5_UPD_HTONL(rule, rule_flag, y);
849           PF_MD5_UPD(rule, action);
850           PF_MD5_UPD(rule, direction);
851           PF_MD5_UPD(rule, af);
852           PF_MD5_UPD(rule, quick);
853           PF_MD5_UPD(rule, ifnot);
854           PF_MD5_UPD(rule, match_tag_not);
855           PF_MD5_UPD(rule, natpass);
856           PF_MD5_UPD(rule, keep_state);
857           PF_MD5_UPD(rule, proto);
858           PF_MD5_UPD(rule, type);
859           PF_MD5_UPD(rule, code);
860           PF_MD5_UPD(rule, flags);
861           PF_MD5_UPD(rule, flagset);
862           PF_MD5_UPD(rule, allow_opts);
863           PF_MD5_UPD(rule, rt);
864           PF_MD5_UPD(rule, tos);
865 }
866 
867 int
pf_commit_rules(u_int32_t ticket,int rs_num,char * anchor)868 pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
869 {
870           struct pf_ruleset   *rs;
871           struct pf_rule                *rule, **old_array;
872           struct pf_rulequeue *old_rules;
873           int                            error;
874           u_int32_t            old_rcount;
875 
876           if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
877                     return (EINVAL);
878           rs = pf_find_ruleset(anchor);
879           if (rs == NULL || !rs->rules[rs_num].inactive.open ||
880               ticket != rs->rules[rs_num].inactive.ticket)
881                     return (EBUSY);
882 
883           /* Calculate checksum for the main ruleset */
884           if (rs == &pf_main_ruleset) {
885                     error = pf_setup_pfsync_matching(rs);
886                     if (error != 0)
887                               return (error);
888           }
889 
890           /* Swap rules, keep the old. */
891           crit_enter();
892           old_rules = rs->rules[rs_num].active.ptr;
893           old_rcount = rs->rules[rs_num].active.rcount;
894           old_array = rs->rules[rs_num].active.ptr_array;
895 
896           rs->rules[rs_num].active.ptr =
897               rs->rules[rs_num].inactive.ptr;
898           rs->rules[rs_num].active.ptr_array =
899               rs->rules[rs_num].inactive.ptr_array;
900           rs->rules[rs_num].active.rcount =
901               rs->rules[rs_num].inactive.rcount;
902           rs->rules[rs_num].inactive.ptr = old_rules;
903           rs->rules[rs_num].inactive.ptr_array = old_array;
904           rs->rules[rs_num].inactive.rcount = old_rcount;
905 
906           rs->rules[rs_num].active.ticket =
907               rs->rules[rs_num].inactive.ticket;
908           pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
909 
910 
911           /* Purge the old rule list. */
912           while ((rule = TAILQ_FIRST(old_rules)) != NULL)
913                     pf_rm_rule(old_rules, rule);
914           if (rs->rules[rs_num].inactive.ptr_array)
915                     kfree(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
916           rs->rules[rs_num].inactive.ptr_array = NULL;
917           rs->rules[rs_num].inactive.rcount = 0;
918           rs->rules[rs_num].inactive.open = 0;
919           pf_remove_if_empty_ruleset(rs);
920           crit_exit();
921           return (0);
922 }
923 
924 int
pf_setup_pfsync_matching(struct pf_ruleset * rs)925 pf_setup_pfsync_matching(struct pf_ruleset *rs)
926 {
927           MD5_CTX                        ctx;
928           struct pf_rule                *rule;
929           int                            rs_cnt;
930           u_int8_t             digest[PF_MD5_DIGEST_LENGTH];
931 
932           MD5Init(&ctx);
933           for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
934                     /* XXX PF_RULESET_SCRUB as well? */
935                     if (rs_cnt == PF_RULESET_SCRUB)
936                               continue;
937 
938                     if (rs->rules[rs_cnt].inactive.ptr_array)
939                               kfree(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
940                     rs->rules[rs_cnt].inactive.ptr_array = NULL;
941 
942                     if (rs->rules[rs_cnt].inactive.rcount) {
943                               rs->rules[rs_cnt].inactive.ptr_array =
944                                   kmalloc(sizeof(caddr_t) *
945                                             rs->rules[rs_cnt].inactive.rcount,
946                                             M_TEMP, M_WAITOK);
947                     }
948 
949                     TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
950                         entries) {
951                               pf_hash_rule(&ctx, rule);
952                               (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
953                     }
954           }
955 
956           MD5Final(digest, &ctx);
957           memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
958           return (0);
959 }
960 
961 int
pf_addr_setup(struct pf_ruleset * ruleset,struct pf_addr_wrap * addr,sa_family_t af)962 pf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr,
963     sa_family_t af)
964 {
965           if (pfi_dynaddr_setup(addr, af) ||
966               pf_tbladdr_setup(ruleset, addr))
967                     return (EINVAL);
968 
969           return (0);
970 }
971 
972 void
pf_addr_copyout(struct pf_addr_wrap * addr)973 pf_addr_copyout(struct pf_addr_wrap *addr)
974 {
975           pfi_dynaddr_copyout(addr);
976           pf_tbladdr_copyout(addr);
977           pf_rtlabel_copyout(addr);
978 }
979 
980 int
pfioctl(struct dev_ioctl_args * ap)981 pfioctl(struct dev_ioctl_args *ap)
982 {
983           u_long cmd = ap->a_cmd;
984           caddr_t addr = ap->a_data;
985           struct pf_pooladdr  *pa = NULL;
986           struct pf_pool                *pool = NULL;
987           int                            error = 0;
988 
989           lwkt_gettoken(&pf_token);
990 
991           /* XXX keep in sync with switch() below */
992           if (securelevel > 1) {
993                     switch (cmd) {
994                     case DIOCGETRULES:
995                     case DIOCGETRULE:
996                     case DIOCGETADDRS:
997                     case DIOCGETADDR:
998                     case DIOCGETSTATE:
999                     case DIOCSETSTATUSIF:
1000                     case DIOCGETSTATUS:
1001                     case DIOCCLRSTATUS:
1002                     case DIOCNATLOOK:
1003                     case DIOCSETDEBUG:
1004                     case DIOCGETSTATES:
1005                     case DIOCGETTIMEOUT:
1006                     case DIOCCLRRULECTRS:
1007                     case DIOCGETLIMIT:
1008                     case DIOCGETALTQS:
1009                     case DIOCGETALTQ:
1010                     case DIOCGETQSTATS:
1011                     case DIOCGETRULESETS:
1012                     case DIOCGETRULESET:
1013                     case DIOCRGETTABLES:
1014                     case DIOCRGETTSTATS:
1015                     case DIOCRCLRTSTATS:
1016                     case DIOCRCLRADDRS:
1017                     case DIOCRADDADDRS:
1018                     case DIOCRDELADDRS:
1019                     case DIOCRSETADDRS:
1020                     case DIOCRGETADDRS:
1021                     case DIOCRGETASTATS:
1022                     case DIOCRCLRASTATS:
1023                     case DIOCRTSTADDRS:
1024                     case DIOCOSFPGET:
1025                     case DIOCGETSRCNODES:
1026                     case DIOCCLRSRCNODES:
1027                     case DIOCIGETIFACES:
1028                     case DIOCSETIFFLAG:
1029                     case DIOCCLRIFFLAG:
1030                     case DIOCGIFSPEED:
1031                               break;
1032                     case DIOCRCLRTABLES:
1033                     case DIOCRADDTABLES:
1034                     case DIOCRDELTABLES:
1035                     case DIOCRSETTFLAGS:
1036                               if (((struct pfioc_table *)addr)->pfrio_flags &
1037                                   PFR_FLAG_DUMMY)
1038                                         break; /* dummy operation ok */
1039                               lwkt_reltoken(&pf_token);
1040                               return (EPERM);
1041                     default:
1042                               lwkt_reltoken(&pf_token);
1043                               return (EPERM);
1044                     }
1045           }
1046 
1047           if (!(ap->a_fflag & FWRITE)) {
1048                     switch (cmd) {
1049                     case DIOCGETRULES:
1050                     case DIOCGETADDRS:
1051                     case DIOCGETADDR:
1052                     case DIOCGETSTATE:
1053                     case DIOCGETSTATUS:
1054                     case DIOCGETSTATES:
1055                     case DIOCGETTIMEOUT:
1056                     case DIOCGETLIMIT:
1057                     case DIOCGETALTQS:
1058                     case DIOCGETALTQ:
1059                     case DIOCGETQSTATS:
1060                     case DIOCGETRULESETS:
1061                     case DIOCGETRULESET:
1062                     case DIOCNATLOOK:
1063                     case DIOCRGETTABLES:
1064                     case DIOCRGETTSTATS:
1065                     case DIOCRGETADDRS:
1066                     case DIOCRGETASTATS:
1067                     case DIOCRTSTADDRS:
1068                     case DIOCOSFPGET:
1069                     case DIOCGETSRCNODES:
1070                     case DIOCIGETIFACES:
1071                     case DIOCGIFSPEED:
1072                               break;
1073                     case DIOCRCLRTABLES:
1074                     case DIOCRADDTABLES:
1075                     case DIOCRDELTABLES:
1076                     case DIOCRCLRTSTATS:
1077                     case DIOCRCLRADDRS:
1078                     case DIOCRADDADDRS:
1079                     case DIOCRDELADDRS:
1080                     case DIOCRSETADDRS:
1081                     case DIOCRSETTFLAGS:
1082                               if (((struct pfioc_table *)addr)->pfrio_flags &
1083                                   PFR_FLAG_DUMMY)
1084                                         break; /* dummy operation ok */
1085                               lwkt_reltoken(&pf_token);
1086                               return (EACCES);
1087                     case DIOCGETRULE:
1088                               if (((struct pfioc_rule *)addr)->action ==
1089                                   PF_GET_CLR_CNTR) {
1090                                         lwkt_reltoken(&pf_token);
1091                                         return (EACCES);
1092                               }
1093                               break;
1094                     default:
1095                               lwkt_reltoken(&pf_token);
1096                               return (EACCES);
1097                     }
1098           }
1099 
1100           switch (cmd) {
1101           case DIOCSTART:
1102                     if (pf_status.running)
1103                               error = EEXIST;
1104                     else {
1105                               error = hook_pf();
1106                               if (error) {
1107                                         DPFPRINTF(PF_DEBUG_MISC,
1108                                             ("pf: pfil registration fail\n"));
1109                                         break;
1110                               }
1111                               pf_status.running = 1;
1112                               pf_status.since = time_second;
1113                               if (pf_status.stateid == 0) {
1114                                         pf_status.stateid = time_second;
1115                                         pf_status.stateid = pf_status.stateid << 32;
1116                               }
1117                               DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
1118                     }
1119                     break;
1120 
1121           case DIOCSTOP:
1122                     if (!pf_status.running)
1123                               error = ENOENT;
1124                     else {
1125                               pf_status.running = 0;
1126                               error = dehook_pf();
1127                               if (error) {
1128                                         pf_status.running = 1;
1129                                         DPFPRINTF(PF_DEBUG_MISC,
1130                                                   ("pf: pfil unregistration failed\n"));
1131                               }
1132                               pf_status.since = time_second;
1133                               DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
1134                     }
1135                     break;
1136 
1137           case DIOCADDRULE: {
1138                     struct pfioc_rule   *pr = (struct pfioc_rule *)addr;
1139                     struct pf_ruleset   *ruleset;
1140                     struct pf_rule                *rule, *tail;
1141                     struct pf_pooladdr  *pa;
1142                     int                            rs_num;
1143 
1144                     pr->anchor[sizeof(pr->anchor) - 1] = 0;
1145                     ruleset = pf_find_ruleset(pr->anchor);
1146                     if (ruleset == NULL) {
1147                               error = EINVAL;
1148                               break;
1149                     }
1150                     rs_num = pf_get_ruleset_number(pr->rule.action);
1151                     if (rs_num >= PF_RULESET_MAX) {
1152                               error = EINVAL;
1153                               break;
1154                     }
1155                     if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1156                               error = EINVAL;
1157                               break;
1158                     }
1159                     if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
1160                               error = EBUSY;
1161                               break;
1162                     }
1163                     if (pr->pool_ticket != ticket_pabuf) {
1164                               error = EBUSY;
1165                               break;
1166                     }
1167                     rule = kmalloc(sizeof(struct pf_rule), M_PFRULEPL, M_WAITOK);
1168                     bcopy(&pr->rule, rule, sizeof(struct pf_rule));
1169                     rule->cuid = ap->a_cred->cr_ruid;
1170                     rule->cpid = 0;
1171                     rule->anchor = NULL;
1172                     rule->kif = NULL;
1173                     TAILQ_INIT(&rule->rpool.list);
1174                     /* initialize refcounting */
1175                     rule->states_cur = 0;
1176                     rule->src_nodes = 0;
1177                     rule->entries.tqe_prev = NULL;
1178 #ifndef INET
1179                     if (rule->af == AF_INET) {
1180                               kfree(rule, M_PFRULEPL);
1181                               error = EAFNOSUPPORT;
1182                               break;
1183                     }
1184 #endif /* INET */
1185 #ifndef INET6
1186                     if (rule->af == AF_INET6) {
1187                               kfree(rule, M_PFRULEPL);
1188                               error = EAFNOSUPPORT;
1189                               break;
1190                     }
1191 #endif /* INET6 */
1192                     tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
1193                         pf_rulequeue);
1194                     if (tail)
1195                               rule->nr = tail->nr + 1;
1196                     else
1197                               rule->nr = 0;
1198                     if (rule->ifname[0]) {
1199                               rule->kif = pfi_kif_get(rule->ifname);
1200                               if (rule->kif == NULL) {
1201                                         kfree(rule, M_PFRULEPL);
1202                                         error = EINVAL;
1203                                         break;
1204                               }
1205                               pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
1206                     }
1207 
1208                     if (rule->rtableid > 0 && rule->rtableid > rt_numfibs)
1209                               error = EBUSY;
1210 
1211 #ifdef ALTQ
1212                     /* set queue IDs */
1213                     if (rule->qname[0] != 0) {
1214                               if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
1215                                         error = EBUSY;
1216                               else if (rule->pqname[0] != 0) {
1217                                         if ((rule->pqid =
1218                                             pf_qname2qid(rule->pqname)) == 0)
1219                                                   error = EBUSY;
1220                               } else
1221                                         rule->pqid = rule->qid;
1222                     }
1223 #endif
1224                     if (rule->tagname[0])
1225                               if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
1226                                         error = EBUSY;
1227                     if (rule->match_tagname[0])
1228                               if ((rule->match_tag =
1229                                   pf_tagname2tag(rule->match_tagname)) == 0)
1230                                         error = EBUSY;
1231                     if (rule->rt && !rule->direction)
1232                               error = EINVAL;
1233 #if NPFLOG > 0
1234                     if (!rule->log)
1235                               rule->logif = 0;
1236                     if (rule->logif >= PFLOGIFS_MAX)
1237                               error = EINVAL;
1238 #endif
1239                     if (pf_rtlabel_add(&rule->src.addr) ||
1240                         pf_rtlabel_add(&rule->dst.addr))
1241                               error = EBUSY;
1242                     if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
1243                               error = EINVAL;
1244                     if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
1245                               error = EINVAL;
1246                     if (pf_anchor_setup(rule, ruleset, pr->anchor_call))
1247                               error = EINVAL;
1248                     TAILQ_FOREACH(pa, &pf_pabuf, entries)
1249                               if (pf_tbladdr_setup(ruleset, &pa->addr))
1250                                         error = EINVAL;
1251 
1252                     if (rule->overload_tblname[0]) {
1253                               if ((rule->overload_tbl = pfr_attach_table(ruleset,
1254                                   rule->overload_tblname)) == NULL)
1255                                         error = EINVAL;
1256                               else
1257                                         rule->overload_tbl->pfrkt_flags |=
1258                                             PFR_TFLAG_ACTIVE;
1259                     }
1260 
1261                     pf_mv_pool(&pf_pabuf, &rule->rpool.list);
1262                     if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
1263                         (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
1264                         (rule->rt > PF_FASTROUTE)) &&
1265                         (TAILQ_FIRST(&rule->rpool.list) == NULL))
1266                               error = EINVAL;
1267 
1268                     if (error) {
1269                               pf_rm_rule(NULL, rule);
1270                               break;
1271                     }
1272                     rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
1273                     rule->evaluations = rule->packets[0] = rule->packets[1] =
1274                         rule->bytes[0] = rule->bytes[1] = 0;
1275                     TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
1276                         rule, entries);
1277                     ruleset->rules[rs_num].inactive.rcount++;
1278                     break;
1279           }
1280 
1281           case DIOCGETRULES: {
1282                     struct pfioc_rule   *pr = (struct pfioc_rule *)addr;
1283                     struct pf_ruleset   *ruleset;
1284                     struct pf_rule                *tail;
1285                     int                            rs_num;
1286 
1287                     pr->anchor[sizeof(pr->anchor) - 1] = 0;
1288                     ruleset = pf_find_ruleset(pr->anchor);
1289                     if (ruleset == NULL) {
1290                               error = EINVAL;
1291                               break;
1292                     }
1293                     rs_num = pf_get_ruleset_number(pr->rule.action);
1294                     if (rs_num >= PF_RULESET_MAX) {
1295                               error = EINVAL;
1296                               break;
1297                     }
1298                     tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
1299                         pf_rulequeue);
1300                     if (tail)
1301                               pr->nr = tail->nr + 1;
1302                     else
1303                               pr->nr = 0;
1304                     pr->ticket = ruleset->rules[rs_num].active.ticket;
1305                     break;
1306           }
1307 
1308           case DIOCGETRULE: {
1309                     struct pfioc_rule   *pr = (struct pfioc_rule *)addr;
1310                     struct pf_ruleset   *ruleset;
1311                     struct pf_rule                *rule;
1312                     int                            rs_num, i;
1313 
1314                     pr->anchor[sizeof(pr->anchor) - 1] = 0;
1315                     ruleset = pf_find_ruleset(pr->anchor);
1316                     if (ruleset == NULL) {
1317                               error = EINVAL;
1318                               break;
1319                     }
1320                     rs_num = pf_get_ruleset_number(pr->rule.action);
1321                     if (rs_num >= PF_RULESET_MAX) {
1322                               error = EINVAL;
1323                               break;
1324                     }
1325                     if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
1326                               error = EBUSY;
1327                               break;
1328                     }
1329                     rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
1330                     while ((rule != NULL) && (rule->nr != pr->nr))
1331                               rule = TAILQ_NEXT(rule, entries);
1332                     if (rule == NULL) {
1333                               error = EBUSY;
1334                               break;
1335                     }
1336                     bcopy(rule, &pr->rule, sizeof(struct pf_rule));
1337                     if (pf_anchor_copyout(ruleset, rule, pr)) {
1338                               error = EBUSY;
1339                               break;
1340                     }
1341                     pf_addr_copyout(&pr->rule.src.addr);
1342                     pf_addr_copyout(&pr->rule.dst.addr);
1343                     for (i = 0; i < PF_SKIP_COUNT; ++i)
1344                               if (rule->skip[i].ptr == NULL)
1345                                         pr->rule.skip[i].nr = (uint32_t)(-1);
1346                               else
1347                                         pr->rule.skip[i].nr =
1348                                             rule->skip[i].ptr->nr;
1349 
1350                     if (pr->action == PF_GET_CLR_CNTR) {
1351                               rule->evaluations = 0;
1352                               rule->packets[0] = rule->packets[1] = 0;
1353                               rule->bytes[0] = rule->bytes[1] = 0;
1354                               rule->states_tot = 0;
1355                     }
1356                     break;
1357           }
1358 
1359           case DIOCCHANGERULE: {
1360                     struct pfioc_rule   *pcr = (struct pfioc_rule *)addr;
1361                     struct pf_ruleset   *ruleset;
1362                     struct pf_rule                *oldrule = NULL, *newrule = NULL;
1363                     u_int32_t            nr = 0;
1364                     int                            rs_num;
1365 
1366                     if (!(pcr->action == PF_CHANGE_REMOVE ||
1367                         pcr->action == PF_CHANGE_GET_TICKET) &&
1368                         pcr->pool_ticket != ticket_pabuf) {
1369                               error = EBUSY;
1370                               break;
1371                     }
1372 
1373                     if (pcr->action < PF_CHANGE_ADD_HEAD ||
1374                         pcr->action > PF_CHANGE_GET_TICKET) {
1375                               error = EINVAL;
1376                               break;
1377                     }
1378                     ruleset = pf_find_ruleset(pcr->anchor);
1379                     if (ruleset == NULL) {
1380                               error = EINVAL;
1381                               break;
1382                     }
1383                     rs_num = pf_get_ruleset_number(pcr->rule.action);
1384                     if (rs_num >= PF_RULESET_MAX) {
1385                               error = EINVAL;
1386                               break;
1387                     }
1388 
1389                     if (pcr->action == PF_CHANGE_GET_TICKET) {
1390                               pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
1391                               break;
1392                     } else {
1393                               if (pcr->ticket !=
1394                                   ruleset->rules[rs_num].active.ticket) {
1395                                         error = EINVAL;
1396                                         break;
1397                               }
1398                               if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1399                                         error = EINVAL;
1400                                         break;
1401                               }
1402                     }
1403 
1404                     if (pcr->action != PF_CHANGE_REMOVE) {
1405                               newrule = kmalloc(sizeof(struct pf_rule), M_PFRULEPL, M_WAITOK|M_NULLOK);
1406                               if (newrule == NULL) {
1407                                         error = ENOMEM;
1408                                         break;
1409                               }
1410                               bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
1411                               newrule->cuid = ap->a_cred->cr_ruid;
1412                               newrule->cpid = 0;
1413                               TAILQ_INIT(&newrule->rpool.list);
1414                               /* initialize refcounting */
1415                               newrule->states_cur = 0;
1416                               newrule->entries.tqe_prev = NULL;
1417 #ifndef INET
1418                               if (newrule->af == AF_INET) {
1419                                         kfree(newrule, M_PFRULEPL);
1420                                         error = EAFNOSUPPORT;
1421                                         break;
1422                               }
1423 #endif /* INET */
1424 #ifndef INET6
1425                               if (newrule->af == AF_INET6) {
1426                                         kfree(newrule, M_PFRULEPL);
1427                                         error = EAFNOSUPPORT;
1428                                         break;
1429                               }
1430 #endif /* INET6 */
1431                               if (newrule->ifname[0]) {
1432                                         newrule->kif = pfi_kif_get(newrule->ifname);
1433                                         if (newrule->kif == NULL) {
1434                                                   kfree(newrule, M_PFRULEPL);
1435                                                   error = EINVAL;
1436                                                   break;
1437                                         }
1438                                         pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
1439                               } else
1440                                         newrule->kif = NULL;
1441 
1442                               if (newrule->rtableid > 0 &&
1443                                   newrule->rtableid > rt_numfibs)
1444                                         error = EBUSY;
1445 
1446 #ifdef ALTQ
1447                               /* set queue IDs */
1448                               if (newrule->qname[0] != 0) {
1449                                         if ((newrule->qid =
1450                                             pf_qname2qid(newrule->qname)) == 0)
1451                                                   error = EBUSY;
1452                                         else if (newrule->pqname[0] != 0) {
1453                                                   if ((newrule->pqid =
1454                                                       pf_qname2qid(newrule->pqname)) == 0)
1455                                                             error = EBUSY;
1456                                         } else
1457                                                   newrule->pqid = newrule->qid;
1458                               }
1459 #endif /* ALTQ */
1460                               if (newrule->tagname[0])
1461                                         if ((newrule->tag =
1462                                             pf_tagname2tag(newrule->tagname)) == 0)
1463                                                   error = EBUSY;
1464                               if (newrule->match_tagname[0])
1465                                         if ((newrule->match_tag = pf_tagname2tag(
1466                                             newrule->match_tagname)) == 0)
1467                                                   error = EBUSY;
1468                               if (newrule->rt && !newrule->direction)
1469                                         error = EINVAL;
1470 #if NPFLOG > 0
1471                               if (!newrule->log)
1472                                         newrule->logif = 0;
1473                               if (newrule->logif >= PFLOGIFS_MAX)
1474                                         error = EINVAL;
1475 #endif
1476                               if (pf_rtlabel_add(&newrule->src.addr) ||
1477                                   pf_rtlabel_add(&newrule->dst.addr))
1478                                         error = EBUSY;
1479                               if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af))
1480                                         error = EINVAL;
1481                               if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af))
1482                                         error = EINVAL;
1483                               if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call))
1484                                         error = EINVAL;
1485                               TAILQ_FOREACH(pa, &pf_pabuf, entries)
1486                                         if (pf_tbladdr_setup(ruleset, &pa->addr))
1487                                                   error = EINVAL;
1488 
1489                               if (newrule->overload_tblname[0]) {
1490                                         if ((newrule->overload_tbl = pfr_attach_table(
1491                                             ruleset, newrule->overload_tblname)) ==
1492                                             NULL)
1493                                                   error = EINVAL;
1494                                         else
1495                                                   newrule->overload_tbl->pfrkt_flags |=
1496                                                       PFR_TFLAG_ACTIVE;
1497                               }
1498 
1499                               pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
1500                               if (((((newrule->action == PF_NAT) ||
1501                                   (newrule->action == PF_RDR) ||
1502                                   (newrule->action == PF_BINAT) ||
1503                                   (newrule->rt > PF_FASTROUTE)) &&
1504                                   !newrule->anchor)) &&
1505                                   (TAILQ_FIRST(&newrule->rpool.list) == NULL))
1506                                         error = EINVAL;
1507 
1508                               if (error) {
1509                                         pf_rm_rule(NULL, newrule);
1510                                         break;
1511                               }
1512                               newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
1513                               newrule->evaluations = 0;
1514                               newrule->packets[0] = newrule->packets[1] = 0;
1515                               newrule->bytes[0] = newrule->bytes[1] = 0;
1516                     }
1517                     pf_empty_pool(&pf_pabuf);
1518 
1519                     if (pcr->action == PF_CHANGE_ADD_HEAD)
1520                               oldrule = TAILQ_FIRST(
1521                                   ruleset->rules[rs_num].active.ptr);
1522                     else if (pcr->action == PF_CHANGE_ADD_TAIL)
1523                               oldrule = TAILQ_LAST(
1524                                   ruleset->rules[rs_num].active.ptr, pf_rulequeue);
1525                     else {
1526                               oldrule = TAILQ_FIRST(
1527                                   ruleset->rules[rs_num].active.ptr);
1528                               while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
1529                                         oldrule = TAILQ_NEXT(oldrule, entries);
1530                               if (oldrule == NULL) {
1531                                         if (newrule != NULL)
1532                                                   pf_rm_rule(NULL, newrule);
1533                                         error = EINVAL;
1534                                         break;
1535                               }
1536                     }
1537 
1538                     if (pcr->action == PF_CHANGE_REMOVE) {
1539                               pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
1540                               ruleset->rules[rs_num].active.rcount--;
1541                     } else {
1542                               if (oldrule == NULL)
1543                                         TAILQ_INSERT_TAIL(
1544                                             ruleset->rules[rs_num].active.ptr,
1545                                             newrule, entries);
1546                               else if (pcr->action == PF_CHANGE_ADD_HEAD ||
1547                                   pcr->action == PF_CHANGE_ADD_BEFORE)
1548                                         TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
1549                               else
1550                                         TAILQ_INSERT_AFTER(
1551                                             ruleset->rules[rs_num].active.ptr,
1552                                             oldrule, newrule, entries);
1553                               ruleset->rules[rs_num].active.rcount++;
1554                     }
1555 
1556                     nr = 0;
1557                     TAILQ_FOREACH(oldrule,
1558                         ruleset->rules[rs_num].active.ptr, entries)
1559                               oldrule->nr = nr++;
1560 
1561                     ruleset->rules[rs_num].active.ticket++;
1562 
1563                     pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1564                     pf_remove_if_empty_ruleset(ruleset);
1565 
1566                     break;
1567           }
1568 
1569           case DIOCCLRSTATES: {
1570                     struct pf_state               *s, *nexts;
1571                     struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
1572                     u_int                          killed = 0;
1573                     globaldata_t save_gd = mycpu;
1574                     int nn;
1575 
1576                     for (nn = 0; nn < ncpus; ++nn) {
1577                               lwkt_setcpu_self(globaldata_find(nn));
1578                               for (s = RB_MIN(pf_state_tree_id, &tree_id[nn]);
1579                                    s; s = nexts) {
1580                                         nexts = RB_NEXT(pf_state_tree_id,
1581                                                             &tree_id[nn], s);
1582 
1583                                         if (!psk->psk_ifname[0] ||
1584                                             !strcmp(psk->psk_ifname,
1585                                                       s->kif->pfik_name)) {
1586                                                   /*
1587                                                    * don't send out individual
1588                                                    * delete messages
1589                                                    */
1590                                                   s->sync_flags = PFSTATE_NOSYNC;
1591                                                   pf_unlink_state(s);
1592                                                   killed++;
1593                                         }
1594                               }
1595                     }
1596                     lwkt_setcpu_self(save_gd);
1597                     psk->psk_killed = killed;
1598                     pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
1599                     break;
1600           }
1601 
1602           case DIOCKILLSTATES: {
1603                     struct pf_state               *s, *nexts;
1604                     struct pf_state_key *sk;
1605                     struct pf_addr                *srcaddr, *dstaddr;
1606                     u_int16_t            srcport, dstport;
1607                     struct pfioc_state_kill       *psk = (struct pfioc_state_kill *)addr;
1608                     u_int                          killed = 0;
1609                     globaldata_t save_gd = mycpu;
1610                     int nn;
1611 
1612                     if (psk->psk_pfcmp.id) {
1613                               if (psk->psk_pfcmp.creatorid == 0)
1614                                         psk->psk_pfcmp.creatorid = pf_status.hostid;
1615                               for (nn = 0; nn < ncpus; ++nn) {
1616                                         lwkt_setcpu_self(globaldata_find(nn));
1617                                         if ((s = pf_find_state_byid(&psk->psk_pfcmp))) {
1618                                                   /* send immediate delete of state */
1619                                                   pfsync_delete_state(s);
1620                                                   s->sync_flags |= PFSTATE_NOSYNC;
1621                                                   pf_unlink_state(s);
1622                                                   ++psk->psk_killed;
1623                                         }
1624                               }
1625                               lwkt_setcpu_self(save_gd);
1626                               break;
1627                     }
1628 
1629                     for (nn = 0; nn < ncpus; ++nn) {
1630                         lwkt_setcpu_self(globaldata_find(nn));
1631                         for (s = RB_MIN(pf_state_tree_id, &tree_id[nn]);
1632                                s; s = nexts) {
1633                                   nexts = RB_NEXT(pf_state_tree_id, &tree_id[nn], s);
1634                                   sk = s->key[PF_SK_WIRE];
1635 
1636                                   if (s->direction == PF_OUT) {
1637                                             srcaddr = &sk->addr[1];
1638                                             dstaddr = &sk->addr[0];
1639                                             srcport = sk->port[0];
1640                                             dstport = sk->port[0];
1641                                   } else {
1642                                             srcaddr = &sk->addr[0];
1643                                             dstaddr = &sk->addr[1];
1644                                             srcport = sk->port[0];
1645                                             dstport = sk->port[0];
1646                                   }
1647                                   if ((!psk->psk_af || sk->af == psk->psk_af)
1648                                         && (!psk->psk_proto || psk->psk_proto ==
1649                                                                    sk->proto) &&
1650                                         PF_MATCHA(psk->psk_src.neg,
1651                                                     &psk->psk_src.addr.v.a.addr,
1652                                                     &psk->psk_src.addr.v.a.mask,
1653                                                     srcaddr, sk->af) &&
1654                                         PF_MATCHA(psk->psk_dst.neg,
1655                                                     &psk->psk_dst.addr.v.a.addr,
1656                                                     &psk->psk_dst.addr.v.a.mask,
1657                                                     dstaddr, sk->af) &&
1658                                         (psk->psk_src.port_op == 0 ||
1659                                          pf_match_port(psk->psk_src.port_op,
1660                                                          psk->psk_src.port[0],
1661                                                          psk->psk_src.port[1],
1662                                                          srcport)) &&
1663                                         (psk->psk_dst.port_op == 0 ||
1664                                          pf_match_port(psk->psk_dst.port_op,
1665                                                          psk->psk_dst.port[0],
1666                                                          psk->psk_dst.port[1],
1667                                                          dstport)) &&
1668                                         (!psk->psk_label[0] ||
1669                                          (s->rule.ptr->label[0] &&
1670                                           !strcmp(psk->psk_label, s->rule.ptr->label))) &&
1671                                         (!psk->psk_ifname[0] ||
1672                                          !strcmp(psk->psk_ifname, s->kif->pfik_name))) {
1673                                             /* send immediate delete of state */
1674                                             pfsync_delete_state(s);
1675                                             s->sync_flags |= PFSTATE_NOSYNC;
1676                                             pf_unlink_state(s);
1677                                             killed++;
1678                                   }
1679                         }
1680                     }
1681                     lwkt_setcpu_self(save_gd);
1682                     psk->psk_killed = killed;
1683                     break;
1684           }
1685 
1686           case DIOCADDSTATE: {
1687                     struct pfioc_state  *ps = (struct pfioc_state *)addr;
1688                     struct pfsync_state *sp = &ps->state;
1689 
1690                     if (sp->timeout >= PFTM_MAX &&
1691                         sp->timeout != PFTM_UNTIL_PACKET) {
1692                               error = EINVAL;
1693                               break;
1694                     }
1695                     error = pfsync_state_import(sp, PFSYNC_SI_IOCTL);
1696                     break;
1697           }
1698 
1699           case DIOCGETSTATE: {
1700                     struct pfioc_state  *ps = (struct pfioc_state *)addr;
1701                     struct pf_state               *s;
1702                     struct pf_state_cmp  id_key;
1703                     globaldata_t save_gd = mycpu;
1704                     int nn;
1705 
1706                     bcopy(ps->state.id, &id_key.id, sizeof(id_key.id));
1707                     id_key.creatorid = ps->state.creatorid;
1708                     s = NULL;
1709                     for (nn = 0; nn < ncpus; ++nn) {
1710                               lwkt_setcpu_self(globaldata_find(nn));
1711                               s = pf_find_state_byid(&id_key);
1712                               if (s)
1713                                         break;
1714                     }
1715                     if (s) {
1716                               pfsync_state_export(&ps->state, s);
1717                     } else {
1718                               error = ENOENT;
1719                     }
1720                     lwkt_setcpu_self(save_gd);
1721                     break;
1722           }
1723 
1724           case DIOCGETSTATES: {
1725                     struct pfioc_states *ps = (struct pfioc_states *)addr;
1726                     struct pf_state               *state;
1727                     struct pfsync_state *p, *pstore;
1728                     u_int32_t            nr = 0;
1729                     globaldata_t save_gd = mycpu;
1730                     int nn;
1731 
1732                     if (ps->ps_len == 0) {
1733                               nr = pf_status.states;
1734                               ps->ps_len = sizeof(struct pfsync_state) * nr;
1735                               break;
1736                     }
1737 
1738                     pstore = kmalloc(sizeof(*pstore), M_TEMP, M_WAITOK);
1739 
1740                     p = ps->ps_states;
1741 
1742                     for (nn = 0; nn < ncpus; ++nn) {
1743                               lwkt_setcpu_self(globaldata_find(nn));
1744                               state = TAILQ_FIRST(&state_list[nn]);
1745                               while (state) {
1746                                         if (state->timeout != PFTM_UNLINKED) {
1747                                                   if ((nr + 1) * sizeof(*p) >
1748                                                       (unsigned)ps->ps_len) {
1749                                                             break;
1750                                                   }
1751                                                   pfsync_state_export(pstore, state);
1752                                                   error = copyout(pstore, p, sizeof(*p));
1753                                                   if (error) {
1754                                                             kfree(pstore, M_TEMP);
1755                                                             lwkt_setcpu_self(save_gd);
1756                                                             goto fail;
1757                                                   }
1758                                                   p++;
1759                                                   nr++;
1760                                         }
1761                                         state = TAILQ_NEXT(state, entry_list);
1762                               }
1763                     }
1764                     lwkt_setcpu_self(save_gd);
1765                     ps->ps_len = sizeof(struct pfsync_state) * nr;
1766                     kfree(pstore, M_TEMP);
1767                     break;
1768           }
1769 
1770           case DIOCGETSTATUS: {
1771                     /*
1772                      * Retrieve pf_status, merge pcpu counters into pf_status
1773                      * for user consumption.
1774                      */
1775                     struct pf_status *s = (struct pf_status *)addr;
1776                     struct pf_counters *pfc;
1777                     int n;
1778                     int i;
1779 
1780                     bcopy(&pf_status, s, sizeof(struct pf_status));
1781                     for (n = 0; n < ncpus; ++n) {
1782                               pfc = &pf_counters[n];
1783                               for (i = 0; i < PFRES_MAX; ++i)
1784                                         s->counters[i] += pfc->counters[i];
1785                               for (i = 0; i < LCNT_MAX; ++i)
1786                                         s->lcounters[i] += pfc->lcounters[i];
1787                               for (i = 0; i < FCNT_MAX; ++i)
1788                                         s->fcounters[i] += pfc->fcounters[i];
1789                               for (i = 0; i < SCNT_MAX; ++i)
1790                                         s->scounters[i] += pfc->scounters[i];
1791                     }
1792                     pfi_update_status(s->ifname, s);
1793                     break;
1794           }
1795 
1796           case DIOCSETSTATUSIF: {
1797                     struct pfioc_if     *pi = (struct pfioc_if *)addr;
1798 
1799                     if (pi->ifname[0] == 0) {
1800                               bzero(pf_status.ifname, IFNAMSIZ);
1801                               break;
1802                     }
1803                     strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);
1804                     break;
1805           }
1806 
1807           case DIOCCLRSTATUS: {
1808                     int i;
1809 
1810                     bzero(pf_status.counters, sizeof(pf_status.counters));
1811                     bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
1812                     bzero(pf_status.scounters, sizeof(pf_status.scounters));
1813                     for (i = 0; i < ncpus; ++i) {
1814                               bzero(pf_counters[i].counters, sizeof(pf_counters[0].counters));
1815                               bzero(pf_counters[i].fcounters, sizeof(pf_counters[0].fcounters));
1816                               bzero(pf_counters[i].scounters, sizeof(pf_counters[0].scounters));
1817                     }
1818 
1819                     pf_status.since = time_second;
1820                     if (*pf_status.ifname)
1821                               pfi_update_status(pf_status.ifname, NULL);
1822                     break;
1823           }
1824 
1825           case DIOCNATLOOK: {
1826                     struct pfioc_natlook          *pnl = (struct pfioc_natlook *)addr;
1827                     struct pf_state_key *sk;
1828                     struct pf_state               *state;
1829                     struct pf_state_key_cmp        key;
1830                     int                            m = 0, direction = pnl->direction;
1831                     int                            sidx, didx;
1832                     globaldata_t save_gd = mycpu;
1833                     int nn;
1834 
1835                     /* NATLOOK src and dst are reversed, so reverse sidx/didx */
1836                     sidx = (direction == PF_IN) ? 1 : 0;
1837                     didx = (direction == PF_IN) ? 0 : 1;
1838 
1839                     if (!pnl->proto ||
1840                         PF_AZERO(&pnl->saddr, pnl->af) ||
1841                         PF_AZERO(&pnl->daddr, pnl->af) ||
1842                         ((pnl->proto == IPPROTO_TCP ||
1843                         pnl->proto == IPPROTO_UDP) &&
1844                         (!pnl->dport || !pnl->sport)))
1845                               error = EINVAL;
1846                     else {
1847                               key.af = pnl->af;
1848                               key.proto = pnl->proto;
1849                               PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af);
1850                               key.port[sidx] = pnl->sport;
1851                               PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af);
1852                               key.port[didx] = pnl->dport;
1853 
1854                               state = NULL;
1855                               for (nn = 0; nn < ncpus; ++nn) {
1856                                         lwkt_setcpu_self(globaldata_find(nn));
1857                                         state = pf_find_state_all(&key, direction, &m);
1858                                         if (state || m > 1)
1859                                                   break;
1860                                         m = 0;
1861                               }
1862 
1863                               if (m > 1) {
1864                                         error = E2BIG;      /* more than one state */
1865                               } else if (state != NULL) {
1866                                         sk = state->key[sidx];
1867                                         PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af);
1868                                         pnl->rsport = sk->port[sidx];
1869                                         PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af);
1870                                         pnl->rdport = sk->port[didx];
1871                               } else {
1872                                         error = ENOENT;
1873                               }
1874                               lwkt_setcpu_self(save_gd);
1875                     }
1876                     break;
1877           }
1878 
1879           case DIOCSETTIMEOUT: {
1880                     struct pfioc_tm     *pt = (struct pfioc_tm *)addr;
1881                     int                  old;
1882 
1883                     if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
1884                         pt->seconds < 0) {
1885                               error = EINVAL;
1886                               goto fail;
1887                     }
1888                     old = pf_default_rule.timeout[pt->timeout];
1889                     if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
1890                               pt->seconds = 1;
1891                     pf_default_rule.timeout[pt->timeout] = pt->seconds;
1892                     if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
1893                               wakeup(pf_purge_thread);
1894                     pt->seconds = old;
1895                     break;
1896           }
1897 
1898           case DIOCGETTIMEOUT: {
1899                     struct pfioc_tm     *pt = (struct pfioc_tm *)addr;
1900 
1901                     if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
1902                               error = EINVAL;
1903                               goto fail;
1904                     }
1905                     pt->seconds = pf_default_rule.timeout[pt->timeout];
1906                     break;
1907           }
1908 
1909           case DIOCGETLIMIT: {
1910                     struct pfioc_limit  *pl = (struct pfioc_limit *)addr;
1911 
1912                     if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1913                               error = EINVAL;
1914                               goto fail;
1915                     }
1916                     pl->limit = pf_pool_limits[pl->index].limit;
1917                     break;
1918           }
1919 
1920           case DIOCSETLIMIT: {
1921                     struct pfioc_limit  *pl = (struct pfioc_limit *)addr;
1922                     int                            old_limit;
1923 
1924                     if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
1925                         pf_pool_limits[pl->index].pp == NULL) {
1926                               error = EINVAL;
1927                               goto fail;
1928                     }
1929 
1930                     /* XXX Get an API to set limits on the zone/pool */
1931                     old_limit = pf_pool_limits[pl->index].limit;
1932                     pf_pool_limits[pl->index].limit = pl->limit;
1933                     pl->limit = old_limit;
1934                     break;
1935           }
1936 
1937           case DIOCSETDEBUG: {
1938                     u_int32_t *level = (u_int32_t *)addr;
1939 
1940                     pf_status.debug = *level;
1941                     break;
1942           }
1943 
1944           case DIOCCLRRULECTRS: {
1945                     /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
1946                     struct pf_ruleset   *ruleset = &pf_main_ruleset;
1947                     struct pf_rule                *rule;
1948 
1949                     TAILQ_FOREACH(rule,
1950                         ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
1951                               rule->evaluations = 0;
1952                               rule->packets[0] = rule->packets[1] = 0;
1953                               rule->bytes[0] = rule->bytes[1] = 0;
1954                     }
1955                     break;
1956           }
1957 
1958           case DIOCGIFSPEED: {
1959                     struct pf_ifspeed   *psp = (struct pf_ifspeed *)addr;
1960                     struct pf_ifspeed   ps;
1961                     struct ifnet                  *ifp;
1962 
1963                     if (psp->ifname[0] != 0) {
1964                               /* Can we completely trust user-land? */
1965                               strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
1966                               ifnet_lock();
1967                               ifp = ifunit(ps.ifname);
1968                               if (ifp )
1969                                         psp->baudrate = ifp->if_baudrate;
1970                               else
1971                                         error = EINVAL;
1972                               ifnet_unlock();
1973                     } else
1974                               error = EINVAL;
1975                     break;
1976           }
1977 #ifdef ALTQ
1978           case DIOCSTARTALTQ: {
1979                     struct pf_altq                *altq;
1980 
1981                     /* enable all altq interfaces on active list */
1982                     TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1983                               if (altq->qname[0] == 0) {
1984                                         error = pf_enable_altq(altq);
1985                                         if (error != 0)
1986                                                   break;
1987                               }
1988                     }
1989                     if (error == 0)
1990                               pf_altq_running = 1;
1991                     DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
1992                     break;
1993           }
1994 
1995           case DIOCSTOPALTQ: {
1996                     struct pf_altq                *altq;
1997 
1998                     /* disable all altq interfaces on active list */
1999                     TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2000                               if (altq->qname[0] == 0) {
2001                                         error = pf_disable_altq(altq);
2002                                         if (error != 0)
2003                                                   break;
2004                               }
2005                     }
2006                     if (error == 0)
2007                               pf_altq_running = 0;
2008                     DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
2009                     break;
2010           }
2011 
2012           case DIOCADDALTQ: {
2013                     struct pfioc_altq   *pa = (struct pfioc_altq *)addr;
2014                     struct pf_altq                *altq, *a;
2015 
2016                     if (pa->ticket != ticket_altqs_inactive) {
2017                               error = EBUSY;
2018                               break;
2019                     }
2020                     altq = kmalloc(sizeof(struct pf_altq), M_PFALTQPL, M_WAITOK|M_NULLOK);
2021                     if (altq == NULL) {
2022                               error = ENOMEM;
2023                               break;
2024                     }
2025                     bcopy(&pa->altq, altq, sizeof(struct pf_altq));
2026 
2027                     /*
2028                      * if this is for a queue, find the discipline and
2029                      * copy the necessary fields
2030                      */
2031                     if (altq->qname[0] != 0) {
2032                               if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
2033                                         error = EBUSY;
2034                                         kfree(altq, M_PFALTQPL);
2035                                         break;
2036                               }
2037                               altq->altq_disc = NULL;
2038                               TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
2039                                         if (strncmp(a->ifname, altq->ifname,
2040                                             IFNAMSIZ) == 0 && a->qname[0] == 0) {
2041                                                   altq->altq_disc = a->altq_disc;
2042                                                   break;
2043                                         }
2044                               }
2045                     }
2046 
2047                     error = altq_add(altq);
2048                     if (error) {
2049                               kfree(altq, M_PFALTQPL);
2050                               break;
2051                     }
2052 
2053                     TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
2054                     bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2055                     break;
2056           }
2057 
2058           case DIOCGETALTQS: {
2059                     struct pfioc_altq   *pa = (struct pfioc_altq *)addr;
2060                     struct pf_altq                *altq;
2061 
2062                     pa->nr = 0;
2063                     TAILQ_FOREACH(altq, pf_altqs_active, entries)
2064                               pa->nr++;
2065                     pa->ticket = ticket_altqs_active;
2066                     break;
2067           }
2068 
2069           case DIOCGETALTQ: {
2070                     struct pfioc_altq   *pa = (struct pfioc_altq *)addr;
2071                     struct pf_altq                *altq;
2072                     u_int32_t            nr;
2073 
2074                     if (pa->ticket != ticket_altqs_active) {
2075                               error = EBUSY;
2076                               break;
2077                     }
2078                     nr = 0;
2079                     altq = TAILQ_FIRST(pf_altqs_active);
2080                     while ((altq != NULL) && (nr < pa->nr)) {
2081                               altq = TAILQ_NEXT(altq, entries);
2082                               nr++;
2083                     }
2084                     if (altq == NULL) {
2085                               error = EBUSY;
2086                               break;
2087                     }
2088                     bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2089                     break;
2090           }
2091 
2092           case DIOCCHANGEALTQ:
2093                     /* CHANGEALTQ not supported yet! */
2094                     error = ENODEV;
2095                     break;
2096 
2097           case DIOCGETQSTATS: {
2098                     struct pfioc_qstats *pq = (struct pfioc_qstats *)addr;
2099                     struct pf_altq                *altq;
2100                     u_int32_t            nr;
2101                     int                            nbytes;
2102 
2103                     if (pq->ticket != ticket_altqs_active) {
2104                               error = EBUSY;
2105                               break;
2106                     }
2107                     nbytes = pq->nbytes;
2108                     nr = 0;
2109                     altq = TAILQ_FIRST(pf_altqs_active);
2110                     while ((altq != NULL) && (nr < pq->nr)) {
2111                               altq = TAILQ_NEXT(altq, entries);
2112                               nr++;
2113                     }
2114                     if (altq == NULL) {
2115                               error = EBUSY;
2116                               break;
2117                     }
2118                     error = altq_getqstats(altq, pq->buf, &nbytes);
2119                     if (error == 0) {
2120                               pq->scheduler = altq->scheduler;
2121                               pq->nbytes = nbytes;
2122                     }
2123                     break;
2124           }
2125 #endif /* ALTQ */
2126 
2127           case DIOCBEGINADDRS: {
2128                     struct pfioc_pooladdr         *pp = (struct pfioc_pooladdr *)addr;
2129 
2130                     pf_empty_pool(&pf_pabuf);
2131                     pp->ticket = ++ticket_pabuf;
2132                     break;
2133           }
2134 
2135           case DIOCADDADDR: {
2136                     struct pfioc_pooladdr         *pp = (struct pfioc_pooladdr *)addr;
2137 
2138                     if (pp->ticket != ticket_pabuf) {
2139                               error = EBUSY;
2140                               break;
2141                     }
2142 #ifndef INET
2143                     if (pp->af == AF_INET) {
2144                               error = EAFNOSUPPORT;
2145                               break;
2146                     }
2147 #endif /* INET */
2148 #ifndef INET6
2149                     if (pp->af == AF_INET6) {
2150                               error = EAFNOSUPPORT;
2151                               break;
2152                     }
2153 #endif /* INET6 */
2154                     if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
2155                         pp->addr.addr.type != PF_ADDR_DYNIFTL &&
2156                         pp->addr.addr.type != PF_ADDR_TABLE) {
2157                               error = EINVAL;
2158                               break;
2159                     }
2160                     pa = kmalloc(sizeof(struct pf_altq), M_PFPOOLADDRPL, M_WAITOK|M_NULLOK);
2161                     if (pa == NULL) {
2162                               error = ENOMEM;
2163                               break;
2164                     }
2165                     bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
2166                     if (pa->ifname[0]) {
2167                               pa->kif = pfi_kif_get(pa->ifname);
2168                               if (pa->kif == NULL) {
2169                                         kfree(ap, M_PFPOOLADDRPL);
2170                                         error = EINVAL;
2171                                         break;
2172                               }
2173                               pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
2174                     }
2175                     if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
2176                               pfi_dynaddr_remove(&pa->addr);
2177                               pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
2178                               kfree(pa, M_PFPOOLADDRPL);
2179                               error = EINVAL;
2180                               break;
2181                     }
2182                     TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
2183                     break;
2184           }
2185 
2186           case DIOCGETADDRS: {
2187                     struct pfioc_pooladdr         *pp = (struct pfioc_pooladdr *)addr;
2188 
2189                     pp->nr = 0;
2190                     pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
2191                         pp->r_num, 0, 1, 0);
2192                     if (pool == NULL) {
2193                               error = EBUSY;
2194                               break;
2195                     }
2196                     TAILQ_FOREACH(pa, &pool->list, entries)
2197                               pp->nr++;
2198                     break;
2199           }
2200 
2201           case DIOCGETADDR: {
2202                     struct pfioc_pooladdr         *pp = (struct pfioc_pooladdr *)addr;
2203                     u_int32_t            nr = 0;
2204 
2205                     pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
2206                         pp->r_num, 0, 1, 1);
2207                     if (pool == NULL) {
2208                               error = EBUSY;
2209                               break;
2210                     }
2211                     pa = TAILQ_FIRST(&pool->list);
2212                     while ((pa != NULL) && (nr < pp->nr)) {
2213                               pa = TAILQ_NEXT(pa, entries);
2214                               nr++;
2215                     }
2216                     if (pa == NULL) {
2217                               error = EBUSY;
2218                               break;
2219                     }
2220                     bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
2221                     pf_addr_copyout(&pp->addr.addr);
2222                     break;
2223           }
2224 
2225           case DIOCCHANGEADDR: {
2226                     struct pfioc_pooladdr         *pca = (struct pfioc_pooladdr *)addr;
2227                     struct pf_pooladdr  *oldpa = NULL, *newpa = NULL;
2228                     struct pf_ruleset   *ruleset;
2229 
2230                     if (pca->action < PF_CHANGE_ADD_HEAD ||
2231                         pca->action > PF_CHANGE_REMOVE) {
2232                               error = EINVAL;
2233                               break;
2234                     }
2235                     if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
2236                         pca->addr.addr.type != PF_ADDR_DYNIFTL &&
2237                         pca->addr.addr.type != PF_ADDR_TABLE) {
2238                               error = EINVAL;
2239                               break;
2240                     }
2241 
2242                     ruleset = pf_find_ruleset(pca->anchor);
2243                     if (ruleset == NULL) {
2244                               error = EBUSY;
2245                               break;
2246                     }
2247                     pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
2248                         pca->r_num, pca->r_last, 1, 1);
2249                     if (pool == NULL) {
2250                               error = EBUSY;
2251                               break;
2252                     }
2253                     if (pca->action != PF_CHANGE_REMOVE) {
2254                               newpa = kmalloc(sizeof(struct pf_pooladdr),
2255                                         M_PFPOOLADDRPL, M_WAITOK|M_NULLOK);
2256                               if (newpa == NULL) {
2257                                         error = ENOMEM;
2258                                         break;
2259                               }
2260                               bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
2261 #ifndef INET
2262                               if (pca->af == AF_INET) {
2263                                         kfree(newpa, M_PFPOOLADDRPL);
2264                                         error = EAFNOSUPPORT;
2265                                         break;
2266                               }
2267 #endif /* INET */
2268 #ifndef INET6
2269                               if (pca->af == AF_INET6) {
2270                                         kfree(newpa, M_PFPOOLADDRPL);
2271                                         error = EAFNOSUPPORT;
2272                                         break;
2273                               }
2274 #endif /* INET6 */
2275                               if (newpa->ifname[0]) {
2276                                         newpa->kif = pfi_kif_get(newpa->ifname);
2277                                         if (newpa->kif == NULL) {
2278                                                   kfree(newpa, M_PFPOOLADDRPL);
2279                                                   error = EINVAL;
2280                                                   break;
2281                                         }
2282                                         pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
2283                               } else
2284                                         newpa->kif = NULL;
2285                               if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
2286                                   pf_tbladdr_setup(ruleset, &newpa->addr)) {
2287                                         pfi_dynaddr_remove(&newpa->addr);
2288                                         pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
2289                                         kfree(newpa, M_PFPOOLADDRPL);
2290                                         error = EINVAL;
2291                                         break;
2292                               }
2293                     }
2294 
2295                     if (pca->action == PF_CHANGE_ADD_HEAD)
2296                               oldpa = TAILQ_FIRST(&pool->list);
2297                     else if (pca->action == PF_CHANGE_ADD_TAIL)
2298                               oldpa = TAILQ_LAST(&pool->list, pf_palist);
2299                     else {
2300                               int       i = 0;
2301 
2302                               oldpa = TAILQ_FIRST(&pool->list);
2303                               while ((oldpa != NULL) && (i < pca->nr)) {
2304                                         oldpa = TAILQ_NEXT(oldpa, entries);
2305                                         i++;
2306                               }
2307                               if (oldpa == NULL) {
2308                                         error = EINVAL;
2309                                         break;
2310                               }
2311                     }
2312 
2313                     if (pca->action == PF_CHANGE_REMOVE) {
2314                               TAILQ_REMOVE(&pool->list, oldpa, entries);
2315                               pfi_dynaddr_remove(&oldpa->addr);
2316                               pf_tbladdr_remove(&oldpa->addr);
2317                               pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
2318                               kfree(oldpa, M_PFPOOLADDRPL);
2319                     } else {
2320                               if (oldpa == NULL)
2321                                         TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
2322                               else if (pca->action == PF_CHANGE_ADD_HEAD ||
2323                                   pca->action == PF_CHANGE_ADD_BEFORE)
2324                                         TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
2325                               else
2326                                         TAILQ_INSERT_AFTER(&pool->list, oldpa,
2327                                             newpa, entries);
2328                     }
2329 
2330                     pool->cur = TAILQ_FIRST(&pool->list);
2331                     PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
2332                         pca->af);
2333                     break;
2334           }
2335 
2336           case DIOCGETRULESETS: {
2337                     struct pfioc_ruleset          *pr = (struct pfioc_ruleset *)addr;
2338                     struct pf_ruleset   *ruleset;
2339                     struct pf_anchor    *anchor;
2340 
2341                     pr->path[sizeof(pr->path) - 1] = 0;
2342                     if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
2343                               error = EINVAL;
2344                               break;
2345                     }
2346                     pr->nr = 0;
2347                     if (ruleset->anchor == NULL) {
2348                               /* XXX kludge for pf_main_ruleset */
2349                               RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
2350                                         if (anchor->parent == NULL)
2351                                                   pr->nr++;
2352                     } else {
2353                               RB_FOREACH(anchor, pf_anchor_node,
2354                                   &ruleset->anchor->children)
2355                                         pr->nr++;
2356                     }
2357                     break;
2358           }
2359 
2360           case DIOCGETRULESET: {
2361                     struct pfioc_ruleset          *pr = (struct pfioc_ruleset *)addr;
2362                     struct pf_ruleset   *ruleset;
2363                     struct pf_anchor    *anchor;
2364                     u_int32_t            nr = 0;
2365 
2366                     pr->path[sizeof(pr->path) - 1] = 0;
2367                     if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
2368                               error = EINVAL;
2369                               break;
2370                     }
2371                     pr->name[0] = 0;
2372                     if (ruleset->anchor == NULL) {
2373                               /* XXX kludge for pf_main_ruleset */
2374                               RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
2375                                         if (anchor->parent == NULL && nr++ == pr->nr) {
2376                                                   strlcpy(pr->name, anchor->name,
2377                                                       sizeof(pr->name));
2378                                                   break;
2379                                         }
2380                     } else {
2381                               RB_FOREACH(anchor, pf_anchor_node,
2382                                   &ruleset->anchor->children)
2383                                         if (nr++ == pr->nr) {
2384                                                   strlcpy(pr->name, anchor->name,
2385                                                       sizeof(pr->name));
2386                                                   break;
2387                                         }
2388                     }
2389                     if (!pr->name[0])
2390                               error = EBUSY;
2391                     break;
2392           }
2393 
2394           case DIOCRCLRTABLES: {
2395                     struct pfioc_table *io = (struct pfioc_table *)addr;
2396 
2397                     if (io->pfrio_esize != 0) {
2398                               error = ENODEV;
2399                               break;
2400                     }
2401                     error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
2402                         io->pfrio_flags | PFR_FLAG_USERIOCTL);
2403                     break;
2404           }
2405 
2406           case DIOCRADDTABLES: {
2407                     struct pfioc_table *io = (struct pfioc_table *)addr;
2408 
2409                     if (io->pfrio_esize != sizeof(struct pfr_table)) {
2410                               error = ENODEV;
2411                               break;
2412                     }
2413                     error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
2414                         &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2415                     break;
2416           }
2417 
2418           case DIOCRDELTABLES: {
2419                     struct pfioc_table *io = (struct pfioc_table *)addr;
2420 
2421                     if (io->pfrio_esize != sizeof(struct pfr_table)) {
2422                               error = ENODEV;
2423                               break;
2424                     }
2425                     error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
2426                         &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2427                     break;
2428           }
2429 
2430           case DIOCRGETTABLES: {
2431                     struct pfioc_table *io = (struct pfioc_table *)addr;
2432 
2433                     if (io->pfrio_esize != sizeof(struct pfr_table)) {
2434                               error = ENODEV;
2435                               break;
2436                     }
2437                     error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
2438                         &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2439                     break;
2440           }
2441 
2442           case DIOCRGETTSTATS: {
2443                     struct pfioc_table *io = (struct pfioc_table *)addr;
2444 
2445                     if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
2446                               error = ENODEV;
2447                               break;
2448                     }
2449                     error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
2450                         &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2451                     break;
2452           }
2453 
2454           case DIOCRCLRTSTATS: {
2455                     struct pfioc_table *io = (struct pfioc_table *)addr;
2456 
2457                     if (io->pfrio_esize != sizeof(struct pfr_table)) {
2458                               error = ENODEV;
2459                               break;
2460                     }
2461                     error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
2462                         &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2463                     break;
2464           }
2465 
2466           case DIOCRSETTFLAGS: {
2467                     struct pfioc_table *io = (struct pfioc_table *)addr;
2468 
2469                     if (io->pfrio_esize != sizeof(struct pfr_table)) {
2470                               error = ENODEV;
2471                               break;
2472                     }
2473                     error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
2474                         io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
2475                         &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2476                     break;
2477           }
2478 
2479           case DIOCRCLRADDRS: {
2480                     struct pfioc_table *io = (struct pfioc_table *)addr;
2481 
2482                     if (io->pfrio_esize != 0) {
2483                               error = ENODEV;
2484                               break;
2485                     }
2486                     error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
2487                         io->pfrio_flags | PFR_FLAG_USERIOCTL);
2488                     break;
2489           }
2490 
2491           case DIOCRADDADDRS: {
2492                     struct pfioc_table *io = (struct pfioc_table *)addr;
2493 
2494                     if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2495                               error = ENODEV;
2496                               break;
2497                     }
2498                     error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
2499                         io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags |
2500                         PFR_FLAG_USERIOCTL);
2501                     break;
2502           }
2503 
2504           case DIOCRDELADDRS: {
2505                     struct pfioc_table *io = (struct pfioc_table *)addr;
2506 
2507                     if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2508                               error = ENODEV;
2509                               break;
2510                     }
2511                     error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
2512                         io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags |
2513                         PFR_FLAG_USERIOCTL);
2514                     break;
2515           }
2516 
2517           case DIOCRSETADDRS: {
2518                     struct pfioc_table *io = (struct pfioc_table *)addr;
2519 
2520                     if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2521                               error = ENODEV;
2522                               break;
2523                     }
2524                     error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
2525                         io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
2526                         &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
2527                         PFR_FLAG_USERIOCTL, 0);
2528                     break;
2529           }
2530 
2531           case DIOCRGETADDRS: {
2532                     struct pfioc_table *io = (struct pfioc_table *)addr;
2533 
2534                     if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2535                               error = ENODEV;
2536                               break;
2537                     }
2538                     error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
2539                         &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2540                     break;
2541           }
2542 
2543           case DIOCRGETASTATS: {
2544                     struct pfioc_table *io = (struct pfioc_table *)addr;
2545 
2546                     if (io->pfrio_esize != sizeof(struct pfr_astats)) {
2547                               error = ENODEV;
2548                               break;
2549                     }
2550                     error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
2551                         &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2552                     break;
2553           }
2554 
2555           case DIOCRCLRASTATS: {
2556                     struct pfioc_table *io = (struct pfioc_table *)addr;
2557 
2558                     if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2559                               error = ENODEV;
2560                               break;
2561                     }
2562                     error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
2563                         io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags |
2564                         PFR_FLAG_USERIOCTL);
2565                     break;
2566           }
2567 
2568           case DIOCRTSTADDRS: {
2569                     struct pfioc_table *io = (struct pfioc_table *)addr;
2570 
2571                     if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2572                               error = ENODEV;
2573                               break;
2574                     }
2575                     error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
2576                         io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags |
2577                         PFR_FLAG_USERIOCTL);
2578                     break;
2579           }
2580 
2581           case DIOCRINADEFINE: {
2582                     struct pfioc_table *io = (struct pfioc_table *)addr;
2583 
2584                     if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2585                               error = ENODEV;
2586                               break;
2587                     }
2588                     error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
2589                         io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
2590                         io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2591                     break;
2592           }
2593 
2594           case DIOCOSFPADD: {
2595                     struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2596                     error = pf_osfp_add(io);
2597                     break;
2598           }
2599 
2600           case DIOCOSFPGET: {
2601                     struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2602                     error = pf_osfp_get(io);
2603                     break;
2604           }
2605 
2606           case DIOCXBEGIN: {
2607                     struct pfioc_trans  *io = (struct pfioc_trans *)addr;
2608                     struct pfioc_trans_e          *ioe;
2609                     struct pfr_table    *table;
2610                     int                            i;
2611 
2612                     if (io->esize != sizeof(*ioe)) {
2613                               error = ENODEV;
2614                               goto fail;
2615                     }
2616                     ioe = kmalloc(sizeof(*ioe), M_TEMP, M_WAITOK);
2617                     table = kmalloc(sizeof(*table), M_TEMP, M_WAITOK);
2618                     for (i = 0; i < io->size; i++) {
2619                               if (copyin(io->array+i, ioe, sizeof(*ioe))) {
2620                                         kfree(table, M_TEMP);
2621                                         kfree(ioe, M_TEMP);
2622                                         error = EFAULT;
2623                                         goto fail;
2624                               }
2625                               switch (ioe->rs_num) {
2626 #ifdef ALTQ
2627                               case PF_RULESET_ALTQ:
2628                                         if (ioe->anchor[0]) {
2629                                                   kfree(table, M_TEMP);
2630                                                   kfree(ioe, M_TEMP);
2631                                                   error = EINVAL;
2632                                                   goto fail;
2633                                         }
2634                                         if ((error = pf_begin_altq(&ioe->ticket))) {
2635                                                   kfree(table, M_TEMP);
2636                                                   kfree(ioe, M_TEMP);
2637                                                   goto fail;
2638                                         }
2639                                         break;
2640 #endif /* ALTQ */
2641                               case PF_RULESET_TABLE:
2642                                         bzero(table, sizeof(*table));
2643                                         strlcpy(table->pfrt_anchor, ioe->anchor,
2644                                             sizeof(table->pfrt_anchor));
2645                                         if ((error = pfr_ina_begin(table,
2646                                             &ioe->ticket, NULL, 0))) {
2647                                                   kfree(table, M_TEMP);
2648                                                   kfree(ioe, M_TEMP);
2649                                                   goto fail;
2650                                         }
2651                                         break;
2652                               default:
2653                                         if ((error = pf_begin_rules(&ioe->ticket,
2654                                             ioe->rs_num, ioe->anchor))) {
2655                                                   kfree(table, M_TEMP);
2656                                                   kfree(ioe, M_TEMP);
2657                                                   goto fail;
2658                                         }
2659                                         break;
2660                               }
2661                               if (copyout(ioe, io->array+i, sizeof(io->array[i]))) {
2662                                         kfree(table, M_TEMP);
2663                                         kfree(ioe, M_TEMP);
2664                                         error = EFAULT;
2665                                         goto fail;
2666                               }
2667                     }
2668                     kfree(table, M_TEMP);
2669                     kfree(ioe, M_TEMP);
2670                     break;
2671           }
2672 
2673           case DIOCXROLLBACK: {
2674                     struct pfioc_trans  *io = (struct pfioc_trans *)addr;
2675                     struct pfioc_trans_e          *ioe;
2676                     struct pfr_table    *table;
2677                     int                            i;
2678 
2679                     if (io->esize != sizeof(*ioe)) {
2680                               error = ENODEV;
2681                               goto fail;
2682                     }
2683                     ioe = kmalloc(sizeof(*ioe), M_TEMP, M_WAITOK);
2684                     table = kmalloc(sizeof(*table), M_TEMP, M_WAITOK);
2685                     for (i = 0; i < io->size; i++) {
2686                               if (copyin(io->array+i, ioe, sizeof(*ioe))) {
2687                                         kfree(table, M_TEMP);
2688                                         kfree(ioe, M_TEMP);
2689                                         error = EFAULT;
2690                                         goto fail;
2691                               }
2692                               switch (ioe->rs_num) {
2693 #ifdef ALTQ
2694                               case PF_RULESET_ALTQ:
2695                                         if (ioe->anchor[0]) {
2696                                                   kfree(table, M_TEMP);
2697                                                   kfree(ioe, M_TEMP);
2698                                                   error = EINVAL;
2699                                                   goto fail;
2700                                         }
2701                                         if ((error = pf_rollback_altq(ioe->ticket))) {
2702                                                   kfree(table, M_TEMP);
2703                                                   kfree(ioe, M_TEMP);
2704                                                   goto fail; /* really bad */
2705                                         }
2706                                         break;
2707 #endif /* ALTQ */
2708                               case PF_RULESET_TABLE:
2709                                         bzero(table, sizeof(*table));
2710                                         strlcpy(table->pfrt_anchor, ioe->anchor,
2711                                             sizeof(table->pfrt_anchor));
2712                                         if ((error = pfr_ina_rollback(table,
2713                                             ioe->ticket, NULL, 0))) {
2714                                                   kfree(table, M_TEMP);
2715                                                   kfree(ioe, M_TEMP);
2716                                                   goto fail; /* really bad */
2717                                         }
2718                                         break;
2719                               default:
2720                                         if ((error = pf_rollback_rules(ioe->ticket,
2721                                             ioe->rs_num, ioe->anchor))) {
2722                                                   kfree(table, M_TEMP);
2723                                                   kfree(ioe, M_TEMP);
2724                                                   goto fail; /* really bad */
2725                                         }
2726                                         break;
2727                               }
2728                     }
2729                     kfree(table, M_TEMP);
2730                     kfree(ioe, M_TEMP);
2731                     break;
2732           }
2733 
2734           case DIOCXCOMMIT: {
2735                     struct pfioc_trans  *io = (struct pfioc_trans *)addr;
2736                     struct pfioc_trans_e          *ioe;
2737                     struct pfr_table    *table;
2738                     struct pf_ruleset   *rs;
2739                     int                            i;
2740 
2741                     if (io->esize != sizeof(*ioe)) {
2742                               error = ENODEV;
2743                               goto fail;
2744                     }
2745                     ioe = kmalloc(sizeof(*ioe), M_TEMP, M_WAITOK);
2746                     table = kmalloc(sizeof(*table), M_TEMP, M_WAITOK);
2747                     /* first makes sure everything will succeed */
2748                     for (i = 0; i < io->size; i++) {
2749                               if (copyin(io->array+i, ioe, sizeof(*ioe))) {
2750                                         kfree(table, M_TEMP);
2751                                         kfree(ioe, M_TEMP);
2752                                         error = EFAULT;
2753                                         goto fail;
2754                               }
2755                               switch (ioe->rs_num) {
2756 #ifdef ALTQ
2757                               case PF_RULESET_ALTQ:
2758                                         if (ioe->anchor[0]) {
2759                                                   kfree(table, M_TEMP);
2760                                                   kfree(ioe, M_TEMP);
2761                                                   error = EINVAL;
2762                                                   goto fail;
2763                                         }
2764                                         if (!altqs_inactive_open || ioe->ticket !=
2765                                             ticket_altqs_inactive) {
2766                                                   kfree(table, M_TEMP);
2767                                                   kfree(ioe, M_TEMP);
2768                                                   error = EBUSY;
2769                                                   goto fail;
2770                                         }
2771                                         break;
2772 #endif /* ALTQ */
2773                               case PF_RULESET_TABLE:
2774                                         rs = pf_find_ruleset(ioe->anchor);
2775                                         if (rs == NULL || !rs->topen || ioe->ticket !=
2776                                              rs->tticket) {
2777                                                   kfree(table, M_TEMP);
2778                                                   kfree(ioe, M_TEMP);
2779                                                   error = EBUSY;
2780                                                   goto fail;
2781                                         }
2782                                         break;
2783                               default:
2784                                         if (ioe->rs_num < 0 || ioe->rs_num >=
2785                                             PF_RULESET_MAX) {
2786                                                   kfree(table, M_TEMP);
2787                                                   kfree(ioe, M_TEMP);
2788                                                   error = EINVAL;
2789                                                   goto fail;
2790                                         }
2791                                         rs = pf_find_ruleset(ioe->anchor);
2792                                         if (rs == NULL ||
2793                                             !rs->rules[ioe->rs_num].inactive.open ||
2794                                             rs->rules[ioe->rs_num].inactive.ticket !=
2795                                             ioe->ticket) {
2796                                                   kfree(table, M_TEMP);
2797                                                   kfree(ioe, M_TEMP);
2798                                                   error = EBUSY;
2799                                                   goto fail;
2800                                         }
2801                                         break;
2802                               }
2803                     }
2804                     /* now do the commit - no errors should happen here */
2805                     for (i = 0; i < io->size; i++) {
2806                               if (copyin(io->array+i, ioe, sizeof(*ioe))) {
2807                                         kfree(table, M_TEMP);
2808                                         kfree(ioe, M_TEMP);
2809                                         error = EFAULT;
2810                                         goto fail;
2811                               }
2812                               switch (ioe->rs_num) {
2813 #ifdef ALTQ
2814                               case PF_RULESET_ALTQ:
2815                                         if ((error = pf_commit_altq(ioe->ticket))) {
2816                                                   kfree(table, M_TEMP);
2817                                                   kfree(ioe, M_TEMP);
2818                                                   goto fail; /* really bad */
2819                                         }
2820                                         break;
2821 #endif /* ALTQ */
2822                               case PF_RULESET_TABLE:
2823                                         bzero(table, sizeof(*table));
2824                                         strlcpy(table->pfrt_anchor, ioe->anchor,
2825                                             sizeof(table->pfrt_anchor));
2826                                         if ((error = pfr_ina_commit(table, ioe->ticket,
2827                                             NULL, NULL, 0))) {
2828                                                   kfree(table, M_TEMP);
2829                                                   kfree(ioe, M_TEMP);
2830                                                   goto fail; /* really bad */
2831                                         }
2832                                         break;
2833                               default:
2834                                         if ((error = pf_commit_rules(ioe->ticket,
2835                                             ioe->rs_num, ioe->anchor))) {
2836                                                   kfree(table, M_TEMP);
2837                                                   kfree(ioe, M_TEMP);
2838                                                   goto fail; /* really bad */
2839                                         }
2840                                         break;
2841                               }
2842                     }
2843                     kfree(table, M_TEMP);
2844                     kfree(ioe, M_TEMP);
2845                     break;
2846           }
2847 
2848           case DIOCGETSRCNODES: {
2849                     struct pfioc_src_nodes        *psn = (struct pfioc_src_nodes *)addr;
2850                     struct pf_src_node  *n, *p, *pstore;
2851                     u_int32_t nr = 0;
2852                     int       space = psn->psn_len;
2853                     int       nn;
2854 
2855                     if (space == 0) {
2856                               for (nn = 0; nn < ncpus; ++nn) {
2857                                         RB_FOREACH(n, pf_src_tree,
2858                                                      &tree_src_tracking[nn]) {
2859                                                   nr++;
2860                                         }
2861                               }
2862                               psn->psn_len = sizeof(struct pf_src_node) * nr;
2863                               break;
2864                     }
2865 
2866                     pstore = kmalloc(sizeof(*pstore), M_TEMP, M_WAITOK);
2867 
2868                     p = psn->psn_src_nodes;
2869 
2870                     /*
2871                      * WARNING: We are not switching cpus so we cannot call
2872                      *            nominal pf.c support routines for cpu-specific
2873                      *            data.
2874                      */
2875                     for (nn = 0; nn < ncpus; ++nn) {
2876                               RB_FOREACH(n, pf_src_tree, &tree_src_tracking[nn]) {
2877                                         int       secs = time_second, diff;
2878 
2879                                         if ((nr + 1) * sizeof(*p) >
2880                                             (unsigned)psn->psn_len) {
2881                                                   break;
2882                                         }
2883 
2884                                         bcopy(n, pstore, sizeof(*pstore));
2885                                         if (n->rule.ptr != NULL)
2886                                                   pstore->rule.nr = n->rule.ptr->nr;
2887                                         pstore->creation = secs - pstore->creation;
2888                                         if (pstore->expire > secs)
2889                                                   pstore->expire -= secs;
2890                                         else
2891                                                   pstore->expire = 0;
2892 
2893                                         /* adjust the connection rate estimate */
2894                                         diff = secs - n->conn_rate.last;
2895                                         if (diff >= n->conn_rate.seconds)
2896                                                   pstore->conn_rate.count = 0;
2897                                         else
2898                                                   pstore->conn_rate.count -=
2899                                                       n->conn_rate.count * diff /
2900                                                       n->conn_rate.seconds;
2901 
2902                                         error = copyout(pstore, p, sizeof(*p));
2903                                         if (error) {
2904                                                   kfree(pstore, M_TEMP);
2905                                                   goto fail;
2906                                         }
2907                                         p++;
2908                                         nr++;
2909                               }
2910                     }
2911                     psn->psn_len = sizeof(struct pf_src_node) * nr;
2912                     kfree(pstore, M_TEMP);
2913                     break;
2914           }
2915 
2916           case DIOCCLRSRCNODES: {
2917                     struct pf_src_node  *n;
2918                     struct pf_state               *state;
2919                     globaldata_t save_gd = mycpu;
2920                     int nn;
2921 
2922                     /*
2923                      * WARNING: We are not switching cpus so we cannot call
2924                      *            nominal pf.c support routines for cpu-specific
2925                      *            data.
2926                      */
2927                     for (nn = 0; nn < ncpus; ++nn) {
2928                               RB_FOREACH(state, pf_state_tree_id, &tree_id[nn]) {
2929                                         state->src_node = NULL;
2930                                         state->nat_src_node = NULL;
2931                               }
2932                               RB_FOREACH(n, pf_src_tree, &tree_src_tracking[nn]) {
2933                                         n->expire = 1;
2934                                         n->states = 0;
2935                               }
2936                     }
2937 
2938                     /*
2939                      * WARNING: Must move to the target cpu for nominal calls
2940                      *            into pf.c
2941                      */
2942                     for (nn = 0; nn < ncpus; ++nn) {
2943                               lwkt_setcpu_self(globaldata_find(nn));
2944                               pf_purge_expired_src_nodes(1);
2945                     }
2946                     lwkt_setcpu_self(save_gd);
2947                     pf_status.src_nodes = 0;
2948                     break;
2949           }
2950 
2951           case DIOCKILLSRCNODES: {
2952                     struct pf_src_node  *sn;
2953                     struct pf_state               *s;
2954                     struct pfioc_src_node_kill *psnk =
2955                         (struct pfioc_src_node_kill *)addr;
2956                     u_int                         killed = 0;
2957                     globaldata_t save_gd = mycpu;
2958                     int nn;
2959 
2960                     /*
2961                      * WARNING: We are not switching cpus so we cannot call
2962                      *            nominal pf.c support routines for cpu-specific
2963                      *            data.
2964                      */
2965                     for (nn = 0; nn < ncpus; ++nn) {
2966                         RB_FOREACH(sn, pf_src_tree, &tree_src_tracking[nn]) {
2967                               if (PF_MATCHA(psnk->psnk_src.neg,
2968                                         &psnk->psnk_src.addr.v.a.addr,
2969                                         &psnk->psnk_src.addr.v.a.mask,
2970                                         &sn->addr, sn->af) &&
2971                                   PF_MATCHA(psnk->psnk_dst.neg,
2972                                         &psnk->psnk_dst.addr.v.a.addr,
2973                                         &psnk->psnk_dst.addr.v.a.mask,
2974                                         &sn->raddr, sn->af)) {
2975                                         /* Handle state to src_node linkage */
2976                                         if (sn->states != 0) {
2977                                                   RB_FOREACH(s, pf_state_tree_id,
2978                                                       &tree_id[nn]) {
2979                                                             if (s->src_node == sn)
2980                                                                       s->src_node = NULL;
2981                                                             if (s->nat_src_node == sn)
2982                                                                       s->nat_src_node = NULL;
2983                                                   }
2984                                                   sn->states = 0;
2985                                         }
2986                                         sn->expire = 1;
2987                                         killed++;
2988                               }
2989                         }
2990                     }
2991                     if (killed > 0) {
2992                               for (nn = 0; nn < ncpus; ++nn) {
2993                                         lwkt_setcpu_self(globaldata_find(nn));
2994                                         pf_purge_expired_src_nodes(1);
2995                               }
2996                               lwkt_setcpu_self(save_gd);
2997                     }
2998 
2999                     psnk->psnk_killed = killed;
3000                     break;
3001           }
3002 
3003           case DIOCSETHOSTID: {
3004                     u_int32_t *hostid = (u_int32_t *)addr;
3005 
3006                     if (*hostid == 0)
3007                               pf_status.hostid = karc4random();
3008                     else
3009                               pf_status.hostid = *hostid;
3010                     break;
3011           }
3012 
3013           case DIOCOSFPFLUSH:
3014                     crit_enter();
3015                     pf_osfp_flush();
3016                     crit_exit();
3017                     break;
3018 
3019           case DIOCIGETIFACES: {
3020                     struct pfioc_iface *io = (struct pfioc_iface *)addr;
3021 
3022                     if (io->pfiio_esize != sizeof(struct pfi_kif)) {
3023                               error = ENODEV;
3024                               break;
3025                     }
3026                     error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,
3027                         &io->pfiio_size);
3028                     break;
3029           }
3030 
3031           case DIOCSETIFFLAG: {
3032                     struct pfioc_iface *io = (struct pfioc_iface *)addr;
3033 
3034                     error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
3035                     break;
3036           }
3037 
3038           case DIOCCLRIFFLAG: {
3039                     struct pfioc_iface *io = (struct pfioc_iface *)addr;
3040 
3041                     error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
3042                     break;
3043           }
3044 
3045           default:
3046                     error = ENODEV;
3047                     break;
3048           }
3049 fail:
3050           lwkt_reltoken(&pf_token);
3051           return (error);
3052 }
3053 
3054 /*
3055  * XXX - Check for version missmatch!!!
3056  */
3057 static void
pf_clear_states(void)3058 pf_clear_states(void)
3059 {
3060           struct pf_state               *s, *nexts;
3061           globaldata_t save_gd = mycpu;
3062           int nn;
3063 
3064           for (nn = 0; nn < ncpus; ++nn) {
3065                     lwkt_setcpu_self(globaldata_find(nn));
3066                     for (s = RB_MIN(pf_state_tree_id, &tree_id[nn]); s; s = nexts) {
3067                               nexts = RB_NEXT(pf_state_tree_id, &tree_id[nn], s);
3068 
3069                               /* don't send out individual delete messages */
3070                               s->sync_flags = PFSTATE_NOSYNC;
3071                               pf_unlink_state(s);
3072                     }
3073 
3074           }
3075           lwkt_setcpu_self(save_gd);
3076 
3077 #if 0 /* PFSYNC */
3078 /*
3079  * XXX This is called on module unload, we do not want to sync that over? */
3080  */
3081           pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
3082 #endif
3083 }
3084 
3085 static int
pf_clear_tables(void)3086 pf_clear_tables(void)
3087 {
3088           struct pfioc_table io;
3089           int error;
3090 
3091           bzero(&io, sizeof(io));
3092 
3093           error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel,
3094               io.pfrio_flags);
3095 
3096           return (error);
3097 }
3098 
3099 static void
pf_clear_srcnodes(void)3100 pf_clear_srcnodes(void)
3101 {
3102           struct pf_src_node  *n;
3103           struct pf_state               *state;
3104           globaldata_t save_gd = mycpu;
3105           int nn;
3106 
3107           for (nn = 0; nn < ncpus; ++nn) {
3108                     lwkt_setcpu_self(globaldata_find(nn));
3109                     RB_FOREACH(state, pf_state_tree_id, &tree_id[nn]) {
3110                               state->src_node = NULL;
3111                               state->nat_src_node = NULL;
3112                     }
3113                     RB_FOREACH(n, pf_src_tree, &tree_src_tracking[nn]) {
3114                               n->expire = 1;
3115                               n->states = 0;
3116                     }
3117                     pf_purge_expired_src_nodes(0);
3118           }
3119           lwkt_setcpu_self(save_gd);
3120 
3121           pf_status.src_nodes = 0;
3122 }
3123 
3124 /*
3125  * XXX - Check for version missmatch!!!
3126  */
3127 
3128 /*
3129  * Duplicate pfctl -Fa operation to get rid of as much as we can.
3130  */
3131 static int
shutdown_pf(void)3132 shutdown_pf(void)
3133 {
3134           int error = 0;
3135           u_int32_t t[5];
3136           char nn = '\0';
3137 
3138 
3139           pf_status.running = 0;
3140           error = dehook_pf();
3141           if (error) {
3142                     pf_status.running = 1;
3143                     DPFPRINTF(PF_DEBUG_MISC,
3144                         ("pf: pfil unregistration failed\n"));
3145                     return(error);
3146           }
3147           do {
3148                     if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn)) != 0) {
3149                               DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n"));
3150                               break;
3151                     }
3152                     if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn)) != 0) {
3153                               DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n"));
3154                               break;              /* XXX: rollback? */
3155                     }
3156                     if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn))    != 0) {
3157                               DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n"));
3158                               break;              /* XXX: rollback? */
3159                     }
3160                     if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn))
3161                         != 0) {
3162                               DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n"));
3163                               break;              /* XXX: rollback? */
3164                     }
3165                     if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn))
3166                         != 0) {
3167                               DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n"));
3168                               break;              /* XXX: rollback? */
3169                     }
3170 
3171                     /* XXX: these should always succeed here */
3172                     pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn);
3173                     pf_commit_rules(t[1], PF_RULESET_FILTER, &nn);
3174                     pf_commit_rules(t[2], PF_RULESET_NAT, &nn);
3175                     pf_commit_rules(t[3], PF_RULESET_BINAT, &nn);
3176                     pf_commit_rules(t[4], PF_RULESET_RDR, &nn);
3177 
3178                     if ((error = pf_clear_tables()) != 0)
3179                               break;
3180 #ifdef ALTQ
3181                     if ((error = pf_begin_altq(&t[0])) != 0) {
3182                               DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n"));
3183                               break;
3184                     }
3185                     pf_commit_altq(t[0]);
3186 #endif
3187                     pf_clear_states();
3188                     pf_clear_srcnodes();
3189 
3190                     /* status does not use malloced mem so no need to cleanup */
3191                     /* fingerprints and interfaces have their own cleanup code */
3192           } while (0);
3193 
3194           return (error);
3195 }
3196 
3197 static int
pf_check_in(void * arg,struct mbuf ** m,struct ifnet * ifp,int dir)3198 pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3199 {
3200           /*
3201            * NOTE: ip_len and ip_off are left in network byte order
3202            */
3203           int chk;
3204 
3205           lwkt_gettoken_shared(&pf_token);
3206 
3207           chk = pf_test(PF_IN, ifp, m, NULL, NULL);
3208           if (chk && *m) {
3209                     m_freem(*m);
3210                     *m = NULL;
3211           }
3212           lwkt_reltoken(&pf_token);
3213           return chk;
3214 }
3215 
3216 static int
pf_check_out(void * arg,struct mbuf ** m,struct ifnet * ifp,int dir)3217 pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3218 {
3219           /*
3220            * NOTE: ip_len and ip_off are left in network byte order
3221            */
3222           int chk;
3223 
3224           lwkt_gettoken_shared(&pf_token);
3225 
3226           /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
3227           if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
3228                     in_delayed_cksum(*m);
3229                     (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
3230           }
3231           chk = pf_test(PF_OUT, ifp, m, NULL, NULL);
3232           if (chk && *m) {
3233                     m_freem(*m);
3234                     *m = NULL;
3235           }
3236           lwkt_reltoken(&pf_token);
3237           return chk;
3238 }
3239 
3240 #ifdef INET6
3241 static int
pf_check6_in(void * arg,struct mbuf ** m,struct ifnet * ifp,int dir)3242 pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3243 {
3244           int chk;
3245 
3246           lwkt_gettoken_shared(&pf_token);
3247 
3248           chk = pf_test6(PF_IN, ifp, m, NULL, NULL);
3249           if (chk && *m) {
3250                     m_freem(*m);
3251                     *m = NULL;
3252           }
3253           lwkt_reltoken(&pf_token);
3254           return chk;
3255 }
3256 
3257 static int
pf_check6_out(void * arg,struct mbuf ** m,struct ifnet * ifp,int dir)3258 pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3259 {
3260           int chk;
3261 
3262           lwkt_gettoken_shared(&pf_token);
3263 
3264           /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
3265           if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
3266                     in_delayed_cksum(*m);
3267                     (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
3268           }
3269           chk = pf_test6(PF_OUT, ifp, m, NULL, NULL);
3270           if (chk && *m) {
3271                     m_freem(*m);
3272                     *m = NULL;
3273           }
3274           lwkt_reltoken(&pf_token);
3275           return chk;
3276 }
3277 #endif /* INET6 */
3278 
3279 static int
hook_pf(void)3280 hook_pf(void)
3281 {
3282           struct pfil_head *pfh_inet;
3283 #ifdef INET6
3284           struct pfil_head *pfh_inet6;
3285 #endif
3286 
3287           lwkt_gettoken(&pf_token);
3288 
3289           if (pf_pfil_hooked) {
3290                     lwkt_reltoken(&pf_token);
3291                     return (0);
3292           }
3293 
3294           pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
3295           if (pfh_inet == NULL) {
3296                     lwkt_reltoken(&pf_token);
3297                     return (ENODEV);
3298           }
3299           pfil_add_hook(pf_check_in, NULL, PFIL_IN, pfh_inet);
3300           pfil_add_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet);
3301 #ifdef INET6
3302           pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
3303           if (pfh_inet6 == NULL) {
3304                     pfil_remove_hook(pf_check_in, NULL, PFIL_IN, pfh_inet);
3305                     pfil_remove_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet);
3306                     lwkt_reltoken(&pf_token);
3307                     return (ENODEV);
3308           }
3309           pfil_add_hook(pf_check6_in, NULL, PFIL_IN, pfh_inet6);
3310           pfil_add_hook(pf_check6_out, NULL, PFIL_OUT, pfh_inet6);
3311 #endif
3312 
3313           pf_pfil_hooked = 1;
3314           lwkt_reltoken(&pf_token);
3315           return (0);
3316 }
3317 
3318 static int
dehook_pf(void)3319 dehook_pf(void)
3320 {
3321           struct pfil_head *pfh_inet;
3322 #ifdef INET6
3323           struct pfil_head *pfh_inet6;
3324 #endif
3325 
3326           lwkt_gettoken(&pf_token);
3327 
3328           if (pf_pfil_hooked == 0) {
3329                     lwkt_reltoken(&pf_token);
3330                     return (0);
3331           }
3332 
3333           pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
3334           if (pfh_inet == NULL) {
3335                     lwkt_reltoken(&pf_token);
3336                     return (ENODEV);
3337           }
3338           pfil_remove_hook(pf_check_in, NULL, PFIL_IN, pfh_inet);
3339           pfil_remove_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet);
3340 #ifdef INET6
3341           pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
3342           if (pfh_inet6 == NULL) {
3343                     lwkt_reltoken(&pf_token);
3344                     return (ENODEV);
3345           }
3346           pfil_remove_hook(pf_check6_in, NULL, PFIL_IN, pfh_inet6);
3347           pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT, pfh_inet6);
3348 #endif
3349 
3350           pf_pfil_hooked = 0;
3351           lwkt_reltoken(&pf_token);
3352           return (0);
3353 }
3354 
3355 static int
pf_load(void)3356 pf_load(void)
3357 {
3358           lwkt_gettoken(&pf_token);
3359 
3360           pf_dev = make_dev(&pf_ops, 0, UID_ROOT, GID_WHEEL, 0600, PF_NAME);
3361           pfattach();
3362           lockinit(&pf_consistency_lock, "pfconslck", 0, LK_CANRECURSE);
3363           lockinit(&pf_global_statetbl_lock, "pfglstlk", 0, 0);
3364           lwkt_reltoken(&pf_token);
3365           return (0);
3366 }
3367 
3368 static int
pf_unload(void)3369 pf_unload(void)
3370 {
3371           int error;
3372           pf_status.running = 0;
3373 
3374           lwkt_gettoken(&pf_token);
3375 
3376           error = dehook_pf();
3377           if (error) {
3378                     /*
3379                      * Should not happen!
3380                      * XXX Due to error code ESRCH, kldunload will show
3381                      * a message like 'No such process'.
3382                      */
3383                     kprintf("pfil unregistration fail\n");
3384                     lwkt_reltoken(&pf_token);
3385                     return error;
3386           }
3387           kprintf("PF shutdown\n");
3388           pf_end_threads = 1;
3389           shutdown_pf();
3390           while (pf_end_threads < 2) {
3391                     wakeup_one(pf_purge_thread);
3392                     tsleep(pf_purge_thread, 0, "pftmo", hz / 10);
3393           }
3394           pfi_cleanup();
3395           pf_osfp_flush();
3396           dev_ops_remove_all(&pf_ops);
3397           lockuninit(&pf_consistency_lock);
3398           lwkt_reltoken(&pf_token);
3399 
3400           pf_normalize_unload();
3401           if (pf_maskhead != NULL) {
3402                     rn_flush(pf_maskhead, rn_freemask);
3403                     rn_freehead(pf_maskhead);
3404                     pf_maskhead = NULL;
3405           }
3406           kmalloc_destroy(&pf_state_pl);
3407           kmalloc_destroy(&pf_frent_pl);
3408           kmalloc_destroy(&pf_cent_pl);
3409 
3410           kfree(tree_src_tracking, M_PF);
3411           kfree(tree_id, M_PF);
3412           kfree(state_list, M_PF);
3413           kfree(pf_counters, M_PF);
3414           kfree(pf_statetbl, M_PF);
3415           kfree(purge_cur, M_PF);
3416 
3417           return 0;
3418 }
3419 
3420 static int
pf_modevent(module_t mod,int type,void * data __unused)3421 pf_modevent(module_t mod, int type, void *data __unused)
3422 {
3423           int error = 0;
3424 
3425           lwkt_gettoken(&pf_token);
3426 
3427           switch(type) {
3428           case MOD_LOAD:
3429                     error = pf_load();
3430                     break;
3431 
3432           case MOD_UNLOAD:
3433                     error = pf_unload();
3434                     break;
3435           default:
3436                     error = EINVAL;
3437                     break;
3438           }
3439           lwkt_reltoken(&pf_token);
3440           return error;
3441 }
3442 
3443 static moduledata_t pf_mod = {
3444           "pf",
3445           pf_modevent,
3446           0
3447 };
3448 
3449 DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_FIRST);
3450 MODULE_VERSION(pf, PF_MODVER);
3451