Deleted Added
sdiff udiff text old ( 126259 ) new ( 126261 )
full compact
1/* $OpenBSD: pf_ioctl.c,v 1.81 2003/08/22 21:50:34 david Exp $ */
2
3/*
4 * Copyright (c) 2001 Daniel Hartmeier
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Effort sponsored in part by the Defense Advanced Research Projects
32 * Agency (DARPA) and Air Force Research Laboratory, Air Force
33 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
34 *
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/mbuf.h>
40#include <sys/filio.h>
41#include <sys/fcntl.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/kernel.h>
45#include <sys/time.h>
46#include <sys/timeout.h>
47#include <sys/pool.h>
48#include <sys/malloc.h>
49
50#include <net/if.h>
51#include <net/if_types.h>
52#include <net/route.h>
53
54#include <netinet/in.h>
55#include <netinet/in_var.h>
56#include <netinet/in_systm.h>
57#include <netinet/ip.h>
58#include <netinet/ip_var.h>
59#include <netinet/ip_icmp.h>
60
61#include <net/pfvar.h>
62
63#ifdef INET6
64#include <netinet/ip6.h>
65#include <netinet/in_pcb.h>
66#endif /* INET6 */
67
68#ifdef ALTQ
69#include <altq/altq.h>
70#endif
71
72void pfattach(int);
73int pfopen(dev_t, int, int, struct proc *);
74int pfclose(dev_t, int, int, struct proc *);
75struct pf_pool *pf_get_pool(char *, char *, u_int32_t,
76 u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t);
77int pf_get_ruleset_number(u_int8_t);
78void pf_init_ruleset(struct pf_ruleset *);
79void pf_mv_pool(struct pf_palist *, struct pf_palist *);
80void pf_empty_pool(struct pf_palist *);
81int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
82
83extern struct timeout pf_expire_to;
84
85struct pf_rule pf_default_rule;
86
87#define TAGID_MAX 50000
88TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags);
89
90#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
91
92void
93pfattach(int num)
94{
95 u_int32_t *timeout = pf_default_rule.timeout;
96
97 pool_init(&pf_tree_pl, sizeof(struct pf_tree_node), 0, 0, 0, "pftrpl",
98 NULL);
99 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
100 &pool_allocator_nointr);
101 pool_init(&pf_addr_pl, sizeof(struct pf_addr_dyn), 0, 0, 0, "pfaddrpl",
102 &pool_allocator_nointr);
103 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
104 NULL);
105 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl",
106 NULL);
107 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
108 "pfpooladdrpl", NULL);
109 pfr_initialize();
110 pf_osfp_initialize();
111
112 pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit,
113 NULL, 0);
114
115 RB_INIT(&tree_lan_ext);
116 RB_INIT(&tree_ext_gwy);
117 TAILQ_INIT(&pf_anchors);
118 pf_init_ruleset(&pf_main_ruleset);
119 TAILQ_INIT(&pf_altqs[0]);
120 TAILQ_INIT(&pf_altqs[1]);
121 TAILQ_INIT(&pf_pabuf);
122 pf_altqs_active = &pf_altqs[0];
123 pf_altqs_inactive = &pf_altqs[1];
124
125 /* default rule should never be garbage collected */
126 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
127 pf_default_rule.action = PF_PASS;
128 pf_default_rule.nr = -1;
129
130 /* initialize default timeouts */
131 timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */
132 timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
133 timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */
134 timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */
135 timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */
136 timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */
137 timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */
138 timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */
139 timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */
140 timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */
141 timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */
142 timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */
143 timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */
144 timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */
145 timeout[PFTM_FRAG] = 30; /* Fragment expire */
146 timeout[PFTM_INTERVAL] = 10; /* Expire interval */
147
148 timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
149 timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
150
151 pf_normalize_init();
152 pf_status.debug = PF_DEBUG_URGENT;
153}
154
155int
156pfopen(dev_t dev, int flags, int fmt, struct proc *p)
157{
158 if (minor(dev) >= 1)
159 return (ENXIO);
160 return (0);
161}
162
163int
164pfclose(dev_t dev, int flags, int fmt, struct proc *p)
165{
166 if (minor(dev) >= 1)
167 return (ENXIO);
168 return (0);
169}
170
171struct pf_pool *
172pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket,
173 u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last,
174 u_int8_t active, u_int8_t check_ticket)
175{
176 struct pf_ruleset *ruleset;
177 struct pf_rule *rule;
178 int rs_num;
179
180 ruleset = pf_find_ruleset(anchorname, rulesetname);
181 if (ruleset == NULL)
182 return (NULL);
183 rs_num = pf_get_ruleset_number(rule_action);
184 if (rs_num >= PF_RULESET_MAX)
185 return (NULL);
186 if (active) {
187 if (check_ticket && ticket !=
188 ruleset->rules[rs_num].active.ticket)
189 return (NULL);
190 if (r_last)
191 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
192 pf_rulequeue);
193 else
194 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
195 } else {
196 if (check_ticket && ticket !=
197 ruleset->rules[rs_num].inactive.ticket)
198 return (NULL);
199 if (r_last)
200 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
201 pf_rulequeue);
202 else
203 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
204 }
205 if (!r_last) {
206 while ((rule != NULL) && (rule->nr != rule_number))
207 rule = TAILQ_NEXT(rule, entries);
208 }
209 if (rule == NULL)
210 return (NULL);
211
212 return (&rule->rpool);
213}
214
215int
216pf_get_ruleset_number(u_int8_t action)
217{
218 switch (action) {
219 case PF_SCRUB:
220 return (PF_RULESET_SCRUB);
221 break;
222 case PF_PASS:
223 case PF_DROP:
224 return (PF_RULESET_FILTER);
225 break;
226 case PF_NAT:
227 case PF_NONAT:
228 return (PF_RULESET_NAT);
229 break;
230 case PF_BINAT:
231 case PF_NOBINAT:
232 return (PF_RULESET_BINAT);
233 break;
234 case PF_RDR:
235 case PF_NORDR:
236 return (PF_RULESET_RDR);
237 break;
238 default:
239 return (PF_RULESET_MAX);
240 break;
241 }
242}
243
244void
245pf_init_ruleset(struct pf_ruleset *ruleset)
246{
247 int i;
248
249 memset(ruleset, 0, sizeof(struct pf_ruleset));
250 for (i = 0; i < PF_RULESET_MAX; i++) {
251 TAILQ_INIT(&ruleset->rules[i].queues[0]);
252 TAILQ_INIT(&ruleset->rules[i].queues[1]);
253 ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
254 ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
255 }
256}
257
258struct pf_anchor *
259pf_find_anchor(const char *anchorname)
260{
261 struct pf_anchor *anchor;
262 int n = -1;
263
264 anchor = TAILQ_FIRST(&pf_anchors);
265 while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0)
266 anchor = TAILQ_NEXT(anchor, entries);
267 if (n == 0)
268 return (anchor);
269 else
270 return (NULL);
271}
272
273struct pf_ruleset *
274pf_find_ruleset(char *anchorname, char *rulesetname)
275{
276 struct pf_anchor *anchor;
277 struct pf_ruleset *ruleset;
278
279 if (!anchorname[0] && !rulesetname[0])
280 return (&pf_main_ruleset);
281 if (!anchorname[0] || !rulesetname[0])
282 return (NULL);
283 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
284 rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
285 anchor = pf_find_anchor(anchorname);
286 if (anchor == NULL)
287 return (NULL);
288 ruleset = TAILQ_FIRST(&anchor->rulesets);
289 while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0)
290 ruleset = TAILQ_NEXT(ruleset, entries);
291 if (ruleset != NULL && !strcmp(ruleset->name, rulesetname))
292 return (ruleset);
293 else
294 return (NULL);
295}
296
297struct pf_ruleset *
298pf_find_or_create_ruleset(char *anchorname, char *rulesetname)
299{
300 struct pf_anchor *anchor, *a;
301 struct pf_ruleset *ruleset, *r;
302
303 if (!anchorname[0] && !rulesetname[0])
304 return (&pf_main_ruleset);
305 if (!anchorname[0] || !rulesetname[0])
306 return (NULL);
307 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
308 rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
309 a = TAILQ_FIRST(&pf_anchors);
310 while (a != NULL && strcmp(a->name, anchorname) < 0)
311 a = TAILQ_NEXT(a, entries);
312 if (a != NULL && !strcmp(a->name, anchorname))
313 anchor = a;
314 else {
315 anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor),
316 M_TEMP, M_NOWAIT);
317 if (anchor == NULL)
318 return (NULL);
319 memset(anchor, 0, sizeof(struct pf_anchor));
320 bcopy(anchorname, anchor->name, sizeof(anchor->name));
321 TAILQ_INIT(&anchor->rulesets);
322 if (a != NULL)
323 TAILQ_INSERT_BEFORE(a, anchor, entries);
324 else
325 TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries);
326 }
327 r = TAILQ_FIRST(&anchor->rulesets);
328 while (r != NULL && strcmp(r->name, rulesetname) < 0)
329 r = TAILQ_NEXT(r, entries);
330 if (r != NULL && !strcmp(r->name, rulesetname))
331 return (r);
332 ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset),
333 M_TEMP, M_NOWAIT);
334 if (ruleset != NULL) {
335 pf_init_ruleset(ruleset);
336 bcopy(rulesetname, ruleset->name, sizeof(ruleset->name));
337 ruleset->anchor = anchor;
338 if (r != NULL)
339 TAILQ_INSERT_BEFORE(r, ruleset, entries);
340 else
341 TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries);
342 }
343 return (ruleset);
344}
345
346void
347pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
348{
349 struct pf_anchor *anchor;
350 int i;
351
352 if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || ruleset->topen)
353 return;
354 for (i = 0; i < PF_RULESET_MAX; ++i)
355 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
356 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr))
357 return;
358
359 anchor = ruleset->anchor;
360 TAILQ_REMOVE(&anchor->rulesets, ruleset, entries);
361 free(ruleset, M_TEMP);
362
363 if (TAILQ_EMPTY(&anchor->rulesets)) {
364 TAILQ_REMOVE(&pf_anchors, anchor, entries);
365 free(anchor, M_TEMP);
366 }
367}
368
369void
370pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
371{
372 struct pf_pooladdr *mv_pool_pa;
373
374 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
375 TAILQ_REMOVE(poola, mv_pool_pa, entries);
376 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
377 }
378}
379
380void
381pf_empty_pool(struct pf_palist *poola)
382{
383 struct pf_pooladdr *empty_pool_pa;
384
385 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
386 pf_dynaddr_remove(&empty_pool_pa->addr);
387 pf_tbladdr_remove(&empty_pool_pa->addr);
388 TAILQ_REMOVE(poola, empty_pool_pa, entries);
389 pool_put(&pf_pooladdr_pl, empty_pool_pa);
390 }
391}
392
393void
394pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
395{
396 if (rulequeue != NULL) {
397 if (rule->states <= 0) {
398 /*
399 * XXX - we need to remove the table *before* detaching
400 * the rule to make sure the table code does not delete
401 * the anchor under our feet.
402 */
403 pf_tbladdr_remove(&rule->src.addr);
404 pf_tbladdr_remove(&rule->dst.addr);
405 }
406 TAILQ_REMOVE(rulequeue, rule, entries);
407 rule->entries.tqe_prev = NULL;
408 rule->nr = -1;
409 }
410 if (rule->states > 0 || rule->entries.tqe_prev != NULL)
411 return;
412 pf_tag_unref(rule->tag);
413 pf_tag_unref(rule->match_tag);
414 pf_dynaddr_remove(&rule->src.addr);
415 pf_dynaddr_remove(&rule->dst.addr);
416 if (rulequeue == NULL) {
417 pf_tbladdr_remove(&rule->src.addr);
418 pf_tbladdr_remove(&rule->dst.addr);
419 }
420 pf_empty_pool(&rule->rpool.list);
421 pool_put(&pf_rule_pl, rule);
422}
423
424u_int16_t
425pf_tagname2tag(char *tagname)
426{
427 struct pf_tagname *tag, *p = NULL;
428 u_int16_t new_tagid = 1;
429
430 TAILQ_FOREACH(tag, &pf_tags, entries)
431 if (strcmp(tagname, tag->name) == 0) {
432 tag->ref++;
433 return (tag->tag);
434 }
435
436 /*
437 * to avoid fragmentation, we do a linear search from the beginning
438 * and take the first free slot we find. if there is none or the list
439 * is empty, append a new entry at the end.
440 */
441
442 /* new entry */
443 if (!TAILQ_EMPTY(&pf_tags))
444 for (p = TAILQ_FIRST(&pf_tags); p != NULL &&
445 p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
446 new_tagid = p->tag + 1;
447
448 if (new_tagid > TAGID_MAX)
449 return (0);
450
451 /* allocate and fill new struct pf_tagname */
452 tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname),
453 M_TEMP, M_NOWAIT);
454 if (tag == NULL)
455 return (0);
456 bzero(tag, sizeof(struct pf_tagname));
457 strlcpy(tag->name, tagname, sizeof(tag->name));
458 tag->tag = new_tagid;
459 tag->ref++;
460
461 if (p != NULL) /* insert new entry before p */
462 TAILQ_INSERT_BEFORE(p, tag, entries);
463 else /* either list empty or no free slot in between */
464 TAILQ_INSERT_TAIL(&pf_tags, tag, entries);
465
466 return (tag->tag);
467}
468
469void
470pf_tag2tagname(u_int16_t tagid, char *p)
471{
472 struct pf_tagname *tag;
473
474 TAILQ_FOREACH(tag, &pf_tags, entries)
475 if (tag->tag == tagid) {
476 strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
477 return;
478 }
479}
480
481void
482pf_tag_unref(u_int16_t tag)
483{
484 struct pf_tagname *p, *next;
485
486 if (tag == 0)
487 return;
488
489 for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) {
490 next = TAILQ_NEXT(p, entries);
491 if (tag == p->tag) {
492 if (--p->ref == 0) {
493 TAILQ_REMOVE(&pf_tags, p, entries);
494 free(p, M_TEMP);
495 }
496 break;
497 }
498 }
499}
500
501int
502pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
503{
504 struct pf_pooladdr *pa = NULL;
505 struct pf_pool *pool = NULL;
506 int s;
507 int error = 0;
508
509 /* XXX keep in sync with switch() below */
510 if (securelevel > 1)
511 switch (cmd) {
512 case DIOCGETRULES:
513 case DIOCGETRULE:
514 case DIOCGETADDRS:
515 case DIOCGETADDR:
516 case DIOCGETSTATE:
517 case DIOCSETSTATUSIF:
518 case DIOCGETSTATUS:
519 case DIOCCLRSTATUS:
520 case DIOCNATLOOK:
521 case DIOCSETDEBUG:
522 case DIOCGETSTATES:
523 case DIOCGETTIMEOUT:
524 case DIOCCLRRULECTRS:
525 case DIOCGETLIMIT:
526 case DIOCGETALTQS:
527 case DIOCGETALTQ:
528 case DIOCGETQSTATS:
529 case DIOCGETANCHORS:
530 case DIOCGETANCHOR:
531 case DIOCGETRULESETS:
532 case DIOCGETRULESET:
533 case DIOCRGETTABLES:
534 case DIOCRGETTSTATS:
535 case DIOCRCLRTSTATS:
536 case DIOCRCLRADDRS:
537 case DIOCRADDADDRS:
538 case DIOCRDELADDRS:
539 case DIOCRSETADDRS:
540 case DIOCRGETADDRS:
541 case DIOCRGETASTATS:
542 case DIOCRCLRASTATS:
543 case DIOCRTSTADDRS:
544 case DIOCOSFPGET:
545 break;
546 default:
547 return (EPERM);
548 }
549
550 if (!(flags & FWRITE))
551 switch (cmd) {
552 case DIOCGETRULES:
553 case DIOCGETRULE:
554 case DIOCGETADDRS:
555 case DIOCGETADDR:
556 case DIOCGETSTATE:
557 case DIOCGETSTATUS:
558 case DIOCGETSTATES:
559 case DIOCGETTIMEOUT:
560 case DIOCGETLIMIT:
561 case DIOCGETALTQS:
562 case DIOCGETALTQ:
563 case DIOCGETQSTATS:
564 case DIOCGETANCHORS:
565 case DIOCGETANCHOR:
566 case DIOCGETRULESETS:
567 case DIOCGETRULESET:
568 case DIOCRGETTABLES:
569 case DIOCRGETTSTATS:
570 case DIOCRGETADDRS:
571 case DIOCRGETASTATS:
572 case DIOCRTSTADDRS:
573 case DIOCOSFPGET:
574 break;
575 default:
576 return (EACCES);
577 }
578
579 switch (cmd) {
580
581 case DIOCSTART:
582 if (pf_status.running)
583 error = EEXIST;
584 else {
585 u_int32_t states = pf_status.states;
586 bzero(&pf_status, sizeof(struct pf_status));
587 pf_status.running = 1;
588 pf_status.states = states;
589 pf_status.since = time.tv_sec;
590 if (status_ifp != NULL)
591 strlcpy(pf_status.ifname,
592 status_ifp->if_xname, IFNAMSIZ);
593 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
594 }
595 break;
596
597 case DIOCSTOP:
598 if (!pf_status.running)
599 error = ENOENT;
600 else {
601 pf_status.running = 0;
602 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
603 }
604 break;
605
606 case DIOCBEGINRULES: {
607 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
608 struct pf_ruleset *ruleset;
609 struct pf_rule *rule;
610 int rs_num;
611
612 ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
613 if (ruleset == NULL) {
614 error = EINVAL;
615 break;
616 }
617 rs_num = pf_get_ruleset_number(pr->rule.action);
618 if (rs_num >= PF_RULESET_MAX) {
619 error = EINVAL;
620 break;
621 }
622 while ((rule =
623 TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
624 pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
625 pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
626 break;
627 }
628
629 case DIOCADDRULE: {
630 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
631 struct pf_ruleset *ruleset;
632 struct pf_rule *rule, *tail;
633 struct pf_pooladdr *pa;
634 int rs_num;
635
636 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
637 if (ruleset == NULL) {
638 error = EINVAL;
639 break;
640 }
641 rs_num = pf_get_ruleset_number(pr->rule.action);
642 if (rs_num >= PF_RULESET_MAX) {
643 error = EINVAL;
644 break;
645 }
646 if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) {
647 error = EINVAL;
648 break;
649 }
650 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
651 error = EINVAL;
652 break;
653 }
654 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
655 error = EBUSY;
656 break;
657 }
658 if (pr->pool_ticket != ticket_pabuf) {
659 error = EBUSY;
660 break;
661 }
662 rule = pool_get(&pf_rule_pl, PR_NOWAIT);
663 if (rule == NULL) {
664 error = ENOMEM;
665 break;
666 }
667 bcopy(&pr->rule, rule, sizeof(struct pf_rule));
668 rule->anchor = NULL;
669 rule->ifp = NULL;
670 TAILQ_INIT(&rule->rpool.list);
671 /* initialize refcounting */
672 rule->states = 0;
673 rule->entries.tqe_prev = NULL;
674#ifndef INET
675 if (rule->af == AF_INET) {
676 pool_put(&pf_rule_pl, rule);
677 error = EAFNOSUPPORT;
678 break;
679 }
680#endif /* INET */
681#ifndef INET6
682 if (rule->af == AF_INET6) {
683 pool_put(&pf_rule_pl, rule);
684 error = EAFNOSUPPORT;
685 break;
686 }
687#endif /* INET6 */
688 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
689 pf_rulequeue);
690 if (tail)
691 rule->nr = tail->nr + 1;
692 else
693 rule->nr = 0;
694 if (rule->ifname[0]) {
695 rule->ifp = ifunit(rule->ifname);
696 if (rule->ifp == NULL) {
697 pool_put(&pf_rule_pl, rule);
698 error = EINVAL;
699 break;
700 }
701 }
702
703 if (rule->tagname[0])
704 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
705 error = EBUSY;
706 if (rule->match_tagname[0])
707 if ((rule->match_tag =
708 pf_tagname2tag(rule->match_tagname)) == 0)
709 error = EBUSY;
710 if (rule->rt && !rule->direction)
711 error = EINVAL;
712 if (pf_dynaddr_setup(&rule->src.addr, rule->af))
713 error = EINVAL;
714 if (pf_dynaddr_setup(&rule->dst.addr, rule->af))
715 error = EINVAL;
716 if (pf_tbladdr_setup(ruleset, &rule->src.addr))
717 error = EINVAL;
718 if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
719 error = EINVAL;
720 TAILQ_FOREACH(pa, &pf_pabuf, entries)
721 if (pf_tbladdr_setup(ruleset, &pa->addr))
722 error = EINVAL;
723
724 pf_mv_pool(&pf_pabuf, &rule->rpool.list);
725 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
726 (rule->action == PF_BINAT)) && !rule->anchorname[0]) ||
727 (rule->rt > PF_FASTROUTE)) &&
728 (TAILQ_FIRST(&rule->rpool.list) == NULL))
729 error = EINVAL;
730
731 if (error) {
732 pf_rm_rule(NULL, rule);
733 break;
734 }
735 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
736 rule->evaluations = rule->packets = rule->bytes = 0;
737 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
738 rule, entries);
739 break;
740 }
741
742 case DIOCCOMMITRULES: {
743 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
744 struct pf_ruleset *ruleset;
745 struct pf_rulequeue *old_rules;
746 struct pf_rule *rule;
747 int rs_num;
748
749 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
750 if (ruleset == NULL) {
751 error = EINVAL;
752 break;
753 }
754 rs_num = pf_get_ruleset_number(pr->rule.action);
755 if (rs_num >= PF_RULESET_MAX) {
756 error = EINVAL;
757 break;
758 }
759 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
760 error = EBUSY;
761 break;
762 }
763
764#ifdef ALTQ
765 /* set queue IDs */
766 if (rs_num == PF_RULESET_FILTER)
767 pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
768#endif
769
770 /* Swap rules, keep the old. */
771 s = splsoftnet();
772 old_rules = ruleset->rules[rs_num].active.ptr;
773 ruleset->rules[rs_num].active.ptr =
774 ruleset->rules[rs_num].inactive.ptr;
775 ruleset->rules[rs_num].inactive.ptr = old_rules;
776 ruleset->rules[rs_num].active.ticket =
777 ruleset->rules[rs_num].inactive.ticket;
778 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
779
780 /* Purge the old rule list. */
781 while ((rule = TAILQ_FIRST(old_rules)) != NULL)
782 pf_rm_rule(old_rules, rule);
783 pf_remove_if_empty_ruleset(ruleset);
784 pf_update_anchor_rules();
785 splx(s);
786 break;
787 }
788
789 case DIOCGETRULES: {
790 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
791 struct pf_ruleset *ruleset;
792 struct pf_rule *tail;
793 int rs_num;
794
795 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
796 if (ruleset == NULL) {
797 error = EINVAL;
798 break;
799 }
800 rs_num = pf_get_ruleset_number(pr->rule.action);
801 if (rs_num >= PF_RULESET_MAX) {
802 error = EINVAL;
803 break;
804 }
805 s = splsoftnet();
806 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
807 pf_rulequeue);
808 if (tail)
809 pr->nr = tail->nr + 1;
810 else
811 pr->nr = 0;
812 pr->ticket = ruleset->rules[rs_num].active.ticket;
813 splx(s);
814 break;
815 }
816
817 case DIOCGETRULE: {
818 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
819 struct pf_ruleset *ruleset;
820 struct pf_rule *rule;
821 int rs_num, i;
822
823 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
824 if (ruleset == NULL) {
825 error = EINVAL;
826 break;
827 }
828 rs_num = pf_get_ruleset_number(pr->rule.action);
829 if (rs_num >= PF_RULESET_MAX) {
830 error = EINVAL;
831 break;
832 }
833 if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
834 error = EBUSY;
835 break;
836 }
837 s = splsoftnet();
838 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
839 while ((rule != NULL) && (rule->nr != pr->nr))
840 rule = TAILQ_NEXT(rule, entries);
841 if (rule == NULL) {
842 error = EBUSY;
843 splx(s);
844 break;
845 }
846 bcopy(rule, &pr->rule, sizeof(struct pf_rule));
847 pf_dynaddr_copyout(&pr->rule.src.addr);
848 pf_dynaddr_copyout(&pr->rule.dst.addr);
849 pf_tbladdr_copyout(&pr->rule.src.addr);
850 pf_tbladdr_copyout(&pr->rule.dst.addr);
851 for (i = 0; i < PF_SKIP_COUNT; ++i)
852 if (rule->skip[i].ptr == NULL)
853 pr->rule.skip[i].nr = -1;
854 else
855 pr->rule.skip[i].nr =
856 rule->skip[i].ptr->nr;
857 splx(s);
858 break;
859 }
860
861 case DIOCCHANGERULE: {
862 struct pfioc_rule *pcr = (struct pfioc_rule *)addr;
863 struct pf_ruleset *ruleset;
864 struct pf_rule *oldrule = NULL, *newrule = NULL;
865 u_int32_t nr = 0;
866 int rs_num;
867
868 if (!(pcr->action == PF_CHANGE_REMOVE ||
869 pcr->action == PF_CHANGE_GET_TICKET) &&
870 pcr->pool_ticket != ticket_pabuf) {
871 error = EBUSY;
872 break;
873 }
874
875 if (pcr->action < PF_CHANGE_ADD_HEAD ||
876 pcr->action > PF_CHANGE_GET_TICKET) {
877 error = EINVAL;
878 break;
879 }
880 ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset);
881 if (ruleset == NULL) {
882 error = EINVAL;
883 break;
884 }
885 rs_num = pf_get_ruleset_number(pcr->rule.action);
886 if (rs_num >= PF_RULESET_MAX) {
887 error = EINVAL;
888 break;
889 }
890
891 if (pcr->action == PF_CHANGE_GET_TICKET) {
892 pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
893 break;
894 } else {
895 if (pcr->ticket !=
896 ruleset->rules[rs_num].active.ticket) {
897 error = EINVAL;
898 break;
899 }
900 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
901 error = EINVAL;
902 break;
903 }
904 }
905
906 if (pcr->action != PF_CHANGE_REMOVE) {
907 newrule = pool_get(&pf_rule_pl, PR_NOWAIT);
908 if (newrule == NULL) {
909 error = ENOMEM;
910 break;
911 }
912 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
913 TAILQ_INIT(&newrule->rpool.list);
914 /* initialize refcounting */
915 newrule->states = 0;
916 newrule->entries.tqe_prev = NULL;
917#ifndef INET
918 if (newrule->af == AF_INET) {
919 pool_put(&pf_rule_pl, newrule);
920 error = EAFNOSUPPORT;
921 break;
922 }
923#endif /* INET */
924#ifndef INET6
925 if (newrule->af == AF_INET6) {
926 pool_put(&pf_rule_pl, newrule);
927 error = EAFNOSUPPORT;
928 break;
929 }
930#endif /* INET6 */
931 if (newrule->ifname[0]) {
932 newrule->ifp = ifunit(newrule->ifname);
933 if (newrule->ifp == NULL) {
934 pool_put(&pf_rule_pl, newrule);
935 error = EINVAL;
936 break;
937 }
938 } else
939 newrule->ifp = NULL;
940
941#ifdef ALTQ
942 /* set queue IDs */
943 if (newrule->qname[0] != 0) {
944 newrule->qid = pf_qname_to_qid(newrule->qname);
945 if (newrule->pqname[0] != 0)
946 newrule->pqid =
947 pf_qname_to_qid(newrule->pqname);
948 else
949 newrule->pqid = newrule->qid;
950 }
951#endif
952 if (newrule->tagname[0])
953 if ((newrule->tag =
954 pf_tagname2tag(newrule->tagname)) == 0)
955 error = EBUSY;
956 if (newrule->match_tagname[0])
957 if ((newrule->match_tag = pf_tagname2tag(
958 newrule->match_tagname)) == 0)
959 error = EBUSY;
960
961 if (newrule->rt && !newrule->direction)
962 error = EINVAL;
963 if (pf_dynaddr_setup(&newrule->src.addr, newrule->af))
964 error = EINVAL;
965 if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af))
966 error = EINVAL;
967 if (pf_tbladdr_setup(ruleset, &newrule->src.addr))
968 error = EINVAL;
969 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
970 error = EINVAL;
971
972 pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
973 if (((((newrule->action == PF_NAT) ||
974 (newrule->action == PF_RDR) ||
975 (newrule->action == PF_BINAT) ||
976 (newrule->rt > PF_FASTROUTE)) &&
977 !newrule->anchorname[0])) &&
978 (TAILQ_FIRST(&newrule->rpool.list) == NULL))
979 error = EINVAL;
980
981 if (error) {
982 pf_rm_rule(NULL, newrule);
983 break;
984 }
985 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
986 newrule->evaluations = newrule->packets = 0;
987 newrule->bytes = 0;
988 }
989 pf_empty_pool(&pf_pabuf);
990
991 s = splsoftnet();
992
993 if (pcr->action == PF_CHANGE_ADD_HEAD)
994 oldrule = TAILQ_FIRST(
995 ruleset->rules[rs_num].active.ptr);
996 else if (pcr->action == PF_CHANGE_ADD_TAIL)
997 oldrule = TAILQ_LAST(
998 ruleset->rules[rs_num].active.ptr, pf_rulequeue);
999 else {
1000 oldrule = TAILQ_FIRST(
1001 ruleset->rules[rs_num].active.ptr);
1002 while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
1003 oldrule = TAILQ_NEXT(oldrule, entries);
1004 if (oldrule == NULL) {
1005 pf_rm_rule(NULL, newrule);
1006 error = EINVAL;
1007 splx(s);
1008 break;
1009 }
1010 }
1011
1012 if (pcr->action == PF_CHANGE_REMOVE)
1013 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
1014 else {
1015 if (oldrule == NULL)
1016 TAILQ_INSERT_TAIL(
1017 ruleset->rules[rs_num].active.ptr,
1018 newrule, entries);
1019 else if (pcr->action == PF_CHANGE_ADD_HEAD ||
1020 pcr->action == PF_CHANGE_ADD_BEFORE)
1021 TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
1022 else
1023 TAILQ_INSERT_AFTER(
1024 ruleset->rules[rs_num].active.ptr,
1025 oldrule, newrule, entries);
1026 }
1027
1028 nr = 0;
1029 TAILQ_FOREACH(oldrule,
1030 ruleset->rules[rs_num].active.ptr, entries)
1031 oldrule->nr = nr++;
1032
1033 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1034 pf_remove_if_empty_ruleset(ruleset);
1035 pf_update_anchor_rules();
1036
1037 ruleset->rules[rs_num].active.ticket++;
1038 splx(s);
1039 break;
1040 }
1041
1042 case DIOCCLRSTATES: {
1043 struct pf_tree_node *n;
1044
1045 s = splsoftnet();
1046 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1047 n->state->timeout = PFTM_PURGE;
1048 pf_purge_expired_states();
1049 pf_status.states = 0;
1050 splx(s);
1051 break;
1052 }
1053
1054 case DIOCKILLSTATES: {
1055 struct pf_tree_node *n;
1056 struct pf_state *st;
1057 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
1058 int killed = 0;
1059
1060 s = splsoftnet();
1061 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1062 st = n->state;
1063 if ((!psk->psk_af || st->af == psk->psk_af) &&
1064 (!psk->psk_proto || psk->psk_proto == st->proto) &&
1065 PF_MATCHA(psk->psk_src.not,
1066 &psk->psk_src.addr.v.a.addr,
1067 &psk->psk_src.addr.v.a.mask, &st->lan.addr,
1068 st->af) &&
1069 PF_MATCHA(psk->psk_dst.not,
1070 &psk->psk_dst.addr.v.a.addr,
1071 &psk->psk_dst.addr.v.a.mask, &st->ext.addr,
1072 st->af) &&
1073 (psk->psk_src.port_op == 0 ||
1074 pf_match_port(psk->psk_src.port_op,
1075 psk->psk_src.port[0], psk->psk_src.port[1],
1076 st->lan.port)) &&
1077 (psk->psk_dst.port_op == 0 ||
1078 pf_match_port(psk->psk_dst.port_op,
1079 psk->psk_dst.port[0], psk->psk_dst.port[1],
1080 st->ext.port))) {
1081 st->timeout = PFTM_PURGE;
1082 killed++;
1083 }
1084 }
1085 pf_purge_expired_states();
1086 splx(s);
1087 psk->psk_af = killed;
1088 break;
1089 }
1090
1091 case DIOCADDSTATE: {
1092 struct pfioc_state *ps = (struct pfioc_state *)addr;
1093 struct pf_state *state;
1094
1095 if (ps->state.timeout >= PFTM_MAX &&
1096 ps->state.timeout != PFTM_UNTIL_PACKET) {
1097 error = EINVAL;
1098 break;
1099 }
1100 state = pool_get(&pf_state_pl, PR_NOWAIT);
1101 if (state == NULL) {
1102 error = ENOMEM;
1103 break;
1104 }
1105 s = splsoftnet();
1106 bcopy(&ps->state, state, sizeof(struct pf_state));
1107 state->rule.ptr = NULL;
1108 state->nat_rule.ptr = NULL;
1109 state->anchor.ptr = NULL;
1110 state->rt_ifp = NULL;
1111 state->creation = time.tv_sec;
1112 state->packets[0] = state->packets[1] = 0;
1113 state->bytes[0] = state->bytes[1] = 0;
1114 if (pf_insert_state(state)) {
1115 pool_put(&pf_state_pl, state);
1116 error = ENOMEM;
1117 }
1118 splx(s);
1119 break;
1120 }
1121
1122 case DIOCGETSTATE: {
1123 struct pfioc_state *ps = (struct pfioc_state *)addr;
1124 struct pf_tree_node *n;
1125 u_int32_t nr;
1126
1127 nr = 0;
1128 s = splsoftnet();
1129 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1130 if (nr >= ps->nr)
1131 break;
1132 nr++;
1133 }
1134 if (n == NULL) {
1135 error = EBUSY;
1136 splx(s);
1137 break;
1138 }
1139 bcopy(n->state, &ps->state, sizeof(struct pf_state));
1140 ps->state.rule.nr = n->state->rule.ptr->nr;
1141 ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1142 -1 : n->state->nat_rule.ptr->nr;
1143 ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ?
1144 -1 : n->state->anchor.ptr->nr;
1145 splx(s);
1146 ps->state.expire = pf_state_expires(n->state);
1147 if (ps->state.expire > time.tv_sec)
1148 ps->state.expire -= time.tv_sec;
1149 else
1150 ps->state.expire = 0;
1151 break;
1152 }
1153
1154 case DIOCGETSTATES: {
1155 struct pfioc_states *ps = (struct pfioc_states *)addr;
1156 struct pf_tree_node *n;
1157 struct pf_state *p, pstore;
1158 u_int32_t nr = 0;
1159 int space = ps->ps_len;
1160
1161 if (space == 0) {
1162 s = splsoftnet();
1163 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1164 nr++;
1165 splx(s);
1166 ps->ps_len = sizeof(struct pf_state) * nr;
1167 return (0);
1168 }
1169
1170 s = splsoftnet();
1171 p = ps->ps_states;
1172 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1173 int secs = time.tv_sec;
1174
1175 if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len)
1176 break;
1177
1178 bcopy(n->state, &pstore, sizeof(pstore));
1179 pstore.rule.nr = n->state->rule.ptr->nr;
1180 pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1181 -1 : n->state->nat_rule.ptr->nr;
1182 pstore.anchor.nr = (n->state->anchor.ptr == NULL) ?
1183 -1 : n->state->anchor.ptr->nr;
1184 pstore.creation = secs - pstore.creation;
1185 pstore.expire = pf_state_expires(n->state);
1186 if (pstore.expire > secs)
1187 pstore.expire -= secs;
1188 else
1189 pstore.expire = 0;
1190 error = copyout(&pstore, p, sizeof(*p));
1191 if (error) {
1192 splx(s);
1193 goto fail;
1194 }
1195 p++;
1196 nr++;
1197 }
1198 ps->ps_len = sizeof(struct pf_state) * nr;
1199 splx(s);
1200 break;
1201 }
1202
1203 case DIOCGETSTATUS: {
1204 struct pf_status *s = (struct pf_status *)addr;
1205 bcopy(&pf_status, s, sizeof(struct pf_status));
1206 break;
1207 }
1208
1209 case DIOCSETSTATUSIF: {
1210 struct pfioc_if *pi = (struct pfioc_if *)addr;
1211 struct ifnet *ifp;
1212
1213 if (pi->ifname[0] == 0) {
1214 status_ifp = NULL;
1215 bzero(pf_status.ifname, IFNAMSIZ);
1216 break;
1217 }
1218 if ((ifp = ifunit(pi->ifname)) == NULL) {
1219 error = EINVAL;
1220 break;
1221 } else if (ifp == status_ifp)
1222 break;
1223 status_ifp = ifp;
1224 /* fallthrough into DIOCCLRSTATUS */
1225 }
1226
1227 case DIOCCLRSTATUS: {
1228 u_int32_t running = pf_status.running;
1229 u_int32_t states = pf_status.states;
1230 u_int32_t since = pf_status.since;
1231 u_int32_t debug = pf_status.debug;
1232
1233 bzero(&pf_status, sizeof(struct pf_status));
1234 pf_status.running = running;
1235 pf_status.states = states;
1236 pf_status.since = since;
1237 pf_status.debug = debug;
1238 if (status_ifp != NULL)
1239 strlcpy(pf_status.ifname,
1240 status_ifp->if_xname, IFNAMSIZ);
1241 break;
1242 }
1243
1244 case DIOCNATLOOK: {
1245 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
1246 struct pf_state *st;
1247 struct pf_tree_node key;
1248 int direction = pnl->direction;
1249
1250 key.af = pnl->af;
1251 key.proto = pnl->proto;
1252
1253 /*
1254 * userland gives us source and dest of connection, reverse
1255 * the lookup so we ask for what happens with the return
1256 * traffic, enabling us to find it in the state tree.
1257 */
1258 PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af);
1259 key.port[1] = pnl->sport;
1260 PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af);
1261 key.port[0] = pnl->dport;
1262
1263 if (!pnl->proto ||
1264 PF_AZERO(&pnl->saddr, pnl->af) ||
1265 PF_AZERO(&pnl->daddr, pnl->af) ||
1266 !pnl->dport || !pnl->sport)
1267 error = EINVAL;
1268 else {
1269 s = splsoftnet();
1270 if (direction == PF_IN)
1271 st = pf_find_state(&tree_ext_gwy, &key);
1272 else
1273 st = pf_find_state(&tree_lan_ext, &key);
1274 if (st != NULL) {
1275 if (direction == PF_IN) {
1276 PF_ACPY(&pnl->rsaddr, &st->lan.addr,
1277 st->af);
1278 pnl->rsport = st->lan.port;
1279 PF_ACPY(&pnl->rdaddr, &pnl->daddr,
1280 pnl->af);
1281 pnl->rdport = pnl->dport;
1282 } else {
1283 PF_ACPY(&pnl->rdaddr, &st->gwy.addr,
1284 st->af);
1285 pnl->rdport = st->gwy.port;
1286 PF_ACPY(&pnl->rsaddr, &pnl->saddr,
1287 pnl->af);
1288 pnl->rsport = pnl->sport;
1289 }
1290 } else
1291 error = ENOENT;
1292 splx(s);
1293 }
1294 break;
1295 }
1296
1297 case DIOCSETTIMEOUT: {
1298 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
1299 int old;
1300
1301 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
1302 pt->seconds < 0) {
1303 error = EINVAL;
1304 goto fail;
1305 }
1306 old = pf_default_rule.timeout[pt->timeout];
1307 pf_default_rule.timeout[pt->timeout] = pt->seconds;
1308 pt->seconds = old;
1309 break;
1310 }
1311
1312 case DIOCGETTIMEOUT: {
1313 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
1314
1315 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
1316 error = EINVAL;
1317 goto fail;
1318 }
1319 pt->seconds = pf_default_rule.timeout[pt->timeout];
1320 break;
1321 }
1322
1323 case DIOCGETLIMIT: {
1324 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
1325
1326 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1327 error = EINVAL;
1328 goto fail;
1329 }
1330 pl->limit = pf_pool_limits[pl->index].limit;
1331 break;
1332 }
1333
1334 case DIOCSETLIMIT: {
1335 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
1336 int old_limit;
1337
1338 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1339 error = EINVAL;
1340 goto fail;
1341 }
1342 if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
1343 pl->limit, NULL, 0) != 0) {
1344 error = EBUSY;
1345 goto fail;
1346 }
1347 old_limit = pf_pool_limits[pl->index].limit;
1348 pf_pool_limits[pl->index].limit = pl->limit;
1349 pl->limit = old_limit;
1350 break;
1351 }
1352
1353 case DIOCSETDEBUG: {
1354 u_int32_t *level = (u_int32_t *)addr;
1355
1356 pf_status.debug = *level;
1357 break;
1358 }
1359
1360 case DIOCCLRRULECTRS: {
1361 struct pf_ruleset *ruleset = &pf_main_ruleset;
1362 struct pf_rule *rule;
1363
1364 s = splsoftnet();
1365 TAILQ_FOREACH(rule,
1366 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
1367 rule->evaluations = rule->packets =
1368 rule->bytes = 0;
1369 splx(s);
1370 break;
1371 }
1372
1373#ifdef ALTQ
1374 case DIOCSTARTALTQ: {
1375 struct pf_altq *altq;
1376 struct ifnet *ifp;
1377 struct tb_profile tb;
1378
1379 /* enable all altq interfaces on active list */
1380 s = splsoftnet();
1381 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1382 if (altq->qname[0] == 0) {
1383 if ((ifp = ifunit(altq->ifname)) == NULL) {
1384 error = EINVAL;
1385 break;
1386 }
1387 if (ifp->if_snd.altq_type != ALTQT_NONE)
1388 error = altq_enable(&ifp->if_snd);
1389 if (error != 0)
1390 break;
1391 /* set tokenbucket regulator */
1392 tb.rate = altq->ifbandwidth;
1393 tb.depth = altq->tbrsize;
1394 error = tbr_set(&ifp->if_snd, &tb);
1395 if (error != 0)
1396 break;
1397 }
1398 }
1399 if (error == 0)
1400 pfaltq_running = 1;
1401 splx(s);
1402 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
1403 break;
1404 }
1405
1406 case DIOCSTOPALTQ: {
1407 struct pf_altq *altq;
1408 struct ifnet *ifp;
1409 struct tb_profile tb;
1410 int err;
1411
1412 /* disable all altq interfaces on active list */
1413 s = splsoftnet();
1414 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1415 if (altq->qname[0] == 0) {
1416 if ((ifp = ifunit(altq->ifname)) == NULL) {
1417 error = EINVAL;
1418 break;
1419 }
1420 if (ifp->if_snd.altq_type != ALTQT_NONE) {
1421 err = altq_disable(&ifp->if_snd);
1422 if (err != 0 && error == 0)
1423 error = err;
1424 }
1425 /* clear tokenbucket regulator */
1426 tb.rate = 0;
1427 err = tbr_set(&ifp->if_snd, &tb);
1428 if (err != 0 && error == 0)
1429 error = err;
1430 }
1431 }
1432 if (error == 0)
1433 pfaltq_running = 0;
1434 splx(s);
1435 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
1436 break;
1437 }
1438
1439 case DIOCBEGINALTQS: {
1440 u_int32_t *ticket = (u_int32_t *)addr;
1441 struct pf_altq *altq;
1442
1443 /* Purge the old altq list */
1444 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1445 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1446 if (altq->qname[0] == 0) {
1447 /* detach and destroy the discipline */
1448 error = altq_remove(altq);
1449 }
1450 pool_put(&pf_altq_pl, altq);
1451 }
1452 *ticket = ++ticket_altqs_inactive;
1453 break;
1454 }
1455
1456 case DIOCADDALTQ: {
1457 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1458 struct pf_altq *altq, *a;
1459
1460 if (pa->ticket != ticket_altqs_inactive) {
1461 error = EBUSY;
1462 break;
1463 }
1464 altq = pool_get(&pf_altq_pl, PR_NOWAIT);
1465 if (altq == NULL) {
1466 error = ENOMEM;
1467 break;
1468 }
1469 bcopy(&pa->altq, altq, sizeof(struct pf_altq));
1470
1471 /*
1472 * if this is for a queue, find the discipline and
1473 * copy the necessary fields
1474 */
1475 if (altq->qname[0] != 0) {
1476 TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
1477 if (strncmp(a->ifname, altq->ifname,
1478 IFNAMSIZ) == 0 && a->qname[0] == 0) {
1479 altq->altq_disc = a->altq_disc;
1480 break;
1481 }
1482 }
1483 }
1484
1485 error = altq_add(altq);
1486 if (error) {
1487 pool_put(&pf_altq_pl, altq);
1488 break;
1489 }
1490
1491 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
1492 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1493 break;
1494 }
1495
1496 case DIOCCOMMITALTQS: {
1497 u_int32_t *ticket = (u_int32_t *)addr;
1498 struct pf_altqqueue *old_altqs;
1499 struct pf_altq *altq;
1500 struct pf_anchor *anchor;
1501 struct pf_ruleset *ruleset;
1502 int err;
1503
1504 if (*ticket != ticket_altqs_inactive) {
1505 error = EBUSY;
1506 break;
1507 }
1508
1509 /* Swap altqs, keep the old. */
1510 s = splsoftnet();
1511 old_altqs = pf_altqs_active;
1512 pf_altqs_active = pf_altqs_inactive;
1513 pf_altqs_inactive = old_altqs;
1514 ticket_altqs_active = ticket_altqs_inactive;
1515
1516 /* Attach new disciplines */
1517 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1518 if (altq->qname[0] == 0) {
1519 /* attach the discipline */
1520 error = altq_pfattach(altq);
1521 if (error) {
1522 splx(s);
1523 goto fail;
1524 }
1525 }
1526 }
1527
1528 /* Purge the old altq list */
1529 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1530 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1531 if (altq->qname[0] == 0) {
1532 /* detach and destroy the discipline */
1533 err = altq_pfdetach(altq);
1534 if (err != 0 && error == 0)
1535 error = err;
1536 err = altq_remove(altq);
1537 if (err != 0 && error == 0)
1538 error = err;
1539 }
1540 pool_put(&pf_altq_pl, altq);
1541 }
1542 splx(s);
1543
1544 /* update queue IDs */
1545 pf_rule_set_qid(
1546 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
1547 TAILQ_FOREACH(anchor, &pf_anchors, entries) {
1548 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
1549 pf_rule_set_qid(
1550 ruleset->rules[PF_RULESET_FILTER].active.ptr
1551 );
1552 }
1553 }
1554 break;
1555 }
1556
1557 case DIOCGETALTQS: {
1558 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1559 struct pf_altq *altq;
1560
1561 pa->nr = 0;
1562 s = splsoftnet();
1563 TAILQ_FOREACH(altq, pf_altqs_active, entries)
1564 pa->nr++;
1565 pa->ticket = ticket_altqs_active;
1566 splx(s);
1567 break;
1568 }
1569
1570 case DIOCGETALTQ: {
1571 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1572 struct pf_altq *altq;
1573 u_int32_t nr;
1574
1575 if (pa->ticket != ticket_altqs_active) {
1576 error = EBUSY;
1577 break;
1578 }
1579 nr = 0;
1580 s = splsoftnet();
1581 altq = TAILQ_FIRST(pf_altqs_active);
1582 while ((altq != NULL) && (nr < pa->nr)) {
1583 altq = TAILQ_NEXT(altq, entries);
1584 nr++;
1585 }
1586 if (altq == NULL) {
1587 error = EBUSY;
1588 splx(s);
1589 break;
1590 }
1591 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1592 splx(s);
1593 break;
1594 }
1595
1596 case DIOCCHANGEALTQ:
1597 /* CHANGEALTQ not supported yet! */
1598 error = ENODEV;
1599 break;
1600
1601 case DIOCGETQSTATS: {
1602 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr;
1603 struct pf_altq *altq;
1604 u_int32_t nr;
1605 int nbytes;
1606
1607 if (pq->ticket != ticket_altqs_active) {
1608 error = EBUSY;
1609 break;
1610 }
1611 nbytes = pq->nbytes;
1612 nr = 0;
1613 s = splsoftnet();
1614 altq = TAILQ_FIRST(pf_altqs_active);
1615 while ((altq != NULL) && (nr < pq->nr)) {
1616 altq = TAILQ_NEXT(altq, entries);
1617 nr++;
1618 }
1619 if (altq == NULL) {
1620 error = EBUSY;
1621 splx(s);
1622 break;
1623 }
1624 error = altq_getqstats(altq, pq->buf, &nbytes);
1625 splx(s);
1626 if (error == 0) {
1627 pq->scheduler = altq->scheduler;
1628 pq->nbytes = nbytes;
1629 }
1630 break;
1631 }
1632#endif /* ALTQ */
1633
1634 case DIOCBEGINADDRS: {
1635 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
1636
1637 pf_empty_pool(&pf_pabuf);
1638 pp->ticket = ++ticket_pabuf;
1639 break;
1640 }
1641
1642 case DIOCADDADDR: {
1643 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
1644
1645#ifndef INET
1646 if (pp->af == AF_INET) {
1647 error = EAFNOSUPPORT;
1648 break;
1649 }
1650#endif /* INET */
1651#ifndef INET6
1652 if (pp->af == AF_INET6) {
1653 error = EAFNOSUPPORT;
1654 break;
1655 }
1656#endif /* INET6 */
1657 if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
1658 pp->addr.addr.type != PF_ADDR_DYNIFTL &&
1659 pp->addr.addr.type != PF_ADDR_TABLE) {
1660 error = EINVAL;
1661 break;
1662 }
1663 pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
1664 if (pa == NULL) {
1665 error = ENOMEM;
1666 break;
1667 }
1668 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
1669 if (pa->ifname[0]) {
1670 pa->ifp = ifunit(pa->ifname);
1671 if (pa->ifp == NULL) {
1672 pool_put(&pf_pooladdr_pl, pa);
1673 error = EINVAL;
1674 break;
1675 }
1676 }
1677 if (pf_dynaddr_setup(&pa->addr, pp->af)) {
1678 pf_dynaddr_remove(&pa->addr);
1679 pool_put(&pf_pooladdr_pl, pa);
1680 error = EINVAL;
1681 break;
1682 }
1683 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
1684 break;
1685 }
1686
1687 case DIOCGETADDRS: {
1688 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
1689
1690 pp->nr = 0;
1691 s = splsoftnet();
1692 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
1693 pp->r_action, pp->r_num, 0, 1, 0);
1694 if (pool == NULL) {
1695 error = EBUSY;
1696 splx(s);
1697 break;
1698 }
1699 TAILQ_FOREACH(pa, &pool->list, entries)
1700 pp->nr++;
1701 splx(s);
1702 break;
1703 }
1704
1705 case DIOCGETADDR: {
1706 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
1707 u_int32_t nr = 0;
1708
1709 s = splsoftnet();
1710 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
1711 pp->r_action, pp->r_num, 0, 1, 1);
1712 if (pool == NULL) {
1713 error = EBUSY;
1714 splx(s);
1715 break;
1716 }
1717 pa = TAILQ_FIRST(&pool->list);
1718 while ((pa != NULL) && (nr < pp->nr)) {
1719 pa = TAILQ_NEXT(pa, entries);
1720 nr++;
1721 }
1722 if (pa == NULL) {
1723 error = EBUSY;
1724 splx(s);
1725 break;
1726 }
1727 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
1728 pf_dynaddr_copyout(&pp->addr.addr);
1729 pf_tbladdr_copyout(&pp->addr.addr);
1730 splx(s);
1731 break;
1732 }
1733
1734 case DIOCCHANGEADDR: {
1735 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr;
1736 struct pf_pooladdr *oldpa = NULL, *newpa = NULL;
1737 struct pf_ruleset *ruleset;
1738
1739 if (pca->action < PF_CHANGE_ADD_HEAD ||
1740 pca->action > PF_CHANGE_REMOVE) {
1741 error = EINVAL;
1742 break;
1743 }
1744 if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
1745 pca->addr.addr.type != PF_ADDR_DYNIFTL &&
1746 pca->addr.addr.type != PF_ADDR_TABLE) {
1747 error = EINVAL;
1748 break;
1749 }
1750
1751 ruleset = pf_find_ruleset(pca->anchor, pca->ruleset);
1752 if (ruleset == NULL) {
1753 error = EBUSY;
1754 break;
1755 }
1756 pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket,
1757 pca->r_action, pca->r_num, pca->r_last, 1, 1);
1758 if (pool == NULL) {
1759 error = EBUSY;
1760 break;
1761 }
1762 if (pca->action != PF_CHANGE_REMOVE) {
1763 newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
1764 if (newpa == NULL) {
1765 error = ENOMEM;
1766 break;
1767 }
1768 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
1769#ifndef INET
1770 if (pca->af == AF_INET) {
1771 pool_put(&pf_pooladdr_pl, newpa);
1772 error = EAFNOSUPPORT;
1773 break;
1774 }
1775#endif /* INET */
1776#ifndef INET6
1777 if (pca->af == AF_INET6) {
1778 pool_put(&pf_pooladdr_pl, newpa);
1779 error = EAFNOSUPPORT;
1780 break;
1781 }
1782#endif /* INET6 */
1783 if (newpa->ifname[0]) {
1784 newpa->ifp = ifunit(newpa->ifname);
1785 if (newpa->ifp == NULL) {
1786 pool_put(&pf_pooladdr_pl, newpa);
1787 error = EINVAL;
1788 break;
1789 }
1790 } else
1791 newpa->ifp = NULL;
1792 if (pf_dynaddr_setup(&newpa->addr, pca->af) ||
1793 pf_tbladdr_setup(ruleset, &newpa->addr)) {
1794 pf_dynaddr_remove(&newpa->addr);
1795 pool_put(&pf_pooladdr_pl, newpa);
1796 error = EINVAL;
1797 break;
1798 }
1799 }
1800
1801 s = splsoftnet();
1802
1803 if (pca->action == PF_CHANGE_ADD_HEAD)
1804 oldpa = TAILQ_FIRST(&pool->list);
1805 else if (pca->action == PF_CHANGE_ADD_TAIL)
1806 oldpa = TAILQ_LAST(&pool->list, pf_palist);
1807 else {
1808 int i = 0;
1809
1810 oldpa = TAILQ_FIRST(&pool->list);
1811 while ((oldpa != NULL) && (i < pca->nr)) {
1812 oldpa = TAILQ_NEXT(oldpa, entries);
1813 i++;
1814 }
1815 if (oldpa == NULL) {
1816 error = EINVAL;
1817 splx(s);
1818 break;
1819 }
1820 }
1821
1822 if (pca->action == PF_CHANGE_REMOVE) {
1823 TAILQ_REMOVE(&pool->list, oldpa, entries);
1824 pf_dynaddr_remove(&oldpa->addr);
1825 pf_tbladdr_remove(&oldpa->addr);
1826 pool_put(&pf_pooladdr_pl, oldpa);
1827 } else {
1828 if (oldpa == NULL)
1829 TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
1830 else if (pca->action == PF_CHANGE_ADD_HEAD ||
1831 pca->action == PF_CHANGE_ADD_BEFORE)
1832 TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
1833 else
1834 TAILQ_INSERT_AFTER(&pool->list, oldpa,
1835 newpa, entries);
1836 }
1837
1838 pool->cur = TAILQ_FIRST(&pool->list);
1839 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
1840 pca->af);
1841 splx(s);
1842 break;
1843 }
1844
1845 case DIOCGETANCHORS: {
1846 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr;
1847 struct pf_anchor *anchor;
1848
1849 pa->nr = 0;
1850 TAILQ_FOREACH(anchor, &pf_anchors, entries)
1851 pa->nr++;
1852 break;
1853 }
1854
1855 case DIOCGETANCHOR: {
1856 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr;
1857 struct pf_anchor *anchor;
1858 u_int32_t nr = 0;
1859
1860 anchor = TAILQ_FIRST(&pf_anchors);
1861 while (anchor != NULL && nr < pa->nr) {
1862 anchor = TAILQ_NEXT(anchor, entries);
1863 nr++;
1864 }
1865 if (anchor == NULL)
1866 error = EBUSY;
1867 else
1868 bcopy(anchor->name, pa->name, sizeof(pa->name));
1869 break;
1870 }
1871
1872 case DIOCGETRULESETS: {
1873 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
1874 struct pf_anchor *anchor;
1875 struct pf_ruleset *ruleset;
1876
1877 pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0;
1878 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
1879 error = EINVAL;
1880 break;
1881 }
1882 pr->nr = 0;
1883 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries)
1884 pr->nr++;
1885 break;
1886 }
1887
1888 case DIOCGETRULESET: {
1889 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
1890 struct pf_anchor *anchor;
1891 struct pf_ruleset *ruleset;
1892 u_int32_t nr = 0;
1893
1894 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
1895 error = EINVAL;
1896 break;
1897 }
1898 ruleset = TAILQ_FIRST(&anchor->rulesets);
1899 while (ruleset != NULL && nr < pr->nr) {
1900 ruleset = TAILQ_NEXT(ruleset, entries);
1901 nr++;
1902 }
1903 if (ruleset == NULL)
1904 error = EBUSY;
1905 else
1906 bcopy(ruleset->name, pr->name, sizeof(pr->name));
1907 break;
1908 }
1909
1910 case DIOCRCLRTABLES: {
1911 struct pfioc_table *io = (struct pfioc_table *)addr;
1912
1913 if (io->pfrio_esize != 0) {
1914 error = ENODEV;
1915 break;
1916 }
1917 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
1918 io->pfrio_flags);
1919 break;
1920 }
1921
1922 case DIOCRADDTABLES: {
1923 struct pfioc_table *io = (struct pfioc_table *)addr;
1924
1925 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1926 error = ENODEV;
1927 break;
1928 }
1929 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
1930 &io->pfrio_nadd, io->pfrio_flags);
1931 break;
1932 }
1933
1934 case DIOCRDELTABLES: {
1935 struct pfioc_table *io = (struct pfioc_table *)addr;
1936
1937 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1938 error = ENODEV;
1939 break;
1940 }
1941 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
1942 &io->pfrio_ndel, io->pfrio_flags);
1943 break;
1944 }
1945
1946 case DIOCRGETTABLES: {
1947 struct pfioc_table *io = (struct pfioc_table *)addr;
1948
1949 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1950 error = ENODEV;
1951 break;
1952 }
1953 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
1954 &io->pfrio_size, io->pfrio_flags);
1955 break;
1956 }
1957
1958 case DIOCRGETTSTATS: {
1959 struct pfioc_table *io = (struct pfioc_table *)addr;
1960
1961 if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
1962 error = ENODEV;
1963 break;
1964 }
1965 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
1966 &io->pfrio_size, io->pfrio_flags);
1967 break;
1968 }
1969
1970 case DIOCRCLRTSTATS: {
1971 struct pfioc_table *io = (struct pfioc_table *)addr;
1972
1973 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1974 error = ENODEV;
1975 break;
1976 }
1977 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
1978 &io->pfrio_nzero, io->pfrio_flags);
1979 break;
1980 }
1981
1982 case DIOCRSETTFLAGS: {
1983 struct pfioc_table *io = (struct pfioc_table *)addr;
1984
1985 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1986 error = ENODEV;
1987 break;
1988 }
1989 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
1990 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
1991 &io->pfrio_ndel, io->pfrio_flags);
1992 break;
1993 }
1994
1995 case DIOCRCLRADDRS: {
1996 struct pfioc_table *io = (struct pfioc_table *)addr;
1997
1998 if (io->pfrio_esize != 0) {
1999 error = ENODEV;
2000 break;
2001 }
2002 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
2003 io->pfrio_flags);
2004 break;
2005 }
2006
2007 case DIOCRADDADDRS: {
2008 struct pfioc_table *io = (struct pfioc_table *)addr;
2009
2010 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2011 error = ENODEV;
2012 break;
2013 }
2014 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
2015 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags);
2016 break;
2017 }
2018
2019 case DIOCRDELADDRS: {
2020 struct pfioc_table *io = (struct pfioc_table *)addr;
2021
2022 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2023 error = ENODEV;
2024 break;
2025 }
2026 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
2027 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags);
2028 break;
2029 }
2030
2031 case DIOCRSETADDRS: {
2032 struct pfioc_table *io = (struct pfioc_table *)addr;
2033
2034 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2035 error = ENODEV;
2036 break;
2037 }
2038 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
2039 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
2040 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags);
2041 break;
2042 }
2043
2044 case DIOCRGETADDRS: {
2045 struct pfioc_table *io = (struct pfioc_table *)addr;
2046
2047 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2048 error = ENODEV;
2049 break;
2050 }
2051 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
2052 &io->pfrio_size, io->pfrio_flags);
2053 break;
2054 }
2055
2056 case DIOCRGETASTATS: {
2057 struct pfioc_table *io = (struct pfioc_table *)addr;
2058
2059 if (io->pfrio_esize != sizeof(struct pfr_astats)) {
2060 error = ENODEV;
2061 break;
2062 }
2063 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
2064 &io->pfrio_size, io->pfrio_flags);
2065 break;
2066 }
2067
2068 case DIOCRCLRASTATS: {
2069 struct pfioc_table *io = (struct pfioc_table *)addr;
2070
2071 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2072 error = ENODEV;
2073 break;
2074 }
2075 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
2076 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags);
2077 break;
2078 }
2079
2080 case DIOCRTSTADDRS: {
2081 struct pfioc_table *io = (struct pfioc_table *)addr;
2082
2083 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2084 error = ENODEV;
2085 break;
2086 }
2087 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
2088 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags);
2089 break;
2090 }
2091
2092 case DIOCRINABEGIN: {
2093 struct pfioc_table *io = (struct pfioc_table *)addr;
2094
2095 if (io->pfrio_esize != 0) {
2096 error = ENODEV;
2097 break;
2098 }
2099 error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket,
2100 &io->pfrio_ndel, io->pfrio_flags);
2101 break;
2102 }
2103
2104 case DIOCRINACOMMIT: {
2105 struct pfioc_table *io = (struct pfioc_table *)addr;
2106
2107 if (io->pfrio_esize != 0) {
2108 error = ENODEV;
2109 break;
2110 }
2111 error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket,
2112 &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags);
2113 break;
2114 }
2115
2116 case DIOCRINADEFINE: {
2117 struct pfioc_table *io = (struct pfioc_table *)addr;
2118
2119 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2120 error = ENODEV;
2121 break;
2122 }
2123 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
2124 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
2125 io->pfrio_ticket, io->pfrio_flags);
2126 break;
2127 }
2128
2129 case DIOCOSFPFLUSH:
2130 s = splsoftnet();
2131 pf_osfp_flush();
2132 splx(s);
2133 break;
2134
2135 case DIOCOSFPADD: {
2136 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2137 s = splsoftnet();
2138 error = pf_osfp_add(io);
2139 splx(s);
2140 break;
2141 }
2142
2143 case DIOCOSFPGET: {
2144 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2145 s = splsoftnet();
2146 error = pf_osfp_get(io);
2147 splx(s);
2148 break;
2149 }
2150
2151 default:
2152 error = ENODEV;
2153 break;
2154 }
2155fail:
2156
2157 return (error);
2158}