xref: /netbsd-src/sys/net/npf/npf_ctl.c (revision a4ddc2c8fb9af816efe3b1c375a5530aef0e89e9)
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