1 /* $NetBSD: npf_ctl.c,v 1.32 2013/11/12 00:46:34 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * NPF device control. 34 * 35 * Implementation of (re)loading, construction of tables and rules. 36 * NPF proplib(9) dictionary consumer. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.32 2013/11/12 00:46:34 rmind Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/conf.h> 44 #include <sys/kmem.h> 45 #include <net/bpf.h> 46 47 #include <prop/proplib.h> 48 49 #include "npf_impl.h" 50 51 #if defined(DEBUG) || defined(DIAGNOSTIC) 52 #define NPF_ERR_DEBUG(e) \ 53 prop_dictionary_set_cstring_nocopy((e), "source-file", __FILE__); \ 54 prop_dictionary_set_uint32((e), "source-line", __LINE__); 55 #else 56 #define NPF_ERR_DEBUG(e) 57 #endif 58 59 /* 60 * npfctl_switch: enable or disable packet inspection. 61 */ 62 int 63 npfctl_switch(void *data) 64 { 65 const bool onoff = *(int *)data ? true : false; 66 int error; 67 68 if (onoff) { 69 /* Enable: add pfil hooks. */ 70 error = npf_pfil_register(false); 71 } else { 72 /* Disable: remove pfil hooks. */ 73 npf_pfil_unregister(false); 74 error = 0; 75 } 76 return error; 77 } 78 79 static int __noinline 80 npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables, 81 prop_dictionary_t errdict) 82 { 83 prop_object_iterator_t it; 84 prop_dictionary_t tbldict; 85 int error = 0; 86 87 /* Tables - array. */ 88 if (prop_object_type(tables) != PROP_TYPE_ARRAY) { 89 NPF_ERR_DEBUG(errdict); 90 return EINVAL; 91 } 92 93 it = prop_array_iterator(tables); 94 while ((tbldict = prop_object_iterator_next(it)) != NULL) { 95 prop_dictionary_t ent; 96 prop_object_iterator_t eit; 97 prop_array_t entries; 98 const char *name; 99 npf_table_t *t; 100 u_int tid; 101 int type; 102 103 /* Table - dictionary. */ 104 if (prop_object_type(tbldict) != PROP_TYPE_DICTIONARY) { 105 NPF_ERR_DEBUG(errdict); 106 error = EINVAL; 107 break; 108 } 109 110 /* Table name, ID and type. Validate them. */ 111 if (!prop_dictionary_get_cstring_nocopy(tbldict, "name", &name)) { 112 NPF_ERR_DEBUG(errdict); 113 error = EINVAL; 114 break; 115 } 116 prop_dictionary_get_uint32(tbldict, "id", &tid); 117 prop_dictionary_get_int32(tbldict, "type", &type); 118 error = npf_table_check(tblset, name, tid, type); 119 if (error) { 120 NPF_ERR_DEBUG(errdict); 121 break; 122 } 123 124 /* Create and insert the table. */ 125 t = npf_table_create(name, tid, type, 1024); /* XXX */ 126 if (t == NULL) { 127 NPF_ERR_DEBUG(errdict); 128 error = ENOMEM; 129 break; 130 } 131 error = npf_tableset_insert(tblset, t); 132 KASSERT(error == 0); 133 134 /* Entries. */ 135 entries = prop_dictionary_get(tbldict, "entries"); 136 if (prop_object_type(entries) != PROP_TYPE_ARRAY) { 137 NPF_ERR_DEBUG(errdict); 138 error = EINVAL; 139 break; 140 } 141 eit = prop_array_iterator(entries); 142 while ((ent = prop_object_iterator_next(eit)) != NULL) { 143 const npf_addr_t *addr; 144 npf_netmask_t mask; 145 int alen; 146 147 /* Get address and mask. Add a table entry. */ 148 prop_object_t obj = prop_dictionary_get(ent, "addr"); 149 addr = (const npf_addr_t *)prop_data_data_nocopy(obj); 150 prop_dictionary_get_uint8(ent, "mask", &mask); 151 alen = prop_data_size(obj); 152 153 error = npf_table_insert(t, alen, addr, mask); 154 if (error) 155 break; 156 } 157 prop_object_iterator_release(eit); 158 if (error) 159 break; 160 } 161 prop_object_iterator_release(it); 162 /* 163 * Note: in a case of error, caller will free the tableset. 164 */ 165 return error; 166 } 167 168 static npf_rproc_t * 169 npf_mk_singlerproc(prop_dictionary_t rpdict) 170 { 171 prop_object_iterator_t it; 172 prop_dictionary_t extdict; 173 prop_array_t extlist; 174 npf_rproc_t *rp; 175 176 extlist = prop_dictionary_get(rpdict, "extcalls"); 177 if (prop_object_type(extlist) != PROP_TYPE_ARRAY) { 178 return NULL; 179 } 180 181 rp = npf_rproc_create(rpdict); 182 if (rp == NULL) { 183 return NULL; 184 } 185 186 it = prop_array_iterator(extlist); 187 while ((extdict = prop_object_iterator_next(it)) != NULL) { 188 const char *name; 189 190 if (!prop_dictionary_get_cstring_nocopy(extdict, 191 "name", &name) || npf_ext_construct(name, rp, extdict)) { 192 npf_rproc_release(rp); 193 rp = NULL; 194 break; 195 } 196 } 197 prop_object_iterator_release(it); 198 return rp; 199 } 200 201 static int __noinline 202 npf_mk_rprocs(npf_rprocset_t *rpset, prop_array_t rprocs, 203 prop_dictionary_t errdict) 204 { 205 prop_object_iterator_t it; 206 prop_dictionary_t rpdict; 207 int error = 0; 208 209 it = prop_array_iterator(rprocs); 210 while ((rpdict = prop_object_iterator_next(it)) != NULL) { 211 npf_rproc_t *rp; 212 213 if ((rp = npf_mk_singlerproc(rpdict)) == NULL) { 214 NPF_ERR_DEBUG(errdict); 215 error = EINVAL; 216 break; 217 } 218 npf_rprocset_insert(rpset, rp); 219 } 220 prop_object_iterator_release(it); 221 return error; 222 } 223 224 static npf_alg_t * 225 npf_mk_singlealg(prop_dictionary_t aldict) 226 { 227 const char *name; 228 229 if (!prop_dictionary_get_cstring_nocopy(aldict, "name", &name)) 230 return NULL; 231 return npf_alg_construct(name); 232 } 233 234 static int __noinline 235 npf_mk_algs(prop_array_t alglist, prop_dictionary_t errdict) 236 { 237 prop_object_iterator_t it; 238 prop_dictionary_t nadict; 239 int error = 0; 240 241 it = prop_array_iterator(alglist); 242 while ((nadict = prop_object_iterator_next(it)) != NULL) { 243 if (npf_mk_singlealg(nadict) == NULL) { 244 NPF_ERR_DEBUG(errdict); 245 error = EINVAL; 246 break; 247 } 248 } 249 prop_object_iterator_release(it); 250 return error; 251 } 252 253 static int __noinline 254 npf_mk_code(prop_object_t obj, int type, void **code, size_t *csize, 255 prop_dictionary_t errdict) 256 { 257 const void *cptr; 258 size_t clen; 259 void *bc; 260 261 if (type != NPF_CODE_BPF) { 262 return ENOTSUP; 263 } 264 cptr = prop_data_data_nocopy(obj); 265 if (cptr == NULL || (clen = prop_data_size(obj)) == 0) { 266 NPF_ERR_DEBUG(errdict); 267 return EINVAL; 268 } 269 if (!npf_bpf_validate(cptr, clen)) { 270 NPF_ERR_DEBUG(errdict); 271 return EINVAL; 272 } 273 bc = kmem_alloc(clen, KM_SLEEP); 274 memcpy(bc, cptr, clen); 275 276 *code = bc; 277 *csize = clen; 278 return 0; 279 } 280 281 static int __noinline 282 npf_mk_singlerule(prop_dictionary_t rldict, npf_rprocset_t *rpset, 283 npf_rule_t **rlret, prop_dictionary_t errdict) 284 { 285 npf_rule_t *rl; 286 const char *rname; 287 prop_object_t obj; 288 int p, error = 0; 289 290 /* Rule - dictionary. */ 291 if (prop_object_type(rldict) != PROP_TYPE_DICTIONARY) { 292 NPF_ERR_DEBUG(errdict); 293 return EINVAL; 294 } 295 if ((rl = npf_rule_alloc(rldict)) == NULL) { 296 NPF_ERR_DEBUG(errdict); 297 return EINVAL; 298 } 299 300 /* Assign rule procedure, if any. */ 301 if (prop_dictionary_get_cstring_nocopy(rldict, "rproc", &rname)) { 302 npf_rproc_t *rp; 303 304 if (rpset == NULL) { 305 error = EINVAL; 306 goto err; 307 } 308 if ((rp = npf_rprocset_lookup(rpset, rname)) == NULL) { 309 NPF_ERR_DEBUG(errdict); 310 error = EINVAL; 311 goto err; 312 } 313 npf_rule_setrproc(rl, rp); 314 } 315 316 /* Filter code (binary data). */ 317 if ((obj = prop_dictionary_get(rldict, "code")) != NULL) { 318 int type; 319 size_t len; 320 void *code; 321 322 prop_dictionary_get_int32(rldict, "code-type", &type); 323 error = npf_mk_code(obj, type, &code, &len, errdict); 324 if (error) { 325 goto err; 326 } 327 npf_rule_setcode(rl, type, code, len); 328 } 329 330 *rlret = rl; 331 return 0; 332 err: 333 npf_rule_free(rl); 334 prop_dictionary_get_int32(rldict, "priority", &p); /* XXX */ 335 prop_dictionary_set_int32(errdict, "id", p); 336 return error; 337 } 338 339 static int __noinline 340 npf_mk_rules(npf_ruleset_t *rlset, prop_array_t rules, npf_rprocset_t *rpset, 341 prop_dictionary_t errdict) 342 { 343 prop_object_iterator_t it; 344 prop_dictionary_t rldict; 345 int error; 346 347 if (prop_object_type(rules) != PROP_TYPE_ARRAY) { 348 NPF_ERR_DEBUG(errdict); 349 return EINVAL; 350 } 351 352 error = 0; 353 it = prop_array_iterator(rules); 354 while ((rldict = prop_object_iterator_next(it)) != NULL) { 355 npf_rule_t *rl = NULL; 356 357 /* Generate a single rule. */ 358 error = npf_mk_singlerule(rldict, rpset, &rl, errdict); 359 if (error) { 360 break; 361 } 362 npf_ruleset_insert(rlset, rl); 363 } 364 prop_object_iterator_release(it); 365 /* 366 * Note: in a case of error, caller will free the ruleset. 367 */ 368 return error; 369 } 370 371 static int __noinline 372 npf_mk_natlist(npf_ruleset_t *nset, prop_array_t natlist, 373 prop_dictionary_t errdict) 374 { 375 prop_object_iterator_t it; 376 prop_dictionary_t natdict; 377 int error; 378 379 /* NAT policies - array. */ 380 if (prop_object_type(natlist) != PROP_TYPE_ARRAY) { 381 NPF_ERR_DEBUG(errdict); 382 return EINVAL; 383 } 384 385 error = 0; 386 it = prop_array_iterator(natlist); 387 while ((natdict = prop_object_iterator_next(it)) != NULL) { 388 npf_rule_t *rl = NULL; 389 npf_natpolicy_t *np; 390 391 /* NAT policy - dictionary. */ 392 if (prop_object_type(natdict) != PROP_TYPE_DICTIONARY) { 393 NPF_ERR_DEBUG(errdict); 394 error = EINVAL; 395 break; 396 } 397 398 /* 399 * NAT policies are standard rules, plus additional 400 * information for translation. Make a rule. 401 */ 402 error = npf_mk_singlerule(natdict, NULL, &rl, errdict); 403 if (error) { 404 break; 405 } 406 npf_ruleset_insert(nset, rl); 407 408 /* If rule is named, it is a group with NAT policies. */ 409 if (prop_dictionary_get(natdict, "name") && 410 prop_dictionary_get(natdict, "subrules")) { 411 continue; 412 } 413 414 /* Allocate a new NAT policy and assign to the rule. */ 415 np = npf_nat_newpolicy(natdict, nset); 416 if (np == NULL) { 417 NPF_ERR_DEBUG(errdict); 418 error = ENOMEM; 419 break; 420 } 421 npf_rule_setnat(rl, np); 422 } 423 prop_object_iterator_release(it); 424 /* 425 * Note: in a case of error, caller will free entire NAT ruleset 426 * with assigned NAT policies. 427 */ 428 return error; 429 } 430 431 /* 432 * npfctl_reload: store passed data i.e. update settings, create passed 433 * tables, rules and atomically activate all them. 434 */ 435 int 436 npfctl_reload(u_long cmd, void *data) 437 { 438 struct plistref *pref = data; 439 prop_dictionary_t npf_dict, errdict; 440 prop_array_t alglist, natlist, tables, rprocs, rules; 441 npf_tableset_t *tblset = NULL; 442 npf_rprocset_t *rpset = NULL; 443 npf_ruleset_t *rlset = NULL; 444 npf_ruleset_t *nset = NULL; 445 uint32_t ver = 0; 446 size_t nitems; 447 bool flush; 448 int error; 449 450 /* Retrieve the dictionary. */ 451 #ifndef _NPF_TESTING 452 error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_dict); 453 if (error) 454 return error; 455 #else 456 npf_dict = (prop_dictionary_t)pref; 457 #endif 458 459 /* Dictionary for error reporting and version check. */ 460 errdict = prop_dictionary_create(); 461 prop_dictionary_get_uint32(npf_dict, "version", &ver); 462 if (ver != NPF_VERSION) { 463 error = EPROGMISMATCH; 464 goto fail; 465 } 466 467 /* ALGs. */ 468 alglist = prop_dictionary_get(npf_dict, "algs"); 469 error = npf_mk_algs(alglist, errdict); 470 if (error) { 471 goto fail; 472 } 473 474 /* NAT policies. */ 475 natlist = prop_dictionary_get(npf_dict, "translation"); 476 if ((nitems = prop_array_count(natlist)) > NPF_MAX_RULES) { 477 goto fail; 478 } 479 480 nset = npf_ruleset_create(nitems); 481 error = npf_mk_natlist(nset, natlist, errdict); 482 if (error) { 483 goto fail; 484 } 485 486 /* Tables. */ 487 tables = prop_dictionary_get(npf_dict, "tables"); 488 if ((nitems = prop_array_count(tables)) > NPF_MAX_TABLES) { 489 goto fail; 490 } 491 tblset = npf_tableset_create(nitems); 492 error = npf_mk_tables(tblset, tables, errdict); 493 if (error) { 494 goto fail; 495 } 496 497 /* Rule procedures. */ 498 rprocs = prop_dictionary_get(npf_dict, "rprocs"); 499 if ((nitems = prop_array_count(rprocs)) > NPF_MAX_RPROCS) { 500 goto fail; 501 } 502 rpset = npf_rprocset_create(); 503 error = npf_mk_rprocs(rpset, rprocs, errdict); 504 if (error) { 505 goto fail; 506 } 507 508 /* Rules. */ 509 rules = prop_dictionary_get(npf_dict, "rules"); 510 if ((nitems = prop_array_count(rules)) > NPF_MAX_RULES) { 511 goto fail; 512 } 513 514 rlset = npf_ruleset_create(nitems); 515 error = npf_mk_rules(rlset, rules, rpset, errdict); 516 if (error) { 517 goto fail; 518 } 519 520 flush = false; 521 prop_dictionary_get_bool(npf_dict, "flush", &flush); 522 523 /* 524 * Finally - perform the reload. 525 */ 526 npf_config_reload(npf_dict, rlset, tblset, nset, rpset, flush); 527 528 /* Turn on/off session tracking accordingly. */ 529 npf_session_tracking(!flush); 530 531 /* Done. Since data is consumed now, we shall not destroy it. */ 532 tblset = NULL; 533 rpset = NULL; 534 rlset = NULL; 535 nset = NULL; 536 fail: 537 /* 538 * Note: destroy rulesets first, to drop references to the tableset. 539 */ 540 KASSERT(error == 0 || (nset || rpset || rlset || tblset)); 541 if (nset) { 542 npf_ruleset_destroy(nset); 543 } 544 if (rlset) { 545 npf_ruleset_destroy(rlset); 546 } 547 if (rpset) { 548 npf_rprocset_destroy(rpset); 549 } 550 if (tblset) { 551 npf_tableset_destroy(tblset); 552 } 553 if (error) { 554 prop_object_release(npf_dict); 555 } 556 557 /* Error report. */ 558 #ifndef _NPF_TESTING 559 prop_dictionary_set_int32(errdict, "errno", error); 560 prop_dictionary_copyout_ioctl(pref, cmd, errdict); 561 prop_object_release(errdict); 562 error = 0; 563 #endif 564 return error; 565 } 566 567 /* 568 * npfctl_rule: add or remove dynamic rules in the specified ruleset. 569 */ 570 int 571 npfctl_rule(u_long cmd, void *data) 572 { 573 struct plistref *pref = data; 574 prop_dictionary_t npf_rule, retdict = NULL; 575 npf_ruleset_t *rlset; 576 npf_rule_t *rl = NULL; 577 const char *ruleset_name; 578 uint32_t rcmd = 0; 579 int error; 580 581 error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_rule); 582 if (error) { 583 return error; 584 } 585 prop_dictionary_get_uint32(npf_rule, "command", &rcmd); 586 if (!prop_dictionary_get_cstring_nocopy(npf_rule, 587 "ruleset-name", &ruleset_name)) { 588 error = EINVAL; 589 goto out; 590 } 591 592 if (rcmd == NPF_CMD_RULE_ADD) { 593 retdict = prop_dictionary_create(); 594 if (npf_mk_singlerule(npf_rule, NULL, &rl, retdict) != 0) { 595 error = EINVAL; 596 goto out; 597 } 598 } 599 600 npf_config_enter(); 601 rlset = npf_config_ruleset(); 602 603 switch (rcmd) { 604 case NPF_CMD_RULE_ADD: { 605 if ((error = npf_ruleset_add(rlset, ruleset_name, rl)) == 0) { 606 /* Success. */ 607 uint64_t id = npf_rule_getid(rl); 608 prop_dictionary_set_uint64(retdict, "id", id); 609 rl = NULL; 610 } 611 break; 612 } 613 case NPF_CMD_RULE_REMOVE: { 614 uint64_t id; 615 616 if (!prop_dictionary_get_uint64(npf_rule, "id", &id)) { 617 error = EINVAL; 618 break; 619 } 620 error = npf_ruleset_remove(rlset, ruleset_name, id); 621 break; 622 } 623 case NPF_CMD_RULE_REMKEY: { 624 prop_object_t obj = prop_dictionary_get(npf_rule, "key"); 625 const void *key = prop_data_data_nocopy(obj); 626 size_t len = prop_data_size(obj); 627 628 if (len == 0 || len > NPF_RULE_MAXKEYLEN) { 629 error = EINVAL; 630 break; 631 } 632 error = npf_ruleset_remkey(rlset, ruleset_name, key, len); 633 break; 634 } 635 case NPF_CMD_RULE_LIST: { 636 retdict = npf_ruleset_list(rlset, ruleset_name); 637 break; 638 } 639 case NPF_CMD_RULE_FLUSH: { 640 error = npf_ruleset_flush(rlset, ruleset_name); 641 break; 642 } 643 default: 644 error = EINVAL; 645 break; 646 } 647 648 /* Destroy any removed rules. */ 649 if (!error && rcmd != NPF_CMD_RULE_ADD && rcmd != NPF_CMD_RULE_LIST) { 650 npf_config_sync(); 651 npf_ruleset_gc(rlset); 652 } 653 npf_config_exit(); 654 655 if (rl) { 656 npf_rule_free(rl); 657 } 658 out: 659 if (retdict) { 660 prop_object_release(npf_rule); 661 prop_dictionary_copyout_ioctl(pref, cmd, retdict); 662 prop_object_release(retdict); 663 } 664 return error; 665 } 666 667 /* 668 * npfctl_getconf: return the config dictionary as it was submitted. 669 * Additionally, indicate whether the ruleset is currently active. 670 */ 671 int 672 npfctl_getconf(u_long cmd, void *data) 673 { 674 struct plistref *pref = data; 675 prop_dictionary_t npf_dict; 676 int error; 677 678 npf_config_enter(); 679 npf_dict = npf_config_dict(); 680 prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p()); 681 error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict); 682 npf_config_exit(); 683 684 return error; 685 } 686 687 /* 688 * npfctl_sessions_save: construct a list of sessions and export for saving. 689 */ 690 int 691 npfctl_sessions_save(u_long cmd, void *data) 692 { 693 struct plistref *pref = data; 694 prop_dictionary_t sesdict; 695 prop_array_t selist, nplist; 696 int error; 697 698 /* Create a dictionary and two lists. */ 699 sesdict = prop_dictionary_create(); 700 selist = prop_array_create(); 701 nplist = prop_array_create(); 702 703 /* Save the sessions. */ 704 error = npf_session_save(selist, nplist); 705 if (error) { 706 goto fail; 707 } 708 709 /* Set the session list, NAT policy list and export the dictionary. */ 710 prop_dictionary_set(sesdict, "session-list", selist); 711 prop_dictionary_set(sesdict, "nat-policy-list", nplist); 712 error = prop_dictionary_copyout_ioctl(pref, cmd, sesdict); 713 fail: 714 prop_object_release(sesdict); 715 return error; 716 } 717 718 /* 719 * npfctl_sessions_load: import a list of sessions, reconstruct them and load. 720 */ 721 int 722 npfctl_sessions_load(u_long cmd, void *data) 723 { 724 const struct plistref *pref = data; 725 npf_sehash_t *sehasht = NULL; 726 prop_dictionary_t sesdict, sedict; 727 prop_object_iterator_t it; 728 prop_array_t selist; 729 int error; 730 731 /* Retrieve the dictionary containing session and NAT policy lists. */ 732 error = prop_dictionary_copyin_ioctl(pref, cmd, &sesdict); 733 if (error) 734 return error; 735 736 /* 737 * Note: session objects contain the references to the NAT policy 738 * entries. Therefore, no need to directly access it. 739 */ 740 selist = prop_dictionary_get(sesdict, "session-list"); 741 if (prop_object_type(selist) != PROP_TYPE_ARRAY) { 742 prop_object_release(selist); 743 return EINVAL; 744 } 745 746 /* Create a session hash table. */ 747 sehasht = sess_htable_create(); 748 749 /* 750 * Iterate through and construct each session. Note: acquire the 751 * config lock as we access NAT policies during the restore. 752 */ 753 error = 0; 754 it = prop_array_iterator(selist); 755 756 npf_config_enter(); 757 while ((sedict = prop_object_iterator_next(it)) != NULL) { 758 /* Session - dictionary. */ 759 if (prop_object_type(sedict) != PROP_TYPE_DICTIONARY) { 760 error = EINVAL; 761 break; 762 } 763 /* Construct and insert real session structure. */ 764 error = npf_session_restore(sehasht, sedict); 765 if (error) { 766 break; 767 } 768 } 769 npf_config_exit(); 770 771 prop_object_iterator_release(it); 772 prop_object_release(selist); 773 774 if (!error) { 775 /* Finally, load the new table. */ 776 npf_session_load(sehasht); 777 } else { 778 /* Destroy session table. */ 779 sess_htable_destroy(sehasht); 780 } 781 return error; 782 } 783 784 /* 785 * npfctl_table: add, remove or query entries in the specified table. 786 * 787 * For maximum performance, interface is avoiding proplib(3)'s overhead. 788 */ 789 int 790 npfctl_table(void *data) 791 { 792 const npf_ioctl_table_t *nct = data; 793 char tname[NPF_TABLE_MAXNAMELEN]; 794 npf_tableset_t *ts; 795 npf_table_t *t; 796 int s, error; 797 798 error = copyinstr(nct->nct_name, tname, sizeof(tname), NULL); 799 if (error) { 800 return error; 801 } 802 803 s = npf_config_read_enter(); /* XXX */ 804 ts = npf_config_tableset(); 805 if ((t = npf_tableset_getbyname(ts, tname)) == NULL) { 806 npf_config_read_exit(s); 807 return EINVAL; 808 } 809 810 switch (nct->nct_cmd) { 811 case NPF_CMD_TABLE_LOOKUP: 812 error = npf_table_lookup(t, nct->nct_data.ent.alen, 813 &nct->nct_data.ent.addr); 814 break; 815 case NPF_CMD_TABLE_ADD: 816 error = npf_table_insert(t, nct->nct_data.ent.alen, 817 &nct->nct_data.ent.addr, nct->nct_data.ent.mask); 818 break; 819 case NPF_CMD_TABLE_REMOVE: 820 error = npf_table_remove(t, nct->nct_data.ent.alen, 821 &nct->nct_data.ent.addr, nct->nct_data.ent.mask); 822 break; 823 case NPF_CMD_TABLE_LIST: 824 error = npf_table_list(t, nct->nct_data.buf.buf, 825 nct->nct_data.buf.len); 826 break; 827 case NPF_CMD_TABLE_FLUSH: 828 error = npf_table_flush(t); 829 break; 830 default: 831 error = EINVAL; 832 break; 833 } 834 npf_config_read_exit(s); 835 836 return error; 837 } 838