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