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