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