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