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