pf_ioctl.c revision 126259
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} 2159