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