]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/pf/pf_ioctl.c
MFV r339226 (peter): Record merge of serf-1.3.9.
[FreeBSD/FreeBSD.git] / sys / netpfil / pf / pf_ioctl.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2001 Daniel Hartmeier
5  * Copyright (c) 2002,2003 Henning Brauer
6  * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  *    - Redistributions of source code must retain the above copyright
14  *      notice, this list of conditions and the following disclaimer.
15  *    - Redistributions in binary form must reproduce the above
16  *      copyright notice, this list of conditions and the following
17  *      disclaimer in the documentation and/or other materials provided
18  *      with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Effort sponsored in part by the Defense Advanced Research Projects
34  * Agency (DARPA) and Air Force Research Laboratory, Air Force
35  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
36  *
37  *      $OpenBSD: pf_ioctl.c,v 1.213 2009/02/15 21:46:12 mbalmer Exp $
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include "opt_inet.h"
44 #include "opt_inet6.h"
45 #include "opt_bpf.h"
46 #include "opt_pf.h"
47
48 #include <sys/param.h>
49 #include <sys/bus.h>
50 #include <sys/conf.h>
51 #include <sys/endian.h>
52 #include <sys/fcntl.h>
53 #include <sys/filio.h>
54 #include <sys/interrupt.h>
55 #include <sys/jail.h>
56 #include <sys/kernel.h>
57 #include <sys/kthread.h>
58 #include <sys/lock.h>
59 #include <sys/mbuf.h>
60 #include <sys/module.h>
61 #include <sys/proc.h>
62 #include <sys/smp.h>
63 #include <sys/socket.h>
64 #include <sys/sysctl.h>
65 #include <sys/md5.h>
66 #include <sys/ucred.h>
67
68 #include <net/if.h>
69 #include <net/if_var.h>
70 #include <net/vnet.h>
71 #include <net/route.h>
72 #include <net/pfil.h>
73 #include <net/pfvar.h>
74 #include <net/if_pfsync.h>
75 #include <net/if_pflog.h>
76
77 #include <netinet/in.h>
78 #include <netinet/ip.h>
79 #include <netinet/ip_var.h>
80 #include <netinet6/ip6_var.h>
81 #include <netinet/ip_icmp.h>
82
83 #ifdef INET6
84 #include <netinet/ip6.h>
85 #endif /* INET6 */
86
87 #ifdef ALTQ
88 #include <net/altq/altq.h>
89 #endif
90
91 static struct pf_pool   *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
92                             u_int8_t, u_int8_t, u_int8_t);
93
94 static void              pf_mv_pool(struct pf_palist *, struct pf_palist *);
95 static void              pf_empty_pool(struct pf_palist *);
96 static int               pfioctl(struct cdev *, u_long, caddr_t, int,
97                             struct thread *);
98 #ifdef ALTQ
99 static int               pf_begin_altq(u_int32_t *);
100 static int               pf_rollback_altq(u_int32_t);
101 static int               pf_commit_altq(u_int32_t);
102 static int               pf_enable_altq(struct pf_altq *);
103 static int               pf_disable_altq(struct pf_altq *);
104 static u_int32_t         pf_qname2qid(char *);
105 static void              pf_qid_unref(u_int32_t);
106 #endif /* ALTQ */
107 static int               pf_begin_rules(u_int32_t *, int, const char *);
108 static int               pf_rollback_rules(u_int32_t, int, char *);
109 static int               pf_setup_pfsync_matching(struct pf_ruleset *);
110 static void              pf_hash_rule(MD5_CTX *, struct pf_rule *);
111 static void              pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
112 static int               pf_commit_rules(u_int32_t, int, char *);
113 static int               pf_addr_setup(struct pf_ruleset *,
114                             struct pf_addr_wrap *, sa_family_t);
115 static void              pf_addr_copyout(struct pf_addr_wrap *);
116 #ifdef ALTQ
117 static int               pf_export_kaltq(struct pf_altq *,
118                             struct pfioc_altq_v1 *, size_t);
119 static int               pf_import_kaltq(struct pfioc_altq_v1 *,
120                             struct pf_altq *, size_t);
121 #endif /* ALTQ */
122
123 VNET_DEFINE(struct pf_rule,     pf_default_rule);
124
125 #ifdef ALTQ
126 VNET_DEFINE_STATIC(int,         pf_altq_running);
127 #define V_pf_altq_running       VNET(pf_altq_running)
128 #endif
129
130 #define TAGID_MAX        50000
131 struct pf_tagname {
132         TAILQ_ENTRY(pf_tagname) entries;
133         char                    name[PF_TAG_NAME_SIZE];
134         uint16_t                tag;
135         int                     ref;
136 };
137
138 TAILQ_HEAD(pf_tags, pf_tagname);
139 #define V_pf_tags               VNET(pf_tags)
140 VNET_DEFINE(struct pf_tags, pf_tags);
141 #define V_pf_qids               VNET(pf_qids)
142 VNET_DEFINE(struct pf_tags, pf_qids);
143 static MALLOC_DEFINE(M_PFTAG, "pf_tag", "pf(4) tag names");
144 static MALLOC_DEFINE(M_PFALTQ, "pf_altq", "pf(4) altq configuration db");
145 static MALLOC_DEFINE(M_PFRULE, "pf_rule", "pf(4) rules");
146
147 #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
148 #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
149 #endif
150
151 static u_int16_t         tagname2tag(struct pf_tags *, char *);
152 static u_int16_t         pf_tagname2tag(char *);
153 static void              tag_unref(struct pf_tags *, u_int16_t);
154
155 #define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
156
157 struct cdev *pf_dev;
158
159 /*
160  * XXX - These are new and need to be checked when moveing to a new version
161  */
162 static void              pf_clear_states(void);
163 static int               pf_clear_tables(void);
164 static void              pf_clear_srcnodes(struct pf_src_node *);
165 static void              pf_kill_srcnodes(struct pfioc_src_node_kill *);
166 static void              pf_tbladdr_copyout(struct pf_addr_wrap *);
167
168 /*
169  * Wrapper functions for pfil(9) hooks
170  */
171 #ifdef INET
172 static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
173     int dir, int flags, struct inpcb *inp);
174 static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
175     int dir, int flags, struct inpcb *inp);
176 #endif
177 #ifdef INET6
178 static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
179     int dir, int flags, struct inpcb *inp);
180 static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
181     int dir, int flags, struct inpcb *inp);
182 #endif
183
184 static int              hook_pf(void);
185 static int              dehook_pf(void);
186 static int              shutdown_pf(void);
187 static int              pf_load(void);
188 static void             pf_unload(void);
189
190 static struct cdevsw pf_cdevsw = {
191         .d_ioctl =      pfioctl,
192         .d_name =       PF_NAME,
193         .d_version =    D_VERSION,
194 };
195
196 volatile VNET_DEFINE_STATIC(int, pf_pfil_hooked);
197 #define V_pf_pfil_hooked        VNET(pf_pfil_hooked)
198
199 /*
200  * We need a flag that is neither hooked nor running to know when
201  * the VNET is "valid".  We primarily need this to control (global)
202  * external event, e.g., eventhandlers.
203  */
204 VNET_DEFINE(int, pf_vnet_active);
205 #define V_pf_vnet_active        VNET(pf_vnet_active)
206
207 int pf_end_threads;
208 struct proc *pf_purge_proc;
209
210 struct rmlock                   pf_rules_lock;
211 struct sx                       pf_ioctl_lock;
212 struct sx                       pf_end_lock;
213
214 /* pfsync */
215 pfsync_state_import_t           *pfsync_state_import_ptr = NULL;
216 pfsync_insert_state_t           *pfsync_insert_state_ptr = NULL;
217 pfsync_update_state_t           *pfsync_update_state_ptr = NULL;
218 pfsync_delete_state_t           *pfsync_delete_state_ptr = NULL;
219 pfsync_clear_states_t           *pfsync_clear_states_ptr = NULL;
220 pfsync_defer_t                  *pfsync_defer_ptr = NULL;
221 /* pflog */
222 pflog_packet_t                  *pflog_packet_ptr = NULL;
223
224 extern u_long   pf_ioctl_maxcount;
225
226 static void
227 pfattach_vnet(void)
228 {
229         u_int32_t *my_timeout = V_pf_default_rule.timeout;
230
231         pf_initialize();
232         pfr_initialize();
233         pfi_initialize_vnet();
234         pf_normalize_init();
235
236         V_pf_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
237         V_pf_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT;
238
239         RB_INIT(&V_pf_anchors);
240         pf_init_ruleset(&pf_main_ruleset);
241
242         /* default rule should never be garbage collected */
243         V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next;
244 #ifdef PF_DEFAULT_TO_DROP
245         V_pf_default_rule.action = PF_DROP;
246 #else
247         V_pf_default_rule.action = PF_PASS;
248 #endif
249         V_pf_default_rule.nr = -1;
250         V_pf_default_rule.rtableid = -1;
251
252         V_pf_default_rule.states_cur = counter_u64_alloc(M_WAITOK);
253         V_pf_default_rule.states_tot = counter_u64_alloc(M_WAITOK);
254         V_pf_default_rule.src_nodes = counter_u64_alloc(M_WAITOK);
255
256         /* initialize default timeouts */
257         my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
258         my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
259         my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
260         my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
261         my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
262         my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
263         my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
264         my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
265         my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
266         my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
267         my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
268         my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
269         my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
270         my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
271         my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
272         my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
273         my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
274         my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
275         my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
276         my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
277
278         bzero(&V_pf_status, sizeof(V_pf_status));
279         V_pf_status.debug = PF_DEBUG_URGENT;
280
281         V_pf_pfil_hooked = 0;
282
283         /* XXX do our best to avoid a conflict */
284         V_pf_status.hostid = arc4random();
285
286         for (int i = 0; i < PFRES_MAX; i++)
287                 V_pf_status.counters[i] = counter_u64_alloc(M_WAITOK);
288         for (int i = 0; i < LCNT_MAX; i++)
289                 V_pf_status.lcounters[i] = counter_u64_alloc(M_WAITOK);
290         for (int i = 0; i < FCNT_MAX; i++)
291                 V_pf_status.fcounters[i] = counter_u64_alloc(M_WAITOK);
292         for (int i = 0; i < SCNT_MAX; i++)
293                 V_pf_status.scounters[i] = counter_u64_alloc(M_WAITOK);
294
295         if (swi_add(NULL, "pf send", pf_intr, curvnet, SWI_NET,
296             INTR_MPSAFE, &V_pf_swi_cookie) != 0)
297                 /* XXXGL: leaked all above. */
298                 return;
299 }
300
301
302 static struct pf_pool *
303 pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
304     u_int32_t rule_number, u_int8_t r_last, u_int8_t active,
305     u_int8_t check_ticket)
306 {
307         struct pf_ruleset       *ruleset;
308         struct pf_rule          *rule;
309         int                      rs_num;
310
311         ruleset = pf_find_ruleset(anchor);
312         if (ruleset == NULL)
313                 return (NULL);
314         rs_num = pf_get_ruleset_number(rule_action);
315         if (rs_num >= PF_RULESET_MAX)
316                 return (NULL);
317         if (active) {
318                 if (check_ticket && ticket !=
319                     ruleset->rules[rs_num].active.ticket)
320                         return (NULL);
321                 if (r_last)
322                         rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
323                             pf_rulequeue);
324                 else
325                         rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
326         } else {
327                 if (check_ticket && ticket !=
328                     ruleset->rules[rs_num].inactive.ticket)
329                         return (NULL);
330                 if (r_last)
331                         rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
332                             pf_rulequeue);
333                 else
334                         rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
335         }
336         if (!r_last) {
337                 while ((rule != NULL) && (rule->nr != rule_number))
338                         rule = TAILQ_NEXT(rule, entries);
339         }
340         if (rule == NULL)
341                 return (NULL);
342
343         return (&rule->rpool);
344 }
345
346 static void
347 pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
348 {
349         struct pf_pooladdr      *mv_pool_pa;
350
351         while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
352                 TAILQ_REMOVE(poola, mv_pool_pa, entries);
353                 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
354         }
355 }
356
357 static void
358 pf_empty_pool(struct pf_palist *poola)
359 {
360         struct pf_pooladdr *pa;
361
362         while ((pa = TAILQ_FIRST(poola)) != NULL) {
363                 switch (pa->addr.type) {
364                 case PF_ADDR_DYNIFTL:
365                         pfi_dynaddr_remove(pa->addr.p.dyn);
366                         break;
367                 case PF_ADDR_TABLE:
368                         /* XXX: this could be unfinished pooladdr on pabuf */
369                         if (pa->addr.p.tbl != NULL)
370                                 pfr_detach_table(pa->addr.p.tbl);
371                         break;
372                 }
373                 if (pa->kif)
374                         pfi_kif_unref(pa->kif);
375                 TAILQ_REMOVE(poola, pa, entries);
376                 free(pa, M_PFRULE);
377         }
378 }
379
380 static void
381 pf_unlink_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
382 {
383
384         PF_RULES_WASSERT();
385
386         TAILQ_REMOVE(rulequeue, rule, entries);
387
388         PF_UNLNKDRULES_LOCK();
389         rule->rule_flag |= PFRULE_REFS;
390         TAILQ_INSERT_TAIL(&V_pf_unlinked_rules, rule, entries);
391         PF_UNLNKDRULES_UNLOCK();
392 }
393
394 void
395 pf_free_rule(struct pf_rule *rule)
396 {
397
398         PF_RULES_WASSERT();
399
400         if (rule->tag)
401                 tag_unref(&V_pf_tags, rule->tag);
402         if (rule->match_tag)
403                 tag_unref(&V_pf_tags, rule->match_tag);
404 #ifdef ALTQ
405         if (rule->pqid != rule->qid)
406                 pf_qid_unref(rule->pqid);
407         pf_qid_unref(rule->qid);
408 #endif
409         switch (rule->src.addr.type) {
410         case PF_ADDR_DYNIFTL:
411                 pfi_dynaddr_remove(rule->src.addr.p.dyn);
412                 break;
413         case PF_ADDR_TABLE:
414                 pfr_detach_table(rule->src.addr.p.tbl);
415                 break;
416         }
417         switch (rule->dst.addr.type) {
418         case PF_ADDR_DYNIFTL:
419                 pfi_dynaddr_remove(rule->dst.addr.p.dyn);
420                 break;
421         case PF_ADDR_TABLE:
422                 pfr_detach_table(rule->dst.addr.p.tbl);
423                 break;
424         }
425         if (rule->overload_tbl)
426                 pfr_detach_table(rule->overload_tbl);
427         if (rule->kif)
428                 pfi_kif_unref(rule->kif);
429         pf_anchor_remove(rule);
430         pf_empty_pool(&rule->rpool.list);
431         counter_u64_free(rule->states_cur);
432         counter_u64_free(rule->states_tot);
433         counter_u64_free(rule->src_nodes);
434         free(rule, M_PFRULE);
435 }
436
437 static u_int16_t
438 tagname2tag(struct pf_tags *head, char *tagname)
439 {
440         struct pf_tagname       *tag, *p = NULL;
441         u_int16_t                new_tagid = 1;
442
443         PF_RULES_WASSERT();
444
445         TAILQ_FOREACH(tag, head, entries)
446                 if (strcmp(tagname, tag->name) == 0) {
447                         tag->ref++;
448                         return (tag->tag);
449                 }
450
451         /*
452          * to avoid fragmentation, we do a linear search from the beginning
453          * and take the first free slot we find. if there is none or the list
454          * is empty, append a new entry at the end.
455          */
456
457         /* new entry */
458         if (!TAILQ_EMPTY(head))
459                 for (p = TAILQ_FIRST(head); p != NULL &&
460                     p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
461                         new_tagid = p->tag + 1;
462
463         if (new_tagid > TAGID_MAX)
464                 return (0);
465
466         /* allocate and fill new struct pf_tagname */
467         tag = malloc(sizeof(*tag), M_PFTAG, M_NOWAIT|M_ZERO);
468         if (tag == NULL)
469                 return (0);
470         strlcpy(tag->name, tagname, sizeof(tag->name));
471         tag->tag = new_tagid;
472         tag->ref++;
473
474         if (p != NULL)  /* insert new entry before p */
475                 TAILQ_INSERT_BEFORE(p, tag, entries);
476         else    /* either list empty or no free slot in between */
477                 TAILQ_INSERT_TAIL(head, tag, entries);
478
479         return (tag->tag);
480 }
481
482 static void
483 tag_unref(struct pf_tags *head, u_int16_t tag)
484 {
485         struct pf_tagname       *p, *next;
486
487         PF_RULES_WASSERT();
488
489         for (p = TAILQ_FIRST(head); p != NULL; p = next) {
490                 next = TAILQ_NEXT(p, entries);
491                 if (tag == p->tag) {
492                         if (--p->ref == 0) {
493                                 TAILQ_REMOVE(head, p, entries);
494                                 free(p, M_PFTAG);
495                         }
496                         break;
497                 }
498         }
499 }
500
501 static u_int16_t
502 pf_tagname2tag(char *tagname)
503 {
504         return (tagname2tag(&V_pf_tags, tagname));
505 }
506
507 #ifdef ALTQ
508 static u_int32_t
509 pf_qname2qid(char *qname)
510 {
511         return ((u_int32_t)tagname2tag(&V_pf_qids, qname));
512 }
513
514 static void
515 pf_qid_unref(u_int32_t qid)
516 {
517         tag_unref(&V_pf_qids, (u_int16_t)qid);
518 }
519
520 static int
521 pf_begin_altq(u_int32_t *ticket)
522 {
523         struct pf_altq  *altq;
524         int              error = 0;
525
526         PF_RULES_WASSERT();
527
528         /* Purge the old altq list */
529         while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
530                 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
531                 if (altq->qname[0] == 0 &&
532                     (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
533                         /* detach and destroy the discipline */
534                         error = altq_remove(altq);
535                 } else
536                         pf_qid_unref(altq->qid);
537                 free(altq, M_PFALTQ);
538         }
539         if (error)
540                 return (error);
541         *ticket = ++V_ticket_altqs_inactive;
542         V_altqs_inactive_open = 1;
543         return (0);
544 }
545
546 static int
547 pf_rollback_altq(u_int32_t ticket)
548 {
549         struct pf_altq  *altq;
550         int              error = 0;
551
552         PF_RULES_WASSERT();
553
554         if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive)
555                 return (0);
556         /* Purge the old altq list */
557         while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
558                 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
559                 if (altq->qname[0] == 0 &&
560                    (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
561                         /* detach and destroy the discipline */
562                         error = altq_remove(altq);
563                 } else
564                         pf_qid_unref(altq->qid);
565                 free(altq, M_PFALTQ);
566         }
567         V_altqs_inactive_open = 0;
568         return (error);
569 }
570
571 static int
572 pf_commit_altq(u_int32_t ticket)
573 {
574         struct pf_altqqueue     *old_altqs;
575         struct pf_altq          *altq;
576         int                      err, error = 0;
577
578         PF_RULES_WASSERT();
579
580         if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive)
581                 return (EBUSY);
582
583         /* swap altqs, keep the old. */
584         old_altqs = V_pf_altqs_active;
585         V_pf_altqs_active = V_pf_altqs_inactive;
586         V_pf_altqs_inactive = old_altqs;
587         V_ticket_altqs_active = V_ticket_altqs_inactive;
588
589         /* Attach new disciplines */
590         TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
591         if (altq->qname[0] == 0 &&
592            (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
593                         /* attach the discipline */
594                         error = altq_pfattach(altq);
595                         if (error == 0 && V_pf_altq_running)
596                                 error = pf_enable_altq(altq);
597                         if (error != 0)
598                                 return (error);
599                 }
600         }
601
602         /* Purge the old altq list */
603         while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
604                 TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
605                 if (altq->qname[0] == 0 &&
606                     (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
607                         /* detach and destroy the discipline */
608                         if (V_pf_altq_running)
609                                 error = pf_disable_altq(altq);
610                         err = altq_pfdetach(altq);
611                         if (err != 0 && error == 0)
612                                 error = err;
613                         err = altq_remove(altq);
614                         if (err != 0 && error == 0)
615                                 error = err;
616                 } else
617                         pf_qid_unref(altq->qid);
618                 free(altq, M_PFALTQ);
619         }
620
621         V_altqs_inactive_open = 0;
622         return (error);
623 }
624
625 static int
626 pf_enable_altq(struct pf_altq *altq)
627 {
628         struct ifnet            *ifp;
629         struct tb_profile        tb;
630         int                      error = 0;
631
632         if ((ifp = ifunit(altq->ifname)) == NULL)
633                 return (EINVAL);
634
635         if (ifp->if_snd.altq_type != ALTQT_NONE)
636                 error = altq_enable(&ifp->if_snd);
637
638         /* set tokenbucket regulator */
639         if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
640                 tb.rate = altq->ifbandwidth;
641                 tb.depth = altq->tbrsize;
642                 error = tbr_set(&ifp->if_snd, &tb);
643         }
644
645         return (error);
646 }
647
648 static int
649 pf_disable_altq(struct pf_altq *altq)
650 {
651         struct ifnet            *ifp;
652         struct tb_profile        tb;
653         int                      error;
654
655         if ((ifp = ifunit(altq->ifname)) == NULL)
656                 return (EINVAL);
657
658         /*
659          * when the discipline is no longer referenced, it was overridden
660          * by a new one.  if so, just return.
661          */
662         if (altq->altq_disc != ifp->if_snd.altq_disc)
663                 return (0);
664
665         error = altq_disable(&ifp->if_snd);
666
667         if (error == 0) {
668                 /* clear tokenbucket regulator */
669                 tb.rate = 0;
670                 error = tbr_set(&ifp->if_snd, &tb);
671         }
672
673         return (error);
674 }
675
676 void
677 pf_altq_ifnet_event(struct ifnet *ifp, int remove)
678 {
679         struct ifnet    *ifp1;
680         struct pf_altq  *a1, *a2, *a3;
681         u_int32_t        ticket;
682         int              error = 0;
683
684         /* Interrupt userland queue modifications */
685         if (V_altqs_inactive_open)
686                 pf_rollback_altq(V_ticket_altqs_inactive);
687
688         /* Start new altq ruleset */
689         if (pf_begin_altq(&ticket))
690                 return;
691
692         /* Copy the current active set */
693         TAILQ_FOREACH(a1, V_pf_altqs_active, entries) {
694                 a2 = malloc(sizeof(*a2), M_PFALTQ, M_NOWAIT);
695                 if (a2 == NULL) {
696                         error = ENOMEM;
697                         break;
698                 }
699                 bcopy(a1, a2, sizeof(struct pf_altq));
700
701                 if (a2->qname[0] != 0) {
702                         if ((a2->qid = pf_qname2qid(a2->qname)) == 0) {
703                                 error = EBUSY;
704                                 free(a2, M_PFALTQ);
705                                 break;
706                         }
707                         a2->altq_disc = NULL;
708                         TAILQ_FOREACH(a3, V_pf_altqs_inactive, entries) {
709                                 if (strncmp(a3->ifname, a2->ifname,
710                                     IFNAMSIZ) == 0 && a3->qname[0] == 0) {
711                                         a2->altq_disc = a3->altq_disc;
712                                         break;
713                                 }
714                         }
715                 }
716                 /* Deactivate the interface in question */
717                 a2->local_flags &= ~PFALTQ_FLAG_IF_REMOVED;
718                 if ((ifp1 = ifunit(a2->ifname)) == NULL ||
719                     (remove && ifp1 == ifp)) {
720                         a2->local_flags |= PFALTQ_FLAG_IF_REMOVED;
721                 } else {
722                         error = altq_add(a2);
723
724                         if (ticket != V_ticket_altqs_inactive)
725                                 error = EBUSY;
726
727                         if (error) {
728                                 free(a2, M_PFALTQ);
729                                 break;
730                         }
731                 }
732
733                 TAILQ_INSERT_TAIL(V_pf_altqs_inactive, a2, entries);
734         }
735
736         if (error != 0)
737                 pf_rollback_altq(ticket);
738         else
739                 pf_commit_altq(ticket);
740 }
741 #endif /* ALTQ */
742
743 static int
744 pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
745 {
746         struct pf_ruleset       *rs;
747         struct pf_rule          *rule;
748
749         PF_RULES_WASSERT();
750
751         if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
752                 return (EINVAL);
753         rs = pf_find_or_create_ruleset(anchor);
754         if (rs == NULL)
755                 return (EINVAL);
756         while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
757                 pf_unlink_rule(rs->rules[rs_num].inactive.ptr, rule);
758                 rs->rules[rs_num].inactive.rcount--;
759         }
760         *ticket = ++rs->rules[rs_num].inactive.ticket;
761         rs->rules[rs_num].inactive.open = 1;
762         return (0);
763 }
764
765 static int
766 pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
767 {
768         struct pf_ruleset       *rs;
769         struct pf_rule          *rule;
770
771         PF_RULES_WASSERT();
772
773         if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
774                 return (EINVAL);
775         rs = pf_find_ruleset(anchor);
776         if (rs == NULL || !rs->rules[rs_num].inactive.open ||
777             rs->rules[rs_num].inactive.ticket != ticket)
778                 return (0);
779         while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
780                 pf_unlink_rule(rs->rules[rs_num].inactive.ptr, rule);
781                 rs->rules[rs_num].inactive.rcount--;
782         }
783         rs->rules[rs_num].inactive.open = 0;
784         return (0);
785 }
786
787 #define PF_MD5_UPD(st, elm)                                             \
788                 MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
789
790 #define PF_MD5_UPD_STR(st, elm)                                         \
791                 MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
792
793 #define PF_MD5_UPD_HTONL(st, elm, stor) do {                            \
794                 (stor) = htonl((st)->elm);                              \
795                 MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
796 } while (0)
797
798 #define PF_MD5_UPD_HTONS(st, elm, stor) do {                            \
799                 (stor) = htons((st)->elm);                              \
800                 MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
801 } while (0)
802
803 static void
804 pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
805 {
806         PF_MD5_UPD(pfr, addr.type);
807         switch (pfr->addr.type) {
808                 case PF_ADDR_DYNIFTL:
809                         PF_MD5_UPD(pfr, addr.v.ifname);
810                         PF_MD5_UPD(pfr, addr.iflags);
811                         break;
812                 case PF_ADDR_TABLE:
813                         PF_MD5_UPD(pfr, addr.v.tblname);
814                         break;
815                 case PF_ADDR_ADDRMASK:
816                         /* XXX ignore af? */
817                         PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
818                         PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
819                         break;
820         }
821
822         PF_MD5_UPD(pfr, port[0]);
823         PF_MD5_UPD(pfr, port[1]);
824         PF_MD5_UPD(pfr, neg);
825         PF_MD5_UPD(pfr, port_op);
826 }
827
828 static void
829 pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
830 {
831         u_int16_t x;
832         u_int32_t y;
833
834         pf_hash_rule_addr(ctx, &rule->src);
835         pf_hash_rule_addr(ctx, &rule->dst);
836         PF_MD5_UPD_STR(rule, label);
837         PF_MD5_UPD_STR(rule, ifname);
838         PF_MD5_UPD_STR(rule, match_tagname);
839         PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
840         PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
841         PF_MD5_UPD_HTONL(rule, prob, y);
842         PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
843         PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
844         PF_MD5_UPD(rule, uid.op);
845         PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
846         PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
847         PF_MD5_UPD(rule, gid.op);
848         PF_MD5_UPD_HTONL(rule, rule_flag, y);
849         PF_MD5_UPD(rule, action);
850         PF_MD5_UPD(rule, direction);
851         PF_MD5_UPD(rule, af);
852         PF_MD5_UPD(rule, quick);
853         PF_MD5_UPD(rule, ifnot);
854         PF_MD5_UPD(rule, match_tag_not);
855         PF_MD5_UPD(rule, natpass);
856         PF_MD5_UPD(rule, keep_state);
857         PF_MD5_UPD(rule, proto);
858         PF_MD5_UPD(rule, type);
859         PF_MD5_UPD(rule, code);
860         PF_MD5_UPD(rule, flags);
861         PF_MD5_UPD(rule, flagset);
862         PF_MD5_UPD(rule, allow_opts);
863         PF_MD5_UPD(rule, rt);
864         PF_MD5_UPD(rule, tos);
865 }
866
867 static int
868 pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
869 {
870         struct pf_ruleset       *rs;
871         struct pf_rule          *rule, **old_array;
872         struct pf_rulequeue     *old_rules;
873         int                      error;
874         u_int32_t                old_rcount;
875
876         PF_RULES_WASSERT();
877
878         if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
879                 return (EINVAL);
880         rs = pf_find_ruleset(anchor);
881         if (rs == NULL || !rs->rules[rs_num].inactive.open ||
882             ticket != rs->rules[rs_num].inactive.ticket)
883                 return (EBUSY);
884
885         /* Calculate checksum for the main ruleset */
886         if (rs == &pf_main_ruleset) {
887                 error = pf_setup_pfsync_matching(rs);
888                 if (error != 0)
889                         return (error);
890         }
891
892         /* Swap rules, keep the old. */
893         old_rules = rs->rules[rs_num].active.ptr;
894         old_rcount = rs->rules[rs_num].active.rcount;
895         old_array = rs->rules[rs_num].active.ptr_array;
896
897         rs->rules[rs_num].active.ptr =
898             rs->rules[rs_num].inactive.ptr;
899         rs->rules[rs_num].active.ptr_array =
900             rs->rules[rs_num].inactive.ptr_array;
901         rs->rules[rs_num].active.rcount =
902             rs->rules[rs_num].inactive.rcount;
903         rs->rules[rs_num].inactive.ptr = old_rules;
904         rs->rules[rs_num].inactive.ptr_array = old_array;
905         rs->rules[rs_num].inactive.rcount = old_rcount;
906
907         rs->rules[rs_num].active.ticket =
908             rs->rules[rs_num].inactive.ticket;
909         pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
910
911
912         /* Purge the old rule list. */
913         while ((rule = TAILQ_FIRST(old_rules)) != NULL)
914                 pf_unlink_rule(old_rules, rule);
915         if (rs->rules[rs_num].inactive.ptr_array)
916                 free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
917         rs->rules[rs_num].inactive.ptr_array = NULL;
918         rs->rules[rs_num].inactive.rcount = 0;
919         rs->rules[rs_num].inactive.open = 0;
920         pf_remove_if_empty_ruleset(rs);
921
922         return (0);
923 }
924
925 static int
926 pf_setup_pfsync_matching(struct pf_ruleset *rs)
927 {
928         MD5_CTX                  ctx;
929         struct pf_rule          *rule;
930         int                      rs_cnt;
931         u_int8_t                 digest[PF_MD5_DIGEST_LENGTH];
932
933         MD5Init(&ctx);
934         for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
935                 /* XXX PF_RULESET_SCRUB as well? */
936                 if (rs_cnt == PF_RULESET_SCRUB)
937                         continue;
938
939                 if (rs->rules[rs_cnt].inactive.ptr_array)
940                         free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
941                 rs->rules[rs_cnt].inactive.ptr_array = NULL;
942
943                 if (rs->rules[rs_cnt].inactive.rcount) {
944                         rs->rules[rs_cnt].inactive.ptr_array =
945                             malloc(sizeof(caddr_t) *
946                             rs->rules[rs_cnt].inactive.rcount,
947                             M_TEMP, M_NOWAIT);
948
949                         if (!rs->rules[rs_cnt].inactive.ptr_array)
950                                 return (ENOMEM);
951                 }
952
953                 TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
954                     entries) {
955                         pf_hash_rule(&ctx, rule);
956                         (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
957                 }
958         }
959
960         MD5Final(digest, &ctx);
961         memcpy(V_pf_status.pf_chksum, digest, sizeof(V_pf_status.pf_chksum));
962         return (0);
963 }
964
965 static int
966 pf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr,
967     sa_family_t af)
968 {
969         int error = 0;
970
971         switch (addr->type) {
972         case PF_ADDR_TABLE:
973                 addr->p.tbl = pfr_attach_table(ruleset, addr->v.tblname);
974                 if (addr->p.tbl == NULL)
975                         error = ENOMEM;
976                 break;
977         case PF_ADDR_DYNIFTL:
978                 error = pfi_dynaddr_setup(addr, af);
979                 break;
980         }
981
982         return (error);
983 }
984
985 static void
986 pf_addr_copyout(struct pf_addr_wrap *addr)
987 {
988
989         switch (addr->type) {
990         case PF_ADDR_DYNIFTL:
991                 pfi_dynaddr_copyout(addr);
992                 break;
993         case PF_ADDR_TABLE:
994                 pf_tbladdr_copyout(addr);
995                 break;
996         }
997 }
998
999 #ifdef ALTQ
1000 /*
1001  * Handle export of struct pf_kaltq to user binaries that may be using any
1002  * version of struct pf_altq.
1003  */
1004 static int
1005 pf_export_kaltq(struct pf_altq *q, struct pfioc_altq_v1 *pa, size_t ioc_size)
1006 {
1007         u_int32_t version;
1008         
1009         if (ioc_size == sizeof(struct pfioc_altq_v0))
1010                 version = 0;
1011         else
1012                 version = pa->version;
1013
1014         if (version > PFIOC_ALTQ_VERSION)
1015                 return (EINVAL);
1016
1017 #define ASSIGN(x) exported_q->x = q->x
1018 #define COPY(x) \
1019         bcopy(&q->x, &exported_q->x, min(sizeof(q->x), sizeof(exported_q->x)))
1020 #define SATU16(x) (u_int32_t)uqmin((x), USHRT_MAX)
1021 #define SATU32(x) (u_int32_t)uqmin((x), UINT_MAX)
1022
1023         switch (version) {
1024         case 0: {
1025                 struct pf_altq_v0 *exported_q =
1026                     &((struct pfioc_altq_v0 *)pa)->altq;
1027
1028                 COPY(ifname);
1029
1030                 ASSIGN(scheduler);
1031                 ASSIGN(tbrsize);
1032                 exported_q->tbrsize = SATU16(q->tbrsize);
1033                 exported_q->ifbandwidth = SATU32(q->ifbandwidth);
1034
1035                 COPY(qname);
1036                 COPY(parent);
1037                 ASSIGN(parent_qid);
1038                 exported_q->bandwidth = SATU32(q->bandwidth);
1039                 ASSIGN(priority);
1040                 ASSIGN(local_flags);
1041
1042                 ASSIGN(qlimit);
1043                 ASSIGN(flags);
1044
1045                 if (q->scheduler == ALTQT_HFSC) {
1046 #define ASSIGN_OPT(x) exported_q->pq_u.hfsc_opts.x = q->pq_u.hfsc_opts.x
1047 #define ASSIGN_OPT_SATU32(x) exported_q->pq_u.hfsc_opts.x = \
1048                             SATU32(q->pq_u.hfsc_opts.x)
1049                         
1050                         ASSIGN_OPT_SATU32(rtsc_m1);
1051                         ASSIGN_OPT(rtsc_d);
1052                         ASSIGN_OPT_SATU32(rtsc_m2);
1053
1054                         ASSIGN_OPT_SATU32(lssc_m1);
1055                         ASSIGN_OPT(lssc_d);
1056                         ASSIGN_OPT_SATU32(lssc_m2);
1057
1058                         ASSIGN_OPT_SATU32(ulsc_m1);
1059                         ASSIGN_OPT(ulsc_d);
1060                         ASSIGN_OPT_SATU32(ulsc_m2);
1061
1062                         ASSIGN_OPT(flags);
1063                         
1064 #undef ASSIGN_OPT
1065 #undef ASSIGN_OPT_SATU32
1066                 } else
1067                         COPY(pq_u);
1068
1069                 ASSIGN(qid);
1070                 break;
1071         }
1072         case 1: {
1073                 struct pf_altq_v1 *exported_q =
1074                     &((struct pfioc_altq_v1 *)pa)->altq;
1075
1076                 COPY(ifname);
1077
1078                 ASSIGN(scheduler);
1079                 ASSIGN(tbrsize);
1080                 ASSIGN(ifbandwidth);
1081
1082                 COPY(qname);
1083                 COPY(parent);
1084                 ASSIGN(parent_qid);
1085                 ASSIGN(bandwidth);
1086                 ASSIGN(priority);
1087                 ASSIGN(local_flags);
1088
1089                 ASSIGN(qlimit);
1090                 ASSIGN(flags);
1091                 COPY(pq_u);
1092
1093                 ASSIGN(qid);
1094                 break;
1095         }
1096         default:
1097                 panic("%s: unhandled struct pfioc_altq version", __func__);
1098                 break;
1099         }
1100
1101 #undef ASSIGN
1102 #undef COPY
1103 #undef SATU16
1104 #undef SATU32
1105
1106         return (0);
1107 }
1108
1109 /*
1110  * Handle import to struct pf_kaltq of struct pf_altq from user binaries
1111  * that may be using any version of it.
1112  */
1113 static int
1114 pf_import_kaltq(struct pfioc_altq_v1 *pa, struct pf_altq *q, size_t ioc_size)
1115 {
1116         u_int32_t version;
1117         
1118         if (ioc_size == sizeof(struct pfioc_altq_v0))
1119                 version = 0;
1120         else
1121                 version = pa->version;
1122
1123         if (version > PFIOC_ALTQ_VERSION)
1124                 return (EINVAL);
1125         
1126 #define ASSIGN(x) q->x = imported_q->x
1127 #define COPY(x) \
1128         bcopy(&imported_q->x, &q->x, min(sizeof(imported_q->x), sizeof(q->x)))
1129
1130         switch (version) {
1131         case 0: {
1132                 struct pf_altq_v0 *imported_q =
1133                     &((struct pfioc_altq_v0 *)pa)->altq;
1134
1135                 COPY(ifname);
1136
1137                 ASSIGN(scheduler);
1138                 ASSIGN(tbrsize); /* 16-bit -> 32-bit */
1139                 ASSIGN(ifbandwidth); /* 32-bit -> 64-bit */
1140
1141                 COPY(qname);
1142                 COPY(parent);
1143                 ASSIGN(parent_qid);
1144                 ASSIGN(bandwidth); /* 32-bit -> 64-bit */
1145                 ASSIGN(priority);
1146                 ASSIGN(local_flags);
1147
1148                 ASSIGN(qlimit);
1149                 ASSIGN(flags);
1150
1151                 if (imported_q->scheduler == ALTQT_HFSC) {
1152 #define ASSIGN_OPT(x) q->pq_u.hfsc_opts.x = imported_q->pq_u.hfsc_opts.x
1153
1154                         /*
1155                          * The m1 and m2 parameters are being copied from
1156                          * 32-bit to 64-bit.
1157                          */
1158                         ASSIGN_OPT(rtsc_m1);
1159                         ASSIGN_OPT(rtsc_d);
1160                         ASSIGN_OPT(rtsc_m2);
1161
1162                         ASSIGN_OPT(lssc_m1);
1163                         ASSIGN_OPT(lssc_d);
1164                         ASSIGN_OPT(lssc_m2);
1165
1166                         ASSIGN_OPT(ulsc_m1);
1167                         ASSIGN_OPT(ulsc_d);
1168                         ASSIGN_OPT(ulsc_m2);
1169
1170                         ASSIGN_OPT(flags);
1171                         
1172 #undef ASSIGN_OPT
1173                 } else
1174                         COPY(pq_u);
1175
1176                 ASSIGN(qid);
1177                 break;
1178         }
1179         case 1: {
1180                 struct pf_altq_v1 *imported_q =
1181                     &((struct pfioc_altq_v1 *)pa)->altq;
1182
1183                 COPY(ifname);
1184
1185                 ASSIGN(scheduler);
1186                 ASSIGN(tbrsize);
1187                 ASSIGN(ifbandwidth);
1188
1189                 COPY(qname);
1190                 COPY(parent);
1191                 ASSIGN(parent_qid);
1192                 ASSIGN(bandwidth);
1193                 ASSIGN(priority);
1194                 ASSIGN(local_flags);
1195
1196                 ASSIGN(qlimit);
1197                 ASSIGN(flags);
1198                 COPY(pq_u);
1199
1200                 ASSIGN(qid);
1201                 break;
1202         }
1203         default:        
1204                 panic("%s: unhandled struct pfioc_altq version", __func__);
1205                 break;
1206         }
1207
1208 #undef ASSIGN
1209 #undef COPY
1210         
1211         return (0);
1212 }
1213 #endif /* ALTQ */
1214
1215 static int
1216 pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
1217 {
1218         int                      error = 0;
1219         PF_RULES_RLOCK_TRACKER;
1220
1221         /* XXX keep in sync with switch() below */
1222         if (securelevel_gt(td->td_ucred, 2))
1223                 switch (cmd) {
1224                 case DIOCGETRULES:
1225                 case DIOCGETRULE:
1226                 case DIOCGETADDRS:
1227                 case DIOCGETADDR:
1228                 case DIOCGETSTATE:
1229                 case DIOCSETSTATUSIF:
1230                 case DIOCGETSTATUS:
1231                 case DIOCCLRSTATUS:
1232                 case DIOCNATLOOK:
1233                 case DIOCSETDEBUG:
1234                 case DIOCGETSTATES:
1235                 case DIOCGETTIMEOUT:
1236                 case DIOCCLRRULECTRS:
1237                 case DIOCGETLIMIT:
1238                 case DIOCGETALTQSV0:
1239                 case DIOCGETALTQSV1:
1240                 case DIOCGETALTQV0:
1241                 case DIOCGETALTQV1:
1242                 case DIOCGETQSTATSV0:
1243                 case DIOCGETQSTATSV1:
1244                 case DIOCGETRULESETS:
1245                 case DIOCGETRULESET:
1246                 case DIOCRGETTABLES:
1247                 case DIOCRGETTSTATS:
1248                 case DIOCRCLRTSTATS:
1249                 case DIOCRCLRADDRS:
1250                 case DIOCRADDADDRS:
1251                 case DIOCRDELADDRS:
1252                 case DIOCRSETADDRS:
1253                 case DIOCRGETADDRS:
1254                 case DIOCRGETASTATS:
1255                 case DIOCRCLRASTATS:
1256                 case DIOCRTSTADDRS:
1257                 case DIOCOSFPGET:
1258                 case DIOCGETSRCNODES:
1259                 case DIOCCLRSRCNODES:
1260                 case DIOCIGETIFACES:
1261                 case DIOCGIFSPEEDV0:
1262                 case DIOCGIFSPEEDV1:
1263                 case DIOCSETIFFLAG:
1264                 case DIOCCLRIFFLAG:
1265                         break;
1266                 case DIOCRCLRTABLES:
1267                 case DIOCRADDTABLES:
1268                 case DIOCRDELTABLES:
1269                 case DIOCRSETTFLAGS:
1270                         if (((struct pfioc_table *)addr)->pfrio_flags &
1271                             PFR_FLAG_DUMMY)
1272                                 break; /* dummy operation ok */
1273                         return (EPERM);
1274                 default:
1275                         return (EPERM);
1276                 }
1277
1278         if (!(flags & FWRITE))
1279                 switch (cmd) {
1280                 case DIOCGETRULES:
1281                 case DIOCGETADDRS:
1282                 case DIOCGETADDR:
1283                 case DIOCGETSTATE:
1284                 case DIOCGETSTATUS:
1285                 case DIOCGETSTATES:
1286                 case DIOCGETTIMEOUT:
1287                 case DIOCGETLIMIT:
1288                 case DIOCGETALTQSV0:
1289                 case DIOCGETALTQSV1:
1290                 case DIOCGETALTQV0:
1291                 case DIOCGETALTQV1:
1292                 case DIOCGETQSTATSV0:
1293                 case DIOCGETQSTATSV1:
1294                 case DIOCGETRULESETS:
1295                 case DIOCGETRULESET:
1296                 case DIOCNATLOOK:
1297                 case DIOCRGETTABLES:
1298                 case DIOCRGETTSTATS:
1299                 case DIOCRGETADDRS:
1300                 case DIOCRGETASTATS:
1301                 case DIOCRTSTADDRS:
1302                 case DIOCOSFPGET:
1303                 case DIOCGETSRCNODES:
1304                 case DIOCIGETIFACES:
1305                 case DIOCGIFSPEEDV1:
1306                 case DIOCGIFSPEEDV0:
1307                         break;
1308                 case DIOCRCLRTABLES:
1309                 case DIOCRADDTABLES:
1310                 case DIOCRDELTABLES:
1311                 case DIOCRCLRTSTATS:
1312                 case DIOCRCLRADDRS:
1313                 case DIOCRADDADDRS:
1314                 case DIOCRDELADDRS:
1315                 case DIOCRSETADDRS:
1316                 case DIOCRSETTFLAGS:
1317                         if (((struct pfioc_table *)addr)->pfrio_flags &
1318                             PFR_FLAG_DUMMY) {
1319                                 flags |= FWRITE; /* need write lock for dummy */
1320                                 break; /* dummy operation ok */
1321                         }
1322                         return (EACCES);
1323                 case DIOCGETRULE:
1324                         if (((struct pfioc_rule *)addr)->action ==
1325                             PF_GET_CLR_CNTR)
1326                                 return (EACCES);
1327                         break;
1328                 default:
1329                         return (EACCES);
1330                 }
1331
1332         CURVNET_SET(TD_TO_VNET(td));
1333
1334         switch (cmd) {
1335         case DIOCSTART:
1336                 sx_xlock(&pf_ioctl_lock);
1337                 if (V_pf_status.running)
1338                         error = EEXIST;
1339                 else {
1340                         int cpu;
1341
1342                         error = hook_pf();
1343                         if (error) {
1344                                 DPFPRINTF(PF_DEBUG_MISC,
1345                                     ("pf: pfil registration failed\n"));
1346                                 break;
1347                         }
1348                         V_pf_status.running = 1;
1349                         V_pf_status.since = time_second;
1350
1351                         CPU_FOREACH(cpu)
1352                                 V_pf_stateid[cpu] = time_second;
1353
1354                         DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
1355                 }
1356                 break;
1357
1358         case DIOCSTOP:
1359                 sx_xlock(&pf_ioctl_lock);
1360                 if (!V_pf_status.running)
1361                         error = ENOENT;
1362                 else {
1363                         V_pf_status.running = 0;
1364                         error = dehook_pf();
1365                         if (error) {
1366                                 V_pf_status.running = 1;
1367                                 DPFPRINTF(PF_DEBUG_MISC,
1368                                     ("pf: pfil unregistration failed\n"));
1369                         }
1370                         V_pf_status.since = time_second;
1371                         DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
1372                 }
1373                 break;
1374
1375         case DIOCADDRULE: {
1376                 struct pfioc_rule       *pr = (struct pfioc_rule *)addr;
1377                 struct pf_ruleset       *ruleset;
1378                 struct pf_rule          *rule, *tail;
1379                 struct pf_pooladdr      *pa;
1380                 struct pfi_kif          *kif = NULL;
1381                 int                      rs_num;
1382
1383                 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1384                         error = EINVAL;
1385                         break;
1386                 }
1387 #ifndef INET
1388                 if (pr->rule.af == AF_INET) {
1389                         error = EAFNOSUPPORT;
1390                         break;
1391                 }
1392 #endif /* INET */
1393 #ifndef INET6
1394                 if (pr->rule.af == AF_INET6) {
1395                         error = EAFNOSUPPORT;
1396                         break;
1397                 }
1398 #endif /* INET6 */
1399
1400                 rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK);
1401                 bcopy(&pr->rule, rule, sizeof(struct pf_rule));
1402                 if (rule->ifname[0])
1403                         kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK);
1404                 rule->states_cur = counter_u64_alloc(M_WAITOK);
1405                 rule->states_tot = counter_u64_alloc(M_WAITOK);
1406                 rule->src_nodes = counter_u64_alloc(M_WAITOK);
1407                 rule->cuid = td->td_ucred->cr_ruid;
1408                 rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
1409                 TAILQ_INIT(&rule->rpool.list);
1410
1411 #define ERROUT(x)       { error = (x); goto DIOCADDRULE_error; }
1412
1413                 PF_RULES_WLOCK();
1414                 pr->anchor[sizeof(pr->anchor) - 1] = 0;
1415                 ruleset = pf_find_ruleset(pr->anchor);
1416                 if (ruleset == NULL)
1417                         ERROUT(EINVAL);
1418                 rs_num = pf_get_ruleset_number(pr->rule.action);
1419                 if (rs_num >= PF_RULESET_MAX)
1420                         ERROUT(EINVAL);
1421                 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
1422                         DPFPRINTF(PF_DEBUG_MISC,
1423                             ("ticket: %d != [%d]%d\n", pr->ticket, rs_num,
1424                             ruleset->rules[rs_num].inactive.ticket));
1425                         ERROUT(EBUSY);
1426                 }
1427                 if (pr->pool_ticket != V_ticket_pabuf) {
1428                         DPFPRINTF(PF_DEBUG_MISC,
1429                             ("pool_ticket: %d != %d\n", pr->pool_ticket,
1430                             V_ticket_pabuf));
1431                         ERROUT(EBUSY);
1432                 }
1433
1434                 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
1435                     pf_rulequeue);
1436                 if (tail)
1437                         rule->nr = tail->nr + 1;
1438                 else
1439                         rule->nr = 0;
1440                 if (rule->ifname[0]) {
1441                         rule->kif = pfi_kif_attach(kif, rule->ifname);
1442                         pfi_kif_ref(rule->kif);
1443                 } else
1444                         rule->kif = NULL;
1445
1446                 if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
1447                         error = EBUSY;
1448
1449 #ifdef ALTQ
1450                 /* set queue IDs */
1451                 if (rule->qname[0] != 0) {
1452                         if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
1453                                 error = EBUSY;
1454                         else if (rule->pqname[0] != 0) {
1455                                 if ((rule->pqid =
1456                                     pf_qname2qid(rule->pqname)) == 0)
1457                                         error = EBUSY;
1458                         } else
1459                                 rule->pqid = rule->qid;
1460                 }
1461 #endif
1462                 if (rule->tagname[0])
1463                         if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
1464                                 error = EBUSY;
1465                 if (rule->match_tagname[0])
1466                         if ((rule->match_tag =
1467                             pf_tagname2tag(rule->match_tagname)) == 0)
1468                                 error = EBUSY;
1469                 if (rule->rt && !rule->direction)
1470                         error = EINVAL;
1471                 if (!rule->log)
1472                         rule->logif = 0;
1473                 if (rule->logif >= PFLOGIFS_MAX)
1474                         error = EINVAL;
1475                 if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
1476                         error = ENOMEM;
1477                 if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
1478                         error = ENOMEM;
1479                 if (pf_anchor_setup(rule, ruleset, pr->anchor_call))
1480                         error = EINVAL;
1481                 if (rule->scrub_flags & PFSTATE_SETPRIO &&
1482                     (rule->set_prio[0] > PF_PRIO_MAX ||
1483                     rule->set_prio[1] > PF_PRIO_MAX))
1484                         error = EINVAL;
1485                 TAILQ_FOREACH(pa, &V_pf_pabuf, entries)
1486                         if (pa->addr.type == PF_ADDR_TABLE) {
1487                                 pa->addr.p.tbl = pfr_attach_table(ruleset,
1488                                     pa->addr.v.tblname);
1489                                 if (pa->addr.p.tbl == NULL)
1490                                         error = ENOMEM;
1491                         }
1492
1493                 rule->overload_tbl = NULL;
1494                 if (rule->overload_tblname[0]) {
1495                         if ((rule->overload_tbl = pfr_attach_table(ruleset,
1496                             rule->overload_tblname)) == NULL)
1497                                 error = EINVAL;
1498                         else
1499                                 rule->overload_tbl->pfrkt_flags |=
1500                                     PFR_TFLAG_ACTIVE;
1501                 }
1502
1503                 pf_mv_pool(&V_pf_pabuf, &rule->rpool.list);
1504                 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
1505                     (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
1506                     (rule->rt > PF_NOPFROUTE)) &&
1507                     (TAILQ_FIRST(&rule->rpool.list) == NULL))
1508                         error = EINVAL;
1509
1510                 if (error) {
1511                         pf_free_rule(rule);
1512                         PF_RULES_WUNLOCK();
1513                         break;
1514                 }
1515
1516                 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
1517                 rule->evaluations = rule->packets[0] = rule->packets[1] =
1518                     rule->bytes[0] = rule->bytes[1] = 0;
1519                 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
1520                     rule, entries);
1521                 ruleset->rules[rs_num].inactive.rcount++;
1522                 PF_RULES_WUNLOCK();
1523                 break;
1524
1525 #undef ERROUT
1526 DIOCADDRULE_error:
1527                 PF_RULES_WUNLOCK();
1528                 counter_u64_free(rule->states_cur);
1529                 counter_u64_free(rule->states_tot);
1530                 counter_u64_free(rule->src_nodes);
1531                 free(rule, M_PFRULE);
1532                 if (kif)
1533                         free(kif, PFI_MTYPE);
1534                 break;
1535         }
1536
1537         case DIOCGETRULES: {
1538                 struct pfioc_rule       *pr = (struct pfioc_rule *)addr;
1539                 struct pf_ruleset       *ruleset;
1540                 struct pf_rule          *tail;
1541                 int                      rs_num;
1542
1543                 PF_RULES_WLOCK();
1544                 pr->anchor[sizeof(pr->anchor) - 1] = 0;
1545                 ruleset = pf_find_ruleset(pr->anchor);
1546                 if (ruleset == NULL) {
1547                         PF_RULES_WUNLOCK();
1548                         error = EINVAL;
1549                         break;
1550                 }
1551                 rs_num = pf_get_ruleset_number(pr->rule.action);
1552                 if (rs_num >= PF_RULESET_MAX) {
1553                         PF_RULES_WUNLOCK();
1554                         error = EINVAL;
1555                         break;
1556                 }
1557                 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
1558                     pf_rulequeue);
1559                 if (tail)
1560                         pr->nr = tail->nr + 1;
1561                 else
1562                         pr->nr = 0;
1563                 pr->ticket = ruleset->rules[rs_num].active.ticket;
1564                 PF_RULES_WUNLOCK();
1565                 break;
1566         }
1567
1568         case DIOCGETRULE: {
1569                 struct pfioc_rule       *pr = (struct pfioc_rule *)addr;
1570                 struct pf_ruleset       *ruleset;
1571                 struct pf_rule          *rule;
1572                 int                      rs_num, i;
1573
1574                 PF_RULES_WLOCK();
1575                 pr->anchor[sizeof(pr->anchor) - 1] = 0;
1576                 ruleset = pf_find_ruleset(pr->anchor);
1577                 if (ruleset == NULL) {
1578                         PF_RULES_WUNLOCK();
1579                         error = EINVAL;
1580                         break;
1581                 }
1582                 rs_num = pf_get_ruleset_number(pr->rule.action);
1583                 if (rs_num >= PF_RULESET_MAX) {
1584                         PF_RULES_WUNLOCK();
1585                         error = EINVAL;
1586                         break;
1587                 }
1588                 if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
1589                         PF_RULES_WUNLOCK();
1590                         error = EBUSY;
1591                         break;
1592                 }
1593                 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
1594                 while ((rule != NULL) && (rule->nr != pr->nr))
1595                         rule = TAILQ_NEXT(rule, entries);
1596                 if (rule == NULL) {
1597                         PF_RULES_WUNLOCK();
1598                         error = EBUSY;
1599                         break;
1600                 }
1601                 bcopy(rule, &pr->rule, sizeof(struct pf_rule));
1602                 pr->rule.u_states_cur = counter_u64_fetch(rule->states_cur);
1603                 pr->rule.u_states_tot = counter_u64_fetch(rule->states_tot);
1604                 pr->rule.u_src_nodes = counter_u64_fetch(rule->src_nodes);
1605                 if (pf_anchor_copyout(ruleset, rule, pr)) {
1606                         PF_RULES_WUNLOCK();
1607                         error = EBUSY;
1608                         break;
1609                 }
1610                 pf_addr_copyout(&pr->rule.src.addr);
1611                 pf_addr_copyout(&pr->rule.dst.addr);
1612                 for (i = 0; i < PF_SKIP_COUNT; ++i)
1613                         if (rule->skip[i].ptr == NULL)
1614                                 pr->rule.skip[i].nr = -1;
1615                         else
1616                                 pr->rule.skip[i].nr =
1617                                     rule->skip[i].ptr->nr;
1618
1619                 if (pr->action == PF_GET_CLR_CNTR) {
1620                         rule->evaluations = 0;
1621                         rule->packets[0] = rule->packets[1] = 0;
1622                         rule->bytes[0] = rule->bytes[1] = 0;
1623                         counter_u64_zero(rule->states_tot);
1624                 }
1625                 PF_RULES_WUNLOCK();
1626                 break;
1627         }
1628
1629         case DIOCCHANGERULE: {
1630                 struct pfioc_rule       *pcr = (struct pfioc_rule *)addr;
1631                 struct pf_ruleset       *ruleset;
1632                 struct pf_rule          *oldrule = NULL, *newrule = NULL;
1633                 struct pfi_kif          *kif = NULL;
1634                 struct pf_pooladdr      *pa;
1635                 u_int32_t                nr = 0;
1636                 int                      rs_num;
1637
1638                 if (pcr->action < PF_CHANGE_ADD_HEAD ||
1639                     pcr->action > PF_CHANGE_GET_TICKET) {
1640                         error = EINVAL;
1641                         break;
1642                 }
1643                 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1644                         error = EINVAL;
1645                         break;
1646                 }
1647
1648                 if (pcr->action != PF_CHANGE_REMOVE) {
1649 #ifndef INET
1650                         if (pcr->rule.af == AF_INET) {
1651                                 error = EAFNOSUPPORT;
1652                                 break;
1653                         }
1654 #endif /* INET */
1655 #ifndef INET6
1656                         if (pcr->rule.af == AF_INET6) {
1657                                 error = EAFNOSUPPORT;
1658                                 break;
1659                         }
1660 #endif /* INET6 */
1661                         newrule = malloc(sizeof(*newrule), M_PFRULE, M_WAITOK);
1662                         bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
1663                         if (newrule->ifname[0])
1664                                 kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK);
1665                         newrule->states_cur = counter_u64_alloc(M_WAITOK);
1666                         newrule->states_tot = counter_u64_alloc(M_WAITOK);
1667                         newrule->src_nodes = counter_u64_alloc(M_WAITOK);
1668                         newrule->cuid = td->td_ucred->cr_ruid;
1669                         newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
1670                         TAILQ_INIT(&newrule->rpool.list);
1671                 }
1672
1673 #define ERROUT(x)       { error = (x); goto DIOCCHANGERULE_error; }
1674
1675                 PF_RULES_WLOCK();
1676                 if (!(pcr->action == PF_CHANGE_REMOVE ||
1677                     pcr->action == PF_CHANGE_GET_TICKET) &&
1678                     pcr->pool_ticket != V_ticket_pabuf)
1679                         ERROUT(EBUSY);
1680
1681                 ruleset = pf_find_ruleset(pcr->anchor);
1682                 if (ruleset == NULL)
1683                         ERROUT(EINVAL);
1684
1685                 rs_num = pf_get_ruleset_number(pcr->rule.action);
1686                 if (rs_num >= PF_RULESET_MAX)
1687                         ERROUT(EINVAL);
1688
1689                 if (pcr->action == PF_CHANGE_GET_TICKET) {
1690                         pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
1691                         ERROUT(0);
1692                 } else if (pcr->ticket !=
1693                             ruleset->rules[rs_num].active.ticket)
1694                                 ERROUT(EINVAL);
1695
1696                 if (pcr->action != PF_CHANGE_REMOVE) {
1697                         if (newrule->ifname[0]) {
1698                                 newrule->kif = pfi_kif_attach(kif,
1699                                     newrule->ifname);
1700                                 pfi_kif_ref(newrule->kif);
1701                         } else
1702                                 newrule->kif = NULL;
1703
1704                         if (newrule->rtableid > 0 &&
1705                             newrule->rtableid >= rt_numfibs)
1706                                 error = EBUSY;
1707
1708 #ifdef ALTQ
1709                         /* set queue IDs */
1710                         if (newrule->qname[0] != 0) {
1711                                 if ((newrule->qid =
1712                                     pf_qname2qid(newrule->qname)) == 0)
1713                                         error = EBUSY;
1714                                 else if (newrule->pqname[0] != 0) {
1715                                         if ((newrule->pqid =
1716                                             pf_qname2qid(newrule->pqname)) == 0)
1717                                                 error = EBUSY;
1718                                 } else
1719                                         newrule->pqid = newrule->qid;
1720                         }
1721 #endif /* ALTQ */
1722                         if (newrule->tagname[0])
1723                                 if ((newrule->tag =
1724                                     pf_tagname2tag(newrule->tagname)) == 0)
1725                                         error = EBUSY;
1726                         if (newrule->match_tagname[0])
1727                                 if ((newrule->match_tag = pf_tagname2tag(
1728                                     newrule->match_tagname)) == 0)
1729                                         error = EBUSY;
1730                         if (newrule->rt && !newrule->direction)
1731                                 error = EINVAL;
1732                         if (!newrule->log)
1733                                 newrule->logif = 0;
1734                         if (newrule->logif >= PFLOGIFS_MAX)
1735                                 error = EINVAL;
1736                         if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af))
1737                                 error = ENOMEM;
1738                         if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af))
1739                                 error = ENOMEM;
1740                         if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call))
1741                                 error = EINVAL;
1742                         TAILQ_FOREACH(pa, &V_pf_pabuf, entries)
1743                                 if (pa->addr.type == PF_ADDR_TABLE) {
1744                                         pa->addr.p.tbl =
1745                                             pfr_attach_table(ruleset,
1746                                             pa->addr.v.tblname);
1747                                         if (pa->addr.p.tbl == NULL)
1748                                                 error = ENOMEM;
1749                                 }
1750
1751                         newrule->overload_tbl = NULL;
1752                         if (newrule->overload_tblname[0]) {
1753                                 if ((newrule->overload_tbl = pfr_attach_table(
1754                                     ruleset, newrule->overload_tblname)) ==
1755                                     NULL)
1756                                         error = EINVAL;
1757                                 else
1758                                         newrule->overload_tbl->pfrkt_flags |=
1759                                             PFR_TFLAG_ACTIVE;
1760                         }
1761
1762                         pf_mv_pool(&V_pf_pabuf, &newrule->rpool.list);
1763                         if (((((newrule->action == PF_NAT) ||
1764                             (newrule->action == PF_RDR) ||
1765                             (newrule->action == PF_BINAT) ||
1766                             (newrule->rt > PF_NOPFROUTE)) &&
1767                             !newrule->anchor)) &&
1768                             (TAILQ_FIRST(&newrule->rpool.list) == NULL))
1769                                 error = EINVAL;
1770
1771                         if (error) {
1772                                 pf_free_rule(newrule);
1773                                 PF_RULES_WUNLOCK();
1774                                 break;
1775                         }
1776
1777                         newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
1778                         newrule->evaluations = 0;
1779                         newrule->packets[0] = newrule->packets[1] = 0;
1780                         newrule->bytes[0] = newrule->bytes[1] = 0;
1781                 }
1782                 pf_empty_pool(&V_pf_pabuf);
1783
1784                 if (pcr->action == PF_CHANGE_ADD_HEAD)
1785                         oldrule = TAILQ_FIRST(
1786                             ruleset->rules[rs_num].active.ptr);
1787                 else if (pcr->action == PF_CHANGE_ADD_TAIL)
1788                         oldrule = TAILQ_LAST(
1789                             ruleset->rules[rs_num].active.ptr, pf_rulequeue);
1790                 else {
1791                         oldrule = TAILQ_FIRST(
1792                             ruleset->rules[rs_num].active.ptr);
1793                         while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
1794                                 oldrule = TAILQ_NEXT(oldrule, entries);
1795                         if (oldrule == NULL) {
1796                                 if (newrule != NULL)
1797                                         pf_free_rule(newrule);
1798                                 PF_RULES_WUNLOCK();
1799                                 error = EINVAL;
1800                                 break;
1801                         }
1802                 }
1803
1804                 if (pcr->action == PF_CHANGE_REMOVE) {
1805                         pf_unlink_rule(ruleset->rules[rs_num].active.ptr,
1806                             oldrule);
1807                         ruleset->rules[rs_num].active.rcount--;
1808                 } else {
1809                         if (oldrule == NULL)
1810                                 TAILQ_INSERT_TAIL(
1811                                     ruleset->rules[rs_num].active.ptr,
1812                                     newrule, entries);
1813                         else if (pcr->action == PF_CHANGE_ADD_HEAD ||
1814                             pcr->action == PF_CHANGE_ADD_BEFORE)
1815                                 TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
1816                         else
1817                                 TAILQ_INSERT_AFTER(
1818                                     ruleset->rules[rs_num].active.ptr,
1819                                     oldrule, newrule, entries);
1820                         ruleset->rules[rs_num].active.rcount++;
1821                 }
1822
1823                 nr = 0;
1824                 TAILQ_FOREACH(oldrule,
1825                     ruleset->rules[rs_num].active.ptr, entries)
1826                         oldrule->nr = nr++;
1827
1828                 ruleset->rules[rs_num].active.ticket++;
1829
1830                 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1831                 pf_remove_if_empty_ruleset(ruleset);
1832
1833                 PF_RULES_WUNLOCK();
1834                 break;
1835
1836 #undef ERROUT
1837 DIOCCHANGERULE_error:
1838                 PF_RULES_WUNLOCK();
1839                 if (newrule != NULL) {
1840                         counter_u64_free(newrule->states_cur);
1841                         counter_u64_free(newrule->states_tot);
1842                         counter_u64_free(newrule->src_nodes);
1843                         free(newrule, M_PFRULE);
1844                 }
1845                 if (kif != NULL)
1846                         free(kif, PFI_MTYPE);
1847                 break;
1848         }
1849
1850         case DIOCCLRSTATES: {
1851                 struct pf_state         *s;
1852                 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
1853                 u_int                    i, killed = 0;
1854
1855                 for (i = 0; i <= pf_hashmask; i++) {
1856                         struct pf_idhash *ih = &V_pf_idhash[i];
1857
1858 relock_DIOCCLRSTATES:
1859                         PF_HASHROW_LOCK(ih);
1860                         LIST_FOREACH(s, &ih->states, entry)
1861                                 if (!psk->psk_ifname[0] ||
1862                                     !strcmp(psk->psk_ifname,
1863                                     s->kif->pfik_name)) {
1864                                         /*
1865                                          * Don't send out individual
1866                                          * delete messages.
1867                                          */
1868                                         s->state_flags |= PFSTATE_NOSYNC;
1869                                         pf_unlink_state(s, PF_ENTER_LOCKED);
1870                                         killed++;
1871                                         goto relock_DIOCCLRSTATES;
1872                                 }
1873                         PF_HASHROW_UNLOCK(ih);
1874                 }
1875                 psk->psk_killed = killed;
1876                 if (pfsync_clear_states_ptr != NULL)
1877                         pfsync_clear_states_ptr(V_pf_status.hostid, psk->psk_ifname);
1878                 break;
1879         }
1880
1881         case DIOCKILLSTATES: {
1882                 struct pf_state         *s;
1883                 struct pf_state_key     *sk;
1884                 struct pf_addr          *srcaddr, *dstaddr;
1885                 u_int16_t                srcport, dstport;
1886                 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
1887                 u_int                    i, killed = 0;
1888
1889                 if (psk->psk_pfcmp.id) {
1890                         if (psk->psk_pfcmp.creatorid == 0)
1891                                 psk->psk_pfcmp.creatorid = V_pf_status.hostid;
1892                         if ((s = pf_find_state_byid(psk->psk_pfcmp.id,
1893                             psk->psk_pfcmp.creatorid))) {
1894                                 pf_unlink_state(s, PF_ENTER_LOCKED);
1895                                 psk->psk_killed = 1;
1896                         }
1897                         break;
1898                 }
1899
1900                 for (i = 0; i <= pf_hashmask; i++) {
1901                         struct pf_idhash *ih = &V_pf_idhash[i];
1902
1903 relock_DIOCKILLSTATES:
1904                         PF_HASHROW_LOCK(ih);
1905                         LIST_FOREACH(s, &ih->states, entry) {
1906                                 sk = s->key[PF_SK_WIRE];
1907                                 if (s->direction == PF_OUT) {
1908                                         srcaddr = &sk->addr[1];
1909                                         dstaddr = &sk->addr[0];
1910                                         srcport = sk->port[1];
1911                                         dstport = sk->port[0];
1912                                 } else {
1913                                         srcaddr = &sk->addr[0];
1914                                         dstaddr = &sk->addr[1];
1915                                         srcport = sk->port[0];
1916                                         dstport = sk->port[1];
1917                                 }
1918
1919                                 if ((!psk->psk_af || sk->af == psk->psk_af)
1920                                     && (!psk->psk_proto || psk->psk_proto ==
1921                                     sk->proto) &&
1922                                     PF_MATCHA(psk->psk_src.neg,
1923                                     &psk->psk_src.addr.v.a.addr,
1924                                     &psk->psk_src.addr.v.a.mask,
1925                                     srcaddr, sk->af) &&
1926                                     PF_MATCHA(psk->psk_dst.neg,
1927                                     &psk->psk_dst.addr.v.a.addr,
1928                                     &psk->psk_dst.addr.v.a.mask,
1929                                     dstaddr, sk->af) &&
1930                                     (psk->psk_src.port_op == 0 ||
1931                                     pf_match_port(psk->psk_src.port_op,
1932                                     psk->psk_src.port[0], psk->psk_src.port[1],
1933                                     srcport)) &&
1934                                     (psk->psk_dst.port_op == 0 ||
1935                                     pf_match_port(psk->psk_dst.port_op,
1936                                     psk->psk_dst.port[0], psk->psk_dst.port[1],
1937                                     dstport)) &&
1938                                     (!psk->psk_label[0] ||
1939                                     (s->rule.ptr->label[0] &&
1940                                     !strcmp(psk->psk_label,
1941                                     s->rule.ptr->label))) &&
1942                                     (!psk->psk_ifname[0] ||
1943                                     !strcmp(psk->psk_ifname,
1944                                     s->kif->pfik_name))) {
1945                                         pf_unlink_state(s, PF_ENTER_LOCKED);
1946                                         killed++;
1947                                         goto relock_DIOCKILLSTATES;
1948                                 }
1949                         }
1950                         PF_HASHROW_UNLOCK(ih);
1951                 }
1952                 psk->psk_killed = killed;
1953                 break;
1954         }
1955
1956         case DIOCADDSTATE: {
1957                 struct pfioc_state      *ps = (struct pfioc_state *)addr;
1958                 struct pfsync_state     *sp = &ps->state;
1959
1960                 if (sp->timeout >= PFTM_MAX) {
1961                         error = EINVAL;
1962                         break;
1963                 }
1964                 if (pfsync_state_import_ptr != NULL) {
1965                         PF_RULES_RLOCK();
1966                         error = pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL);
1967                         PF_RULES_RUNLOCK();
1968                 } else
1969                         error = EOPNOTSUPP;
1970                 break;
1971         }
1972
1973         case DIOCGETSTATE: {
1974                 struct pfioc_state      *ps = (struct pfioc_state *)addr;
1975                 struct pf_state         *s;
1976
1977                 s = pf_find_state_byid(ps->state.id, ps->state.creatorid);
1978                 if (s == NULL) {
1979                         error = ENOENT;
1980                         break;
1981                 }
1982
1983                 pfsync_state_export(&ps->state, s);
1984                 PF_STATE_UNLOCK(s);
1985                 break;
1986         }
1987
1988         case DIOCGETSTATES: {
1989                 struct pfioc_states     *ps = (struct pfioc_states *)addr;
1990                 struct pf_state         *s;
1991                 struct pfsync_state     *pstore, *p;
1992                 int i, nr;
1993
1994                 if (ps->ps_len == 0) {
1995                         nr = uma_zone_get_cur(V_pf_state_z);
1996                         ps->ps_len = sizeof(struct pfsync_state) * nr;
1997                         break;
1998                 }
1999
2000                 p = pstore = malloc(ps->ps_len, M_TEMP, M_WAITOK);
2001                 nr = 0;
2002
2003                 for (i = 0; i <= pf_hashmask; i++) {
2004                         struct pf_idhash *ih = &V_pf_idhash[i];
2005
2006                         PF_HASHROW_LOCK(ih);
2007                         LIST_FOREACH(s, &ih->states, entry) {
2008
2009                                 if (s->timeout == PFTM_UNLINKED)
2010                                         continue;
2011
2012                                 if ((nr+1) * sizeof(*p) > ps->ps_len) {
2013                                         PF_HASHROW_UNLOCK(ih);
2014                                         goto DIOCGETSTATES_full;
2015                                 }
2016                                 pfsync_state_export(p, s);
2017                                 p++;
2018                                 nr++;
2019                         }
2020                         PF_HASHROW_UNLOCK(ih);
2021                 }
2022 DIOCGETSTATES_full:
2023                 error = copyout(pstore, ps->ps_states,
2024                     sizeof(struct pfsync_state) * nr);
2025                 if (error) {
2026                         free(pstore, M_TEMP);
2027                         break;
2028                 }
2029                 ps->ps_len = sizeof(struct pfsync_state) * nr;
2030                 free(pstore, M_TEMP);
2031
2032                 break;
2033         }
2034
2035         case DIOCGETSTATUS: {
2036                 struct pf_status *s = (struct pf_status *)addr;
2037
2038                 PF_RULES_RLOCK();
2039                 s->running = V_pf_status.running;
2040                 s->since   = V_pf_status.since;
2041                 s->debug   = V_pf_status.debug;
2042                 s->hostid  = V_pf_status.hostid;
2043                 s->states  = V_pf_status.states;
2044                 s->src_nodes = V_pf_status.src_nodes;
2045
2046                 for (int i = 0; i < PFRES_MAX; i++)
2047                         s->counters[i] =
2048                             counter_u64_fetch(V_pf_status.counters[i]);
2049                 for (int i = 0; i < LCNT_MAX; i++)
2050                         s->lcounters[i] =
2051                             counter_u64_fetch(V_pf_status.lcounters[i]);
2052                 for (int i = 0; i < FCNT_MAX; i++)
2053                         s->fcounters[i] =
2054                             counter_u64_fetch(V_pf_status.fcounters[i]);
2055                 for (int i = 0; i < SCNT_MAX; i++)
2056                         s->scounters[i] =
2057                             counter_u64_fetch(V_pf_status.scounters[i]);
2058
2059                 bcopy(V_pf_status.ifname, s->ifname, IFNAMSIZ);
2060                 bcopy(V_pf_status.pf_chksum, s->pf_chksum,
2061                     PF_MD5_DIGEST_LENGTH);
2062
2063                 pfi_update_status(s->ifname, s);
2064                 PF_RULES_RUNLOCK();
2065                 break;
2066         }
2067
2068         case DIOCSETSTATUSIF: {
2069                 struct pfioc_if *pi = (struct pfioc_if *)addr;
2070
2071                 if (pi->ifname[0] == 0) {
2072                         bzero(V_pf_status.ifname, IFNAMSIZ);
2073                         break;
2074                 }
2075                 PF_RULES_WLOCK();
2076                 strlcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ);
2077                 PF_RULES_WUNLOCK();
2078                 break;
2079         }
2080
2081         case DIOCCLRSTATUS: {
2082                 PF_RULES_WLOCK();
2083                 for (int i = 0; i < PFRES_MAX; i++)
2084                         counter_u64_zero(V_pf_status.counters[i]);
2085                 for (int i = 0; i < FCNT_MAX; i++)
2086                         counter_u64_zero(V_pf_status.fcounters[i]);
2087                 for (int i = 0; i < SCNT_MAX; i++)
2088                         counter_u64_zero(V_pf_status.scounters[i]);
2089                 for (int i = 0; i < LCNT_MAX; i++)
2090                         counter_u64_zero(V_pf_status.lcounters[i]);
2091                 V_pf_status.since = time_second;
2092                 if (*V_pf_status.ifname)
2093                         pfi_update_status(V_pf_status.ifname, NULL);
2094                 PF_RULES_WUNLOCK();
2095                 break;
2096         }
2097
2098         case DIOCNATLOOK: {
2099                 struct pfioc_natlook    *pnl = (struct pfioc_natlook *)addr;
2100                 struct pf_state_key     *sk;
2101                 struct pf_state         *state;
2102                 struct pf_state_key_cmp  key;
2103                 int                      m = 0, direction = pnl->direction;
2104                 int                      sidx, didx;
2105
2106                 /* NATLOOK src and dst are reversed, so reverse sidx/didx */
2107                 sidx = (direction == PF_IN) ? 1 : 0;
2108                 didx = (direction == PF_IN) ? 0 : 1;
2109
2110                 if (!pnl->proto ||
2111                     PF_AZERO(&pnl->saddr, pnl->af) ||
2112                     PF_AZERO(&pnl->daddr, pnl->af) ||
2113                     ((pnl->proto == IPPROTO_TCP ||
2114                     pnl->proto == IPPROTO_UDP) &&
2115                     (!pnl->dport || !pnl->sport)))
2116                         error = EINVAL;
2117                 else {
2118                         bzero(&key, sizeof(key));
2119                         key.af = pnl->af;
2120                         key.proto = pnl->proto;
2121                         PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af);
2122                         key.port[sidx] = pnl->sport;
2123                         PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af);
2124                         key.port[didx] = pnl->dport;
2125
2126                         state = pf_find_state_all(&key, direction, &m);
2127
2128                         if (m > 1)
2129                                 error = E2BIG;  /* more than one state */
2130                         else if (state != NULL) {
2131                                 /* XXXGL: not locked read */
2132                                 sk = state->key[sidx];
2133                                 PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af);
2134                                 pnl->rsport = sk->port[sidx];
2135                                 PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af);
2136                                 pnl->rdport = sk->port[didx];
2137                         } else
2138                                 error = ENOENT;
2139                 }
2140                 break;
2141         }
2142
2143         case DIOCSETTIMEOUT: {
2144                 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
2145                 int              old;
2146
2147                 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
2148                     pt->seconds < 0) {
2149                         error = EINVAL;
2150                         break;
2151                 }
2152                 PF_RULES_WLOCK();
2153                 old = V_pf_default_rule.timeout[pt->timeout];
2154                 if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
2155                         pt->seconds = 1;
2156                 V_pf_default_rule.timeout[pt->timeout] = pt->seconds;
2157                 if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
2158                         wakeup(pf_purge_thread);
2159                 pt->seconds = old;
2160                 PF_RULES_WUNLOCK();
2161                 break;
2162         }
2163
2164         case DIOCGETTIMEOUT: {
2165                 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
2166
2167                 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
2168                         error = EINVAL;
2169                         break;
2170                 }
2171                 PF_RULES_RLOCK();
2172                 pt->seconds = V_pf_default_rule.timeout[pt->timeout];
2173                 PF_RULES_RUNLOCK();
2174                 break;
2175         }
2176
2177         case DIOCGETLIMIT: {
2178                 struct pfioc_limit      *pl = (struct pfioc_limit *)addr;
2179
2180                 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
2181                         error = EINVAL;
2182                         break;
2183                 }
2184                 PF_RULES_RLOCK();
2185                 pl->limit = V_pf_limits[pl->index].limit;
2186                 PF_RULES_RUNLOCK();
2187                 break;
2188         }
2189
2190         case DIOCSETLIMIT: {
2191                 struct pfioc_limit      *pl = (struct pfioc_limit *)addr;
2192                 int                      old_limit;
2193
2194                 PF_RULES_WLOCK();
2195                 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
2196                     V_pf_limits[pl->index].zone == NULL) {
2197                         PF_RULES_WUNLOCK();
2198                         error = EINVAL;
2199                         break;
2200                 }
2201                 uma_zone_set_max(V_pf_limits[pl->index].zone, pl->limit);
2202                 old_limit = V_pf_limits[pl->index].limit;
2203                 V_pf_limits[pl->index].limit = pl->limit;
2204                 pl->limit = old_limit;
2205                 PF_RULES_WUNLOCK();
2206                 break;
2207         }
2208
2209         case DIOCSETDEBUG: {
2210                 u_int32_t       *level = (u_int32_t *)addr;
2211
2212                 PF_RULES_WLOCK();
2213                 V_pf_status.debug = *level;
2214                 PF_RULES_WUNLOCK();
2215                 break;
2216         }
2217
2218         case DIOCCLRRULECTRS: {
2219                 /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
2220                 struct pf_ruleset       *ruleset = &pf_main_ruleset;
2221                 struct pf_rule          *rule;
2222
2223                 PF_RULES_WLOCK();
2224                 TAILQ_FOREACH(rule,
2225                     ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
2226                         rule->evaluations = 0;
2227                         rule->packets[0] = rule->packets[1] = 0;
2228                         rule->bytes[0] = rule->bytes[1] = 0;
2229                 }
2230                 PF_RULES_WUNLOCK();
2231                 break;
2232         }
2233
2234         case DIOCGIFSPEEDV0:
2235         case DIOCGIFSPEEDV1: {
2236                 struct pf_ifspeed_v1    *psp = (struct pf_ifspeed_v1 *)addr;
2237                 struct pf_ifspeed_v1    ps;
2238                 struct ifnet            *ifp;
2239
2240                 if (psp->ifname[0] != 0) {
2241                         /* Can we completely trust user-land? */
2242                         strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
2243                         ifp = ifunit(ps.ifname);
2244                         if (ifp != NULL) {
2245                                 psp->baudrate32 =
2246                                     (u_int32_t)uqmin(ifp->if_baudrate, UINT_MAX);
2247                                 if (cmd == DIOCGIFSPEEDV1)
2248                                         psp->baudrate = ifp->if_baudrate;
2249                         } else
2250                                 error = EINVAL;
2251                 } else
2252                         error = EINVAL;
2253                 break;
2254         }
2255
2256 #ifdef ALTQ
2257         case DIOCSTARTALTQ: {
2258                 struct pf_altq          *altq;
2259
2260                 PF_RULES_WLOCK();
2261                 /* enable all altq interfaces on active list */
2262                 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
2263                         if (altq->qname[0] == 0 && (altq->local_flags &
2264                             PFALTQ_FLAG_IF_REMOVED) == 0) {
2265                                 error = pf_enable_altq(altq);
2266                                 if (error != 0)
2267                                         break;
2268                         }
2269                 }
2270                 if (error == 0)
2271                         V_pf_altq_running = 1;
2272                 PF_RULES_WUNLOCK();
2273                 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
2274                 break;
2275         }
2276
2277         case DIOCSTOPALTQ: {
2278                 struct pf_altq          *altq;
2279
2280                 PF_RULES_WLOCK();
2281                 /* disable all altq interfaces on active list */
2282                 TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
2283                         if (altq->qname[0] == 0 && (altq->local_flags &
2284                             PFALTQ_FLAG_IF_REMOVED) == 0) {
2285                                 error = pf_disable_altq(altq);
2286                                 if (error != 0)
2287                                         break;
2288                         }
2289                 }
2290                 if (error == 0)
2291                         V_pf_altq_running = 0;
2292                 PF_RULES_WUNLOCK();
2293                 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
2294                 break;
2295         }
2296
2297         case DIOCADDALTQV0:
2298         case DIOCADDALTQV1: {
2299                 struct pfioc_altq_v1    *pa = (struct pfioc_altq_v1 *)addr;
2300                 struct pf_altq          *altq, *a;
2301                 struct ifnet            *ifp;
2302
2303                 altq = malloc(sizeof(*altq), M_PFALTQ, M_WAITOK | M_ZERO);
2304                 error = pf_import_kaltq(pa, altq, IOCPARM_LEN(cmd));
2305                 if (error)
2306                         break;
2307                 altq->local_flags = 0;
2308
2309                 PF_RULES_WLOCK();
2310                 if (pa->ticket != V_ticket_altqs_inactive) {
2311                         PF_RULES_WUNLOCK();
2312                         free(altq, M_PFALTQ);
2313                         error = EBUSY;
2314                         break;
2315                 }
2316
2317                 /*
2318                  * if this is for a queue, find the discipline and
2319                  * copy the necessary fields
2320                  */
2321                 if (altq->qname[0] != 0) {
2322                         if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
2323                                 PF_RULES_WUNLOCK();
2324                                 error = EBUSY;
2325                                 free(altq, M_PFALTQ);
2326                                 break;
2327                         }
2328                         altq->altq_disc = NULL;
2329                         TAILQ_FOREACH(a, V_pf_altqs_inactive, entries) {
2330                                 if (strncmp(a->ifname, altq->ifname,
2331                                     IFNAMSIZ) == 0 && a->qname[0] == 0) {
2332                                         altq->altq_disc = a->altq_disc;
2333                                         break;
2334                                 }
2335                         }
2336                 }
2337
2338                 if ((ifp = ifunit(altq->ifname)) == NULL)
2339                         altq->local_flags |= PFALTQ_FLAG_IF_REMOVED;
2340                 else
2341                         error = altq_add(altq);
2342
2343                 if (error) {
2344                         PF_RULES_WUNLOCK();
2345                         free(altq, M_PFALTQ);
2346                         break;
2347                 }
2348
2349                 TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries);
2350                 /* version error check done on import above */
2351                 pf_export_kaltq(altq, pa, IOCPARM_LEN(cmd));
2352                 PF_RULES_WUNLOCK();
2353                 break;
2354         }
2355
2356         case DIOCGETALTQSV0:
2357         case DIOCGETALTQSV1: {
2358                 struct pfioc_altq_v1    *pa = (struct pfioc_altq_v1 *)addr;
2359                 struct pf_altq          *altq;
2360
2361                 PF_RULES_RLOCK();
2362                 pa->nr = 0;
2363                 TAILQ_FOREACH(altq, V_pf_altqs_active, entries)
2364                         pa->nr++;
2365                 pa->ticket = V_ticket_altqs_active;
2366                 PF_RULES_RUNLOCK();
2367                 break;
2368         }
2369
2370         case DIOCGETALTQV0:
2371         case DIOCGETALTQV1: {
2372                 struct pfioc_altq_v1    *pa = (struct pfioc_altq_v1 *)addr;
2373                 struct pf_altq          *altq;
2374                 u_int32_t                nr;
2375
2376                 PF_RULES_RLOCK();
2377                 if (pa->ticket != V_ticket_altqs_active) {
2378                         PF_RULES_RUNLOCK();
2379                         error = EBUSY;
2380                         break;
2381                 }
2382                 nr = 0;
2383                 altq = TAILQ_FIRST(V_pf_altqs_active);
2384                 while ((altq != NULL) && (nr < pa->nr)) {
2385                         altq = TAILQ_NEXT(altq, entries);
2386                         nr++;
2387                 }
2388                 if (altq == NULL) {
2389                         PF_RULES_RUNLOCK();
2390                         error = EBUSY;
2391                         break;
2392                 }
2393                 pf_export_kaltq(altq, pa, IOCPARM_LEN(cmd));
2394                 PF_RULES_RUNLOCK();
2395                 break;
2396         }
2397
2398         case DIOCCHANGEALTQV0:
2399         case DIOCCHANGEALTQV1:
2400                 /* CHANGEALTQ not supported yet! */
2401                 error = ENODEV;
2402                 break;
2403
2404         case DIOCGETQSTATSV0:
2405         case DIOCGETQSTATSV1: {
2406                 struct pfioc_qstats_v1  *pq = (struct pfioc_qstats_v1 *)addr;
2407                 struct pf_altq          *altq;
2408                 u_int32_t                nr;
2409                 int                      nbytes;
2410                 u_int32_t                version;
2411
2412                 PF_RULES_RLOCK();
2413                 if (pq->ticket != V_ticket_altqs_active) {
2414                         PF_RULES_RUNLOCK();
2415                         error = EBUSY;
2416                         break;
2417                 }
2418                 nbytes = pq->nbytes;
2419                 nr = 0;
2420                 altq = TAILQ_FIRST(V_pf_altqs_active);
2421                 while ((altq != NULL) && (nr < pq->nr)) {
2422                         altq = TAILQ_NEXT(altq, entries);
2423                         nr++;
2424                 }
2425                 if (altq == NULL) {
2426                         PF_RULES_RUNLOCK();
2427                         error = EBUSY;
2428                         break;
2429                 }
2430
2431                 if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) {
2432                         PF_RULES_RUNLOCK();
2433                         error = ENXIO;
2434                         break;
2435                 }
2436                 PF_RULES_RUNLOCK();
2437                 if (cmd == DIOCGETQSTATSV0)
2438                         version = 0;  /* DIOCGETQSTATSV0 means stats struct v0 */
2439                 else
2440                         version = pq->version;
2441                 error = altq_getqstats(altq, pq->buf, &nbytes, version);
2442                 if (error == 0) {
2443                         pq->scheduler = altq->scheduler;
2444                         pq->nbytes = nbytes;
2445                 }
2446                 break;
2447         }
2448 #endif /* ALTQ */
2449
2450         case DIOCBEGINADDRS: {
2451                 struct pfioc_pooladdr   *pp = (struct pfioc_pooladdr *)addr;
2452
2453                 PF_RULES_WLOCK();
2454                 pf_empty_pool(&V_pf_pabuf);
2455                 pp->ticket = ++V_ticket_pabuf;
2456                 PF_RULES_WUNLOCK();
2457                 break;
2458         }
2459
2460         case DIOCADDADDR: {
2461                 struct pfioc_pooladdr   *pp = (struct pfioc_pooladdr *)addr;
2462                 struct pf_pooladdr      *pa;
2463                 struct pfi_kif          *kif = NULL;
2464
2465 #ifndef INET
2466                 if (pp->af == AF_INET) {
2467                         error = EAFNOSUPPORT;
2468                         break;
2469                 }
2470 #endif /* INET */
2471 #ifndef INET6
2472                 if (pp->af == AF_INET6) {
2473                         error = EAFNOSUPPORT;
2474                         break;
2475                 }
2476 #endif /* INET6 */
2477                 if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
2478                     pp->addr.addr.type != PF_ADDR_DYNIFTL &&
2479                     pp->addr.addr.type != PF_ADDR_TABLE) {
2480                         error = EINVAL;
2481                         break;
2482                 }
2483                 pa = malloc(sizeof(*pa), M_PFRULE, M_WAITOK);
2484                 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
2485                 if (pa->ifname[0])
2486                         kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK);
2487                 PF_RULES_WLOCK();
2488                 if (pp->ticket != V_ticket_pabuf) {
2489                         PF_RULES_WUNLOCK();
2490                         if (pa->ifname[0])
2491                                 free(kif, PFI_MTYPE);
2492                         free(pa, M_PFRULE);
2493                         error = EBUSY;
2494                         break;
2495                 }
2496                 if (pa->ifname[0]) {
2497                         pa->kif = pfi_kif_attach(kif, pa->ifname);
2498                         pfi_kif_ref(pa->kif);
2499                 } else
2500                         pa->kif = NULL;
2501                 if (pa->addr.type == PF_ADDR_DYNIFTL && ((error =
2502                     pfi_dynaddr_setup(&pa->addr, pp->af)) != 0)) {
2503                         if (pa->ifname[0])
2504                                 pfi_kif_unref(pa->kif);
2505                         PF_RULES_WUNLOCK();
2506                         free(pa, M_PFRULE);
2507                         break;
2508                 }
2509                 TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries);
2510                 PF_RULES_WUNLOCK();
2511                 break;
2512         }
2513
2514         case DIOCGETADDRS: {
2515                 struct pfioc_pooladdr   *pp = (struct pfioc_pooladdr *)addr;
2516                 struct pf_pool          *pool;
2517                 struct pf_pooladdr      *pa;
2518
2519                 PF_RULES_RLOCK();
2520                 pp->nr = 0;
2521                 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
2522                     pp->r_num, 0, 1, 0);
2523                 if (pool == NULL) {
2524                         PF_RULES_RUNLOCK();
2525                         error = EBUSY;
2526                         break;
2527                 }
2528                 TAILQ_FOREACH(pa, &pool->list, entries)
2529                         pp->nr++;
2530                 PF_RULES_RUNLOCK();
2531                 break;
2532         }
2533
2534         case DIOCGETADDR: {
2535                 struct pfioc_pooladdr   *pp = (struct pfioc_pooladdr *)addr;
2536                 struct pf_pool          *pool;
2537                 struct pf_pooladdr      *pa;
2538                 u_int32_t                nr = 0;
2539
2540                 PF_RULES_RLOCK();
2541                 pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
2542                     pp->r_num, 0, 1, 1);
2543                 if (pool == NULL) {
2544                         PF_RULES_RUNLOCK();
2545                         error = EBUSY;
2546                         break;
2547                 }
2548                 pa = TAILQ_FIRST(&pool->list);
2549                 while ((pa != NULL) && (nr < pp->nr)) {
2550                         pa = TAILQ_NEXT(pa, entries);
2551                         nr++;
2552                 }
2553                 if (pa == NULL) {
2554                         PF_RULES_RUNLOCK();
2555                         error = EBUSY;
2556                         break;
2557                 }
2558                 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
2559                 pf_addr_copyout(&pp->addr.addr);
2560                 PF_RULES_RUNLOCK();
2561                 break;
2562         }
2563
2564         case DIOCCHANGEADDR: {
2565                 struct pfioc_pooladdr   *pca = (struct pfioc_pooladdr *)addr;
2566                 struct pf_pool          *pool;
2567                 struct pf_pooladdr      *oldpa = NULL, *newpa = NULL;
2568                 struct pf_ruleset       *ruleset;
2569                 struct pfi_kif          *kif = NULL;
2570
2571                 if (pca->action < PF_CHANGE_ADD_HEAD ||
2572                     pca->action > PF_CHANGE_REMOVE) {
2573                         error = EINVAL;
2574                         break;
2575                 }
2576                 if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
2577                     pca->addr.addr.type != PF_ADDR_DYNIFTL &&
2578                     pca->addr.addr.type != PF_ADDR_TABLE) {
2579                         error = EINVAL;
2580                         break;
2581                 }
2582
2583                 if (pca->action != PF_CHANGE_REMOVE) {
2584 #ifndef INET
2585                         if (pca->af == AF_INET) {
2586                                 error = EAFNOSUPPORT;
2587                                 break;
2588                         }
2589 #endif /* INET */
2590 #ifndef INET6
2591                         if (pca->af == AF_INET6) {
2592                                 error = EAFNOSUPPORT;
2593                                 break;
2594                         }
2595 #endif /* INET6 */
2596                         newpa = malloc(sizeof(*newpa), M_PFRULE, M_WAITOK);
2597                         bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
2598                         if (newpa->ifname[0])
2599                                 kif = malloc(sizeof(*kif), PFI_MTYPE, M_WAITOK);
2600                         newpa->kif = NULL;
2601                 }
2602
2603 #define ERROUT(x)       { error = (x); goto DIOCCHANGEADDR_error; }
2604                 PF_RULES_WLOCK();
2605                 ruleset = pf_find_ruleset(pca->anchor);
2606                 if (ruleset == NULL)
2607                         ERROUT(EBUSY);
2608
2609                 pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
2610                     pca->r_num, pca->r_last, 1, 1);
2611                 if (pool == NULL)
2612                         ERROUT(EBUSY);
2613
2614                 if (pca->action != PF_CHANGE_REMOVE) {
2615                         if (newpa->ifname[0]) {
2616                                 newpa->kif = pfi_kif_attach(kif, newpa->ifname);
2617                                 pfi_kif_ref(newpa->kif);
2618                                 kif = NULL;
2619                         }
2620
2621                         switch (newpa->addr.type) {
2622                         case PF_ADDR_DYNIFTL:
2623                                 error = pfi_dynaddr_setup(&newpa->addr,
2624                                     pca->af);
2625                                 break;
2626                         case PF_ADDR_TABLE:
2627                                 newpa->addr.p.tbl = pfr_attach_table(ruleset,
2628                                     newpa->addr.v.tblname);
2629                                 if (newpa->addr.p.tbl == NULL)
2630                                         error = ENOMEM;
2631                                 break;
2632                         }
2633                         if (error)
2634                                 goto DIOCCHANGEADDR_error;
2635                 }
2636
2637                 switch (pca->action) {
2638                 case PF_CHANGE_ADD_HEAD:
2639                         oldpa = TAILQ_FIRST(&pool->list);
2640                         break;
2641                 case PF_CHANGE_ADD_TAIL:
2642                         oldpa = TAILQ_LAST(&pool->list, pf_palist);
2643                         break;
2644                 default:
2645                         oldpa = TAILQ_FIRST(&pool->list);
2646                         for (int i = 0; oldpa && i < pca->nr; i++)
2647                                 oldpa = TAILQ_NEXT(oldpa, entries);
2648
2649                         if (oldpa == NULL)
2650                                 ERROUT(EINVAL);
2651                 }
2652
2653                 if (pca->action == PF_CHANGE_REMOVE) {
2654                         TAILQ_REMOVE(&pool->list, oldpa, entries);
2655                         switch (oldpa->addr.type) {
2656                         case PF_ADDR_DYNIFTL:
2657                                 pfi_dynaddr_remove(oldpa->addr.p.dyn);
2658                                 break;
2659                         case PF_ADDR_TABLE:
2660                                 pfr_detach_table(oldpa->addr.p.tbl);
2661                                 break;
2662                         }
2663                         if (oldpa->kif)
2664                                 pfi_kif_unref(oldpa->kif);
2665                         free(oldpa, M_PFRULE);
2666                 } else {
2667                         if (oldpa == NULL)
2668                                 TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
2669                         else if (pca->action == PF_CHANGE_ADD_HEAD ||
2670                             pca->action == PF_CHANGE_ADD_BEFORE)
2671                                 TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
2672                         else
2673                                 TAILQ_INSERT_AFTER(&pool->list, oldpa,
2674                                     newpa, entries);
2675                 }
2676
2677                 pool->cur = TAILQ_FIRST(&pool->list);
2678                 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, pca->af);
2679                 PF_RULES_WUNLOCK();
2680                 break;
2681
2682 #undef ERROUT
2683 DIOCCHANGEADDR_error:
2684                 if (newpa != NULL) {
2685                         if (newpa->kif)
2686                                 pfi_kif_unref(newpa->kif);
2687                         free(newpa, M_PFRULE);
2688                 }
2689                 PF_RULES_WUNLOCK();
2690                 if (kif != NULL)
2691                         free(kif, PFI_MTYPE);
2692                 break;
2693         }
2694
2695         case DIOCGETRULESETS: {
2696                 struct pfioc_ruleset    *pr = (struct pfioc_ruleset *)addr;
2697                 struct pf_ruleset       *ruleset;
2698                 struct pf_anchor        *anchor;
2699
2700                 PF_RULES_RLOCK();
2701                 pr->path[sizeof(pr->path) - 1] = 0;
2702                 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
2703                         PF_RULES_RUNLOCK();
2704                         error = ENOENT;
2705                         break;
2706                 }
2707                 pr->nr = 0;
2708                 if (ruleset->anchor == NULL) {
2709                         /* XXX kludge for pf_main_ruleset */
2710                         RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors)
2711                                 if (anchor->parent == NULL)
2712                                         pr->nr++;
2713                 } else {
2714                         RB_FOREACH(anchor, pf_anchor_node,
2715                             &ruleset->anchor->children)
2716                                 pr->nr++;
2717                 }
2718                 PF_RULES_RUNLOCK();
2719                 break;
2720         }
2721
2722         case DIOCGETRULESET: {
2723                 struct pfioc_ruleset    *pr = (struct pfioc_ruleset *)addr;
2724                 struct pf_ruleset       *ruleset;
2725                 struct pf_anchor        *anchor;
2726                 u_int32_t                nr = 0;
2727
2728                 PF_RULES_RLOCK();
2729                 pr->path[sizeof(pr->path) - 1] = 0;
2730                 if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
2731                         PF_RULES_RUNLOCK();
2732                         error = ENOENT;
2733                         break;
2734                 }
2735                 pr->name[0] = 0;
2736                 if (ruleset->anchor == NULL) {
2737                         /* XXX kludge for pf_main_ruleset */
2738                         RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors)
2739                                 if (anchor->parent == NULL && nr++ == pr->nr) {
2740                                         strlcpy(pr->name, anchor->name,
2741                                             sizeof(pr->name));
2742                                         break;
2743                                 }
2744                 } else {
2745                         RB_FOREACH(anchor, pf_anchor_node,
2746                             &ruleset->anchor->children)
2747                                 if (nr++ == pr->nr) {
2748                                         strlcpy(pr->name, anchor->name,
2749                                             sizeof(pr->name));
2750                                         break;
2751                                 }
2752                 }
2753                 if (!pr->name[0])
2754                         error = EBUSY;
2755                 PF_RULES_RUNLOCK();
2756                 break;
2757         }
2758
2759         case DIOCRCLRTABLES: {
2760                 struct pfioc_table *io = (struct pfioc_table *)addr;
2761
2762                 if (io->pfrio_esize != 0) {
2763                         error = ENODEV;
2764                         break;
2765                 }
2766                 PF_RULES_WLOCK();
2767                 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
2768                     io->pfrio_flags | PFR_FLAG_USERIOCTL);
2769                 PF_RULES_WUNLOCK();
2770                 break;
2771         }
2772
2773         case DIOCRADDTABLES: {
2774                 struct pfioc_table *io = (struct pfioc_table *)addr;
2775                 struct pfr_table *pfrts;
2776                 size_t totlen;
2777
2778                 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2779                         error = ENODEV;
2780                         break;
2781                 }
2782
2783                 if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
2784                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
2785                         error = ENOMEM;
2786                         break;
2787                 }
2788
2789                 totlen = io->pfrio_size * sizeof(struct pfr_table);
2790                 pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
2791                     M_TEMP, M_WAITOK);
2792                 error = copyin(io->pfrio_buffer, pfrts, totlen);
2793                 if (error) {
2794                         free(pfrts, M_TEMP);
2795                         break;
2796                 }
2797                 PF_RULES_WLOCK();
2798                 error = pfr_add_tables(pfrts, io->pfrio_size,
2799                     &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2800                 PF_RULES_WUNLOCK();
2801                 free(pfrts, M_TEMP);
2802                 break;
2803         }
2804
2805         case DIOCRDELTABLES: {
2806                 struct pfioc_table *io = (struct pfioc_table *)addr;
2807                 struct pfr_table *pfrts;
2808                 size_t totlen;
2809
2810                 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2811                         error = ENODEV;
2812                         break;
2813                 }
2814
2815                 if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
2816                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
2817                         error = ENOMEM;
2818                         break;
2819                 }
2820
2821                 totlen = io->pfrio_size * sizeof(struct pfr_table);
2822                 pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
2823                     M_TEMP, M_WAITOK);
2824                 error = copyin(io->pfrio_buffer, pfrts, totlen);
2825                 if (error) {
2826                         free(pfrts, M_TEMP);
2827                         break;
2828                 }
2829                 PF_RULES_WLOCK();
2830                 error = pfr_del_tables(pfrts, io->pfrio_size,
2831                     &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2832                 PF_RULES_WUNLOCK();
2833                 free(pfrts, M_TEMP);
2834                 break;
2835         }
2836
2837         case DIOCRGETTABLES: {
2838                 struct pfioc_table *io = (struct pfioc_table *)addr;
2839                 struct pfr_table *pfrts;
2840                 size_t totlen, n;
2841
2842                 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2843                         error = ENODEV;
2844                         break;
2845                 }
2846                 PF_RULES_RLOCK();
2847                 n = pfr_table_count(&io->pfrio_table, io->pfrio_flags);
2848                 io->pfrio_size = min(io->pfrio_size, n);
2849
2850                 totlen = io->pfrio_size * sizeof(struct pfr_table);
2851
2852                 pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
2853                     M_TEMP, M_NOWAIT);
2854                 if (pfrts == NULL) {
2855                         error = ENOMEM;
2856                         PF_RULES_RUNLOCK();
2857                         break;
2858                 }
2859                 error = pfr_get_tables(&io->pfrio_table, pfrts,
2860                     &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2861                 PF_RULES_RUNLOCK();
2862                 if (error == 0)
2863                         error = copyout(pfrts, io->pfrio_buffer, totlen);
2864                 free(pfrts, M_TEMP);
2865                 break;
2866         }
2867
2868         case DIOCRGETTSTATS: {
2869                 struct pfioc_table *io = (struct pfioc_table *)addr;
2870                 struct pfr_tstats *pfrtstats;
2871                 size_t totlen, n;
2872
2873                 if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
2874                         error = ENODEV;
2875                         break;
2876                 }
2877                 PF_RULES_WLOCK();
2878                 n = pfr_table_count(&io->pfrio_table, io->pfrio_flags);
2879                 io->pfrio_size = min(io->pfrio_size, n);
2880
2881                 totlen = io->pfrio_size * sizeof(struct pfr_tstats);
2882                 pfrtstats = mallocarray(io->pfrio_size,
2883                     sizeof(struct pfr_tstats), M_TEMP, M_NOWAIT);
2884                 if (pfrtstats == NULL) {
2885                         error = ENOMEM;
2886                         PF_RULES_WUNLOCK();
2887                         break;
2888                 }
2889                 error = pfr_get_tstats(&io->pfrio_table, pfrtstats,
2890                     &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2891                 PF_RULES_WUNLOCK();
2892                 if (error == 0)
2893                         error = copyout(pfrtstats, io->pfrio_buffer, totlen);
2894                 free(pfrtstats, M_TEMP);
2895                 break;
2896         }
2897
2898         case DIOCRCLRTSTATS: {
2899                 struct pfioc_table *io = (struct pfioc_table *)addr;
2900                 struct pfr_table *pfrts;
2901                 size_t totlen, n;
2902
2903                 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2904                         error = ENODEV;
2905                         break;
2906                 }
2907
2908                 PF_RULES_WLOCK();
2909                 n = pfr_table_count(&io->pfrio_table, io->pfrio_flags);
2910                 io->pfrio_size = min(io->pfrio_size, n);
2911
2912                 totlen = io->pfrio_size * sizeof(struct pfr_table);
2913                 pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
2914                     M_TEMP, M_NOWAIT);
2915                 if (pfrts == NULL) {
2916                         error = ENOMEM;
2917                         PF_RULES_WUNLOCK();
2918                         break;
2919                 }
2920                 error = copyin(io->pfrio_buffer, pfrts, totlen);
2921                 if (error) {
2922                         free(pfrts, M_TEMP);
2923                         PF_RULES_WUNLOCK();
2924                         break;
2925                 }
2926                 error = pfr_clr_tstats(pfrts, io->pfrio_size,
2927                     &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2928                 PF_RULES_WUNLOCK();
2929                 free(pfrts, M_TEMP);
2930                 break;
2931         }
2932
2933         case DIOCRSETTFLAGS: {
2934                 struct pfioc_table *io = (struct pfioc_table *)addr;
2935                 struct pfr_table *pfrts;
2936                 size_t totlen, n;
2937
2938                 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2939                         error = ENODEV;
2940                         break;
2941                 }
2942
2943                 PF_RULES_WLOCK();
2944                 n = pfr_table_count(&io->pfrio_table, io->pfrio_flags);
2945                 io->pfrio_size = min(io->pfrio_size, n);
2946
2947                 totlen = io->pfrio_size * sizeof(struct pfr_table);
2948                 pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
2949                     M_TEMP, M_NOWAIT);
2950                 if (pfrts == NULL) {
2951                         error = ENOMEM;
2952                         PF_RULES_WUNLOCK();
2953                         break;
2954                 }
2955                 error = copyin(io->pfrio_buffer, pfrts, totlen);
2956                 if (error) {
2957                         free(pfrts, M_TEMP);
2958                         PF_RULES_WUNLOCK();
2959                         break;
2960                 }
2961                 error = pfr_set_tflags(pfrts, io->pfrio_size,
2962                     io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
2963                     &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
2964                 PF_RULES_WUNLOCK();
2965                 free(pfrts, M_TEMP);
2966                 break;
2967         }
2968
2969         case DIOCRCLRADDRS: {
2970                 struct pfioc_table *io = (struct pfioc_table *)addr;
2971
2972                 if (io->pfrio_esize != 0) {
2973                         error = ENODEV;
2974                         break;
2975                 }
2976                 PF_RULES_WLOCK();
2977                 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
2978                     io->pfrio_flags | PFR_FLAG_USERIOCTL);
2979                 PF_RULES_WUNLOCK();
2980                 break;
2981         }
2982
2983         case DIOCRADDADDRS: {
2984                 struct pfioc_table *io = (struct pfioc_table *)addr;
2985                 struct pfr_addr *pfras;
2986                 size_t totlen;
2987
2988                 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2989                         error = ENODEV;
2990                         break;
2991                 }
2992                 if (io->pfrio_size < 0 ||
2993                     io->pfrio_size > pf_ioctl_maxcount ||
2994                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
2995                         error = EINVAL;
2996                         break;
2997                 }
2998                 totlen = io->pfrio_size * sizeof(struct pfr_addr);
2999                 pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
3000                     M_TEMP, M_NOWAIT);
3001                 if (! pfras) {
3002                         error = ENOMEM;
3003                         break;
3004                 }
3005                 error = copyin(io->pfrio_buffer, pfras, totlen);
3006                 if (error) {
3007                         free(pfras, M_TEMP);
3008                         break;
3009                 }
3010                 PF_RULES_WLOCK();
3011                 error = pfr_add_addrs(&io->pfrio_table, pfras,
3012                     io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags |
3013                     PFR_FLAG_USERIOCTL);
3014                 PF_RULES_WUNLOCK();
3015                 if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
3016                         error = copyout(pfras, io->pfrio_buffer, totlen);
3017                 free(pfras, M_TEMP);
3018                 break;
3019         }
3020
3021         case DIOCRDELADDRS: {
3022                 struct pfioc_table *io = (struct pfioc_table *)addr;
3023                 struct pfr_addr *pfras;
3024                 size_t totlen;
3025
3026                 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3027                         error = ENODEV;
3028                         break;
3029                 }
3030                 if (io->pfrio_size < 0 ||
3031                     io->pfrio_size > pf_ioctl_maxcount ||
3032                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
3033                         error = EINVAL;
3034                         break;
3035                 }
3036                 totlen = io->pfrio_size * sizeof(struct pfr_addr);
3037                 pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
3038                     M_TEMP, M_NOWAIT);
3039                 if (! pfras) {
3040                         error = ENOMEM;
3041                         break;
3042                 }
3043                 error = copyin(io->pfrio_buffer, pfras, totlen);
3044                 if (error) {
3045                         free(pfras, M_TEMP);
3046                         break;
3047                 }
3048                 PF_RULES_WLOCK();
3049                 error = pfr_del_addrs(&io->pfrio_table, pfras,
3050                     io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags |
3051                     PFR_FLAG_USERIOCTL);
3052                 PF_RULES_WUNLOCK();
3053                 if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
3054                         error = copyout(pfras, io->pfrio_buffer, totlen);
3055                 free(pfras, M_TEMP);
3056                 break;
3057         }
3058
3059         case DIOCRSETADDRS: {
3060                 struct pfioc_table *io = (struct pfioc_table *)addr;
3061                 struct pfr_addr *pfras;
3062                 size_t totlen, count;
3063
3064                 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3065                         error = ENODEV;
3066                         break;
3067                 }
3068                 if (io->pfrio_size < 0 || io->pfrio_size2 < 0) {
3069                         error = EINVAL;
3070                         break;
3071                 }
3072                 count = max(io->pfrio_size, io->pfrio_size2);
3073                 if (count > pf_ioctl_maxcount ||
3074                     WOULD_OVERFLOW(count, sizeof(struct pfr_addr))) {
3075                         error = EINVAL;
3076                         break;
3077                 }
3078                 totlen = count * sizeof(struct pfr_addr);
3079                 pfras = mallocarray(count, sizeof(struct pfr_addr), M_TEMP,
3080                     M_NOWAIT);
3081                 if (! pfras) {
3082                         error = ENOMEM;
3083                         break;
3084                 }
3085                 error = copyin(io->pfrio_buffer, pfras, totlen);
3086                 if (error) {
3087                         free(pfras, M_TEMP);
3088                         break;
3089                 }
3090                 PF_RULES_WLOCK();
3091                 error = pfr_set_addrs(&io->pfrio_table, pfras,
3092                     io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
3093                     &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
3094                     PFR_FLAG_USERIOCTL, 0);
3095                 PF_RULES_WUNLOCK();
3096                 if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
3097                         error = copyout(pfras, io->pfrio_buffer, totlen);
3098                 free(pfras, M_TEMP);
3099                 break;
3100         }
3101
3102         case DIOCRGETADDRS: {
3103                 struct pfioc_table *io = (struct pfioc_table *)addr;
3104                 struct pfr_addr *pfras;
3105                 size_t totlen;
3106
3107                 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3108                         error = ENODEV;
3109                         break;
3110                 }
3111                 if (io->pfrio_size < 0 ||
3112                     io->pfrio_size > pf_ioctl_maxcount ||
3113                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
3114                         error = EINVAL;
3115                         break;
3116                 }
3117                 totlen = io->pfrio_size * sizeof(struct pfr_addr);
3118                 pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
3119                     M_TEMP, M_NOWAIT);
3120                 if (! pfras) {
3121                         error = ENOMEM;
3122                         break;
3123                 }
3124                 PF_RULES_RLOCK();
3125                 error = pfr_get_addrs(&io->pfrio_table, pfras,
3126                     &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3127                 PF_RULES_RUNLOCK();
3128                 if (error == 0)
3129                         error = copyout(pfras, io->pfrio_buffer, totlen);
3130                 free(pfras, M_TEMP);
3131                 break;
3132         }
3133
3134         case DIOCRGETASTATS: {
3135                 struct pfioc_table *io = (struct pfioc_table *)addr;
3136                 struct pfr_astats *pfrastats;
3137                 size_t totlen;
3138
3139                 if (io->pfrio_esize != sizeof(struct pfr_astats)) {
3140                         error = ENODEV;
3141                         break;
3142                 }
3143                 if (io->pfrio_size < 0 ||
3144                     io->pfrio_size > pf_ioctl_maxcount ||
3145                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_astats))) {
3146                         error = EINVAL;
3147                         break;
3148                 }
3149                 totlen = io->pfrio_size * sizeof(struct pfr_astats);
3150                 pfrastats = mallocarray(io->pfrio_size,
3151                     sizeof(struct pfr_astats), M_TEMP, M_NOWAIT);
3152                 if (! pfrastats) {
3153                         error = ENOMEM;
3154                         break;
3155                 }
3156                 PF_RULES_RLOCK();
3157                 error = pfr_get_astats(&io->pfrio_table, pfrastats,
3158                     &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3159                 PF_RULES_RUNLOCK();
3160                 if (error == 0)
3161                         error = copyout(pfrastats, io->pfrio_buffer, totlen);
3162                 free(pfrastats, M_TEMP);
3163                 break;
3164         }
3165
3166         case DIOCRCLRASTATS: {
3167                 struct pfioc_table *io = (struct pfioc_table *)addr;
3168                 struct pfr_addr *pfras;
3169                 size_t totlen;
3170
3171                 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3172                         error = ENODEV;
3173                         break;
3174                 }
3175                 if (io->pfrio_size < 0 ||
3176                     io->pfrio_size > pf_ioctl_maxcount ||
3177                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
3178                         error = EINVAL;
3179                         break;
3180                 }
3181                 totlen = io->pfrio_size * sizeof(struct pfr_addr);
3182                 pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
3183                     M_TEMP, M_NOWAIT);
3184                 if (! pfras) {
3185                         error = ENOMEM;
3186                         break;
3187                 }
3188                 error = copyin(io->pfrio_buffer, pfras, totlen);
3189                 if (error) {
3190                         free(pfras, M_TEMP);
3191                         break;
3192                 }
3193                 PF_RULES_WLOCK();
3194                 error = pfr_clr_astats(&io->pfrio_table, pfras,
3195                     io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags |
3196                     PFR_FLAG_USERIOCTL);
3197                 PF_RULES_WUNLOCK();
3198                 if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
3199                         error = copyout(pfras, io->pfrio_buffer, totlen);
3200                 free(pfras, M_TEMP);
3201                 break;
3202         }
3203
3204         case DIOCRTSTADDRS: {
3205                 struct pfioc_table *io = (struct pfioc_table *)addr;
3206                 struct pfr_addr *pfras;
3207                 size_t totlen;
3208
3209                 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3210                         error = ENODEV;
3211                         break;
3212                 }
3213                 if (io->pfrio_size < 0 ||
3214                     io->pfrio_size > pf_ioctl_maxcount ||
3215                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
3216                         error = EINVAL;
3217                         break;
3218                 }
3219                 totlen = io->pfrio_size * sizeof(struct pfr_addr);
3220                 pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
3221                     M_TEMP, M_NOWAIT);
3222                 if (! pfras) {
3223                         error = ENOMEM;
3224                         break;
3225                 }
3226                 error = copyin(io->pfrio_buffer, pfras, totlen);
3227                 if (error) {
3228                         free(pfras, M_TEMP);
3229                         break;
3230                 }
3231                 PF_RULES_RLOCK();
3232                 error = pfr_tst_addrs(&io->pfrio_table, pfras,
3233                     io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags |
3234                     PFR_FLAG_USERIOCTL);
3235                 PF_RULES_RUNLOCK();
3236                 if (error == 0)
3237                         error = copyout(pfras, io->pfrio_buffer, totlen);
3238                 free(pfras, M_TEMP);
3239                 break;
3240         }
3241
3242         case DIOCRINADEFINE: {
3243                 struct pfioc_table *io = (struct pfioc_table *)addr;
3244                 struct pfr_addr *pfras;
3245                 size_t totlen;
3246
3247                 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3248                         error = ENODEV;
3249                         break;
3250                 }
3251                 if (io->pfrio_size < 0 ||
3252                     io->pfrio_size > pf_ioctl_maxcount ||
3253                     WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
3254                         error = EINVAL;
3255                         break;
3256                 }
3257                 totlen = io->pfrio_size * sizeof(struct pfr_addr);
3258                 pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
3259                     M_TEMP, M_NOWAIT);
3260                 if (! pfras) {
3261                         error = ENOMEM;
3262                         break;
3263                 }
3264                 error = copyin(io->pfrio_buffer, pfras, totlen);
3265                 if (error) {
3266                         free(pfras, M_TEMP);
3267                         break;
3268                 }
3269                 PF_RULES_WLOCK();
3270                 error = pfr_ina_define(&io->pfrio_table, pfras,
3271                     io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
3272                     io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3273                 PF_RULES_WUNLOCK();
3274                 free(pfras, M_TEMP);
3275                 break;
3276         }
3277
3278         case DIOCOSFPADD: {
3279                 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
3280                 PF_RULES_WLOCK();
3281                 error = pf_osfp_add(io);
3282                 PF_RULES_WUNLOCK();
3283                 break;
3284         }
3285
3286         case DIOCOSFPGET: {
3287                 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
3288                 PF_RULES_RLOCK();
3289                 error = pf_osfp_get(io);
3290                 PF_RULES_RUNLOCK();
3291                 break;
3292         }
3293
3294         case DIOCXBEGIN: {
3295                 struct pfioc_trans      *io = (struct pfioc_trans *)addr;
3296                 struct pfioc_trans_e    *ioes, *ioe;
3297                 size_t                   totlen;
3298                 int                      i;
3299
3300                 if (io->esize != sizeof(*ioe)) {
3301                         error = ENODEV;
3302                         break;
3303                 }
3304                 if (io->size < 0 ||
3305                     io->size > pf_ioctl_maxcount ||
3306                     WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
3307                         error = EINVAL;
3308                         break;
3309                 }
3310                 totlen = sizeof(struct pfioc_trans_e) * io->size;
3311                 ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
3312                     M_TEMP, M_NOWAIT);
3313                 if (! ioes) {
3314                         error = ENOMEM;
3315                         break;
3316                 }
3317                 error = copyin(io->array, ioes, totlen);
3318                 if (error) {
3319                         free(ioes, M_TEMP);
3320                         break;
3321                 }
3322                 PF_RULES_WLOCK();
3323                 for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
3324                         switch (ioe->rs_num) {
3325 #ifdef ALTQ
3326                         case PF_RULESET_ALTQ:
3327                                 if (ioe->anchor[0]) {
3328                                         PF_RULES_WUNLOCK();
3329                                         free(ioes, M_TEMP);
3330                                         error = EINVAL;
3331                                         goto fail;
3332                                 }
3333                                 if ((error = pf_begin_altq(&ioe->ticket))) {
3334                                         PF_RULES_WUNLOCK();
3335                                         free(ioes, M_TEMP);
3336                                         goto fail;
3337                                 }
3338                                 break;
3339 #endif /* ALTQ */
3340                         case PF_RULESET_TABLE:
3341                             {
3342                                 struct pfr_table table;
3343
3344                                 bzero(&table, sizeof(table));
3345                                 strlcpy(table.pfrt_anchor, ioe->anchor,
3346                                     sizeof(table.pfrt_anchor));
3347                                 if ((error = pfr_ina_begin(&table,
3348                                     &ioe->ticket, NULL, 0))) {
3349                                         PF_RULES_WUNLOCK();
3350                                         free(ioes, M_TEMP);
3351                                         goto fail;
3352                                 }
3353                                 break;
3354                             }
3355                         default:
3356                                 if ((error = pf_begin_rules(&ioe->ticket,
3357                                     ioe->rs_num, ioe->anchor))) {
3358                                         PF_RULES_WUNLOCK();
3359                                         free(ioes, M_TEMP);
3360                                         goto fail;
3361                                 }
3362                                 break;
3363                         }
3364                 }
3365                 PF_RULES_WUNLOCK();
3366                 error = copyout(ioes, io->array, totlen);
3367                 free(ioes, M_TEMP);
3368                 break;
3369         }
3370
3371         case DIOCXROLLBACK: {
3372                 struct pfioc_trans      *io = (struct pfioc_trans *)addr;
3373                 struct pfioc_trans_e    *ioe, *ioes;
3374                 size_t                   totlen;
3375                 int                      i;
3376
3377                 if (io->esize != sizeof(*ioe)) {
3378                         error = ENODEV;
3379                         break;
3380                 }
3381                 if (io->size < 0 ||
3382                     io->size > pf_ioctl_maxcount ||
3383                     WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
3384                         error = EINVAL;
3385                         break;
3386                 }
3387                 totlen = sizeof(struct pfioc_trans_e) * io->size;
3388                 ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
3389                     M_TEMP, M_NOWAIT);
3390                 if (! ioes) {
3391                         error = ENOMEM;
3392                         break;
3393                 }
3394                 error = copyin(io->array, ioes, totlen);
3395                 if (error) {
3396                         free(ioes, M_TEMP);
3397                         break;
3398                 }
3399                 PF_RULES_WLOCK();
3400                 for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
3401                         switch (ioe->rs_num) {
3402 #ifdef ALTQ
3403                         case PF_RULESET_ALTQ:
3404                                 if (ioe->anchor[0]) {
3405                                         PF_RULES_WUNLOCK();
3406                                         free(ioes, M_TEMP);
3407                                         error = EINVAL;
3408                                         goto fail;
3409                                 }
3410                                 if ((error = pf_rollback_altq(ioe->ticket))) {
3411                                         PF_RULES_WUNLOCK();
3412                                         free(ioes, M_TEMP);
3413                                         goto fail; /* really bad */
3414                                 }
3415                                 break;
3416 #endif /* ALTQ */
3417                         case PF_RULESET_TABLE:
3418                             {
3419                                 struct pfr_table table;
3420
3421                                 bzero(&table, sizeof(table));
3422                                 strlcpy(table.pfrt_anchor, ioe->anchor,
3423                                     sizeof(table.pfrt_anchor));
3424                                 if ((error = pfr_ina_rollback(&table,
3425                                     ioe->ticket, NULL, 0))) {
3426                                         PF_RULES_WUNLOCK();
3427                                         free(ioes, M_TEMP);
3428                                         goto fail; /* really bad */
3429                                 }
3430                                 break;
3431                             }
3432                         default:
3433                                 if ((error = pf_rollback_rules(ioe->ticket,
3434                                     ioe->rs_num, ioe->anchor))) {
3435                                         PF_RULES_WUNLOCK();
3436                                         free(ioes, M_TEMP);
3437                                         goto fail; /* really bad */
3438                                 }
3439                                 break;
3440                         }
3441                 }
3442                 PF_RULES_WUNLOCK();
3443                 free(ioes, M_TEMP);
3444                 break;
3445         }
3446
3447         case DIOCXCOMMIT: {
3448                 struct pfioc_trans      *io = (struct pfioc_trans *)addr;
3449                 struct pfioc_trans_e    *ioe, *ioes;
3450                 struct pf_ruleset       *rs;
3451                 size_t                   totlen;
3452                 int                      i;
3453
3454                 if (io->esize != sizeof(*ioe)) {
3455                         error = ENODEV;
3456                         break;
3457                 }
3458
3459                 if (io->size < 0 ||
3460                     io->size > pf_ioctl_maxcount ||
3461                     WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
3462                         error = EINVAL;
3463                         break;
3464                 }
3465
3466                 totlen = sizeof(struct pfioc_trans_e) * io->size;
3467                 ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
3468                     M_TEMP, M_NOWAIT);
3469                 if (ioes == NULL) {
3470                         error = ENOMEM;
3471                         break;
3472                 }
3473                 error = copyin(io->array, ioes, totlen);
3474                 if (error) {
3475                         free(ioes, M_TEMP);
3476                         break;
3477                 }
3478                 PF_RULES_WLOCK();
3479                 /* First makes sure everything will succeed. */
3480                 for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
3481                         switch (ioe->rs_num) {
3482 #ifdef ALTQ
3483                         case PF_RULESET_ALTQ:
3484                                 if (ioe->anchor[0]) {
3485                                         PF_RULES_WUNLOCK();
3486                                         free(ioes, M_TEMP);
3487                                         error = EINVAL;
3488                                         goto fail;
3489                                 }
3490                                 if (!V_altqs_inactive_open || ioe->ticket !=
3491                                     V_ticket_altqs_inactive) {
3492                                         PF_RULES_WUNLOCK();
3493                                         free(ioes, M_TEMP);
3494                                         error = EBUSY;
3495                                         goto fail;
3496                                 }
3497                                 break;
3498 #endif /* ALTQ */
3499                         case PF_RULESET_TABLE:
3500                                 rs = pf_find_ruleset(ioe->anchor);
3501                                 if (rs == NULL || !rs->topen || ioe->ticket !=
3502                                     rs->tticket) {
3503                                         PF_RULES_WUNLOCK();
3504                                         free(ioes, M_TEMP);
3505                                         error = EBUSY;
3506                                         goto fail;
3507                                 }
3508                                 break;
3509                         default:
3510                                 if (ioe->rs_num < 0 || ioe->rs_num >=
3511                                     PF_RULESET_MAX) {
3512                                         PF_RULES_WUNLOCK();
3513                                         free(ioes, M_TEMP);
3514                                         error = EINVAL;
3515                                         goto fail;
3516                                 }
3517                                 rs = pf_find_ruleset(ioe->anchor);
3518                                 if (rs == NULL ||
3519                                     !rs->rules[ioe->rs_num].inactive.open ||
3520                                     rs->rules[ioe->rs_num].inactive.ticket !=
3521                                     ioe->ticket) {
3522                                         PF_RULES_WUNLOCK();
3523                                         free(ioes, M_TEMP);
3524                                         error = EBUSY;
3525                                         goto fail;
3526                                 }
3527                                 break;
3528                         }
3529                 }
3530                 /* Now do the commit - no errors should happen here. */
3531                 for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
3532                         switch (ioe->rs_num) {
3533 #ifdef ALTQ
3534                         case PF_RULESET_ALTQ:
3535                                 if ((error = pf_commit_altq(ioe->ticket))) {
3536                                         PF_RULES_WUNLOCK();
3537                                         free(ioes, M_TEMP);
3538                                         goto fail; /* really bad */
3539                                 }
3540                                 break;
3541 #endif /* ALTQ */
3542                         case PF_RULESET_TABLE:
3543                             {
3544                                 struct pfr_table table;
3545
3546                                 bzero(&table, sizeof(table));
3547                                 strlcpy(table.pfrt_anchor, ioe->anchor,
3548                                     sizeof(table.pfrt_anchor));
3549                                 if ((error = pfr_ina_commit(&table,
3550                                     ioe->ticket, NULL, NULL, 0))) {
3551                                         PF_RULES_WUNLOCK();
3552                                         free(ioes, M_TEMP);
3553                                         goto fail; /* really bad */
3554                                 }
3555                                 break;
3556                             }
3557                         default:
3558                                 if ((error = pf_commit_rules(ioe->ticket,
3559                                     ioe->rs_num, ioe->anchor))) {
3560                                         PF_RULES_WUNLOCK();
3561                                         free(ioes, M_TEMP);
3562                                         goto fail; /* really bad */
3563                                 }
3564                                 break;
3565                         }
3566                 }
3567                 PF_RULES_WUNLOCK();
3568                 free(ioes, M_TEMP);
3569                 break;
3570         }
3571
3572         case DIOCGETSRCNODES: {
3573                 struct pfioc_src_nodes  *psn = (struct pfioc_src_nodes *)addr;
3574                 struct pf_srchash       *sh;
3575                 struct pf_src_node      *n, *p, *pstore;
3576                 uint32_t                 i, nr = 0;
3577
3578                 if (psn->psn_len == 0) {
3579                         for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask;
3580                             i++, sh++) {
3581                                 PF_HASHROW_LOCK(sh);
3582                                 LIST_FOREACH(n, &sh->nodes, entry)
3583                                         nr++;
3584                                 PF_HASHROW_UNLOCK(sh);
3585                         }
3586                         psn->psn_len = sizeof(struct pf_src_node) * nr;
3587                         break;
3588                 }
3589
3590                 p = pstore = malloc(psn->psn_len, M_TEMP, M_WAITOK);
3591                 for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask;
3592                     i++, sh++) {
3593                     PF_HASHROW_LOCK(sh);
3594                     LIST_FOREACH(n, &sh->nodes, entry) {
3595                         int     secs = time_uptime, diff;
3596
3597                         if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
3598                                 break;
3599
3600                         bcopy(n, p, sizeof(struct pf_src_node));
3601                         if (n->rule.ptr != NULL)
3602                                 p->rule.nr = n->rule.ptr->nr;
3603                         p->creation = secs - p->creation;
3604                         if (p->expire > secs)
3605                                 p->expire -= secs;
3606                         else
3607                                 p->expire = 0;
3608
3609                         /* Adjust the connection rate estimate. */
3610                         diff = secs - n->conn_rate.last;
3611                         if (diff >= n->conn_rate.seconds)
3612                                 p->conn_rate.count = 0;
3613                         else
3614                                 p->conn_rate.count -=
3615                                     n->conn_rate.count * diff /
3616                                     n->conn_rate.seconds;
3617                         p++;
3618                         nr++;
3619                     }
3620                     PF_HASHROW_UNLOCK(sh);
3621                 }
3622                 error = copyout(pstore, psn->psn_src_nodes,
3623                     sizeof(struct pf_src_node) * nr);
3624                 if (error) {
3625                         free(pstore, M_TEMP);
3626                         break;
3627                 }
3628                 psn->psn_len = sizeof(struct pf_src_node) * nr;
3629                 free(pstore, M_TEMP);
3630                 break;
3631         }
3632
3633         case DIOCCLRSRCNODES: {
3634
3635                 pf_clear_srcnodes(NULL);
3636                 pf_purge_expired_src_nodes();
3637                 break;
3638         }
3639
3640         case DIOCKILLSRCNODES:
3641                 pf_kill_srcnodes((struct pfioc_src_node_kill *)addr);
3642                 break;
3643
3644         case DIOCSETHOSTID: {
3645                 u_int32_t       *hostid = (u_int32_t *)addr;
3646
3647                 PF_RULES_WLOCK();
3648                 if (*hostid == 0)
3649                         V_pf_status.hostid = arc4random();
3650                 else
3651                         V_pf_status.hostid = *hostid;
3652                 PF_RULES_WUNLOCK();
3653                 break;
3654         }
3655
3656         case DIOCOSFPFLUSH:
3657                 PF_RULES_WLOCK();
3658                 pf_osfp_flush();
3659                 PF_RULES_WUNLOCK();
3660                 break;
3661
3662         case DIOCIGETIFACES: {
3663                 struct pfioc_iface *io = (struct pfioc_iface *)addr;
3664                 struct pfi_kif *ifstore;
3665                 size_t bufsiz;
3666
3667                 if (io->pfiio_esize != sizeof(struct pfi_kif)) {
3668                         error = ENODEV;
3669                         break;
3670                 }
3671
3672                 if (io->pfiio_size < 0 ||
3673                     io->pfiio_size > pf_ioctl_maxcount ||
3674                     WOULD_OVERFLOW(io->pfiio_size, sizeof(struct pfi_kif))) {
3675                         error = EINVAL;
3676                         break;
3677                 }
3678
3679                 bufsiz = io->pfiio_size * sizeof(struct pfi_kif);
3680                 ifstore = mallocarray(io->pfiio_size, sizeof(struct pfi_kif),
3681                     M_TEMP, M_NOWAIT);
3682                 if (ifstore == NULL) {
3683                         error = ENOMEM;
3684                         break;
3685                 }
3686
3687                 PF_RULES_RLOCK();
3688                 pfi_get_ifaces(io->pfiio_name, ifstore, &io->pfiio_size);
3689                 PF_RULES_RUNLOCK();
3690                 error = copyout(ifstore, io->pfiio_buffer, bufsiz);
3691                 free(ifstore, M_TEMP);
3692                 break;
3693         }
3694
3695         case DIOCSETIFFLAG: {
3696                 struct pfioc_iface *io = (struct pfioc_iface *)addr;
3697
3698                 PF_RULES_WLOCK();
3699                 error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
3700                 PF_RULES_WUNLOCK();
3701                 break;
3702         }
3703
3704         case DIOCCLRIFFLAG: {
3705                 struct pfioc_iface *io = (struct pfioc_iface *)addr;
3706
3707                 PF_RULES_WLOCK();
3708                 error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
3709                 PF_RULES_WUNLOCK();
3710                 break;
3711         }
3712
3713         default:
3714                 error = ENODEV;
3715                 break;
3716         }
3717 fail:
3718         if (sx_xlocked(&pf_ioctl_lock))
3719                 sx_xunlock(&pf_ioctl_lock);
3720         CURVNET_RESTORE();
3721
3722         return (error);
3723 }
3724
3725 void
3726 pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
3727 {
3728         bzero(sp, sizeof(struct pfsync_state));
3729
3730         /* copy from state key */
3731         sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
3732         sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
3733         sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
3734         sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
3735         sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
3736         sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
3737         sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
3738         sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
3739         sp->proto = st->key[PF_SK_WIRE]->proto;
3740         sp->af = st->key[PF_SK_WIRE]->af;
3741
3742         /* copy from state */
3743         strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
3744         bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
3745         sp->creation = htonl(time_uptime - st->creation);
3746         sp->expire = pf_state_expires(st);
3747         if (sp->expire <= time_uptime)
3748                 sp->expire = htonl(0);
3749         else
3750                 sp->expire = htonl(sp->expire - time_uptime);
3751
3752         sp->direction = st->direction;
3753         sp->log = st->log;
3754         sp->timeout = st->timeout;
3755         sp->state_flags = st->state_flags;
3756         if (st->src_node)
3757                 sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
3758         if (st->nat_src_node)
3759                 sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
3760
3761         sp->id = st->id;
3762         sp->creatorid = st->creatorid;
3763         pf_state_peer_hton(&st->src, &sp->src);
3764         pf_state_peer_hton(&st->dst, &sp->dst);
3765
3766         if (st->rule.ptr == NULL)
3767                 sp->rule = htonl(-1);
3768         else
3769                 sp->rule = htonl(st->rule.ptr->nr);
3770         if (st->anchor.ptr == NULL)
3771                 sp->anchor = htonl(-1);
3772         else
3773                 sp->anchor = htonl(st->anchor.ptr->nr);
3774         if (st->nat_rule.ptr == NULL)
3775                 sp->nat_rule = htonl(-1);
3776         else
3777                 sp->nat_rule = htonl(st->nat_rule.ptr->nr);
3778
3779         pf_state_counter_hton(st->packets[0], sp->packets[0]);
3780         pf_state_counter_hton(st->packets[1], sp->packets[1]);
3781         pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
3782         pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
3783
3784 }
3785
3786 static void
3787 pf_tbladdr_copyout(struct pf_addr_wrap *aw)
3788 {
3789         struct pfr_ktable *kt;
3790
3791         KASSERT(aw->type == PF_ADDR_TABLE, ("%s: type %u", __func__, aw->type));
3792
3793         kt = aw->p.tbl;
3794         if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
3795                 kt = kt->pfrkt_root;
3796         aw->p.tbl = NULL;
3797         aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
3798                 kt->pfrkt_cnt : -1;
3799 }
3800
3801 /*
3802  * XXX - Check for version missmatch!!!
3803  */
3804 static void
3805 pf_clear_states(void)
3806 {
3807         struct pf_state *s;
3808         u_int i;
3809
3810         for (i = 0; i <= pf_hashmask; i++) {
3811                 struct pf_idhash *ih = &V_pf_idhash[i];
3812 relock:
3813                 PF_HASHROW_LOCK(ih);
3814                 LIST_FOREACH(s, &ih->states, entry) {
3815                         s->timeout = PFTM_PURGE;
3816                         /* Don't send out individual delete messages. */
3817                         s->state_flags |= PFSTATE_NOSYNC;
3818                         pf_unlink_state(s, PF_ENTER_LOCKED);
3819                         goto relock;
3820                 }
3821                 PF_HASHROW_UNLOCK(ih);
3822         }
3823 }
3824
3825 static int
3826 pf_clear_tables(void)
3827 {
3828         struct pfioc_table io;
3829         int error;
3830
3831         bzero(&io, sizeof(io));
3832
3833         error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel,
3834             io.pfrio_flags);
3835
3836         return (error);
3837 }
3838
3839 static void
3840 pf_clear_srcnodes(struct pf_src_node *n)
3841 {
3842         struct pf_state *s;
3843         int i;
3844
3845         for (i = 0; i <= pf_hashmask; i++) {
3846                 struct pf_idhash *ih = &V_pf_idhash[i];
3847
3848                 PF_HASHROW_LOCK(ih);
3849                 LIST_FOREACH(s, &ih->states, entry) {
3850                         if (n == NULL || n == s->src_node)
3851                                 s->src_node = NULL;
3852                         if (n == NULL || n == s->nat_src_node)
3853                                 s->nat_src_node = NULL;
3854                 }
3855                 PF_HASHROW_UNLOCK(ih);
3856         }
3857
3858         if (n == NULL) {
3859                 struct pf_srchash *sh;
3860
3861                 for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask;
3862                     i++, sh++) {
3863                         PF_HASHROW_LOCK(sh);
3864                         LIST_FOREACH(n, &sh->nodes, entry) {
3865                                 n->expire = 1;
3866                                 n->states = 0;
3867                         }
3868                         PF_HASHROW_UNLOCK(sh);
3869                 }
3870         } else {
3871                 /* XXX: hash slot should already be locked here. */
3872                 n->expire = 1;
3873                 n->states = 0;
3874         }
3875 }
3876
3877 static void
3878 pf_kill_srcnodes(struct pfioc_src_node_kill *psnk)
3879 {
3880         struct pf_src_node_list  kill;
3881
3882         LIST_INIT(&kill);
3883         for (int i = 0; i <= pf_srchashmask; i++) {
3884                 struct pf_srchash *sh = &V_pf_srchash[i];
3885                 struct pf_src_node *sn, *tmp;
3886
3887                 PF_HASHROW_LOCK(sh);
3888                 LIST_FOREACH_SAFE(sn, &sh->nodes, entry, tmp)
3889                         if (PF_MATCHA(psnk->psnk_src.neg,
3890                               &psnk->psnk_src.addr.v.a.addr,
3891                               &psnk->psnk_src.addr.v.a.mask,
3892                               &sn->addr, sn->af) &&
3893                             PF_MATCHA(psnk->psnk_dst.neg,
3894                               &psnk->psnk_dst.addr.v.a.addr,
3895                               &psnk->psnk_dst.addr.v.a.mask,
3896                               &sn->raddr, sn->af)) {
3897                                 pf_unlink_src_node(sn);
3898                                 LIST_INSERT_HEAD(&kill, sn, entry);
3899                                 sn->expire = 1;
3900                         }
3901                 PF_HASHROW_UNLOCK(sh);
3902         }
3903
3904         for (int i = 0; i <= pf_hashmask; i++) {
3905                 struct pf_idhash *ih = &V_pf_idhash[i];
3906                 struct pf_state *s;
3907
3908                 PF_HASHROW_LOCK(ih);
3909                 LIST_FOREACH(s, &ih->states, entry) {
3910                         if (s->src_node && s->src_node->expire == 1)
3911                                 s->src_node = NULL;
3912                         if (s->nat_src_node && s->nat_src_node->expire == 1)
3913                                 s->nat_src_node = NULL;
3914                 }
3915                 PF_HASHROW_UNLOCK(ih);
3916         }
3917
3918         psnk->psnk_killed = pf_free_src_nodes(&kill);
3919 }
3920
3921 /*
3922  * XXX - Check for version missmatch!!!
3923  */
3924
3925 /*
3926  * Duplicate pfctl -Fa operation to get rid of as much as we can.
3927  */
3928 static int
3929 shutdown_pf(void)
3930 {
3931         int error = 0;
3932         u_int32_t t[5];
3933         char nn = '\0';
3934
3935         do {
3936                 if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn))
3937                     != 0) {
3938                         DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n"));
3939                         break;
3940                 }
3941                 if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn))
3942                     != 0) {
3943                         DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n"));
3944                         break;          /* XXX: rollback? */
3945                 }
3946                 if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn))
3947                     != 0) {
3948                         DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n"));
3949                         break;          /* XXX: rollback? */
3950                 }
3951                 if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn))
3952                     != 0) {
3953                         DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n"));
3954                         break;          /* XXX: rollback? */
3955                 }
3956                 if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn))
3957                     != 0) {
3958                         DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n"));
3959                         break;          /* XXX: rollback? */
3960                 }
3961
3962                 /* XXX: these should always succeed here */
3963                 pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn);
3964                 pf_commit_rules(t[1], PF_RULESET_FILTER, &nn);
3965                 pf_commit_rules(t[2], PF_RULESET_NAT, &nn);
3966                 pf_commit_rules(t[3], PF_RULESET_BINAT, &nn);
3967                 pf_commit_rules(t[4], PF_RULESET_RDR, &nn);
3968
3969                 if ((error = pf_clear_tables()) != 0)
3970                         break;
3971
3972 #ifdef ALTQ
3973                 if ((error = pf_begin_altq(&t[0])) != 0) {
3974                         DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n"));
3975                         break;
3976                 }
3977                 pf_commit_altq(t[0]);
3978 #endif
3979
3980                 pf_clear_states();
3981
3982                 pf_clear_srcnodes(NULL);
3983
3984                 /* status does not use malloced mem so no need to cleanup */
3985                 /* fingerprints and interfaces have their own cleanup code */
3986
3987                 /* Free counters last as we updated them during shutdown. */
3988                 counter_u64_free(V_pf_default_rule.states_cur);
3989                 counter_u64_free(V_pf_default_rule.states_tot);
3990                 counter_u64_free(V_pf_default_rule.src_nodes);
3991
3992                 for (int i = 0; i < PFRES_MAX; i++)
3993                         counter_u64_free(V_pf_status.counters[i]);
3994                 for (int i = 0; i < LCNT_MAX; i++)
3995                         counter_u64_free(V_pf_status.lcounters[i]);
3996                 for (int i = 0; i < FCNT_MAX; i++)
3997                         counter_u64_free(V_pf_status.fcounters[i]);
3998                 for (int i = 0; i < SCNT_MAX; i++)
3999                         counter_u64_free(V_pf_status.scounters[i]);
4000         } while(0);
4001
4002         return (error);
4003 }
4004
4005 #ifdef INET
4006 static int
4007 pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, int flags,
4008     struct inpcb *inp)
4009 {
4010         int chk;
4011
4012         chk = pf_test(PF_IN, flags, ifp, m, inp);
4013         if (chk && *m) {
4014                 m_freem(*m);
4015                 *m = NULL;
4016         }
4017
4018         if (chk != PF_PASS)
4019                 return (EACCES);
4020         return (0);
4021 }
4022
4023 static int
4024 pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, int flags,
4025     struct inpcb *inp)
4026 {
4027         int chk;
4028
4029         chk = pf_test(PF_OUT, flags, ifp, m, inp);
4030         if (chk && *m) {
4031                 m_freem(*m);
4032                 *m = NULL;
4033         }
4034
4035         if (chk != PF_PASS)
4036                 return (EACCES);
4037         return (0);
4038 }
4039 #endif
4040
4041 #ifdef INET6
4042 static int
4043 pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, int flags,
4044     struct inpcb *inp)
4045 {
4046         int chk;
4047
4048         /*
4049          * In case of loopback traffic IPv6 uses the real interface in
4050          * order to support scoped addresses. In order to support stateful
4051          * filtering we have change this to lo0 as it is the case in IPv4.
4052          */
4053         CURVNET_SET(ifp->if_vnet);
4054         chk = pf_test6(PF_IN, flags, (*m)->m_flags & M_LOOP ? V_loif : ifp, m, inp);
4055         CURVNET_RESTORE();
4056         if (chk && *m) {
4057                 m_freem(*m);
4058                 *m = NULL;
4059         }
4060         if (chk != PF_PASS)
4061                 return (EACCES);
4062         return (0);
4063 }
4064
4065 static int
4066 pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, int flags,
4067     struct inpcb *inp)
4068 {
4069         int chk;
4070
4071         CURVNET_SET(ifp->if_vnet);
4072         chk = pf_test6(PF_OUT, flags, ifp, m, inp);
4073         CURVNET_RESTORE();
4074         if (chk && *m) {
4075                 m_freem(*m);
4076                 *m = NULL;
4077         }
4078         if (chk != PF_PASS)
4079                 return (EACCES);
4080         return (0);
4081 }
4082 #endif /* INET6 */
4083
4084 static int
4085 hook_pf(void)
4086 {
4087 #ifdef INET
4088         struct pfil_head *pfh_inet;
4089 #endif
4090 #ifdef INET6
4091         struct pfil_head *pfh_inet6;
4092 #endif
4093
4094         if (V_pf_pfil_hooked)
4095                 return (0);
4096
4097 #ifdef INET
4098         pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
4099         if (pfh_inet == NULL)
4100                 return (ESRCH); /* XXX */
4101         pfil_add_hook_flags(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
4102         pfil_add_hook_flags(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
4103 #endif
4104 #ifdef INET6
4105         pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
4106         if (pfh_inet6 == NULL) {
4107 #ifdef INET
4108                 pfil_remove_hook_flags(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
4109                     pfh_inet);
4110                 pfil_remove_hook_flags(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
4111                     pfh_inet);
4112 #endif
4113                 return (ESRCH); /* XXX */
4114         }
4115         pfil_add_hook_flags(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
4116         pfil_add_hook_flags(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
4117 #endif
4118
4119         V_pf_pfil_hooked = 1;
4120         return (0);
4121 }
4122
4123 static int
4124 dehook_pf(void)
4125 {
4126 #ifdef INET
4127         struct pfil_head *pfh_inet;
4128 #endif
4129 #ifdef INET6
4130         struct pfil_head *pfh_inet6;
4131 #endif
4132
4133         if (V_pf_pfil_hooked == 0)
4134                 return (0);
4135
4136 #ifdef INET
4137         pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
4138         if (pfh_inet == NULL)
4139                 return (ESRCH); /* XXX */
4140         pfil_remove_hook_flags(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
4141             pfh_inet);
4142         pfil_remove_hook_flags(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
4143             pfh_inet);
4144 #endif
4145 #ifdef INET6
4146         pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
4147         if (pfh_inet6 == NULL)
4148                 return (ESRCH); /* XXX */
4149         pfil_remove_hook_flags(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
4150             pfh_inet6);
4151         pfil_remove_hook_flags(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
4152             pfh_inet6);
4153 #endif
4154
4155         V_pf_pfil_hooked = 0;
4156         return (0);
4157 }
4158
4159 static void
4160 pf_load_vnet(void)
4161 {
4162         TAILQ_INIT(&V_pf_tags);
4163         TAILQ_INIT(&V_pf_qids);
4164
4165         pfattach_vnet();
4166         V_pf_vnet_active = 1;
4167 }
4168
4169 static int
4170 pf_load(void)
4171 {
4172         int error;
4173
4174         rm_init(&pf_rules_lock, "pf rulesets");
4175         sx_init(&pf_ioctl_lock, "pf ioctl");
4176         sx_init(&pf_end_lock, "pf end thread");
4177
4178         pf_mtag_initialize();
4179
4180         pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME);
4181         if (pf_dev == NULL)
4182                 return (ENOMEM);
4183
4184         pf_end_threads = 0;
4185         error = kproc_create(pf_purge_thread, NULL, &pf_purge_proc, 0, 0, "pf purge");
4186         if (error != 0)
4187                 return (error);
4188
4189         pfi_initialize();
4190
4191         return (0);
4192 }
4193
4194 static void
4195 pf_unload_vnet(void)
4196 {
4197         int error;
4198
4199         V_pf_vnet_active = 0;
4200         V_pf_status.running = 0;
4201         error = dehook_pf();
4202         if (error) {
4203                 /*
4204                  * Should not happen!
4205                  * XXX Due to error code ESRCH, kldunload will show
4206                  * a message like 'No such process'.
4207                  */
4208                 printf("%s : pfil unregisteration fail\n", __FUNCTION__);
4209                 return;
4210         }
4211
4212         PF_RULES_WLOCK();
4213         shutdown_pf();
4214         PF_RULES_WUNLOCK();
4215
4216         swi_remove(V_pf_swi_cookie);
4217
4218         pf_unload_vnet_purge();
4219
4220         pf_normalize_cleanup();
4221         PF_RULES_WLOCK();
4222         pfi_cleanup_vnet();
4223         PF_RULES_WUNLOCK();
4224         pfr_cleanup();
4225         pf_osfp_flush();
4226         pf_cleanup();
4227         if (IS_DEFAULT_VNET(curvnet))
4228                 pf_mtag_cleanup();
4229 }
4230
4231 static void
4232 pf_unload(void)
4233 {
4234
4235         sx_xlock(&pf_end_lock);
4236         pf_end_threads = 1;
4237         while (pf_end_threads < 2) {
4238                 wakeup_one(pf_purge_thread);
4239                 sx_sleep(pf_purge_proc, &pf_end_lock, 0, "pftmo", 0);
4240         }
4241         sx_xunlock(&pf_end_lock);
4242
4243         if (pf_dev != NULL)
4244                 destroy_dev(pf_dev);
4245
4246         pfi_cleanup();
4247
4248         rm_destroy(&pf_rules_lock);
4249         sx_destroy(&pf_ioctl_lock);
4250         sx_destroy(&pf_end_lock);
4251 }
4252
4253 static void
4254 vnet_pf_init(void *unused __unused)
4255 {
4256
4257         pf_load_vnet();
4258 }
4259 VNET_SYSINIT(vnet_pf_init, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD, 
4260     vnet_pf_init, NULL);
4261
4262 static void
4263 vnet_pf_uninit(const void *unused __unused)
4264 {
4265
4266         pf_unload_vnet();
4267
4268 SYSUNINIT(pf_unload, SI_SUB_PROTO_FIREWALL, SI_ORDER_SECOND, pf_unload, NULL);
4269 VNET_SYSUNINIT(vnet_pf_uninit, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
4270     vnet_pf_uninit, NULL);
4271
4272
4273 static int
4274 pf_modevent(module_t mod, int type, void *data)
4275 {
4276         int error = 0;
4277
4278         switch(type) {
4279         case MOD_LOAD:
4280                 error = pf_load();
4281                 break;
4282         case MOD_UNLOAD:
4283                 /* Handled in SYSUNINIT(pf_unload) to ensure it's done after
4284                  * the vnet_pf_uninit()s */
4285                 break;
4286         default:
4287                 error = EINVAL;
4288                 break;
4289         }
4290
4291         return (error);
4292 }
4293
4294 static moduledata_t pf_mod = {
4295         "pf",
4296         pf_modevent,
4297         0
4298 };
4299
4300 DECLARE_MODULE(pf, pf_mod, SI_SUB_PROTO_FIREWALL, SI_ORDER_SECOND);
4301 MODULE_VERSION(pf, PF_MODVER);