xref: /freebsd/sys/netpfil/ipfw/ip_fw_sockopt.c (revision 2c8d04d0228871c24017509cf039e7c5d97d97be)
1 /*-
2  * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
3  * Copyright (c) 2014 Yandex LLC
4  * Copyright (c) 2014 Alexander V. Chernikov
5  *
6  * Supported by: Valeria Paoli
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 /*
34  * Control socket and rule management routines for ipfw.
35  * Control is currently implemented via IP_FW3 setsockopt() code.
36  */
37 
38 #include "opt_ipfw.h"
39 #include "opt_inet.h"
40 #ifndef INET
41 #error IPFIREWALL requires INET.
42 #endif /* INET */
43 #include "opt_inet6.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/malloc.h>
48 #include <sys/mbuf.h>	/* struct m_tag used by nested headers */
49 #include <sys/kernel.h>
50 #include <sys/lock.h>
51 #include <sys/priv.h>
52 #include <sys/proc.h>
53 #include <sys/rwlock.h>
54 #include <sys/rmlock.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/sysctl.h>
58 #include <sys/syslog.h>
59 #include <sys/fnv_hash.h>
60 #include <net/if.h>
61 #include <net/route.h>
62 #include <net/vnet.h>
63 #include <vm/vm.h>
64 #include <vm/vm_extern.h>
65 
66 #include <netinet/in.h>
67 #include <netinet/ip_var.h> /* hooks */
68 #include <netinet/ip_fw.h>
69 
70 #include <netpfil/ipfw/ip_fw_private.h>
71 #include <netpfil/ipfw/ip_fw_table.h>
72 
73 #ifdef MAC
74 #include <security/mac/mac_framework.h>
75 #endif
76 
77 static int ipfw_ctl(struct sockopt *sopt);
78 static int check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len,
79     struct rule_check_info *ci);
80 static int check_ipfw_rule1(struct ip_fw_rule *rule, int size,
81     struct rule_check_info *ci);
82 static int check_ipfw_rule0(struct ip_fw_rule0 *rule, int size,
83     struct rule_check_info *ci);
84 static int rewrite_rule_uidx(struct ip_fw_chain *chain,
85     struct rule_check_info *ci);
86 
87 #define	NAMEDOBJ_HASH_SIZE	32
88 
89 struct namedobj_instance {
90 	struct namedobjects_head	*names;
91 	struct namedobjects_head	*values;
92 	uint32_t nn_size;		/* names hash size */
93 	uint32_t nv_size;		/* number hash size */
94 	u_long *idx_mask;		/* used items bitmask */
95 	uint32_t max_blocks;		/* number of "long" blocks in bitmask */
96 	uint32_t count;			/* number of items */
97 	uint16_t free_off[IPFW_MAX_SETS];	/* first possible free offset */
98 	objhash_hash_f	*hash_f;
99 	objhash_cmp_f	*cmp_f;
100 };
101 #define	BLOCK_ITEMS	(8 * sizeof(u_long))	/* Number of items for ffsl() */
102 
103 static uint32_t objhash_hash_name(struct namedobj_instance *ni,
104     const void *key, uint32_t kopt);
105 static uint32_t objhash_hash_idx(struct namedobj_instance *ni, uint32_t val);
106 static int objhash_cmp_name(struct named_object *no, const void *name,
107     uint32_t set);
108 
109 MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
110 
111 static int dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
112     struct sockopt_data *sd);
113 static int add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
114     struct sockopt_data *sd);
115 static int del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
116     struct sockopt_data *sd);
117 static int clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
118     struct sockopt_data *sd);
119 static int move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
120     struct sockopt_data *sd);
121 static int manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
122     struct sockopt_data *sd);
123 static int dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
124     struct sockopt_data *sd);
125 static int dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
126     struct sockopt_data *sd);
127 
128 /* ctl3 handler data */
129 struct mtx ctl3_lock;
130 #define	CTL3_LOCK_INIT()	mtx_init(&ctl3_lock, "ctl3_lock", NULL, MTX_DEF)
131 #define	CTL3_LOCK_DESTROY()	mtx_destroy(&ctl3_lock)
132 #define	CTL3_LOCK()		mtx_lock(&ctl3_lock)
133 #define	CTL3_UNLOCK()		mtx_unlock(&ctl3_lock)
134 
135 static struct ipfw_sopt_handler *ctl3_handlers;
136 static size_t ctl3_hsize;
137 static uint64_t ctl3_refct, ctl3_gencnt;
138 #define	CTL3_SMALLBUF	4096			/* small page-size write buffer */
139 #define	CTL3_LARGEBUF	16 * 1024 * 1024	/* handle large rulesets */
140 
141 static int ipfw_flush_sopt_data(struct sockopt_data *sd);
142 
143 static struct ipfw_sopt_handler	scodes[] = {
144 	{ IP_FW_XGET,		0,	HDIR_GET,	dump_config },
145 	{ IP_FW_XADD,		0,	HDIR_BOTH,	add_rules },
146 	{ IP_FW_XDEL,		0,	HDIR_BOTH,	del_rules },
147 	{ IP_FW_XZERO,		0,	HDIR_SET,	clear_rules },
148 	{ IP_FW_XRESETLOG,	0,	HDIR_SET,	clear_rules },
149 	{ IP_FW_XMOVE,		0,	HDIR_SET,	move_rules },
150 	{ IP_FW_SET_SWAP,	0,	HDIR_SET,	manage_sets },
151 	{ IP_FW_SET_MOVE,	0,	HDIR_SET,	manage_sets },
152 	{ IP_FW_SET_ENABLE,	0,	HDIR_SET,	manage_sets },
153 	{ IP_FW_DUMP_SOPTCODES,	0,	HDIR_GET,	dump_soptcodes },
154 	{ IP_FW_DUMP_SRVOBJECTS,0,	HDIR_GET,	dump_srvobjects },
155 };
156 
157 static int
158 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule);
159 static struct opcode_obj_rewrite *find_op_rw(ipfw_insn *cmd,
160     uint16_t *puidx, uint8_t *ptype);
161 static int mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
162     uint32_t *bmask);
163 static int ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
164     struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti);
165 static int ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd,
166     struct tid_info *ti, struct obj_idx *pidx, int *unresolved);
167 static void unref_rule_objects(struct ip_fw_chain *chain, struct ip_fw *rule);
168 static void unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd,
169     struct obj_idx *oib, struct obj_idx *end);
170 static int export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
171     struct sockopt_data *sd);
172 
173 /*
174  * Opcode object rewriter variables
175  */
176 struct opcode_obj_rewrite *ctl3_rewriters;
177 static size_t ctl3_rsize;
178 
179 /*
180  * static variables followed by global ones
181  */
182 
183 static VNET_DEFINE(uma_zone_t, ipfw_cntr_zone);
184 #define	V_ipfw_cntr_zone		VNET(ipfw_cntr_zone)
185 
186 void
187 ipfw_init_counters()
188 {
189 
190 	V_ipfw_cntr_zone = uma_zcreate("IPFW counters",
191 	    IPFW_RULE_CNTR_SIZE, NULL, NULL, NULL, NULL,
192 	    UMA_ALIGN_PTR, UMA_ZONE_PCPU);
193 }
194 
195 void
196 ipfw_destroy_counters()
197 {
198 
199 	uma_zdestroy(V_ipfw_cntr_zone);
200 }
201 
202 struct ip_fw *
203 ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize)
204 {
205 	struct ip_fw *rule;
206 
207 	rule = malloc(rulesize, M_IPFW, M_WAITOK | M_ZERO);
208 	rule->cntr = uma_zalloc(V_ipfw_cntr_zone, M_WAITOK | M_ZERO);
209 
210 	return (rule);
211 }
212 
213 static void
214 free_rule(struct ip_fw *rule)
215 {
216 
217 	uma_zfree(V_ipfw_cntr_zone, rule->cntr);
218 	free(rule, M_IPFW);
219 }
220 
221 
222 /*
223  * Find the smallest rule >= key, id.
224  * We could use bsearch but it is so simple that we code it directly
225  */
226 int
227 ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id)
228 {
229 	int i, lo, hi;
230 	struct ip_fw *r;
231 
232   	for (lo = 0, hi = chain->n_rules - 1; lo < hi;) {
233 		i = (lo + hi) / 2;
234 		r = chain->map[i];
235 		if (r->rulenum < key)
236 			lo = i + 1;	/* continue from the next one */
237 		else if (r->rulenum > key)
238 			hi = i;		/* this might be good */
239 		else if (r->id < id)
240 			lo = i + 1;	/* continue from the next one */
241 		else /* r->id >= id */
242 			hi = i;		/* this might be good */
243 	}
244 	return hi;
245 }
246 
247 /*
248  * Builds skipto cache on rule set @map.
249  */
250 static void
251 update_skipto_cache(struct ip_fw_chain *chain, struct ip_fw **map)
252 {
253 	int *smap, rulenum;
254 	int i, mi;
255 
256 	IPFW_UH_WLOCK_ASSERT(chain);
257 
258 	mi = 0;
259 	rulenum = map[mi]->rulenum;
260 	smap = chain->idxmap_back;
261 
262 	if (smap == NULL)
263 		return;
264 
265 	for (i = 0; i < 65536; i++) {
266 		smap[i] = mi;
267 		/* Use the same rule index until i < rulenum */
268 		if (i != rulenum || i == 65535)
269 			continue;
270 		/* Find next rule with num > i */
271 		rulenum = map[++mi]->rulenum;
272 		while (rulenum == i)
273 			rulenum = map[++mi]->rulenum;
274 	}
275 }
276 
277 /*
278  * Swaps prepared (backup) index with current one.
279  */
280 static void
281 swap_skipto_cache(struct ip_fw_chain *chain)
282 {
283 	int *map;
284 
285 	IPFW_UH_WLOCK_ASSERT(chain);
286 	IPFW_WLOCK_ASSERT(chain);
287 
288 	map = chain->idxmap;
289 	chain->idxmap = chain->idxmap_back;
290 	chain->idxmap_back = map;
291 }
292 
293 /*
294  * Allocate and initialize skipto cache.
295  */
296 void
297 ipfw_init_skipto_cache(struct ip_fw_chain *chain)
298 {
299 	int *idxmap, *idxmap_back;
300 
301 	idxmap = malloc(65536 * sizeof(uint32_t *), M_IPFW,
302 	    M_WAITOK | M_ZERO);
303 	idxmap_back = malloc(65536 * sizeof(uint32_t *), M_IPFW,
304 	    M_WAITOK | M_ZERO);
305 
306 	/*
307 	 * Note we may be called at any time after initialization,
308 	 * for example, on first skipto rule, so we need to
309 	 * provide valid chain->idxmap on return
310 	 */
311 
312 	IPFW_UH_WLOCK(chain);
313 	if (chain->idxmap != NULL) {
314 		IPFW_UH_WUNLOCK(chain);
315 		free(idxmap, M_IPFW);
316 		free(idxmap_back, M_IPFW);
317 		return;
318 	}
319 
320 	/* Set backup pointer first to permit building cache */
321 	chain->idxmap_back = idxmap_back;
322 	update_skipto_cache(chain, chain->map);
323 	IPFW_WLOCK(chain);
324 	/* It is now safe to set chain->idxmap ptr */
325 	chain->idxmap = idxmap;
326 	swap_skipto_cache(chain);
327 	IPFW_WUNLOCK(chain);
328 	IPFW_UH_WUNLOCK(chain);
329 }
330 
331 /*
332  * Destroys skipto cache.
333  */
334 void
335 ipfw_destroy_skipto_cache(struct ip_fw_chain *chain)
336 {
337 
338 	if (chain->idxmap != NULL)
339 		free(chain->idxmap, M_IPFW);
340 	if (chain->idxmap != NULL)
341 		free(chain->idxmap_back, M_IPFW);
342 }
343 
344 
345 /*
346  * allocate a new map, returns the chain locked. extra is the number
347  * of entries to add or delete.
348  */
349 static struct ip_fw **
350 get_map(struct ip_fw_chain *chain, int extra, int locked)
351 {
352 
353 	for (;;) {
354 		struct ip_fw **map;
355 		int i, mflags;
356 
357 		mflags = M_ZERO | ((locked != 0) ? M_NOWAIT : M_WAITOK);
358 
359 		i = chain->n_rules + extra;
360 		map = malloc(i * sizeof(struct ip_fw *), M_IPFW, mflags);
361 		if (map == NULL) {
362 			printf("%s: cannot allocate map\n", __FUNCTION__);
363 			return NULL;
364 		}
365 		if (!locked)
366 			IPFW_UH_WLOCK(chain);
367 		if (i >= chain->n_rules + extra) /* good */
368 			return map;
369 		/* otherwise we lost the race, free and retry */
370 		if (!locked)
371 			IPFW_UH_WUNLOCK(chain);
372 		free(map, M_IPFW);
373 	}
374 }
375 
376 /*
377  * swap the maps. It is supposed to be called with IPFW_UH_WLOCK
378  */
379 static struct ip_fw **
380 swap_map(struct ip_fw_chain *chain, struct ip_fw **new_map, int new_len)
381 {
382 	struct ip_fw **old_map;
383 
384 	IPFW_WLOCK(chain);
385 	chain->id++;
386 	chain->n_rules = new_len;
387 	old_map = chain->map;
388 	chain->map = new_map;
389 	swap_skipto_cache(chain);
390 	IPFW_WUNLOCK(chain);
391 	return old_map;
392 }
393 
394 
395 static void
396 export_cntr1_base(struct ip_fw *krule, struct ip_fw_bcounter *cntr)
397 {
398 
399 	cntr->size = sizeof(*cntr);
400 
401 	if (krule->cntr != NULL) {
402 		cntr->pcnt = counter_u64_fetch(krule->cntr);
403 		cntr->bcnt = counter_u64_fetch(krule->cntr + 1);
404 		cntr->timestamp = krule->timestamp;
405 	}
406 	if (cntr->timestamp > 0)
407 		cntr->timestamp += boottime.tv_sec;
408 }
409 
410 static void
411 export_cntr0_base(struct ip_fw *krule, struct ip_fw_bcounter0 *cntr)
412 {
413 
414 	if (krule->cntr != NULL) {
415 		cntr->pcnt = counter_u64_fetch(krule->cntr);
416 		cntr->bcnt = counter_u64_fetch(krule->cntr + 1);
417 		cntr->timestamp = krule->timestamp;
418 	}
419 	if (cntr->timestamp > 0)
420 		cntr->timestamp += boottime.tv_sec;
421 }
422 
423 /*
424  * Copies rule @urule from v1 userland format (current).
425  * to kernel @krule.
426  * Assume @krule is zeroed.
427  */
428 static void
429 import_rule1(struct rule_check_info *ci)
430 {
431 	struct ip_fw_rule *urule;
432 	struct ip_fw *krule;
433 
434 	urule = (struct ip_fw_rule *)ci->urule;
435 	krule = (struct ip_fw *)ci->krule;
436 
437 	/* copy header */
438 	krule->act_ofs = urule->act_ofs;
439 	krule->cmd_len = urule->cmd_len;
440 	krule->rulenum = urule->rulenum;
441 	krule->set = urule->set;
442 	krule->flags = urule->flags;
443 
444 	/* Save rulenum offset */
445 	ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum);
446 
447 	/* Copy opcodes */
448 	memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t));
449 }
450 
451 /*
452  * Export rule into v1 format (Current).
453  * Layout:
454  * [ ipfw_obj_tlv(IPFW_TLV_RULE_ENT)
455  *     [ ip_fw_rule ] OR
456  *     [ ip_fw_bcounter ip_fw_rule] (depends on rcntrs).
457  * ]
458  * Assume @data is zeroed.
459  */
460 static void
461 export_rule1(struct ip_fw *krule, caddr_t data, int len, int rcntrs)
462 {
463 	struct ip_fw_bcounter *cntr;
464 	struct ip_fw_rule *urule;
465 	ipfw_obj_tlv *tlv;
466 
467 	/* Fill in TLV header */
468 	tlv = (ipfw_obj_tlv *)data;
469 	tlv->type = IPFW_TLV_RULE_ENT;
470 	tlv->length = len;
471 
472 	if (rcntrs != 0) {
473 		/* Copy counters */
474 		cntr = (struct ip_fw_bcounter *)(tlv + 1);
475 		urule = (struct ip_fw_rule *)(cntr + 1);
476 		export_cntr1_base(krule, cntr);
477 	} else
478 		urule = (struct ip_fw_rule *)(tlv + 1);
479 
480 	/* copy header */
481 	urule->act_ofs = krule->act_ofs;
482 	urule->cmd_len = krule->cmd_len;
483 	urule->rulenum = krule->rulenum;
484 	urule->set = krule->set;
485 	urule->flags = krule->flags;
486 	urule->id = krule->id;
487 
488 	/* Copy opcodes */
489 	memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t));
490 }
491 
492 
493 /*
494  * Copies rule @urule from FreeBSD8 userland format (v0)
495  * to kernel @krule.
496  * Assume @krule is zeroed.
497  */
498 static void
499 import_rule0(struct rule_check_info *ci)
500 {
501 	struct ip_fw_rule0 *urule;
502 	struct ip_fw *krule;
503 	int cmdlen, l;
504 	ipfw_insn *cmd;
505 	ipfw_insn_limit *lcmd;
506 	ipfw_insn_if *cmdif;
507 
508 	urule = (struct ip_fw_rule0 *)ci->urule;
509 	krule = (struct ip_fw *)ci->krule;
510 
511 	/* copy header */
512 	krule->act_ofs = urule->act_ofs;
513 	krule->cmd_len = urule->cmd_len;
514 	krule->rulenum = urule->rulenum;
515 	krule->set = urule->set;
516 	if ((urule->_pad & 1) != 0)
517 		krule->flags |= IPFW_RULE_NOOPT;
518 
519 	/* Save rulenum offset */
520 	ci->urule_numoff = offsetof(struct ip_fw_rule0, rulenum);
521 
522 	/* Copy opcodes */
523 	memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t));
524 
525 	/*
526 	 * Alter opcodes:
527 	 * 1) convert tablearg value from 65335 to 0
528 	 * 2) Add high bit to O_SETFIB/O_SETDSCP values (to make room for targ).
529 	 * 3) convert table number in iface opcodes to u16
530 	 */
531 	l = krule->cmd_len;
532 	cmd = krule->cmd;
533 	cmdlen = 0;
534 
535 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
536 		cmdlen = F_LEN(cmd);
537 
538 		switch (cmd->opcode) {
539 		/* Opcodes supporting tablearg */
540 		case O_TAG:
541 		case O_TAGGED:
542 		case O_PIPE:
543 		case O_QUEUE:
544 		case O_DIVERT:
545 		case O_TEE:
546 		case O_SKIPTO:
547 		case O_CALLRETURN:
548 		case O_NETGRAPH:
549 		case O_NGTEE:
550 		case O_NAT:
551 			if (cmd->arg1 == 65535)
552 				cmd->arg1 = IP_FW_TARG;
553 			break;
554 		case O_SETFIB:
555 		case O_SETDSCP:
556 			if (cmd->arg1 == 65535)
557 				cmd->arg1 = IP_FW_TARG;
558 			else
559 				cmd->arg1 |= 0x8000;
560 			break;
561 		case O_LIMIT:
562 			lcmd = (ipfw_insn_limit *)cmd;
563 			if (lcmd->conn_limit == 65535)
564 				lcmd->conn_limit = IP_FW_TARG;
565 			break;
566 		/* Interface tables */
567 		case O_XMIT:
568 		case O_RECV:
569 		case O_VIA:
570 			/* Interface table, possibly */
571 			cmdif = (ipfw_insn_if *)cmd;
572 			if (cmdif->name[0] != '\1')
573 				break;
574 
575 			cmdif->p.kidx = (uint16_t)cmdif->p.glob;
576 			break;
577 		}
578 	}
579 }
580 
581 /*
582  * Copies rule @krule from kernel to FreeBSD8 userland format (v0)
583  */
584 static void
585 export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len)
586 {
587 	int cmdlen, l;
588 	ipfw_insn *cmd;
589 	ipfw_insn_limit *lcmd;
590 	ipfw_insn_if *cmdif;
591 
592 	/* copy header */
593 	memset(urule, 0, len);
594 	urule->act_ofs = krule->act_ofs;
595 	urule->cmd_len = krule->cmd_len;
596 	urule->rulenum = krule->rulenum;
597 	urule->set = krule->set;
598 	if ((krule->flags & IPFW_RULE_NOOPT) != 0)
599 		urule->_pad |= 1;
600 
601 	/* Copy opcodes */
602 	memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t));
603 
604 	/* Export counters */
605 	export_cntr0_base(krule, (struct ip_fw_bcounter0 *)&urule->pcnt);
606 
607 	/*
608 	 * Alter opcodes:
609 	 * 1) convert tablearg value from 0 to 65335
610 	 * 2) Remove highest bit from O_SETFIB/O_SETDSCP values.
611 	 * 3) convert table number in iface opcodes to int
612 	 */
613 	l = urule->cmd_len;
614 	cmd = urule->cmd;
615 	cmdlen = 0;
616 
617 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
618 		cmdlen = F_LEN(cmd);
619 
620 		switch (cmd->opcode) {
621 		/* Opcodes supporting tablearg */
622 		case O_TAG:
623 		case O_TAGGED:
624 		case O_PIPE:
625 		case O_QUEUE:
626 		case O_DIVERT:
627 		case O_TEE:
628 		case O_SKIPTO:
629 		case O_CALLRETURN:
630 		case O_NETGRAPH:
631 		case O_NGTEE:
632 		case O_NAT:
633 			if (cmd->arg1 == IP_FW_TARG)
634 				cmd->arg1 = 65535;
635 			break;
636 		case O_SETFIB:
637 		case O_SETDSCP:
638 			if (cmd->arg1 == IP_FW_TARG)
639 				cmd->arg1 = 65535;
640 			else
641 				cmd->arg1 &= ~0x8000;
642 			break;
643 		case O_LIMIT:
644 			lcmd = (ipfw_insn_limit *)cmd;
645 			if (lcmd->conn_limit == IP_FW_TARG)
646 				lcmd->conn_limit = 65535;
647 			break;
648 		/* Interface tables */
649 		case O_XMIT:
650 		case O_RECV:
651 		case O_VIA:
652 			/* Interface table, possibly */
653 			cmdif = (ipfw_insn_if *)cmd;
654 			if (cmdif->name[0] != '\1')
655 				break;
656 
657 			cmdif->p.glob = cmdif->p.kidx;
658 			break;
659 		}
660 	}
661 }
662 
663 /*
664  * Add new rule(s) to the list possibly creating rule number for each.
665  * Update the rule_number in the input struct so the caller knows it as well.
666  * Must be called without IPFW_UH held
667  */
668 static int
669 commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count)
670 {
671 	int error, i, insert_before, tcount;
672 	uint16_t rulenum, *pnum;
673 	struct rule_check_info *ci;
674 	struct ip_fw *krule;
675 	struct ip_fw **map;	/* the new array of pointers */
676 
677 	/* Check if we need to do table/obj index remap */
678 	tcount = 0;
679 	for (ci = rci, i = 0; i < count; ci++, i++) {
680 		if (ci->object_opcodes == 0)
681 			continue;
682 
683 		/*
684 		 * Rule has some object opcodes.
685 		 * We need to find (and create non-existing)
686 		 * kernel objects, and reference existing ones.
687 		 */
688 		error = rewrite_rule_uidx(chain, ci);
689 		if (error != 0) {
690 
691 			/*
692 			 * rewrite failed, state for current rule
693 			 * has been reverted. Check if we need to
694 			 * revert more.
695 			 */
696 			if (tcount > 0) {
697 
698 				/*
699 				 * We have some more table rules
700 				 * we need to rollback.
701 				 */
702 
703 				IPFW_UH_WLOCK(chain);
704 				while (ci != rci) {
705 					ci--;
706 					if (ci->object_opcodes == 0)
707 						continue;
708 					unref_rule_objects(chain,ci->krule);
709 
710 				}
711 				IPFW_UH_WUNLOCK(chain);
712 
713 			}
714 
715 			return (error);
716 		}
717 
718 		tcount++;
719 	}
720 
721 	/* get_map returns with IPFW_UH_WLOCK if successful */
722 	map = get_map(chain, count, 0 /* not locked */);
723 	if (map == NULL) {
724 		if (tcount > 0) {
725 			/* Unbind tables */
726 			IPFW_UH_WLOCK(chain);
727 			for (ci = rci, i = 0; i < count; ci++, i++) {
728 				if (ci->object_opcodes == 0)
729 					continue;
730 
731 				unref_rule_objects(chain, ci->krule);
732 			}
733 			IPFW_UH_WUNLOCK(chain);
734 		}
735 
736 		return (ENOSPC);
737 	}
738 
739 	if (V_autoinc_step < 1)
740 		V_autoinc_step = 1;
741 	else if (V_autoinc_step > 1000)
742 		V_autoinc_step = 1000;
743 
744 	/* FIXME: Handle count > 1 */
745 	ci = rci;
746 	krule = ci->krule;
747 	rulenum = krule->rulenum;
748 
749 	/* find the insertion point, we will insert before */
750 	insert_before = rulenum ? rulenum + 1 : IPFW_DEFAULT_RULE;
751 	i = ipfw_find_rule(chain, insert_before, 0);
752 	/* duplicate first part */
753 	if (i > 0)
754 		bcopy(chain->map, map, i * sizeof(struct ip_fw *));
755 	map[i] = krule;
756 	/* duplicate remaining part, we always have the default rule */
757 	bcopy(chain->map + i, map + i + 1,
758 		sizeof(struct ip_fw *) *(chain->n_rules - i));
759 	if (rulenum == 0) {
760 		/* Compute rule number and write it back */
761 		rulenum = i > 0 ? map[i-1]->rulenum : 0;
762 		if (rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
763 			rulenum += V_autoinc_step;
764 		krule->rulenum = rulenum;
765 		/* Save number to userland rule */
766 		pnum = (uint16_t *)((caddr_t)ci->urule + ci->urule_numoff);
767 		*pnum = rulenum;
768 	}
769 
770 	krule->id = chain->id + 1;
771 	update_skipto_cache(chain, map);
772 	map = swap_map(chain, map, chain->n_rules + 1);
773 	chain->static_len += RULEUSIZE0(krule);
774 	IPFW_UH_WUNLOCK(chain);
775 	if (map)
776 		free(map, M_IPFW);
777 	return (0);
778 }
779 
780 /*
781  * Adds @rule to the list of rules to reap
782  */
783 void
784 ipfw_reap_add(struct ip_fw_chain *chain, struct ip_fw **head,
785     struct ip_fw *rule)
786 {
787 
788 	IPFW_UH_WLOCK_ASSERT(chain);
789 
790 	/* Unlink rule from everywhere */
791 	unref_rule_objects(chain, rule);
792 
793 	*((struct ip_fw **)rule) = *head;
794 	*head = rule;
795 }
796 
797 /*
798  * Reclaim storage associated with a list of rules.  This is
799  * typically the list created using remove_rule.
800  * A NULL pointer on input is handled correctly.
801  */
802 void
803 ipfw_reap_rules(struct ip_fw *head)
804 {
805 	struct ip_fw *rule;
806 
807 	while ((rule = head) != NULL) {
808 		head = *((struct ip_fw **)head);
809 		free_rule(rule);
810 	}
811 }
812 
813 /*
814  * Rules to keep are
815  *	(default || reserved || !match_set || !match_number)
816  * where
817  *   default ::= (rule->rulenum == IPFW_DEFAULT_RULE)
818  *	// the default rule is always protected
819  *
820  *   reserved ::= (cmd == 0 && n == 0 && rule->set == RESVD_SET)
821  *	// RESVD_SET is protected only if cmd == 0 and n == 0 ("ipfw flush")
822  *
823  *   match_set ::= (cmd == 0 || rule->set == set)
824  *	// set number is ignored for cmd == 0
825  *
826  *   match_number ::= (cmd == 1 || n == 0 || n == rule->rulenum)
827  *	// number is ignored for cmd == 1 or n == 0
828  *
829  */
830 int
831 ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt)
832 {
833 
834 	/* Don't match default rule for modification queries */
835 	if (rule->rulenum == IPFW_DEFAULT_RULE &&
836 	    (rt->flags & IPFW_RCFLAG_DEFAULT) == 0)
837 		return (0);
838 
839 	/* Don't match rules in reserved set for flush requests */
840 	if ((rt->flags & IPFW_RCFLAG_ALL) != 0 && rule->set == RESVD_SET)
841 		return (0);
842 
843 	/* If we're filtering by set, don't match other sets */
844 	if ((rt->flags & IPFW_RCFLAG_SET) != 0 && rule->set != rt->set)
845 		return (0);
846 
847 	if ((rt->flags & IPFW_RCFLAG_RANGE) != 0 &&
848 	    (rule->rulenum < rt->start_rule || rule->rulenum > rt->end_rule))
849 		return (0);
850 
851 	return (1);
852 }
853 
854 struct manage_sets_args {
855 	uint16_t	set;
856 	uint8_t		new_set;
857 };
858 
859 static int
860 swap_sets_cb(struct namedobj_instance *ni, struct named_object *no,
861     void *arg)
862 {
863 	struct manage_sets_args *args;
864 
865 	args = (struct manage_sets_args *)arg;
866 	if (no->set == (uint8_t)args->set)
867 		no->set = args->new_set;
868 	else if (no->set == args->new_set)
869 		no->set = (uint8_t)args->set;
870 	return (0);
871 }
872 
873 static int
874 move_sets_cb(struct namedobj_instance *ni, struct named_object *no,
875     void *arg)
876 {
877 	struct manage_sets_args *args;
878 
879 	args = (struct manage_sets_args *)arg;
880 	if (no->set == (uint8_t)args->set)
881 		no->set = args->new_set;
882 	return (0);
883 }
884 
885 static int
886 test_sets_cb(struct namedobj_instance *ni, struct named_object *no,
887     void *arg)
888 {
889 	struct manage_sets_args *args;
890 
891 	args = (struct manage_sets_args *)arg;
892 	if (no->set != (uint8_t)args->set)
893 		return (0);
894 	if (ipfw_objhash_lookup_name_type(ni, args->new_set,
895 	    no->etlv, no->name) != NULL)
896 		return (EEXIST);
897 	return (0);
898 }
899 
900 /*
901  * Generic function to handler moving and swapping sets.
902  */
903 int
904 ipfw_obj_manage_sets(struct namedobj_instance *ni, uint16_t type,
905     uint16_t set, uint8_t new_set, enum ipfw_sets_cmd cmd)
906 {
907 	struct manage_sets_args args;
908 	struct named_object *no;
909 
910 	args.set = set;
911 	args.new_set = new_set;
912 	switch (cmd) {
913 	case SWAP_ALL:
914 		return (ipfw_objhash_foreach_type(ni, swap_sets_cb,
915 		    &args, type));
916 	case TEST_ALL:
917 		return (ipfw_objhash_foreach_type(ni, test_sets_cb,
918 		    &args, type));
919 	case MOVE_ALL:
920 		return (ipfw_objhash_foreach_type(ni, move_sets_cb,
921 		    &args, type));
922 	case COUNT_ONE:
923 		/*
924 		 * @set used to pass kidx.
925 		 * When @new_set is zero - reset object counter,
926 		 * otherwise increment it.
927 		 */
928 		no = ipfw_objhash_lookup_kidx(ni, set);
929 		if (new_set != 0)
930 			no->ocnt++;
931 		else
932 			no->ocnt = 0;
933 		return (0);
934 	case TEST_ONE:
935 		/* @set used to pass kidx */
936 		no = ipfw_objhash_lookup_kidx(ni, set);
937 		/*
938 		 * First check number of references:
939 		 * when it differs, this mean other rules are holding
940 		 * reference to given object, so it is not possible to
941 		 * change its set. Note that refcnt may account references
942 		 * to some going-to-be-added rules. Since we don't know
943 		 * their numbers (and even if they will be added) it is
944 		 * perfectly OK to return error here.
945 		 */
946 		if (no->ocnt != no->refcnt)
947 			return (EBUSY);
948 		if (ipfw_objhash_lookup_name_type(ni, new_set, type,
949 		    no->name) != NULL)
950 			return (EEXIST);
951 		return (0);
952 	case MOVE_ONE:
953 		/* @set used to pass kidx */
954 		no = ipfw_objhash_lookup_kidx(ni, set);
955 		no->set = new_set;
956 		return (0);
957 	}
958 	return (EINVAL);
959 }
960 
961 /*
962  * Delete rules matching range @rt.
963  * Saves number of deleted rules in @ndel.
964  *
965  * Returns 0 on success.
966  */
967 static int
968 delete_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int *ndel)
969 {
970 	struct ip_fw *reap, *rule, **map;
971 	int end, start;
972 	int i, n, ndyn, ofs;
973 
974 	reap = NULL;
975 	IPFW_UH_WLOCK(chain);	/* arbitrate writers */
976 
977 	/*
978 	 * Stage 1: Determine range to inspect.
979 	 * Range is half-inclusive, e.g [start, end).
980 	 */
981 	start = 0;
982 	end = chain->n_rules - 1;
983 
984 	if ((rt->flags & IPFW_RCFLAG_RANGE) != 0) {
985 		start = ipfw_find_rule(chain, rt->start_rule, 0);
986 
987 		end = ipfw_find_rule(chain, rt->end_rule, 0);
988 		if (rt->end_rule != IPFW_DEFAULT_RULE)
989 			while (chain->map[end]->rulenum == rt->end_rule)
990 				end++;
991 	}
992 
993 	/* Allocate new map of the same size */
994 	map = get_map(chain, 0, 1 /* locked */);
995 	if (map == NULL) {
996 		IPFW_UH_WUNLOCK(chain);
997 		return (ENOMEM);
998 	}
999 
1000 	n = 0;
1001 	ndyn = 0;
1002 	ofs = start;
1003 	/* 1. bcopy the initial part of the map */
1004 	if (start > 0)
1005 		bcopy(chain->map, map, start * sizeof(struct ip_fw *));
1006 	/* 2. copy active rules between start and end */
1007 	for (i = start; i < end; i++) {
1008 		rule = chain->map[i];
1009 		if (ipfw_match_range(rule, rt) == 0) {
1010 			map[ofs++] = rule;
1011 			continue;
1012 		}
1013 
1014 		n++;
1015 		if (ipfw_is_dyn_rule(rule) != 0)
1016 			ndyn++;
1017 	}
1018 	/* 3. copy the final part of the map */
1019 	bcopy(chain->map + end, map + ofs,
1020 		(chain->n_rules - end) * sizeof(struct ip_fw *));
1021 	/* 4. recalculate skipto cache */
1022 	update_skipto_cache(chain, map);
1023 	/* 5. swap the maps (under UH_WLOCK + WHLOCK) */
1024 	map = swap_map(chain, map, chain->n_rules - n);
1025 	/* 6. Remove all dynamic states originated by deleted rules */
1026 	if (ndyn > 0)
1027 		ipfw_expire_dyn_rules(chain, rt);
1028 	/* 7. now remove the rules deleted from the old map */
1029 	for (i = start; i < end; i++) {
1030 		rule = map[i];
1031 		if (ipfw_match_range(rule, rt) == 0)
1032 			continue;
1033 		chain->static_len -= RULEUSIZE0(rule);
1034 		ipfw_reap_add(chain, &reap, rule);
1035 	}
1036 	IPFW_UH_WUNLOCK(chain);
1037 
1038 	ipfw_reap_rules(reap);
1039 	if (map != NULL)
1040 		free(map, M_IPFW);
1041 	*ndel = n;
1042 	return (0);
1043 }
1044 
1045 static int
1046 move_objects(struct ip_fw_chain *ch, ipfw_range_tlv *rt)
1047 {
1048 	struct opcode_obj_rewrite *rw;
1049 	struct ip_fw *rule;
1050 	ipfw_insn *cmd;
1051 	int cmdlen, i, l, c;
1052 	uint16_t kidx;
1053 
1054 	IPFW_UH_WLOCK_ASSERT(ch);
1055 
1056 	/* Stage 1: count number of references by given rules */
1057 	for (c = 0, i = 0; i < ch->n_rules - 1; i++) {
1058 		rule = ch->map[i];
1059 		if (ipfw_match_range(rule, rt) == 0)
1060 			continue;
1061 		if (rule->set == rt->new_set) /* nothing to do */
1062 			continue;
1063 		/* Search opcodes with named objects */
1064 		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
1065 		    l > 0; l -= cmdlen, cmd += cmdlen) {
1066 			cmdlen = F_LEN(cmd);
1067 			rw = find_op_rw(cmd, &kidx, NULL);
1068 			if (rw == NULL || rw->manage_sets == NULL)
1069 				continue;
1070 			/*
1071 			 * When manage_sets() returns non-zero value to
1072 			 * COUNT_ONE command, consider this as an object
1073 			 * doesn't support sets (e.g. disabled with sysctl).
1074 			 * So, skip checks for this object.
1075 			 */
1076 			if (rw->manage_sets(ch, kidx, 1, COUNT_ONE) != 0)
1077 				continue;
1078 			c++;
1079 		}
1080 	}
1081 	if (c == 0) /* No objects found */
1082 		return (0);
1083 	/* Stage 2: verify "ownership" */
1084 	for (c = 0, i = 0; (i < ch->n_rules - 1) && c == 0; i++) {
1085 		rule = ch->map[i];
1086 		if (ipfw_match_range(rule, rt) == 0)
1087 			continue;
1088 		if (rule->set == rt->new_set) /* nothing to do */
1089 			continue;
1090 		/* Search opcodes with named objects */
1091 		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
1092 		    l > 0 && c == 0; l -= cmdlen, cmd += cmdlen) {
1093 			cmdlen = F_LEN(cmd);
1094 			rw = find_op_rw(cmd, &kidx, NULL);
1095 			if (rw == NULL || rw->manage_sets == NULL)
1096 				continue;
1097 			/* Test for ownership and conflicting names */
1098 			c = rw->manage_sets(ch, kidx,
1099 			    (uint8_t)rt->new_set, TEST_ONE);
1100 		}
1101 	}
1102 	/* Stage 3: change set and cleanup */
1103 	for (i = 0; i < ch->n_rules - 1; i++) {
1104 		rule = ch->map[i];
1105 		if (ipfw_match_range(rule, rt) == 0)
1106 			continue;
1107 		if (rule->set == rt->new_set) /* nothing to do */
1108 			continue;
1109 		/* Search opcodes with named objects */
1110 		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
1111 		    l > 0; l -= cmdlen, cmd += cmdlen) {
1112 			cmdlen = F_LEN(cmd);
1113 			rw = find_op_rw(cmd, &kidx, NULL);
1114 			if (rw == NULL || rw->manage_sets == NULL)
1115 				continue;
1116 			/* cleanup object counter */
1117 			rw->manage_sets(ch, kidx,
1118 			    0 /* reset counter */, COUNT_ONE);
1119 			if (c != 0)
1120 				continue;
1121 			/* change set */
1122 			rw->manage_sets(ch, kidx,
1123 			    (uint8_t)rt->new_set, MOVE_ONE);
1124 		}
1125 	}
1126 	return (c);
1127 }/*
1128  * Changes set of given rule rannge @rt
1129  * with each other.
1130  *
1131  * Returns 0 on success.
1132  */
1133 static int
1134 move_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
1135 {
1136 	struct ip_fw *rule;
1137 	int i;
1138 
1139 	IPFW_UH_WLOCK(chain);
1140 
1141 	/*
1142 	 * Move rules with matching paramenerts to a new set.
1143 	 * This one is much more complex. We have to ensure
1144 	 * that all referenced tables (if any) are referenced
1145 	 * by given rule subset only. Otherwise, we can't move
1146 	 * them to new set and have to return error.
1147 	 */
1148 	if ((i = move_objects(chain, rt)) != 0) {
1149 		IPFW_UH_WUNLOCK(chain);
1150 		return (i);
1151 	}
1152 
1153 	/* XXX: We have to do swap holding WLOCK */
1154 	for (i = 0; i < chain->n_rules; i++) {
1155 		rule = chain->map[i];
1156 		if (ipfw_match_range(rule, rt) == 0)
1157 			continue;
1158 		rule->set = rt->new_set;
1159 	}
1160 
1161 	IPFW_UH_WUNLOCK(chain);
1162 
1163 	return (0);
1164 }
1165 
1166 /*
1167  * Clear counters for a specific rule.
1168  * Normally run under IPFW_UH_RLOCK, but these are idempotent ops
1169  * so we only care that rules do not disappear.
1170  */
1171 static void
1172 clear_counters(struct ip_fw *rule, int log_only)
1173 {
1174 	ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule);
1175 
1176 	if (log_only == 0)
1177 		IPFW_ZERO_RULE_COUNTER(rule);
1178 	if (l->o.opcode == O_LOG)
1179 		l->log_left = l->max_log;
1180 }
1181 
1182 /*
1183  * Flushes rules counters and/or log values on matching range.
1184  *
1185  * Returns number of items cleared.
1186  */
1187 static int
1188 clear_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int log_only)
1189 {
1190 	struct ip_fw *rule;
1191 	int num;
1192 	int i;
1193 
1194 	num = 0;
1195 	rt->flags |= IPFW_RCFLAG_DEFAULT;
1196 
1197 	IPFW_UH_WLOCK(chain);	/* arbitrate writers */
1198 	for (i = 0; i < chain->n_rules; i++) {
1199 		rule = chain->map[i];
1200 		if (ipfw_match_range(rule, rt) == 0)
1201 			continue;
1202 		clear_counters(rule, log_only);
1203 		num++;
1204 	}
1205 	IPFW_UH_WUNLOCK(chain);
1206 
1207 	return (num);
1208 }
1209 
1210 static int
1211 check_range_tlv(ipfw_range_tlv *rt)
1212 {
1213 
1214 	if (rt->head.length != sizeof(*rt))
1215 		return (1);
1216 	if (rt->start_rule > rt->end_rule)
1217 		return (1);
1218 	if (rt->set >= IPFW_MAX_SETS || rt->new_set >= IPFW_MAX_SETS)
1219 		return (1);
1220 
1221 	if ((rt->flags & IPFW_RCFLAG_USER) != rt->flags)
1222 		return (1);
1223 
1224 	return (0);
1225 }
1226 
1227 /*
1228  * Delete rules matching specified parameters
1229  * Data layout (v0)(current):
1230  * Request: [ ipfw_obj_header ipfw_range_tlv ]
1231  * Reply: [ ipfw_obj_header ipfw_range_tlv ]
1232  *
1233  * Saves number of deleted rules in ipfw_range_tlv->new_set.
1234  *
1235  * Returns 0 on success.
1236  */
1237 static int
1238 del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
1239     struct sockopt_data *sd)
1240 {
1241 	ipfw_range_header *rh;
1242 	int error, ndel;
1243 
1244 	if (sd->valsize != sizeof(*rh))
1245 		return (EINVAL);
1246 
1247 	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
1248 
1249 	if (check_range_tlv(&rh->range) != 0)
1250 		return (EINVAL);
1251 
1252 	ndel = 0;
1253 	if ((error = delete_range(chain, &rh->range, &ndel)) != 0)
1254 		return (error);
1255 
1256 	/* Save number of rules deleted */
1257 	rh->range.new_set = ndel;
1258 	return (0);
1259 }
1260 
1261 /*
1262  * Move rules/sets matching specified parameters
1263  * Data layout (v0)(current):
1264  * Request: [ ipfw_obj_header ipfw_range_tlv ]
1265  *
1266  * Returns 0 on success.
1267  */
1268 static int
1269 move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
1270     struct sockopt_data *sd)
1271 {
1272 	ipfw_range_header *rh;
1273 
1274 	if (sd->valsize != sizeof(*rh))
1275 		return (EINVAL);
1276 
1277 	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
1278 
1279 	if (check_range_tlv(&rh->range) != 0)
1280 		return (EINVAL);
1281 
1282 	return (move_range(chain, &rh->range));
1283 }
1284 
1285 /*
1286  * Clear rule accounting data matching specified parameters
1287  * Data layout (v0)(current):
1288  * Request: [ ipfw_obj_header ipfw_range_tlv ]
1289  * Reply: [ ipfw_obj_header ipfw_range_tlv ]
1290  *
1291  * Saves number of cleared rules in ipfw_range_tlv->new_set.
1292  *
1293  * Returns 0 on success.
1294  */
1295 static int
1296 clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
1297     struct sockopt_data *sd)
1298 {
1299 	ipfw_range_header *rh;
1300 	int log_only, num;
1301 	char *msg;
1302 
1303 	if (sd->valsize != sizeof(*rh))
1304 		return (EINVAL);
1305 
1306 	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
1307 
1308 	if (check_range_tlv(&rh->range) != 0)
1309 		return (EINVAL);
1310 
1311 	log_only = (op3->opcode == IP_FW_XRESETLOG);
1312 
1313 	num = clear_range(chain, &rh->range, log_only);
1314 
1315 	if (rh->range.flags & IPFW_RCFLAG_ALL)
1316 		msg = log_only ? "All logging counts reset" :
1317 		    "Accounting cleared";
1318 	else
1319 		msg = log_only ? "logging count reset" : "cleared";
1320 
1321 	if (V_fw_verbose) {
1322 		int lev = LOG_SECURITY | LOG_NOTICE;
1323 		log(lev, "ipfw: %s.\n", msg);
1324 	}
1325 
1326 	/* Save number of rules cleared */
1327 	rh->range.new_set = num;
1328 	return (0);
1329 }
1330 
1331 static void
1332 enable_sets(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
1333 {
1334 	uint32_t v_set;
1335 
1336 	IPFW_UH_WLOCK_ASSERT(chain);
1337 
1338 	/* Change enabled/disabled sets mask */
1339 	v_set = (V_set_disable | rt->set) & ~rt->new_set;
1340 	v_set &= ~(1 << RESVD_SET); /* set RESVD_SET always enabled */
1341 	IPFW_WLOCK(chain);
1342 	V_set_disable = v_set;
1343 	IPFW_WUNLOCK(chain);
1344 }
1345 
1346 static int
1347 swap_sets(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int mv)
1348 {
1349 	struct opcode_obj_rewrite *rw;
1350 	struct ip_fw *rule;
1351 	int i;
1352 
1353 	IPFW_UH_WLOCK_ASSERT(chain);
1354 
1355 	if (rt->set == rt->new_set) /* nothing to do */
1356 		return (0);
1357 
1358 	if (mv != 0) {
1359 		/*
1360 		 * Berfore moving the rules we need to check that
1361 		 * there aren't any conflicting named objects.
1362 		 */
1363 		for (rw = ctl3_rewriters;
1364 		    rw < ctl3_rewriters + ctl3_rsize; rw++) {
1365 			if (rw->manage_sets == NULL)
1366 				continue;
1367 			i = rw->manage_sets(chain, (uint8_t)rt->set,
1368 			    (uint8_t)rt->new_set, TEST_ALL);
1369 			if (i != 0)
1370 				return (EEXIST);
1371 		}
1372 	}
1373 	/* Swap or move two sets */
1374 	for (i = 0; i < chain->n_rules - 1; i++) {
1375 		rule = chain->map[i];
1376 		if (rule->set == (uint8_t)rt->set)
1377 			rule->set = (uint8_t)rt->new_set;
1378 		else if (rule->set == (uint8_t)rt->new_set && mv == 0)
1379 			rule->set = (uint8_t)rt->set;
1380 	}
1381 	for (rw = ctl3_rewriters; rw < ctl3_rewriters + ctl3_rsize; rw++) {
1382 		if (rw->manage_sets == NULL)
1383 			continue;
1384 		rw->manage_sets(chain, (uint8_t)rt->set,
1385 		    (uint8_t)rt->new_set, mv != 0 ? MOVE_ALL: SWAP_ALL);
1386 	}
1387 	return (0);
1388 }
1389 
1390 /*
1391  * Swaps or moves set
1392  * Data layout (v0)(current):
1393  * Request: [ ipfw_obj_header ipfw_range_tlv ]
1394  *
1395  * Returns 0 on success.
1396  */
1397 static int
1398 manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
1399     struct sockopt_data *sd)
1400 {
1401 	ipfw_range_header *rh;
1402 	int ret;
1403 
1404 	if (sd->valsize != sizeof(*rh))
1405 		return (EINVAL);
1406 
1407 	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
1408 
1409 	if (rh->range.head.length != sizeof(ipfw_range_tlv))
1410 		return (1);
1411 	if (rh->range.set >= IPFW_MAX_SETS ||
1412 	    rh->range.new_set >= IPFW_MAX_SETS)
1413 		return (EINVAL);
1414 
1415 	ret = 0;
1416 	IPFW_UH_WLOCK(chain);
1417 	switch (op3->opcode) {
1418 	case IP_FW_SET_SWAP:
1419 	case IP_FW_SET_MOVE:
1420 		ret = swap_sets(chain, &rh->range,
1421 		    op3->opcode == IP_FW_SET_MOVE);
1422 		break;
1423 	case IP_FW_SET_ENABLE:
1424 		enable_sets(chain, &rh->range);
1425 		break;
1426 	}
1427 	IPFW_UH_WUNLOCK(chain);
1428 
1429 	return (ret);
1430 }
1431 
1432 /**
1433  * Remove all rules with given number, or do set manipulation.
1434  * Assumes chain != NULL && *chain != NULL.
1435  *
1436  * The argument is an uint32_t. The low 16 bit are the rule or set number;
1437  * the next 8 bits are the new set; the top 8 bits indicate the command:
1438  *
1439  *	0	delete rules numbered "rulenum"
1440  *	1	delete rules in set "rulenum"
1441  *	2	move rules "rulenum" to set "new_set"
1442  *	3	move rules from set "rulenum" to set "new_set"
1443  *	4	swap sets "rulenum" and "new_set"
1444  *	5	delete rules "rulenum" and set "new_set"
1445  */
1446 static int
1447 del_entry(struct ip_fw_chain *chain, uint32_t arg)
1448 {
1449 	uint32_t num;	/* rule number or old_set */
1450 	uint8_t cmd, new_set;
1451 	int do_del, ndel;
1452 	int error = 0;
1453 	ipfw_range_tlv rt;
1454 
1455 	num = arg & 0xffff;
1456 	cmd = (arg >> 24) & 0xff;
1457 	new_set = (arg >> 16) & 0xff;
1458 
1459 	if (cmd > 5 || new_set > RESVD_SET)
1460 		return EINVAL;
1461 	if (cmd == 0 || cmd == 2 || cmd == 5) {
1462 		if (num >= IPFW_DEFAULT_RULE)
1463 			return EINVAL;
1464 	} else {
1465 		if (num > RESVD_SET)	/* old_set */
1466 			return EINVAL;
1467 	}
1468 
1469 	/* Convert old requests into new representation */
1470 	memset(&rt, 0, sizeof(rt));
1471 	rt.start_rule = num;
1472 	rt.end_rule = num;
1473 	rt.set = num;
1474 	rt.new_set = new_set;
1475 	do_del = 0;
1476 
1477 	switch (cmd) {
1478 	case 0: /* delete rules numbered "rulenum" */
1479 		if (num == 0)
1480 			rt.flags |= IPFW_RCFLAG_ALL;
1481 		else
1482 			rt.flags |= IPFW_RCFLAG_RANGE;
1483 		do_del = 1;
1484 		break;
1485 	case 1: /* delete rules in set "rulenum" */
1486 		rt.flags |= IPFW_RCFLAG_SET;
1487 		do_del = 1;
1488 		break;
1489 	case 5: /* delete rules "rulenum" and set "new_set" */
1490 		rt.flags |= IPFW_RCFLAG_RANGE | IPFW_RCFLAG_SET;
1491 		rt.set = new_set;
1492 		rt.new_set = 0;
1493 		do_del = 1;
1494 		break;
1495 	case 2: /* move rules "rulenum" to set "new_set" */
1496 		rt.flags |= IPFW_RCFLAG_RANGE;
1497 		break;
1498 	case 3: /* move rules from set "rulenum" to set "new_set" */
1499 		IPFW_UH_WLOCK(chain);
1500 		error = swap_sets(chain, &rt, 1);
1501 		IPFW_UH_WUNLOCK(chain);
1502 		return (error);
1503 	case 4: /* swap sets "rulenum" and "new_set" */
1504 		IPFW_UH_WLOCK(chain);
1505 		error = swap_sets(chain, &rt, 0);
1506 		IPFW_UH_WUNLOCK(chain);
1507 		return (error);
1508 	default:
1509 		return (ENOTSUP);
1510 	}
1511 
1512 	if (do_del != 0) {
1513 		if ((error = delete_range(chain, &rt, &ndel)) != 0)
1514 			return (error);
1515 
1516 		if (ndel == 0 && (cmd != 1 && num != 0))
1517 			return (EINVAL);
1518 
1519 		return (0);
1520 	}
1521 
1522 	return (move_range(chain, &rt));
1523 }
1524 
1525 /**
1526  * Reset some or all counters on firewall rules.
1527  * The argument `arg' is an u_int32_t. The low 16 bit are the rule number,
1528  * the next 8 bits are the set number, the top 8 bits are the command:
1529  *	0	work with rules from all set's;
1530  *	1	work with rules only from specified set.
1531  * Specified rule number is zero if we want to clear all entries.
1532  * log_only is 1 if we only want to reset logs, zero otherwise.
1533  */
1534 static int
1535 zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only)
1536 {
1537 	struct ip_fw *rule;
1538 	char *msg;
1539 	int i;
1540 
1541 	uint16_t rulenum = arg & 0xffff;
1542 	uint8_t set = (arg >> 16) & 0xff;
1543 	uint8_t cmd = (arg >> 24) & 0xff;
1544 
1545 	if (cmd > 1)
1546 		return (EINVAL);
1547 	if (cmd == 1 && set > RESVD_SET)
1548 		return (EINVAL);
1549 
1550 	IPFW_UH_RLOCK(chain);
1551 	if (rulenum == 0) {
1552 		V_norule_counter = 0;
1553 		for (i = 0; i < chain->n_rules; i++) {
1554 			rule = chain->map[i];
1555 			/* Skip rules not in our set. */
1556 			if (cmd == 1 && rule->set != set)
1557 				continue;
1558 			clear_counters(rule, log_only);
1559 		}
1560 		msg = log_only ? "All logging counts reset" :
1561 		    "Accounting cleared";
1562 	} else {
1563 		int cleared = 0;
1564 		for (i = 0; i < chain->n_rules; i++) {
1565 			rule = chain->map[i];
1566 			if (rule->rulenum == rulenum) {
1567 				if (cmd == 0 || rule->set == set)
1568 					clear_counters(rule, log_only);
1569 				cleared = 1;
1570 			}
1571 			if (rule->rulenum > rulenum)
1572 				break;
1573 		}
1574 		if (!cleared) {	/* we did not find any matching rules */
1575 			IPFW_UH_RUNLOCK(chain);
1576 			return (EINVAL);
1577 		}
1578 		msg = log_only ? "logging count reset" : "cleared";
1579 	}
1580 	IPFW_UH_RUNLOCK(chain);
1581 
1582 	if (V_fw_verbose) {
1583 		int lev = LOG_SECURITY | LOG_NOTICE;
1584 
1585 		if (rulenum)
1586 			log(lev, "ipfw: Entry %d %s.\n", rulenum, msg);
1587 		else
1588 			log(lev, "ipfw: %s.\n", msg);
1589 	}
1590 	return (0);
1591 }
1592 
1593 
1594 /*
1595  * Check rule head in FreeBSD11 format
1596  *
1597  */
1598 static int
1599 check_ipfw_rule1(struct ip_fw_rule *rule, int size,
1600     struct rule_check_info *ci)
1601 {
1602 	int l;
1603 
1604 	if (size < sizeof(*rule)) {
1605 		printf("ipfw: rule too short\n");
1606 		return (EINVAL);
1607 	}
1608 
1609 	/* Check for valid cmd_len */
1610 	l = roundup2(RULESIZE(rule), sizeof(uint64_t));
1611 	if (l != size) {
1612 		printf("ipfw: size mismatch (have %d want %d)\n", size, l);
1613 		return (EINVAL);
1614 	}
1615 	if (rule->act_ofs >= rule->cmd_len) {
1616 		printf("ipfw: bogus action offset (%u > %u)\n",
1617 		    rule->act_ofs, rule->cmd_len - 1);
1618 		return (EINVAL);
1619 	}
1620 
1621 	if (rule->rulenum > IPFW_DEFAULT_RULE - 1)
1622 		return (EINVAL);
1623 
1624 	return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci));
1625 }
1626 
1627 /*
1628  * Check rule head in FreeBSD8 format
1629  *
1630  */
1631 static int
1632 check_ipfw_rule0(struct ip_fw_rule0 *rule, int size,
1633     struct rule_check_info *ci)
1634 {
1635 	int l;
1636 
1637 	if (size < sizeof(*rule)) {
1638 		printf("ipfw: rule too short\n");
1639 		return (EINVAL);
1640 	}
1641 
1642 	/* Check for valid cmd_len */
1643 	l = sizeof(*rule) + rule->cmd_len * 4 - 4;
1644 	if (l != size) {
1645 		printf("ipfw: size mismatch (have %d want %d)\n", size, l);
1646 		return (EINVAL);
1647 	}
1648 	if (rule->act_ofs >= rule->cmd_len) {
1649 		printf("ipfw: bogus action offset (%u > %u)\n",
1650 		    rule->act_ofs, rule->cmd_len - 1);
1651 		return (EINVAL);
1652 	}
1653 
1654 	if (rule->rulenum > IPFW_DEFAULT_RULE - 1)
1655 		return (EINVAL);
1656 
1657 	return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci));
1658 }
1659 
1660 static int
1661 check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
1662 {
1663 	int cmdlen, l;
1664 	int have_action;
1665 
1666 	have_action = 0;
1667 
1668 	/*
1669 	 * Now go for the individual checks. Very simple ones, basically only
1670 	 * instruction sizes.
1671 	 */
1672 	for (l = cmd_len; l > 0 ; l -= cmdlen, cmd += cmdlen) {
1673 		cmdlen = F_LEN(cmd);
1674 		if (cmdlen > l) {
1675 			printf("ipfw: opcode %d size truncated\n",
1676 			    cmd->opcode);
1677 			return EINVAL;
1678 		}
1679 		switch (cmd->opcode) {
1680 		case O_PROBE_STATE:
1681 		case O_KEEP_STATE:
1682 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1683 				goto bad_size;
1684 			ci->object_opcodes++;
1685 			break;
1686 		case O_PROTO:
1687 		case O_IP_SRC_ME:
1688 		case O_IP_DST_ME:
1689 		case O_LAYER2:
1690 		case O_IN:
1691 		case O_FRAG:
1692 		case O_DIVERTED:
1693 		case O_IPOPT:
1694 		case O_IPTOS:
1695 		case O_IPPRECEDENCE:
1696 		case O_IPVER:
1697 		case O_SOCKARG:
1698 		case O_TCPFLAGS:
1699 		case O_TCPOPTS:
1700 		case O_ESTAB:
1701 		case O_VERREVPATH:
1702 		case O_VERSRCREACH:
1703 		case O_ANTISPOOF:
1704 		case O_IPSEC:
1705 #ifdef INET6
1706 		case O_IP6_SRC_ME:
1707 		case O_IP6_DST_ME:
1708 		case O_EXT_HDR:
1709 		case O_IP6:
1710 #endif
1711 		case O_IP4:
1712 		case O_TAG:
1713 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1714 				goto bad_size;
1715 			break;
1716 
1717 		case O_EXTERNAL_ACTION:
1718 			if (cmd->arg1 == 0 ||
1719 			    cmdlen != F_INSN_SIZE(ipfw_insn)) {
1720 				printf("ipfw: invalid external "
1721 				    "action opcode\n");
1722 				return (EINVAL);
1723 			}
1724 			ci->object_opcodes++;
1725 			/* Do we have O_EXTERNAL_INSTANCE opcode? */
1726 			if (l != cmdlen) {
1727 				l -= cmdlen;
1728 				cmd += cmdlen;
1729 				cmdlen = F_LEN(cmd);
1730 				if (cmd->opcode != O_EXTERNAL_INSTANCE) {
1731 					printf("ipfw: invalid opcode "
1732 					    "next to external action %u\n",
1733 					    cmd->opcode);
1734 					return (EINVAL);
1735 				}
1736 				if (cmd->arg1 == 0 ||
1737 				    cmdlen != F_INSN_SIZE(ipfw_insn)) {
1738 					printf("ipfw: invalid external "
1739 					    "action instance opcode\n");
1740 					return (EINVAL);
1741 				}
1742 				ci->object_opcodes++;
1743 			}
1744 			goto check_action;
1745 
1746 		case O_FIB:
1747 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1748 				goto bad_size;
1749 			if (cmd->arg1 >= rt_numfibs) {
1750 				printf("ipfw: invalid fib number %d\n",
1751 					cmd->arg1);
1752 				return EINVAL;
1753 			}
1754 			break;
1755 
1756 		case O_SETFIB:
1757 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1758 				goto bad_size;
1759 			if ((cmd->arg1 != IP_FW_TARG) &&
1760 			    ((cmd->arg1 & 0x7FFF) >= rt_numfibs)) {
1761 				printf("ipfw: invalid fib number %d\n",
1762 					cmd->arg1 & 0x7FFF);
1763 				return EINVAL;
1764 			}
1765 			goto check_action;
1766 
1767 		case O_UID:
1768 		case O_GID:
1769 		case O_JAIL:
1770 		case O_IP_SRC:
1771 		case O_IP_DST:
1772 		case O_TCPSEQ:
1773 		case O_TCPACK:
1774 		case O_PROB:
1775 		case O_ICMPTYPE:
1776 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1777 				goto bad_size;
1778 			break;
1779 
1780 		case O_LIMIT:
1781 			if (cmdlen != F_INSN_SIZE(ipfw_insn_limit))
1782 				goto bad_size;
1783 			ci->object_opcodes++;
1784 			break;
1785 
1786 		case O_LOG:
1787 			if (cmdlen != F_INSN_SIZE(ipfw_insn_log))
1788 				goto bad_size;
1789 
1790 			((ipfw_insn_log *)cmd)->log_left =
1791 			    ((ipfw_insn_log *)cmd)->max_log;
1792 
1793 			break;
1794 
1795 		case O_IP_SRC_MASK:
1796 		case O_IP_DST_MASK:
1797 			/* only odd command lengths */
1798 			if ((cmdlen & 1) == 0)
1799 				goto bad_size;
1800 			break;
1801 
1802 		case O_IP_SRC_SET:
1803 		case O_IP_DST_SET:
1804 			if (cmd->arg1 == 0 || cmd->arg1 > 256) {
1805 				printf("ipfw: invalid set size %d\n",
1806 					cmd->arg1);
1807 				return EINVAL;
1808 			}
1809 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
1810 			    (cmd->arg1+31)/32 )
1811 				goto bad_size;
1812 			break;
1813 
1814 		case O_IP_SRC_LOOKUP:
1815 		case O_IP_DST_LOOKUP:
1816 			if (cmd->arg1 >= V_fw_tables_max) {
1817 				printf("ipfw: invalid table number %d\n",
1818 				    cmd->arg1);
1819 				return (EINVAL);
1820 			}
1821 			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
1822 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
1823 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1824 				goto bad_size;
1825 			ci->object_opcodes++;
1826 			break;
1827 		case O_IP_FLOW_LOOKUP:
1828 			if (cmd->arg1 >= V_fw_tables_max) {
1829 				printf("ipfw: invalid table number %d\n",
1830 				    cmd->arg1);
1831 				return (EINVAL);
1832 			}
1833 			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
1834 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1835 				goto bad_size;
1836 			ci->object_opcodes++;
1837 			break;
1838 		case O_MACADDR2:
1839 			if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
1840 				goto bad_size;
1841 			break;
1842 
1843 		case O_NOP:
1844 		case O_IPID:
1845 		case O_IPTTL:
1846 		case O_IPLEN:
1847 		case O_TCPDATALEN:
1848 		case O_TCPWIN:
1849 		case O_TAGGED:
1850 			if (cmdlen < 1 || cmdlen > 31)
1851 				goto bad_size;
1852 			break;
1853 
1854 		case O_DSCP:
1855 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1)
1856 				goto bad_size;
1857 			break;
1858 
1859 		case O_MAC_TYPE:
1860 		case O_IP_SRCPORT:
1861 		case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
1862 			if (cmdlen < 2 || cmdlen > 31)
1863 				goto bad_size;
1864 			break;
1865 
1866 		case O_RECV:
1867 		case O_XMIT:
1868 		case O_VIA:
1869 			if (cmdlen != F_INSN_SIZE(ipfw_insn_if))
1870 				goto bad_size;
1871 			ci->object_opcodes++;
1872 			break;
1873 
1874 		case O_ALTQ:
1875 			if (cmdlen != F_INSN_SIZE(ipfw_insn_altq))
1876 				goto bad_size;
1877 			break;
1878 
1879 		case O_PIPE:
1880 		case O_QUEUE:
1881 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1882 				goto bad_size;
1883 			goto check_action;
1884 
1885 		case O_FORWARD_IP:
1886 			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa))
1887 				goto bad_size;
1888 			goto check_action;
1889 #ifdef INET6
1890 		case O_FORWARD_IP6:
1891 			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6))
1892 				goto bad_size;
1893 			goto check_action;
1894 #endif /* INET6 */
1895 
1896 		case O_DIVERT:
1897 		case O_TEE:
1898 			if (ip_divert_ptr == NULL)
1899 				return EINVAL;
1900 			else
1901 				goto check_size;
1902 		case O_NETGRAPH:
1903 		case O_NGTEE:
1904 			if (ng_ipfw_input_p == NULL)
1905 				return EINVAL;
1906 			else
1907 				goto check_size;
1908 		case O_NAT:
1909 			if (!IPFW_NAT_LOADED)
1910 				return EINVAL;
1911 			if (cmdlen != F_INSN_SIZE(ipfw_insn_nat))
1912  				goto bad_size;
1913  			goto check_action;
1914 		case O_CHECK_STATE:
1915 			ci->object_opcodes++;
1916 			/* FALLTHROUGH */
1917 		case O_FORWARD_MAC: /* XXX not implemented yet */
1918 		case O_COUNT:
1919 		case O_ACCEPT:
1920 		case O_DENY:
1921 		case O_REJECT:
1922 		case O_SETDSCP:
1923 #ifdef INET6
1924 		case O_UNREACH6:
1925 #endif
1926 		case O_SKIPTO:
1927 		case O_REASS:
1928 		case O_CALLRETURN:
1929 check_size:
1930 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1931 				goto bad_size;
1932 check_action:
1933 			if (have_action) {
1934 				printf("ipfw: opcode %d, multiple actions"
1935 					" not allowed\n",
1936 					cmd->opcode);
1937 				return (EINVAL);
1938 			}
1939 			have_action = 1;
1940 			if (l != cmdlen) {
1941 				printf("ipfw: opcode %d, action must be"
1942 					" last opcode\n",
1943 					cmd->opcode);
1944 				return (EINVAL);
1945 			}
1946 			break;
1947 #ifdef INET6
1948 		case O_IP6_SRC:
1949 		case O_IP6_DST:
1950 			if (cmdlen != F_INSN_SIZE(struct in6_addr) +
1951 			    F_INSN_SIZE(ipfw_insn))
1952 				goto bad_size;
1953 			break;
1954 
1955 		case O_FLOW6ID:
1956 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
1957 			    ((ipfw_insn_u32 *)cmd)->o.arg1)
1958 				goto bad_size;
1959 			break;
1960 
1961 		case O_IP6_SRC_MASK:
1962 		case O_IP6_DST_MASK:
1963 			if ( !(cmdlen & 1) || cmdlen > 127)
1964 				goto bad_size;
1965 			break;
1966 		case O_ICMP6TYPE:
1967 			if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
1968 				goto bad_size;
1969 			break;
1970 #endif
1971 
1972 		default:
1973 			switch (cmd->opcode) {
1974 #ifndef INET6
1975 			case O_IP6_SRC_ME:
1976 			case O_IP6_DST_ME:
1977 			case O_EXT_HDR:
1978 			case O_IP6:
1979 			case O_UNREACH6:
1980 			case O_IP6_SRC:
1981 			case O_IP6_DST:
1982 			case O_FLOW6ID:
1983 			case O_IP6_SRC_MASK:
1984 			case O_IP6_DST_MASK:
1985 			case O_ICMP6TYPE:
1986 				printf("ipfw: no IPv6 support in kernel\n");
1987 				return (EPROTONOSUPPORT);
1988 #endif
1989 			default:
1990 				printf("ipfw: opcode %d, unknown opcode\n",
1991 					cmd->opcode);
1992 				return (EINVAL);
1993 			}
1994 		}
1995 	}
1996 	if (have_action == 0) {
1997 		printf("ipfw: missing action\n");
1998 		return (EINVAL);
1999 	}
2000 	return 0;
2001 
2002 bad_size:
2003 	printf("ipfw: opcode %d size %d wrong\n",
2004 		cmd->opcode, cmdlen);
2005 	return (EINVAL);
2006 }
2007 
2008 
2009 /*
2010  * Translation of requests for compatibility with FreeBSD 7.2/8.
2011  * a static variable tells us if we have an old client from userland,
2012  * and if necessary we translate requests and responses between the
2013  * two formats.
2014  */
2015 static int is7 = 0;
2016 
2017 struct ip_fw7 {
2018 	struct ip_fw7	*next;		/* linked list of rules     */
2019 	struct ip_fw7	*next_rule;	/* ptr to next [skipto] rule    */
2020 	/* 'next_rule' is used to pass up 'set_disable' status      */
2021 
2022 	uint16_t	act_ofs;	/* offset of action in 32-bit units */
2023 	uint16_t	cmd_len;	/* # of 32-bit words in cmd */
2024 	uint16_t	rulenum;	/* rule number          */
2025 	uint8_t		set;		/* rule set (0..31)     */
2026 	// #define RESVD_SET   31  /* set for default and persistent rules */
2027 	uint8_t		_pad;		/* padding          */
2028 	// uint32_t        id;             /* rule id, only in v.8 */
2029 	/* These fields are present in all rules.           */
2030 	uint64_t	pcnt;		/* Packet counter       */
2031 	uint64_t	bcnt;		/* Byte counter         */
2032 	uint32_t	timestamp;	/* tv_sec of last match     */
2033 
2034 	ipfw_insn	cmd[1];		/* storage for commands     */
2035 };
2036 
2037 static int convert_rule_to_7(struct ip_fw_rule0 *rule);
2038 static int convert_rule_to_8(struct ip_fw_rule0 *rule);
2039 
2040 #ifndef RULESIZE7
2041 #define RULESIZE7(rule)  (sizeof(struct ip_fw7) + \
2042 	((struct ip_fw7 *)(rule))->cmd_len * 4 - 4)
2043 #endif
2044 
2045 
2046 /*
2047  * Copy the static and dynamic rules to the supplied buffer
2048  * and return the amount of space actually used.
2049  * Must be run under IPFW_UH_RLOCK
2050  */
2051 static size_t
2052 ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
2053 {
2054 	char *bp = buf;
2055 	char *ep = bp + space;
2056 	struct ip_fw *rule;
2057 	struct ip_fw_rule0 *dst;
2058 	int error, i, l, warnflag;
2059 	time_t	boot_seconds;
2060 
2061 	warnflag = 0;
2062 
2063         boot_seconds = boottime.tv_sec;
2064 	for (i = 0; i < chain->n_rules; i++) {
2065 		rule = chain->map[i];
2066 
2067 		if (is7) {
2068 		    /* Convert rule to FreeBSd 7.2 format */
2069 		    l = RULESIZE7(rule);
2070 		    if (bp + l + sizeof(uint32_t) <= ep) {
2071 			bcopy(rule, bp, l + sizeof(uint32_t));
2072 			error = set_legacy_obj_kidx(chain,
2073 			    (struct ip_fw_rule0 *)bp);
2074 			if (error != 0)
2075 				return (0);
2076 			error = convert_rule_to_7((struct ip_fw_rule0 *) bp);
2077 			if (error)
2078 				return 0; /*XXX correct? */
2079 			/*
2080 			 * XXX HACK. Store the disable mask in the "next"
2081 			 * pointer in a wild attempt to keep the ABI the same.
2082 			 * Why do we do this on EVERY rule?
2083 			 */
2084 			bcopy(&V_set_disable,
2085 				&(((struct ip_fw7 *)bp)->next_rule),
2086 				sizeof(V_set_disable));
2087 			if (((struct ip_fw7 *)bp)->timestamp)
2088 			    ((struct ip_fw7 *)bp)->timestamp += boot_seconds;
2089 			bp += l;
2090 		    }
2091 		    continue; /* go to next rule */
2092 		}
2093 
2094 		l = RULEUSIZE0(rule);
2095 		if (bp + l > ep) { /* should not happen */
2096 			printf("overflow dumping static rules\n");
2097 			break;
2098 		}
2099 		dst = (struct ip_fw_rule0 *)bp;
2100 		export_rule0(rule, dst, l);
2101 		error = set_legacy_obj_kidx(chain, dst);
2102 
2103 		/*
2104 		 * XXX HACK. Store the disable mask in the "next"
2105 		 * pointer in a wild attempt to keep the ABI the same.
2106 		 * Why do we do this on EVERY rule?
2107 		 *
2108 		 * XXX: "ipfw set show" (ab)uses IP_FW_GET to read disabled mask
2109 		 * so we need to fail _after_ saving at least one mask.
2110 		 */
2111 		bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable));
2112 		if (dst->timestamp)
2113 			dst->timestamp += boot_seconds;
2114 		bp += l;
2115 
2116 		if (error != 0) {
2117 			if (error == 2) {
2118 				/* Non-fatal table rewrite error. */
2119 				warnflag = 1;
2120 				continue;
2121 			}
2122 			printf("Stop on rule %d. Fail to convert table\n",
2123 			    rule->rulenum);
2124 			break;
2125 		}
2126 	}
2127 	if (warnflag != 0)
2128 		printf("ipfw: process %s is using legacy interfaces,"
2129 		    " consider rebuilding\n", "");
2130 	ipfw_get_dynamic(chain, &bp, ep); /* protected by the dynamic lock */
2131 	return (bp - (char *)buf);
2132 }
2133 
2134 
2135 struct dump_args {
2136 	uint32_t	b;	/* start rule */
2137 	uint32_t	e;	/* end rule */
2138 	uint32_t	rcount;	/* number of rules */
2139 	uint32_t	rsize;	/* rules size */
2140 	uint32_t	tcount;	/* number of tables */
2141 	int		rcounters;	/* counters */
2142 };
2143 
2144 void
2145 ipfw_export_obj_ntlv(struct named_object *no, ipfw_obj_ntlv *ntlv)
2146 {
2147 
2148 	ntlv->head.type = no->etlv;
2149 	ntlv->head.length = sizeof(*ntlv);
2150 	ntlv->idx = no->kidx;
2151 	strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
2152 }
2153 
2154 /*
2155  * Export named object info in instance @ni, identified by @kidx
2156  * to ipfw_obj_ntlv. TLV is allocated from @sd space.
2157  *
2158  * Returns 0 on success.
2159  */
2160 static int
2161 export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
2162     struct sockopt_data *sd)
2163 {
2164 	struct named_object *no;
2165 	ipfw_obj_ntlv *ntlv;
2166 
2167 	no = ipfw_objhash_lookup_kidx(ni, kidx);
2168 	KASSERT(no != NULL, ("invalid object kernel index passed"));
2169 
2170 	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
2171 	if (ntlv == NULL)
2172 		return (ENOMEM);
2173 
2174 	ipfw_export_obj_ntlv(no, ntlv);
2175 	return (0);
2176 }
2177 
2178 /*
2179  * Dumps static rules with table TLVs in buffer @sd.
2180  *
2181  * Returns 0 on success.
2182  */
2183 static int
2184 dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
2185     uint32_t *bmask, struct sockopt_data *sd)
2186 {
2187 	int error;
2188 	int i, l;
2189 	uint32_t tcount;
2190 	ipfw_obj_ctlv *ctlv;
2191 	struct ip_fw *krule;
2192 	struct namedobj_instance *ni;
2193 	caddr_t dst;
2194 
2195 	/* Dump table names first (if any) */
2196 	if (da->tcount > 0) {
2197 		/* Header first */
2198 		ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
2199 		if (ctlv == NULL)
2200 			return (ENOMEM);
2201 		ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
2202 		ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) +
2203 		    sizeof(*ctlv);
2204 		ctlv->count = da->tcount;
2205 		ctlv->objsize = sizeof(ipfw_obj_ntlv);
2206 	}
2207 
2208 	i = 0;
2209 	tcount = da->tcount;
2210 	ni = ipfw_get_table_objhash(chain);
2211 	while (tcount > 0) {
2212 		if ((bmask[i / 32] & (1 << (i % 32))) == 0) {
2213 			i++;
2214 			continue;
2215 		}
2216 
2217 		/* Jump to shared named object bitmask */
2218 		if (i >= IPFW_TABLES_MAX) {
2219 			ni = CHAIN_TO_SRV(chain);
2220 			i -= IPFW_TABLES_MAX;
2221 			bmask += IPFW_TABLES_MAX / 32;
2222 		}
2223 
2224 		if ((error = export_objhash_ntlv(ni, i, sd)) != 0)
2225 			return (error);
2226 
2227 		i++;
2228 		tcount--;
2229 	}
2230 
2231 	/* Dump rules */
2232 	ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
2233 	if (ctlv == NULL)
2234 		return (ENOMEM);
2235 	ctlv->head.type = IPFW_TLV_RULE_LIST;
2236 	ctlv->head.length = da->rsize + sizeof(*ctlv);
2237 	ctlv->count = da->rcount;
2238 
2239 	for (i = da->b; i < da->e; i++) {
2240 		krule = chain->map[i];
2241 
2242 		l = RULEUSIZE1(krule) + sizeof(ipfw_obj_tlv);
2243 		if (da->rcounters != 0)
2244 			l += sizeof(struct ip_fw_bcounter);
2245 		dst = (caddr_t)ipfw_get_sopt_space(sd, l);
2246 		if (dst == NULL)
2247 			return (ENOMEM);
2248 
2249 		export_rule1(krule, dst, l, da->rcounters);
2250 	}
2251 
2252 	return (0);
2253 }
2254 
2255 /*
2256  * Marks every object index used in @rule with bit in @bmask.
2257  * Used to generate bitmask of referenced tables/objects for given ruleset
2258  * or its part.
2259  *
2260  * Returns number of newly-referenced objects.
2261  */
2262 static int
2263 mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
2264     uint32_t *bmask)
2265 {
2266 	struct opcode_obj_rewrite *rw;
2267 	ipfw_insn *cmd;
2268 	int bidx, cmdlen, l, count;
2269 	uint16_t kidx;
2270 	uint8_t subtype;
2271 
2272 	l = rule->cmd_len;
2273 	cmd = rule->cmd;
2274 	cmdlen = 0;
2275 	count = 0;
2276 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2277 		cmdlen = F_LEN(cmd);
2278 
2279 		rw = find_op_rw(cmd, &kidx, &subtype);
2280 		if (rw == NULL)
2281 			continue;
2282 
2283 		bidx = kidx / 32;
2284 		/*
2285 		 * Maintain separate bitmasks for table and
2286 		 * non-table objects.
2287 		 */
2288 		if (rw->etlv != IPFW_TLV_TBL_NAME)
2289 			bidx += IPFW_TABLES_MAX / 32;
2290 
2291 		if ((bmask[bidx] & (1 << (kidx % 32))) == 0)
2292 			count++;
2293 
2294 		bmask[bidx] |= 1 << (kidx % 32);
2295 	}
2296 
2297 	return (count);
2298 }
2299 
2300 /*
2301  * Dumps requested objects data
2302  * Data layout (version 0)(current):
2303  * Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags
2304  *   size = ipfw_cfg_lheader.size
2305  * Reply: [ ipfw_cfg_lheader
2306  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
2307  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST)
2308  *     ipfw_obj_tlv(IPFW_TLV_RULE_ENT) [ ip_fw_bcounter (optional) ip_fw_rule ]
2309  *   ] (optional)
2310  *   [ ipfw_obj_ctlv(IPFW_TLV_STATE_LIST) ipfw_obj_dyntlv x N ] (optional)
2311  * ]
2312  * * NOTE IPFW_TLV_STATE_LIST has the single valid field: objsize.
2313  * The rest (size, count) are set to zero and needs to be ignored.
2314  *
2315  * Returns 0 on success.
2316  */
2317 static int
2318 dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2319     struct sockopt_data *sd)
2320 {
2321 	ipfw_cfg_lheader *hdr;
2322 	struct ip_fw *rule;
2323 	size_t sz, rnum;
2324 	uint32_t hdr_flags;
2325 	int error, i;
2326 	struct dump_args da;
2327 	uint32_t *bmask;
2328 
2329 	hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
2330 	if (hdr == NULL)
2331 		return (EINVAL);
2332 
2333 	error = 0;
2334 	bmask = NULL;
2335 	/* Allocate needed state. Note we allocate 2xspace mask, for table&srv  */
2336 	if (hdr->flags & IPFW_CFG_GET_STATIC)
2337 		bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO);
2338 
2339 	IPFW_UH_RLOCK(chain);
2340 
2341 	/*
2342 	 * STAGE 1: Determine size/count for objects in range.
2343 	 * Prepare used tables bitmask.
2344 	 */
2345 	sz = sizeof(ipfw_cfg_lheader);
2346 	memset(&da, 0, sizeof(da));
2347 
2348 	da.b = 0;
2349 	da.e = chain->n_rules;
2350 
2351 	if (hdr->end_rule != 0) {
2352 		/* Handle custom range */
2353 		if ((rnum = hdr->start_rule) > IPFW_DEFAULT_RULE)
2354 			rnum = IPFW_DEFAULT_RULE;
2355 		da.b = ipfw_find_rule(chain, rnum, 0);
2356 		rnum = hdr->end_rule;
2357 		rnum = (rnum < IPFW_DEFAULT_RULE) ? rnum+1 : IPFW_DEFAULT_RULE;
2358 		da.e = ipfw_find_rule(chain, rnum, 0) + 1;
2359 	}
2360 
2361 	if (hdr->flags & IPFW_CFG_GET_STATIC) {
2362 		for (i = da.b; i < da.e; i++) {
2363 			rule = chain->map[i];
2364 			da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv);
2365 			da.rcount++;
2366 			/* Update bitmask of used objects for given range */
2367 			da.tcount += mark_object_kidx(chain, rule, bmask);
2368 		}
2369 		/* Add counters if requested */
2370 		if (hdr->flags & IPFW_CFG_GET_COUNTERS) {
2371 			da.rsize += sizeof(struct ip_fw_bcounter) * da.rcount;
2372 			da.rcounters = 1;
2373 		}
2374 
2375 		if (da.tcount > 0)
2376 			sz += da.tcount * sizeof(ipfw_obj_ntlv) +
2377 			    sizeof(ipfw_obj_ctlv);
2378 		sz += da.rsize + sizeof(ipfw_obj_ctlv);
2379 	}
2380 
2381 	if (hdr->flags & IPFW_CFG_GET_STATES)
2382 		sz += ipfw_dyn_get_count() * sizeof(ipfw_obj_dyntlv) +
2383 		     sizeof(ipfw_obj_ctlv);
2384 
2385 
2386 	/*
2387 	 * Fill header anyway.
2388 	 * Note we have to save header fields to stable storage
2389 	 * buffer inside @sd can be flushed after dumping rules
2390 	 */
2391 	hdr->size = sz;
2392 	hdr->set_mask = ~V_set_disable;
2393 	hdr_flags = hdr->flags;
2394 	hdr = NULL;
2395 
2396 	if (sd->valsize < sz) {
2397 		error = ENOMEM;
2398 		goto cleanup;
2399 	}
2400 
2401 	/* STAGE2: Store actual data */
2402 	if (hdr_flags & IPFW_CFG_GET_STATIC) {
2403 		error = dump_static_rules(chain, &da, bmask, sd);
2404 		if (error != 0)
2405 			goto cleanup;
2406 	}
2407 
2408 	if (hdr_flags & IPFW_CFG_GET_STATES)
2409 		error = ipfw_dump_states(chain, sd);
2410 
2411 cleanup:
2412 	IPFW_UH_RUNLOCK(chain);
2413 
2414 	if (bmask != NULL)
2415 		free(bmask, M_TEMP);
2416 
2417 	return (error);
2418 }
2419 
2420 int
2421 ipfw_check_object_name_generic(const char *name)
2422 {
2423 	int nsize;
2424 
2425 	nsize = sizeof(((ipfw_obj_ntlv *)0)->name);
2426 	if (strnlen(name, nsize) == nsize)
2427 		return (EINVAL);
2428 	if (name[0] == '\0')
2429 		return (EINVAL);
2430 	return (0);
2431 }
2432 
2433 /*
2434  * Creates non-existent objects referenced by rule.
2435  *
2436  * Return 0 on success.
2437  */
2438 int
2439 create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd,
2440     struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti)
2441 {
2442 	struct opcode_obj_rewrite *rw;
2443 	struct obj_idx *p;
2444 	uint16_t kidx;
2445 	int error;
2446 
2447 	/*
2448 	 * Compatibility stuff: do actual creation for non-existing,
2449 	 * but referenced objects.
2450 	 */
2451 	for (p = oib; p < pidx; p++) {
2452 		if (p->kidx != 0)
2453 			continue;
2454 
2455 		ti->uidx = p->uidx;
2456 		ti->type = p->type;
2457 		ti->atype = 0;
2458 
2459 		rw = find_op_rw(cmd + p->off, NULL, NULL);
2460 		KASSERT(rw != NULL, ("Unable to find handler for op %d",
2461 		    (cmd + p->off)->opcode));
2462 
2463 		if (rw->create_object == NULL)
2464 			error = EOPNOTSUPP;
2465 		else
2466 			error = rw->create_object(ch, ti, &kidx);
2467 		if (error == 0) {
2468 			p->kidx = kidx;
2469 			continue;
2470 		}
2471 
2472 		/*
2473 		 * Error happened. We have to rollback everything.
2474 		 * Drop all already acquired references.
2475 		 */
2476 		IPFW_UH_WLOCK(ch);
2477 		unref_oib_objects(ch, cmd, oib, pidx);
2478 		IPFW_UH_WUNLOCK(ch);
2479 
2480 		return (error);
2481 	}
2482 
2483 	return (0);
2484 }
2485 
2486 /*
2487  * Compatibility function for old ipfw(8) binaries.
2488  * Rewrites table/nat kernel indices with userland ones.
2489  * Convert tables matching '/^\d+$/' to their atoi() value.
2490  * Use number 65535 for other tables.
2491  *
2492  * Returns 0 on success.
2493  */
2494 static int
2495 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule)
2496 {
2497 	struct opcode_obj_rewrite *rw;
2498 	struct named_object *no;
2499 	ipfw_insn *cmd;
2500 	char *end;
2501 	long val;
2502 	int cmdlen, error, l;
2503 	uint16_t kidx, uidx;
2504 	uint8_t subtype;
2505 
2506 	error = 0;
2507 
2508 	l = rule->cmd_len;
2509 	cmd = rule->cmd;
2510 	cmdlen = 0;
2511 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2512 		cmdlen = F_LEN(cmd);
2513 
2514 		/* Check if is index in given opcode */
2515 		rw = find_op_rw(cmd, &kidx, &subtype);
2516 		if (rw == NULL)
2517 			continue;
2518 
2519 		/* Try to find referenced kernel object */
2520 		no = rw->find_bykidx(ch, kidx);
2521 		if (no == NULL)
2522 			continue;
2523 
2524 		val = strtol(no->name, &end, 10);
2525 		if (*end == '\0' && val < 65535) {
2526 			uidx = val;
2527 		} else {
2528 
2529 			/*
2530 			 * We are called via legacy opcode.
2531 			 * Save error and show table as fake number
2532 			 * not to make ipfw(8) hang.
2533 			 */
2534 			uidx = 65535;
2535 			error = 2;
2536 		}
2537 
2538 		rw->update(cmd, uidx);
2539 	}
2540 
2541 	return (error);
2542 }
2543 
2544 
2545 /*
2546  * Unreferences all already-referenced objects in given @cmd rule,
2547  * using information in @oib.
2548  *
2549  * Used to rollback partially converted rule on error.
2550  */
2551 static void
2552 unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib,
2553     struct obj_idx *end)
2554 {
2555 	struct opcode_obj_rewrite *rw;
2556 	struct named_object *no;
2557 	struct obj_idx *p;
2558 
2559 	IPFW_UH_WLOCK_ASSERT(ch);
2560 
2561 	for (p = oib; p < end; p++) {
2562 		if (p->kidx == 0)
2563 			continue;
2564 
2565 		rw = find_op_rw(cmd + p->off, NULL, NULL);
2566 		KASSERT(rw != NULL, ("Unable to find handler for op %d",
2567 		    (cmd + p->off)->opcode));
2568 
2569 		/* Find & unref by existing idx */
2570 		no = rw->find_bykidx(ch, p->kidx);
2571 		KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx));
2572 		no->refcnt--;
2573 	}
2574 }
2575 
2576 /*
2577  * Remove references from every object used in @rule.
2578  * Used at rule removal code.
2579  */
2580 static void
2581 unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule)
2582 {
2583 	struct opcode_obj_rewrite *rw;
2584 	struct named_object *no;
2585 	ipfw_insn *cmd;
2586 	int cmdlen, l;
2587 	uint16_t kidx;
2588 	uint8_t subtype;
2589 
2590 	IPFW_UH_WLOCK_ASSERT(ch);
2591 
2592 	l = rule->cmd_len;
2593 	cmd = rule->cmd;
2594 	cmdlen = 0;
2595 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2596 		cmdlen = F_LEN(cmd);
2597 
2598 		rw = find_op_rw(cmd, &kidx, &subtype);
2599 		if (rw == NULL)
2600 			continue;
2601 		no = rw->find_bykidx(ch, kidx);
2602 
2603 		KASSERT(no != NULL, ("table id %d not found", kidx));
2604 		KASSERT(no->subtype == subtype,
2605 		    ("wrong type %d (%d) for table id %d",
2606 		    no->subtype, subtype, kidx));
2607 		KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
2608 		    kidx, no->refcnt));
2609 
2610 		if (no->refcnt == 1 && rw->destroy_object != NULL)
2611 			rw->destroy_object(ch, no);
2612 		else
2613 			no->refcnt--;
2614 	}
2615 }
2616 
2617 
2618 /*
2619  * Find and reference object (if any) stored in instruction @cmd.
2620  *
2621  * Saves object info in @pidx, sets
2622  *  - @unresolved to 1 if object should exists but not found
2623  *
2624  * Returns non-zero value in case of error.
2625  */
2626 static int
2627 ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti,
2628     struct obj_idx *pidx, int *unresolved)
2629 {
2630 	struct named_object *no;
2631 	struct opcode_obj_rewrite *rw;
2632 	int error;
2633 
2634 	/* Check if this opcode is candidate for rewrite */
2635 	rw = find_op_rw(cmd, &ti->uidx, &ti->type);
2636 	if (rw == NULL)
2637 		return (0);
2638 
2639 	/* Need to rewrite. Save necessary fields */
2640 	pidx->uidx = ti->uidx;
2641 	pidx->type = ti->type;
2642 
2643 	/* Try to find referenced kernel object */
2644 	error = rw->find_byname(ch, ti, &no);
2645 	if (error != 0)
2646 		return (error);
2647 	if (no == NULL) {
2648 		/*
2649 		 * Report about unresolved object for automaic
2650 		 * creation.
2651 		 */
2652 		*unresolved = 1;
2653 		return (0);
2654 	}
2655 
2656 	/* Found. Bump refcount and update kidx. */
2657 	no->refcnt++;
2658 	rw->update(cmd, no->kidx);
2659 	return (0);
2660 }
2661 
2662 /*
2663  * Finds and bumps refcount for objects referenced by given @rule.
2664  * Auto-creates non-existing tables.
2665  * Fills in @oib array with userland/kernel indexes.
2666  *
2667  * Returns 0 on success.
2668  */
2669 static int
2670 ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
2671     struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti)
2672 {
2673 	struct obj_idx *pidx;
2674 	ipfw_insn *cmd;
2675 	int cmdlen, error, l, unresolved;
2676 
2677 	pidx = oib;
2678 	l = rule->cmd_len;
2679 	cmd = rule->cmd;
2680 	cmdlen = 0;
2681 	error = 0;
2682 
2683 	IPFW_UH_WLOCK(ch);
2684 
2685 	/* Increase refcount on each existing referenced table. */
2686 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2687 		cmdlen = F_LEN(cmd);
2688 		unresolved = 0;
2689 
2690 		error = ref_opcode_object(ch, cmd, ti, pidx, &unresolved);
2691 		if (error != 0)
2692 			break;
2693 		/*
2694 		 * Compatibility stuff for old clients:
2695 		 * prepare to automaitcally create non-existing objects.
2696 		 */
2697 		if (unresolved != 0) {
2698 			pidx->off = rule->cmd_len - l;
2699 			pidx++;
2700 		}
2701 	}
2702 
2703 	if (error != 0) {
2704 		/* Unref everything we have already done */
2705 		unref_oib_objects(ch, rule->cmd, oib, pidx);
2706 		IPFW_UH_WUNLOCK(ch);
2707 		return (error);
2708 	}
2709 	IPFW_UH_WUNLOCK(ch);
2710 
2711 	/* Perform auto-creation for non-existing objects */
2712 	if (pidx != oib)
2713 		error = create_objects_compat(ch, rule->cmd, oib, pidx, ti);
2714 
2715 	/* Calculate real number of dynamic objects */
2716 	ci->object_opcodes = (uint16_t)(pidx - oib);
2717 
2718 	return (error);
2719 }
2720 
2721 /*
2722  * Checks is opcode is referencing table of appropriate type.
2723  * Adds reference count for found table if true.
2724  * Rewrites user-supplied opcode values with kernel ones.
2725  *
2726  * Returns 0 on success and appropriate error code otherwise.
2727  */
2728 static int
2729 rewrite_rule_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci)
2730 {
2731 	int error;
2732 	ipfw_insn *cmd;
2733 	uint8_t type;
2734 	struct obj_idx *p, *pidx_first, *pidx_last;
2735 	struct tid_info ti;
2736 
2737 	/*
2738 	 * Prepare an array for storing opcode indices.
2739 	 * Use stack allocation by default.
2740 	 */
2741 	if (ci->object_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
2742 		/* Stack */
2743 		pidx_first = ci->obuf;
2744 	} else
2745 		pidx_first = malloc(
2746 		    ci->object_opcodes * sizeof(struct obj_idx),
2747 		    M_IPFW, M_WAITOK | M_ZERO);
2748 
2749 	error = 0;
2750 	type = 0;
2751 	memset(&ti, 0, sizeof(ti));
2752 
2753 	/* Use set rule is assigned to. */
2754 	ti.set = ci->krule->set;
2755 	if (ci->ctlv != NULL) {
2756 		ti.tlvs = (void *)(ci->ctlv + 1);
2757 		ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
2758 	}
2759 
2760 	/* Reference all used tables and other objects */
2761 	error = ref_rule_objects(chain, ci->krule, ci, pidx_first, &ti);
2762 	if (error != 0)
2763 		goto free;
2764 	/*
2765 	 * Note that ref_rule_objects() might have updated ci->object_opcodes
2766 	 * to reflect actual number of object opcodes.
2767 	 */
2768 
2769 	/* Perform rewrite of remaining opcodes */
2770 	p = pidx_first;
2771 	pidx_last = pidx_first + ci->object_opcodes;
2772 	for (p = pidx_first; p < pidx_last; p++) {
2773 		cmd = ci->krule->cmd + p->off;
2774 		update_opcode_kidx(cmd, p->kidx);
2775 	}
2776 
2777 free:
2778 	if (pidx_first != ci->obuf)
2779 		free(pidx_first, M_IPFW);
2780 
2781 	return (error);
2782 }
2783 
2784 /*
2785  * Adds one or more rules to ipfw @chain.
2786  * Data layout (version 0)(current):
2787  * Request:
2788  * [
2789  *   ip_fw3_opheader
2790  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1)
2791  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3)
2792  * ]
2793  * Reply:
2794  * [
2795  *   ip_fw3_opheader
2796  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
2797  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ]
2798  * ]
2799  *
2800  * Rules in reply are modified to store their actual ruleset number.
2801  *
2802  * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending
2803  * according to their idx field and there has to be no duplicates.
2804  * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending.
2805  * (*3) Each ip_fw structure needs to be aligned to u64 boundary.
2806  *
2807  * Returns 0 on success.
2808  */
2809 static int
2810 add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2811     struct sockopt_data *sd)
2812 {
2813 	ipfw_obj_ctlv *ctlv, *rtlv, *tstate;
2814 	ipfw_obj_ntlv *ntlv;
2815 	int clen, error, idx;
2816 	uint32_t count, read;
2817 	struct ip_fw_rule *r;
2818 	struct rule_check_info rci, *ci, *cbuf;
2819 	int i, rsize;
2820 
2821 	op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize);
2822 	ctlv = (ipfw_obj_ctlv *)(op3 + 1);
2823 
2824 	read = sizeof(ip_fw3_opheader);
2825 	rtlv = NULL;
2826 	tstate = NULL;
2827 	cbuf = NULL;
2828 	memset(&rci, 0, sizeof(struct rule_check_info));
2829 
2830 	if (read + sizeof(*ctlv) > sd->valsize)
2831 		return (EINVAL);
2832 
2833 	if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
2834 		clen = ctlv->head.length;
2835 		/* Check size and alignment */
2836 		if (clen > sd->valsize || clen < sizeof(*ctlv))
2837 			return (EINVAL);
2838 		if ((clen % sizeof(uint64_t)) != 0)
2839 			return (EINVAL);
2840 
2841 		/*
2842 		 * Some table names or other named objects.
2843 		 * Check for validness.
2844 		 */
2845 		count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv);
2846 		if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv))
2847 			return (EINVAL);
2848 
2849 		/*
2850 		 * Check each TLV.
2851 		 * Ensure TLVs are sorted ascending and
2852 		 * there are no duplicates.
2853 		 */
2854 		idx = -1;
2855 		ntlv = (ipfw_obj_ntlv *)(ctlv + 1);
2856 		while (count > 0) {
2857 			if (ntlv->head.length != sizeof(ipfw_obj_ntlv))
2858 				return (EINVAL);
2859 
2860 			error = ipfw_check_object_name_generic(ntlv->name);
2861 			if (error != 0)
2862 				return (error);
2863 
2864 			if (ntlv->idx <= idx)
2865 				return (EINVAL);
2866 
2867 			idx = ntlv->idx;
2868 			count--;
2869 			ntlv++;
2870 		}
2871 
2872 		tstate = ctlv;
2873 		read += ctlv->head.length;
2874 		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
2875 	}
2876 
2877 	if (read + sizeof(*ctlv) > sd->valsize)
2878 		return (EINVAL);
2879 
2880 	if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
2881 		clen = ctlv->head.length;
2882 		if (clen + read > sd->valsize || clen < sizeof(*ctlv))
2883 			return (EINVAL);
2884 		if ((clen % sizeof(uint64_t)) != 0)
2885 			return (EINVAL);
2886 
2887 		/*
2888 		 * TODO: Permit adding multiple rules at once
2889 		 */
2890 		if (ctlv->count != 1)
2891 			return (ENOTSUP);
2892 
2893 		clen -= sizeof(*ctlv);
2894 
2895 		if (ctlv->count > clen / sizeof(struct ip_fw_rule))
2896 			return (EINVAL);
2897 
2898 		/* Allocate state for each rule or use stack */
2899 		if (ctlv->count == 1) {
2900 			memset(&rci, 0, sizeof(struct rule_check_info));
2901 			cbuf = &rci;
2902 		} else
2903 			cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP,
2904 			    M_WAITOK | M_ZERO);
2905 		ci = cbuf;
2906 
2907 		/*
2908 		 * Check each rule for validness.
2909 		 * Ensure numbered rules are sorted ascending
2910 		 * and properly aligned
2911 		 */
2912 		idx = 0;
2913 		r = (struct ip_fw_rule *)(ctlv + 1);
2914 		count = 0;
2915 		error = 0;
2916 		while (clen > 0) {
2917 			rsize = roundup2(RULESIZE(r), sizeof(uint64_t));
2918 			if (rsize > clen || ctlv->count <= count) {
2919 				error = EINVAL;
2920 				break;
2921 			}
2922 
2923 			ci->ctlv = tstate;
2924 			error = check_ipfw_rule1(r, rsize, ci);
2925 			if (error != 0)
2926 				break;
2927 
2928 			/* Check sorting */
2929 			if (r->rulenum != 0 && r->rulenum < idx) {
2930 				printf("rulenum %d idx %d\n", r->rulenum, idx);
2931 				error = EINVAL;
2932 				break;
2933 			}
2934 			idx = r->rulenum;
2935 
2936 			ci->urule = (caddr_t)r;
2937 
2938 			rsize = roundup2(rsize, sizeof(uint64_t));
2939 			clen -= rsize;
2940 			r = (struct ip_fw_rule *)((caddr_t)r + rsize);
2941 			count++;
2942 			ci++;
2943 		}
2944 
2945 		if (ctlv->count != count || error != 0) {
2946 			if (cbuf != &rci)
2947 				free(cbuf, M_TEMP);
2948 			return (EINVAL);
2949 		}
2950 
2951 		rtlv = ctlv;
2952 		read += ctlv->head.length;
2953 		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
2954 	}
2955 
2956 	if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) {
2957 		if (cbuf != NULL && cbuf != &rci)
2958 			free(cbuf, M_TEMP);
2959 		return (EINVAL);
2960 	}
2961 
2962 	/*
2963 	 * Passed rules seems to be valid.
2964 	 * Allocate storage and try to add them to chain.
2965 	 */
2966 	for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) {
2967 		clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule);
2968 		ci->krule = ipfw_alloc_rule(chain, clen);
2969 		import_rule1(ci);
2970 	}
2971 
2972 	if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) {
2973 		/* Free allocate krules */
2974 		for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++)
2975 			free_rule(ci->krule);
2976 	}
2977 
2978 	if (cbuf != NULL && cbuf != &rci)
2979 		free(cbuf, M_TEMP);
2980 
2981 	return (error);
2982 }
2983 
2984 /*
2985  * Lists all sopts currently registered.
2986  * Data layout (v0)(current):
2987  * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
2988  * Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ]
2989  *
2990  * Returns 0 on success
2991  */
2992 static int
2993 dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2994     struct sockopt_data *sd)
2995 {
2996 	struct _ipfw_obj_lheader *olh;
2997 	ipfw_sopt_info *i;
2998 	struct ipfw_sopt_handler *sh;
2999 	uint32_t count, n, size;
3000 
3001 	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
3002 	if (olh == NULL)
3003 		return (EINVAL);
3004 	if (sd->valsize < olh->size)
3005 		return (EINVAL);
3006 
3007 	CTL3_LOCK();
3008 	count = ctl3_hsize;
3009 	size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader);
3010 
3011 	/* Fill in header regadless of buffer size */
3012 	olh->count = count;
3013 	olh->objsize = sizeof(ipfw_sopt_info);
3014 
3015 	if (size > olh->size) {
3016 		olh->size = size;
3017 		CTL3_UNLOCK();
3018 		return (ENOMEM);
3019 	}
3020 	olh->size = size;
3021 
3022 	for (n = 1; n <= count; n++) {
3023 		i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i));
3024 		KASSERT(i != NULL, ("previously checked buffer is not enough"));
3025 		sh = &ctl3_handlers[n];
3026 		i->opcode = sh->opcode;
3027 		i->version = sh->version;
3028 		i->refcnt = sh->refcnt;
3029 	}
3030 	CTL3_UNLOCK();
3031 
3032 	return (0);
3033 }
3034 
3035 /*
3036  * Compares two opcodes.
3037  * Used both in qsort() and bsearch().
3038  *
3039  * Returns 0 if match is found.
3040  */
3041 static int
3042 compare_opcodes(const void *_a, const void *_b)
3043 {
3044 	const struct opcode_obj_rewrite *a, *b;
3045 
3046 	a = (const struct opcode_obj_rewrite *)_a;
3047 	b = (const struct opcode_obj_rewrite *)_b;
3048 
3049 	if (a->opcode < b->opcode)
3050 		return (-1);
3051 	else if (a->opcode > b->opcode)
3052 		return (1);
3053 
3054 	return (0);
3055 }
3056 
3057 /*
3058  * XXX: Rewrite bsearch()
3059  */
3060 static int
3061 find_op_rw_range(uint16_t op, struct opcode_obj_rewrite **plo,
3062     struct opcode_obj_rewrite **phi)
3063 {
3064 	struct opcode_obj_rewrite *ctl3_max, *lo, *hi, h, *rw;
3065 
3066 	memset(&h, 0, sizeof(h));
3067 	h.opcode = op;
3068 
3069 	rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters,
3070 	    ctl3_rsize, sizeof(h), compare_opcodes);
3071 	if (rw == NULL)
3072 		return (1);
3073 
3074 	/* Find the first element matching the same opcode */
3075 	lo = rw;
3076 	for ( ; lo > ctl3_rewriters && (lo - 1)->opcode == op; lo--)
3077 		;
3078 
3079 	/* Find the last element matching the same opcode */
3080 	hi = rw;
3081 	ctl3_max = ctl3_rewriters + ctl3_rsize;
3082 	for ( ; (hi + 1) < ctl3_max && (hi + 1)->opcode == op; hi++)
3083 		;
3084 
3085 	*plo = lo;
3086 	*phi = hi;
3087 
3088 	return (0);
3089 }
3090 
3091 /*
3092  * Finds opcode object rewriter based on @code.
3093  *
3094  * Returns pointer to handler or NULL.
3095  */
3096 static struct opcode_obj_rewrite *
3097 find_op_rw(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
3098 {
3099 	struct opcode_obj_rewrite *rw, *lo, *hi;
3100 	uint16_t uidx;
3101 	uint8_t subtype;
3102 
3103 	if (find_op_rw_range(cmd->opcode, &lo, &hi) != 0)
3104 		return (NULL);
3105 
3106 	for (rw = lo; rw <= hi; rw++) {
3107 		if (rw->classifier(cmd, &uidx, &subtype) == 0) {
3108 			if (puidx != NULL)
3109 				*puidx = uidx;
3110 			if (ptype != NULL)
3111 				*ptype = subtype;
3112 			return (rw);
3113 		}
3114 	}
3115 
3116 	return (NULL);
3117 }
3118 int
3119 classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx)
3120 {
3121 
3122 	if (find_op_rw(cmd, puidx, NULL) == 0)
3123 		return (1);
3124 	return (0);
3125 }
3126 
3127 void
3128 update_opcode_kidx(ipfw_insn *cmd, uint16_t idx)
3129 {
3130 	struct opcode_obj_rewrite *rw;
3131 
3132 	rw = find_op_rw(cmd, NULL, NULL);
3133 	KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode));
3134 	rw->update(cmd, idx);
3135 }
3136 
3137 void
3138 ipfw_init_obj_rewriter()
3139 {
3140 
3141 	ctl3_rewriters = NULL;
3142 	ctl3_rsize = 0;
3143 }
3144 
3145 void
3146 ipfw_destroy_obj_rewriter()
3147 {
3148 
3149 	if (ctl3_rewriters != NULL)
3150 		free(ctl3_rewriters, M_IPFW);
3151 	ctl3_rewriters = NULL;
3152 	ctl3_rsize = 0;
3153 }
3154 
3155 /*
3156  * Adds one or more opcode object rewrite handlers to the global array.
3157  * Function may sleep.
3158  */
3159 void
3160 ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
3161 {
3162 	size_t sz;
3163 	struct opcode_obj_rewrite *tmp;
3164 
3165 	CTL3_LOCK();
3166 
3167 	for (;;) {
3168 		sz = ctl3_rsize + count;
3169 		CTL3_UNLOCK();
3170 		tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO);
3171 		CTL3_LOCK();
3172 		if (ctl3_rsize + count <= sz)
3173 			break;
3174 
3175 		/* Retry */
3176 		free(tmp, M_IPFW);
3177 	}
3178 
3179 	/* Merge old & new arrays */
3180 	sz = ctl3_rsize + count;
3181 	memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw));
3182 	memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw));
3183 	qsort(tmp, sz, sizeof(*rw), compare_opcodes);
3184 	/* Switch new and free old */
3185 	if (ctl3_rewriters != NULL)
3186 		free(ctl3_rewriters, M_IPFW);
3187 	ctl3_rewriters = tmp;
3188 	ctl3_rsize = sz;
3189 
3190 	CTL3_UNLOCK();
3191 }
3192 
3193 /*
3194  * Removes one or more object rewrite handlers from the global array.
3195  */
3196 int
3197 ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
3198 {
3199 	size_t sz;
3200 	struct opcode_obj_rewrite *ctl3_max, *ktmp, *lo, *hi;
3201 	int i;
3202 
3203 	CTL3_LOCK();
3204 
3205 	for (i = 0; i < count; i++) {
3206 		if (find_op_rw_range(rw[i].opcode, &lo, &hi) != 0)
3207 			continue;
3208 
3209 		for (ktmp = lo; ktmp <= hi; ktmp++) {
3210 			if (ktmp->classifier != rw[i].classifier)
3211 				continue;
3212 
3213 			ctl3_max = ctl3_rewriters + ctl3_rsize;
3214 			sz = (ctl3_max - (ktmp + 1)) * sizeof(*ktmp);
3215 			memmove(ktmp, ktmp + 1, sz);
3216 			ctl3_rsize--;
3217 			break;
3218 		}
3219 
3220 	}
3221 
3222 	if (ctl3_rsize == 0) {
3223 		if (ctl3_rewriters != NULL)
3224 			free(ctl3_rewriters, M_IPFW);
3225 		ctl3_rewriters = NULL;
3226 	}
3227 
3228 	CTL3_UNLOCK();
3229 
3230 	return (0);
3231 }
3232 
3233 static int
3234 export_objhash_ntlv_internal(struct namedobj_instance *ni,
3235     struct named_object *no, void *arg)
3236 {
3237 	struct sockopt_data *sd;
3238 	ipfw_obj_ntlv *ntlv;
3239 
3240 	sd = (struct sockopt_data *)arg;
3241 	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
3242 	if (ntlv == NULL)
3243 		return (ENOMEM);
3244 	ipfw_export_obj_ntlv(no, ntlv);
3245 	return (0);
3246 }
3247 
3248 /*
3249  * Lists all service objects.
3250  * Data layout (v0)(current):
3251  * Request: [ ipfw_obj_lheader ] size = ipfw_obj_lheader.size
3252  * Reply: [ ipfw_obj_lheader [ ipfw_obj_ntlv x N ] (optional) ]
3253  * Returns 0 on success
3254  */
3255 static int
3256 dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
3257     struct sockopt_data *sd)
3258 {
3259 	ipfw_obj_lheader *hdr;
3260 	int count;
3261 
3262 	hdr = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
3263 	if (hdr == NULL)
3264 		return (EINVAL);
3265 
3266 	IPFW_UH_RLOCK(chain);
3267 	count = ipfw_objhash_count(CHAIN_TO_SRV(chain));
3268 	hdr->size = sizeof(ipfw_obj_lheader) + count * sizeof(ipfw_obj_ntlv);
3269 	if (sd->valsize < hdr->size) {
3270 		IPFW_UH_RUNLOCK(chain);
3271 		return (ENOMEM);
3272 	}
3273 	hdr->count = count;
3274 	hdr->objsize = sizeof(ipfw_obj_ntlv);
3275 	if (count > 0)
3276 		ipfw_objhash_foreach(CHAIN_TO_SRV(chain),
3277 		    export_objhash_ntlv_internal, sd);
3278 	IPFW_UH_RUNLOCK(chain);
3279 	return (0);
3280 }
3281 
3282 /*
3283  * Compares two sopt handlers (code, version and handler ptr).
3284  * Used both as qsort() and bsearch().
3285  * Does not compare handler for latter case.
3286  *
3287  * Returns 0 if match is found.
3288  */
3289 static int
3290 compare_sh(const void *_a, const void *_b)
3291 {
3292 	const struct ipfw_sopt_handler *a, *b;
3293 
3294 	a = (const struct ipfw_sopt_handler *)_a;
3295 	b = (const struct ipfw_sopt_handler *)_b;
3296 
3297 	if (a->opcode < b->opcode)
3298 		return (-1);
3299 	else if (a->opcode > b->opcode)
3300 		return (1);
3301 
3302 	if (a->version < b->version)
3303 		return (-1);
3304 	else if (a->version > b->version)
3305 		return (1);
3306 
3307 	/* bsearch helper */
3308 	if (a->handler == NULL)
3309 		return (0);
3310 
3311 	if ((uintptr_t)a->handler < (uintptr_t)b->handler)
3312 		return (-1);
3313 	else if ((uintptr_t)a->handler > (uintptr_t)b->handler)
3314 		return (1);
3315 
3316 	return (0);
3317 }
3318 
3319 /*
3320  * Finds sopt handler based on @code and @version.
3321  *
3322  * Returns pointer to handler or NULL.
3323  */
3324 static struct ipfw_sopt_handler *
3325 find_sh(uint16_t code, uint8_t version, sopt_handler_f *handler)
3326 {
3327 	struct ipfw_sopt_handler *sh, h;
3328 
3329 	memset(&h, 0, sizeof(h));
3330 	h.opcode = code;
3331 	h.version = version;
3332 	h.handler = handler;
3333 
3334 	sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers,
3335 	    ctl3_hsize, sizeof(h), compare_sh);
3336 
3337 	return (sh);
3338 }
3339 
3340 static int
3341 find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh)
3342 {
3343 	struct ipfw_sopt_handler *sh;
3344 
3345 	CTL3_LOCK();
3346 	if ((sh = find_sh(opcode, version, NULL)) == NULL) {
3347 		CTL3_UNLOCK();
3348 		printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n",
3349 		    opcode, version);
3350 		return (EINVAL);
3351 	}
3352 	sh->refcnt++;
3353 	ctl3_refct++;
3354 	/* Copy handler data to requested buffer */
3355 	*psh = *sh;
3356 	CTL3_UNLOCK();
3357 
3358 	return (0);
3359 }
3360 
3361 static void
3362 find_unref_sh(struct ipfw_sopt_handler *psh)
3363 {
3364 	struct ipfw_sopt_handler *sh;
3365 
3366 	CTL3_LOCK();
3367 	sh = find_sh(psh->opcode, psh->version, NULL);
3368 	KASSERT(sh != NULL, ("ctl3 handler disappeared"));
3369 	sh->refcnt--;
3370 	ctl3_refct--;
3371 	CTL3_UNLOCK();
3372 }
3373 
3374 void
3375 ipfw_init_sopt_handler()
3376 {
3377 
3378 	CTL3_LOCK_INIT();
3379 	IPFW_ADD_SOPT_HANDLER(1, scodes);
3380 }
3381 
3382 void
3383 ipfw_destroy_sopt_handler()
3384 {
3385 
3386 	IPFW_DEL_SOPT_HANDLER(1, scodes);
3387 	CTL3_LOCK_DESTROY();
3388 }
3389 
3390 /*
3391  * Adds one or more sockopt handlers to the global array.
3392  * Function may sleep.
3393  */
3394 void
3395 ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
3396 {
3397 	size_t sz;
3398 	struct ipfw_sopt_handler *tmp;
3399 
3400 	CTL3_LOCK();
3401 
3402 	for (;;) {
3403 		sz = ctl3_hsize + count;
3404 		CTL3_UNLOCK();
3405 		tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO);
3406 		CTL3_LOCK();
3407 		if (ctl3_hsize + count <= sz)
3408 			break;
3409 
3410 		/* Retry */
3411 		free(tmp, M_IPFW);
3412 	}
3413 
3414 	/* Merge old & new arrays */
3415 	sz = ctl3_hsize + count;
3416 	memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh));
3417 	memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh));
3418 	qsort(tmp, sz, sizeof(*sh), compare_sh);
3419 	/* Switch new and free old */
3420 	if (ctl3_handlers != NULL)
3421 		free(ctl3_handlers, M_IPFW);
3422 	ctl3_handlers = tmp;
3423 	ctl3_hsize = sz;
3424 	ctl3_gencnt++;
3425 
3426 	CTL3_UNLOCK();
3427 }
3428 
3429 /*
3430  * Removes one or more sockopt handlers from the global array.
3431  */
3432 int
3433 ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
3434 {
3435 	size_t sz;
3436 	struct ipfw_sopt_handler *tmp, *h;
3437 	int i;
3438 
3439 	CTL3_LOCK();
3440 
3441 	for (i = 0; i < count; i++) {
3442 		tmp = &sh[i];
3443 		h = find_sh(tmp->opcode, tmp->version, tmp->handler);
3444 		if (h == NULL)
3445 			continue;
3446 
3447 		sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h);
3448 		memmove(h, h + 1, sz);
3449 		ctl3_hsize--;
3450 	}
3451 
3452 	if (ctl3_hsize == 0) {
3453 		if (ctl3_handlers != NULL)
3454 			free(ctl3_handlers, M_IPFW);
3455 		ctl3_handlers = NULL;
3456 	}
3457 
3458 	ctl3_gencnt++;
3459 
3460 	CTL3_UNLOCK();
3461 
3462 	return (0);
3463 }
3464 
3465 /*
3466  * Writes data accumulated in @sd to sockopt buffer.
3467  * Zeroes internal @sd buffer.
3468  */
3469 static int
3470 ipfw_flush_sopt_data(struct sockopt_data *sd)
3471 {
3472 	struct sockopt *sopt;
3473 	int error;
3474 	size_t sz;
3475 
3476 	sz = sd->koff;
3477 	if (sz == 0)
3478 		return (0);
3479 
3480 	sopt = sd->sopt;
3481 
3482 	if (sopt->sopt_dir == SOPT_GET) {
3483 		error = copyout(sd->kbuf, sopt->sopt_val, sz);
3484 		if (error != 0)
3485 			return (error);
3486 	}
3487 
3488 	memset(sd->kbuf, 0, sd->ksize);
3489 	sd->ktotal += sz;
3490 	sd->koff = 0;
3491 	if (sd->ktotal + sd->ksize < sd->valsize)
3492 		sd->kavail = sd->ksize;
3493 	else
3494 		sd->kavail = sd->valsize - sd->ktotal;
3495 
3496 	/* Update sopt buffer data */
3497 	sopt->sopt_valsize = sd->ktotal;
3498 	sopt->sopt_val = sd->sopt_val + sd->ktotal;
3499 
3500 	return (0);
3501 }
3502 
3503 /*
3504  * Ensures that @sd buffer has contiguous @neeeded number of
3505  * bytes.
3506  *
3507  * Returns pointer to requested space or NULL.
3508  */
3509 caddr_t
3510 ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed)
3511 {
3512 	int error;
3513 	caddr_t addr;
3514 
3515 	if (sd->kavail < needed) {
3516 		/*
3517 		 * Flush data and try another time.
3518 		 */
3519 		error = ipfw_flush_sopt_data(sd);
3520 
3521 		if (sd->kavail < needed || error != 0)
3522 			return (NULL);
3523 	}
3524 
3525 	addr = sd->kbuf + sd->koff;
3526 	sd->koff += needed;
3527 	sd->kavail -= needed;
3528 	return (addr);
3529 }
3530 
3531 /*
3532  * Requests @needed contiguous bytes from @sd buffer.
3533  * Function is used to notify subsystem that we are
3534  * interesed in first @needed bytes (request header)
3535  * and the rest buffer can be safely zeroed.
3536  *
3537  * Returns pointer to requested space or NULL.
3538  */
3539 caddr_t
3540 ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed)
3541 {
3542 	caddr_t addr;
3543 
3544 	if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL)
3545 		return (NULL);
3546 
3547 	if (sd->kavail > 0)
3548 		memset(sd->kbuf + sd->koff, 0, sd->kavail);
3549 
3550 	return (addr);
3551 }
3552 
3553 /*
3554  * New sockopt handler.
3555  */
3556 int
3557 ipfw_ctl3(struct sockopt *sopt)
3558 {
3559 	int error, locked;
3560 	size_t size, valsize;
3561 	struct ip_fw_chain *chain;
3562 	char xbuf[256];
3563 	struct sockopt_data sdata;
3564 	struct ipfw_sopt_handler h;
3565 	ip_fw3_opheader *op3 = NULL;
3566 
3567 	error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
3568 	if (error != 0)
3569 		return (error);
3570 
3571 	if (sopt->sopt_name != IP_FW3)
3572 		return (ipfw_ctl(sopt));
3573 
3574 	chain = &V_layer3_chain;
3575 	error = 0;
3576 
3577 	/* Save original valsize before it is altered via sooptcopyin() */
3578 	valsize = sopt->sopt_valsize;
3579 	memset(&sdata, 0, sizeof(sdata));
3580 	/* Read op3 header first to determine actual operation */
3581 	op3 = (ip_fw3_opheader *)xbuf;
3582 	error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3));
3583 	if (error != 0)
3584 		return (error);
3585 	sopt->sopt_valsize = valsize;
3586 
3587 	/*
3588 	 * Find and reference command.
3589 	 */
3590 	error = find_ref_sh(op3->opcode, op3->version, &h);
3591 	if (error != 0)
3592 		return (error);
3593 
3594 	/*
3595 	 * Disallow modifications in really-really secure mode, but still allow
3596 	 * the logging counters to be reset.
3597 	 */
3598 	if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) {
3599 		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
3600 		if (error != 0) {
3601 			find_unref_sh(&h);
3602 			return (error);
3603 		}
3604 	}
3605 
3606 	/*
3607 	 * Fill in sockopt_data structure that may be useful for
3608 	 * IP_FW3 get requests.
3609 	 */
3610 	locked = 0;
3611 	if (valsize <= sizeof(xbuf)) {
3612 		/* use on-stack buffer */
3613 		sdata.kbuf = xbuf;
3614 		sdata.ksize = sizeof(xbuf);
3615 		sdata.kavail = valsize;
3616 	} else {
3617 
3618 		/*
3619 		 * Determine opcode type/buffer size:
3620 		 * allocate sliding-window buf for data export or
3621 		 * contiguous buffer for special ops.
3622 		 */
3623 		if ((h.dir & HDIR_SET) != 0) {
3624 			/* Set request. Allocate contigous buffer. */
3625 			if (valsize > CTL3_LARGEBUF) {
3626 				find_unref_sh(&h);
3627 				return (EFBIG);
3628 			}
3629 
3630 			size = valsize;
3631 		} else {
3632 			/* Get request. Allocate sliding window buffer */
3633 			size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF;
3634 
3635 			if (size < valsize) {
3636 				/* We have to wire user buffer */
3637 				error = vslock(sopt->sopt_val, valsize);
3638 				if (error != 0)
3639 					return (error);
3640 				locked = 1;
3641 			}
3642 		}
3643 
3644 		sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
3645 		sdata.ksize = size;
3646 		sdata.kavail = size;
3647 	}
3648 
3649 	sdata.sopt = sopt;
3650 	sdata.sopt_val = sopt->sopt_val;
3651 	sdata.valsize = valsize;
3652 
3653 	/*
3654 	 * Copy either all request (if valsize < bsize_max)
3655 	 * or first bsize_max bytes to guarantee most consumers
3656 	 * that all necessary data has been copied).
3657 	 * Anyway, copy not less than sizeof(ip_fw3_opheader).
3658 	 */
3659 	if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize,
3660 	    sizeof(ip_fw3_opheader))) != 0)
3661 		return (error);
3662 	op3 = (ip_fw3_opheader *)sdata.kbuf;
3663 
3664 	/* Finally, run handler */
3665 	error = h.handler(chain, op3, &sdata);
3666 	find_unref_sh(&h);
3667 
3668 	/* Flush state and free buffers */
3669 	if (error == 0)
3670 		error = ipfw_flush_sopt_data(&sdata);
3671 	else
3672 		ipfw_flush_sopt_data(&sdata);
3673 
3674 	if (locked != 0)
3675 		vsunlock(sdata.sopt_val, valsize);
3676 
3677 	/* Restore original pointer and set number of bytes written */
3678 	sopt->sopt_val = sdata.sopt_val;
3679 	sopt->sopt_valsize = sdata.ktotal;
3680 	if (sdata.kbuf != xbuf)
3681 		free(sdata.kbuf, M_TEMP);
3682 
3683 	return (error);
3684 }
3685 
3686 /**
3687  * {set|get}sockopt parser.
3688  */
3689 int
3690 ipfw_ctl(struct sockopt *sopt)
3691 {
3692 #define	RULE_MAXSIZE	(512*sizeof(u_int32_t))
3693 	int error;
3694 	size_t size, valsize;
3695 	struct ip_fw *buf;
3696 	struct ip_fw_rule0 *rule;
3697 	struct ip_fw_chain *chain;
3698 	u_int32_t rulenum[2];
3699 	uint32_t opt;
3700 	struct rule_check_info ci;
3701 	IPFW_RLOCK_TRACKER;
3702 
3703 	chain = &V_layer3_chain;
3704 	error = 0;
3705 
3706 	/* Save original valsize before it is altered via sooptcopyin() */
3707 	valsize = sopt->sopt_valsize;
3708 	opt = sopt->sopt_name;
3709 
3710 	/*
3711 	 * Disallow modifications in really-really secure mode, but still allow
3712 	 * the logging counters to be reset.
3713 	 */
3714 	if (opt == IP_FW_ADD ||
3715 	    (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) {
3716 		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
3717 		if (error != 0)
3718 			return (error);
3719 	}
3720 
3721 	switch (opt) {
3722 	case IP_FW_GET:
3723 		/*
3724 		 * pass up a copy of the current rules. Static rules
3725 		 * come first (the last of which has number IPFW_DEFAULT_RULE),
3726 		 * followed by a possibly empty list of dynamic rule.
3727 		 * The last dynamic rule has NULL in the "next" field.
3728 		 *
3729 		 * Note that the calculated size is used to bound the
3730 		 * amount of data returned to the user.  The rule set may
3731 		 * change between calculating the size and returning the
3732 		 * data in which case we'll just return what fits.
3733 		 */
3734 		for (;;) {
3735 			int len = 0, want;
3736 
3737 			size = chain->static_len;
3738 			size += ipfw_dyn_len();
3739 			if (size >= sopt->sopt_valsize)
3740 				break;
3741 			buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
3742 			IPFW_UH_RLOCK(chain);
3743 			/* check again how much space we need */
3744 			want = chain->static_len + ipfw_dyn_len();
3745 			if (size >= want)
3746 				len = ipfw_getrules(chain, buf, size);
3747 			IPFW_UH_RUNLOCK(chain);
3748 			if (size >= want)
3749 				error = sooptcopyout(sopt, buf, len);
3750 			free(buf, M_TEMP);
3751 			if (size >= want)
3752 				break;
3753 		}
3754 		break;
3755 
3756 	case IP_FW_FLUSH:
3757 		/* locking is done within del_entry() */
3758 		error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
3759 		break;
3760 
3761 	case IP_FW_ADD:
3762 		rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);
3763 		error = sooptcopyin(sopt, rule, RULE_MAXSIZE,
3764 			sizeof(struct ip_fw7) );
3765 
3766 		memset(&ci, 0, sizeof(struct rule_check_info));
3767 
3768 		/*
3769 		 * If the size of commands equals RULESIZE7 then we assume
3770 		 * a FreeBSD7.2 binary is talking to us (set is7=1).
3771 		 * is7 is persistent so the next 'ipfw list' command
3772 		 * will use this format.
3773 		 * NOTE: If wrong version is guessed (this can happen if
3774 		 *       the first ipfw command is 'ipfw [pipe] list')
3775 		 *       the ipfw binary may crash or loop infinitly...
3776 		 */
3777 		size = sopt->sopt_valsize;
3778 		if (size == RULESIZE7(rule)) {
3779 		    is7 = 1;
3780 		    error = convert_rule_to_8(rule);
3781 		    if (error) {
3782 			free(rule, M_TEMP);
3783 			return error;
3784 		    }
3785 		    size = RULESIZE(rule);
3786 		} else
3787 		    is7 = 0;
3788 		if (error == 0)
3789 			error = check_ipfw_rule0(rule, size, &ci);
3790 		if (error == 0) {
3791 			/* locking is done within add_rule() */
3792 			struct ip_fw *krule;
3793 			krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule));
3794 			ci.urule = (caddr_t)rule;
3795 			ci.krule = krule;
3796 			import_rule0(&ci);
3797 			error = commit_rules(chain, &ci, 1);
3798 			if (error != 0)
3799 				free_rule(ci.krule);
3800 			else if (sopt->sopt_dir == SOPT_GET) {
3801 				if (is7) {
3802 					error = convert_rule_to_7(rule);
3803 					size = RULESIZE7(rule);
3804 					if (error) {
3805 						free(rule, M_TEMP);
3806 						return error;
3807 					}
3808 				}
3809 				error = sooptcopyout(sopt, rule, size);
3810 			}
3811 		}
3812 		free(rule, M_TEMP);
3813 		break;
3814 
3815 	case IP_FW_DEL:
3816 		/*
3817 		 * IP_FW_DEL is used for deleting single rules or sets,
3818 		 * and (ab)used to atomically manipulate sets. Argument size
3819 		 * is used to distinguish between the two:
3820 		 *    sizeof(u_int32_t)
3821 		 *	delete single rule or set of rules,
3822 		 *	or reassign rules (or sets) to a different set.
3823 		 *    2*sizeof(u_int32_t)
3824 		 *	atomic disable/enable sets.
3825 		 *	first u_int32_t contains sets to be disabled,
3826 		 *	second u_int32_t contains sets to be enabled.
3827 		 */
3828 		error = sooptcopyin(sopt, rulenum,
3829 			2*sizeof(u_int32_t), sizeof(u_int32_t));
3830 		if (error)
3831 			break;
3832 		size = sopt->sopt_valsize;
3833 		if (size == sizeof(u_int32_t) && rulenum[0] != 0) {
3834 			/* delete or reassign, locking done in del_entry() */
3835 			error = del_entry(chain, rulenum[0]);
3836 		} else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */
3837 			IPFW_UH_WLOCK(chain);
3838 			V_set_disable =
3839 			    (V_set_disable | rulenum[0]) & ~rulenum[1] &
3840 			    ~(1<<RESVD_SET); /* set RESVD_SET always enabled */
3841 			IPFW_UH_WUNLOCK(chain);
3842 		} else
3843 			error = EINVAL;
3844 		break;
3845 
3846 	case IP_FW_ZERO:
3847 	case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */
3848 		rulenum[0] = 0;
3849 		if (sopt->sopt_val != 0) {
3850 		    error = sooptcopyin(sopt, rulenum,
3851 			    sizeof(u_int32_t), sizeof(u_int32_t));
3852 		    if (error)
3853 			break;
3854 		}
3855 		error = zero_entry(chain, rulenum[0],
3856 			sopt->sopt_name == IP_FW_RESETLOG);
3857 		break;
3858 
3859 	/*--- TABLE opcodes ---*/
3860 	case IP_FW_TABLE_ADD:
3861 	case IP_FW_TABLE_DEL:
3862 		{
3863 			ipfw_table_entry ent;
3864 			struct tentry_info tei;
3865 			struct tid_info ti;
3866 			struct table_value v;
3867 
3868 			error = sooptcopyin(sopt, &ent,
3869 			    sizeof(ent), sizeof(ent));
3870 			if (error)
3871 				break;
3872 
3873 			memset(&tei, 0, sizeof(tei));
3874 			tei.paddr = &ent.addr;
3875 			tei.subtype = AF_INET;
3876 			tei.masklen = ent.masklen;
3877 			ipfw_import_table_value_legacy(ent.value, &v);
3878 			tei.pvalue = &v;
3879 			memset(&ti, 0, sizeof(ti));
3880 			ti.uidx = ent.tbl;
3881 			ti.type = IPFW_TABLE_CIDR;
3882 
3883 			error = (opt == IP_FW_TABLE_ADD) ?
3884 			    add_table_entry(chain, &ti, &tei, 0, 1) :
3885 			    del_table_entry(chain, &ti, &tei, 0, 1);
3886 		}
3887 		break;
3888 
3889 
3890 	case IP_FW_TABLE_FLUSH:
3891 		{
3892 			u_int16_t tbl;
3893 			struct tid_info ti;
3894 
3895 			error = sooptcopyin(sopt, &tbl,
3896 			    sizeof(tbl), sizeof(tbl));
3897 			if (error)
3898 				break;
3899 			memset(&ti, 0, sizeof(ti));
3900 			ti.uidx = tbl;
3901 			error = flush_table(chain, &ti);
3902 		}
3903 		break;
3904 
3905 	case IP_FW_TABLE_GETSIZE:
3906 		{
3907 			u_int32_t tbl, cnt;
3908 			struct tid_info ti;
3909 
3910 			if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
3911 			    sizeof(tbl))))
3912 				break;
3913 			memset(&ti, 0, sizeof(ti));
3914 			ti.uidx = tbl;
3915 			IPFW_RLOCK(chain);
3916 			error = ipfw_count_table(chain, &ti, &cnt);
3917 			IPFW_RUNLOCK(chain);
3918 			if (error)
3919 				break;
3920 			error = sooptcopyout(sopt, &cnt, sizeof(cnt));
3921 		}
3922 		break;
3923 
3924 	case IP_FW_TABLE_LIST:
3925 		{
3926 			ipfw_table *tbl;
3927 			struct tid_info ti;
3928 
3929 			if (sopt->sopt_valsize < sizeof(*tbl)) {
3930 				error = EINVAL;
3931 				break;
3932 			}
3933 			size = sopt->sopt_valsize;
3934 			tbl = malloc(size, M_TEMP, M_WAITOK);
3935 			error = sooptcopyin(sopt, tbl, size, sizeof(*tbl));
3936 			if (error) {
3937 				free(tbl, M_TEMP);
3938 				break;
3939 			}
3940 			tbl->size = (size - sizeof(*tbl)) /
3941 			    sizeof(ipfw_table_entry);
3942 			memset(&ti, 0, sizeof(ti));
3943 			ti.uidx = tbl->tbl;
3944 			IPFW_RLOCK(chain);
3945 			error = ipfw_dump_table_legacy(chain, &ti, tbl);
3946 			IPFW_RUNLOCK(chain);
3947 			if (error) {
3948 				free(tbl, M_TEMP);
3949 				break;
3950 			}
3951 			error = sooptcopyout(sopt, tbl, size);
3952 			free(tbl, M_TEMP);
3953 		}
3954 		break;
3955 
3956 	/*--- NAT operations are protected by the IPFW_LOCK ---*/
3957 	case IP_FW_NAT_CFG:
3958 		if (IPFW_NAT_LOADED)
3959 			error = ipfw_nat_cfg_ptr(sopt);
3960 		else {
3961 			printf("IP_FW_NAT_CFG: %s\n",
3962 			    "ipfw_nat not present, please load it");
3963 			error = EINVAL;
3964 		}
3965 		break;
3966 
3967 	case IP_FW_NAT_DEL:
3968 		if (IPFW_NAT_LOADED)
3969 			error = ipfw_nat_del_ptr(sopt);
3970 		else {
3971 			printf("IP_FW_NAT_DEL: %s\n",
3972 			    "ipfw_nat not present, please load it");
3973 			error = EINVAL;
3974 		}
3975 		break;
3976 
3977 	case IP_FW_NAT_GET_CONFIG:
3978 		if (IPFW_NAT_LOADED)
3979 			error = ipfw_nat_get_cfg_ptr(sopt);
3980 		else {
3981 			printf("IP_FW_NAT_GET_CFG: %s\n",
3982 			    "ipfw_nat not present, please load it");
3983 			error = EINVAL;
3984 		}
3985 		break;
3986 
3987 	case IP_FW_NAT_GET_LOG:
3988 		if (IPFW_NAT_LOADED)
3989 			error = ipfw_nat_get_log_ptr(sopt);
3990 		else {
3991 			printf("IP_FW_NAT_GET_LOG: %s\n",
3992 			    "ipfw_nat not present, please load it");
3993 			error = EINVAL;
3994 		}
3995 		break;
3996 
3997 	default:
3998 		printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);
3999 		error = EINVAL;
4000 	}
4001 
4002 	return (error);
4003 #undef RULE_MAXSIZE
4004 }
4005 #define	RULE_MAXSIZE	(256*sizeof(u_int32_t))
4006 
4007 /* Functions to convert rules 7.2 <==> 8.0 */
4008 static int
4009 convert_rule_to_7(struct ip_fw_rule0 *rule)
4010 {
4011 	/* Used to modify original rule */
4012 	struct ip_fw7 *rule7 = (struct ip_fw7 *)rule;
4013 	/* copy of original rule, version 8 */
4014 	struct ip_fw_rule0 *tmp;
4015 
4016 	/* Used to copy commands */
4017 	ipfw_insn *ccmd, *dst;
4018 	int ll = 0, ccmdlen = 0;
4019 
4020 	tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
4021 	if (tmp == NULL) {
4022 		return 1; //XXX error
4023 	}
4024 	bcopy(rule, tmp, RULE_MAXSIZE);
4025 
4026 	/* Copy fields */
4027 	//rule7->_pad = tmp->_pad;
4028 	rule7->set = tmp->set;
4029 	rule7->rulenum = tmp->rulenum;
4030 	rule7->cmd_len = tmp->cmd_len;
4031 	rule7->act_ofs = tmp->act_ofs;
4032 	rule7->next_rule = (struct ip_fw7 *)tmp->next_rule;
4033 	rule7->cmd_len = tmp->cmd_len;
4034 	rule7->pcnt = tmp->pcnt;
4035 	rule7->bcnt = tmp->bcnt;
4036 	rule7->timestamp = tmp->timestamp;
4037 
4038 	/* Copy commands */
4039 	for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ;
4040 			ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
4041 		ccmdlen = F_LEN(ccmd);
4042 
4043 		bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
4044 
4045 		if (dst->opcode > O_NAT)
4046 			/* O_REASS doesn't exists in 7.2 version, so
4047 			 * decrement opcode if it is after O_REASS
4048 			 */
4049 			dst->opcode--;
4050 
4051 		if (ccmdlen > ll) {
4052 			printf("ipfw: opcode %d size truncated\n",
4053 				ccmd->opcode);
4054 			return EINVAL;
4055 		}
4056 	}
4057 	free(tmp, M_TEMP);
4058 
4059 	return 0;
4060 }
4061 
4062 static int
4063 convert_rule_to_8(struct ip_fw_rule0 *rule)
4064 {
4065 	/* Used to modify original rule */
4066 	struct ip_fw7 *rule7 = (struct ip_fw7 *) rule;
4067 
4068 	/* Used to copy commands */
4069 	ipfw_insn *ccmd, *dst;
4070 	int ll = 0, ccmdlen = 0;
4071 
4072 	/* Copy of original rule */
4073 	struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
4074 	if (tmp == NULL) {
4075 		return 1; //XXX error
4076 	}
4077 
4078 	bcopy(rule7, tmp, RULE_MAXSIZE);
4079 
4080 	for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ;
4081 			ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
4082 		ccmdlen = F_LEN(ccmd);
4083 
4084 		bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
4085 
4086 		if (dst->opcode > O_NAT)
4087 			/* O_REASS doesn't exists in 7.2 version, so
4088 			 * increment opcode if it is after O_REASS
4089 			 */
4090 			dst->opcode++;
4091 
4092 		if (ccmdlen > ll) {
4093 			printf("ipfw: opcode %d size truncated\n",
4094 			    ccmd->opcode);
4095 			return EINVAL;
4096 		}
4097 	}
4098 
4099 	rule->_pad = tmp->_pad;
4100 	rule->set = tmp->set;
4101 	rule->rulenum = tmp->rulenum;
4102 	rule->cmd_len = tmp->cmd_len;
4103 	rule->act_ofs = tmp->act_ofs;
4104 	rule->next_rule = (struct ip_fw *)tmp->next_rule;
4105 	rule->cmd_len = tmp->cmd_len;
4106 	rule->id = 0; /* XXX see if is ok = 0 */
4107 	rule->pcnt = tmp->pcnt;
4108 	rule->bcnt = tmp->bcnt;
4109 	rule->timestamp = tmp->timestamp;
4110 
4111 	free (tmp, M_TEMP);
4112 	return 0;
4113 }
4114 
4115 /*
4116  * Named object api
4117  *
4118  */
4119 
4120 void
4121 ipfw_init_srv(struct ip_fw_chain *ch)
4122 {
4123 
4124 	ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT);
4125 	ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT,
4126 	    M_IPFW, M_WAITOK | M_ZERO);
4127 }
4128 
4129 void
4130 ipfw_destroy_srv(struct ip_fw_chain *ch)
4131 {
4132 
4133 	free(ch->srvstate, M_IPFW);
4134 	ipfw_objhash_destroy(ch->srvmap);
4135 }
4136 
4137 /*
4138  * Allocate new bitmask which can be used to enlarge/shrink
4139  * named instance index.
4140  */
4141 void
4142 ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks)
4143 {
4144 	size_t size;
4145 	int max_blocks;
4146 	u_long *idx_mask;
4147 
4148 	KASSERT((items % BLOCK_ITEMS) == 0,
4149 	   ("bitmask size needs to power of 2 and greater or equal to %zu",
4150 	    BLOCK_ITEMS));
4151 
4152 	max_blocks = items / BLOCK_ITEMS;
4153 	size = items / 8;
4154 	idx_mask = malloc(size * IPFW_MAX_SETS, M_IPFW, M_WAITOK);
4155 	/* Mark all as free */
4156 	memset(idx_mask, 0xFF, size * IPFW_MAX_SETS);
4157 	*idx_mask &= ~(u_long)1; /* Skip index 0 */
4158 
4159 	*idx = idx_mask;
4160 	*pblocks = max_blocks;
4161 }
4162 
4163 /*
4164  * Copy current bitmask index to new one.
4165  */
4166 void
4167 ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks)
4168 {
4169 	int old_blocks, new_blocks;
4170 	u_long *old_idx, *new_idx;
4171 	int i;
4172 
4173 	old_idx = ni->idx_mask;
4174 	old_blocks = ni->max_blocks;
4175 	new_idx = *idx;
4176 	new_blocks = *blocks;
4177 
4178 	for (i = 0; i < IPFW_MAX_SETS; i++) {
4179 		memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i],
4180 		    old_blocks * sizeof(u_long));
4181 	}
4182 }
4183 
4184 /*
4185  * Swaps current @ni index with new one.
4186  */
4187 void
4188 ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks)
4189 {
4190 	int old_blocks;
4191 	u_long *old_idx;
4192 
4193 	old_idx = ni->idx_mask;
4194 	old_blocks = ni->max_blocks;
4195 
4196 	ni->idx_mask = *idx;
4197 	ni->max_blocks = *blocks;
4198 
4199 	/* Save old values */
4200 	*idx = old_idx;
4201 	*blocks = old_blocks;
4202 }
4203 
4204 void
4205 ipfw_objhash_bitmap_free(void *idx, int blocks)
4206 {
4207 
4208 	free(idx, M_IPFW);
4209 }
4210 
4211 /*
4212  * Creates named hash instance.
4213  * Must be called without holding any locks.
4214  * Return pointer to new instance.
4215  */
4216 struct namedobj_instance *
4217 ipfw_objhash_create(uint32_t items)
4218 {
4219 	struct namedobj_instance *ni;
4220 	int i;
4221 	size_t size;
4222 
4223 	size = sizeof(struct namedobj_instance) +
4224 	    sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE +
4225 	    sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE;
4226 
4227 	ni = malloc(size, M_IPFW, M_WAITOK | M_ZERO);
4228 	ni->nn_size = NAMEDOBJ_HASH_SIZE;
4229 	ni->nv_size = NAMEDOBJ_HASH_SIZE;
4230 
4231 	ni->names = (struct namedobjects_head *)(ni +1);
4232 	ni->values = &ni->names[ni->nn_size];
4233 
4234 	for (i = 0; i < ni->nn_size; i++)
4235 		TAILQ_INIT(&ni->names[i]);
4236 
4237 	for (i = 0; i < ni->nv_size; i++)
4238 		TAILQ_INIT(&ni->values[i]);
4239 
4240 	/* Set default hashing/comparison functions */
4241 	ni->hash_f = objhash_hash_name;
4242 	ni->cmp_f = objhash_cmp_name;
4243 
4244 	/* Allocate bitmask separately due to possible resize */
4245 	ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks);
4246 
4247 	return (ni);
4248 }
4249 
4250 void
4251 ipfw_objhash_destroy(struct namedobj_instance *ni)
4252 {
4253 
4254 	free(ni->idx_mask, M_IPFW);
4255 	free(ni, M_IPFW);
4256 }
4257 
4258 void
4259 ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f,
4260     objhash_cmp_f *cmp_f)
4261 {
4262 
4263 	ni->hash_f = hash_f;
4264 	ni->cmp_f = cmp_f;
4265 }
4266 
4267 static uint32_t
4268 objhash_hash_name(struct namedobj_instance *ni, const void *name, uint32_t set)
4269 {
4270 
4271 	return (fnv_32_str((const char *)name, FNV1_32_INIT));
4272 }
4273 
4274 static int
4275 objhash_cmp_name(struct named_object *no, const void *name, uint32_t set)
4276 {
4277 
4278 	if ((strcmp(no->name, (const char *)name) == 0) && (no->set == set))
4279 		return (0);
4280 
4281 	return (1);
4282 }
4283 
4284 static uint32_t
4285 objhash_hash_idx(struct namedobj_instance *ni, uint32_t val)
4286 {
4287 	uint32_t v;
4288 
4289 	v = val % (ni->nv_size - 1);
4290 
4291 	return (v);
4292 }
4293 
4294 struct named_object *
4295 ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name)
4296 {
4297 	struct named_object *no;
4298 	uint32_t hash;
4299 
4300 	hash = ni->hash_f(ni, name, set) % ni->nn_size;
4301 
4302 	TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
4303 		if (ni->cmp_f(no, name, set) == 0)
4304 			return (no);
4305 	}
4306 
4307 	return (NULL);
4308 }
4309 
4310 /*
4311  * Find named object by @uid.
4312  * Check @tlvs for valid data inside.
4313  *
4314  * Returns pointer to found TLV or NULL.
4315  */
4316 ipfw_obj_ntlv *
4317 ipfw_find_name_tlv_type(void *tlvs, int len, uint16_t uidx, uint32_t etlv)
4318 {
4319 	ipfw_obj_ntlv *ntlv;
4320 	uintptr_t pa, pe;
4321 	int l;
4322 
4323 	pa = (uintptr_t)tlvs;
4324 	pe = pa + len;
4325 	l = 0;
4326 	for (; pa < pe; pa += l) {
4327 		ntlv = (ipfw_obj_ntlv *)pa;
4328 		l = ntlv->head.length;
4329 
4330 		if (l != sizeof(*ntlv))
4331 			return (NULL);
4332 
4333 		if (ntlv->idx != uidx)
4334 			continue;
4335 		/*
4336 		 * When userland has specified zero TLV type, do
4337 		 * not compare it with eltv. In some cases userland
4338 		 * doesn't know what type should it have. Use only
4339 		 * uidx and name for search named_object.
4340 		 */
4341 		if (ntlv->head.type != 0 &&
4342 		    ntlv->head.type != (uint16_t)etlv)
4343 			continue;
4344 
4345 		if (ipfw_check_object_name_generic(ntlv->name) != 0)
4346 			return (NULL);
4347 
4348 		return (ntlv);
4349 	}
4350 
4351 	return (NULL);
4352 }
4353 
4354 /*
4355  * Finds object config based on either legacy index
4356  * or name in ntlv.
4357  * Note @ti structure contains unchecked data from userland.
4358  *
4359  * Returns 0 in success and fills in @pno with found config
4360  */
4361 int
4362 ipfw_objhash_find_type(struct namedobj_instance *ni, struct tid_info *ti,
4363     uint32_t etlv, struct named_object **pno)
4364 {
4365 	char *name;
4366 	ipfw_obj_ntlv *ntlv;
4367 	uint32_t set;
4368 
4369 	if (ti->tlvs == NULL)
4370 		return (EINVAL);
4371 
4372 	ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx, etlv);
4373 	if (ntlv == NULL)
4374 		return (EINVAL);
4375 	name = ntlv->name;
4376 
4377 	/*
4378 	 * Use set provided by @ti instead of @ntlv one.
4379 	 * This is needed due to different sets behavior
4380 	 * controlled by V_fw_tables_sets.
4381 	 */
4382 	set = ti->set;
4383 	*pno = ipfw_objhash_lookup_name(ni, set, name);
4384 	if (*pno == NULL)
4385 		return (ESRCH);
4386 	return (0);
4387 }
4388 
4389 /*
4390  * Find named object by name, considering also its TLV type.
4391  */
4392 struct named_object *
4393 ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set,
4394     uint32_t type, const char *name)
4395 {
4396 	struct named_object *no;
4397 	uint32_t hash;
4398 
4399 	hash = ni->hash_f(ni, name, set) % ni->nn_size;
4400 
4401 	TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
4402 		if (ni->cmp_f(no, name, set) == 0 &&
4403 		    no->etlv == (uint16_t)type)
4404 			return (no);
4405 	}
4406 
4407 	return (NULL);
4408 }
4409 
4410 struct named_object *
4411 ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx)
4412 {
4413 	struct named_object *no;
4414 	uint32_t hash;
4415 
4416 	hash = objhash_hash_idx(ni, kidx);
4417 
4418 	TAILQ_FOREACH(no, &ni->values[hash], nv_next) {
4419 		if (no->kidx == kidx)
4420 			return (no);
4421 	}
4422 
4423 	return (NULL);
4424 }
4425 
4426 int
4427 ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a,
4428     struct named_object *b)
4429 {
4430 
4431 	if ((strcmp(a->name, b->name) == 0) && a->set == b->set)
4432 		return (1);
4433 
4434 	return (0);
4435 }
4436 
4437 void
4438 ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no)
4439 {
4440 	uint32_t hash;
4441 
4442 	hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
4443 	TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next);
4444 
4445 	hash = objhash_hash_idx(ni, no->kidx);
4446 	TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next);
4447 
4448 	ni->count++;
4449 }
4450 
4451 void
4452 ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no)
4453 {
4454 	uint32_t hash;
4455 
4456 	hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
4457 	TAILQ_REMOVE(&ni->names[hash], no, nn_next);
4458 
4459 	hash = objhash_hash_idx(ni, no->kidx);
4460 	TAILQ_REMOVE(&ni->values[hash], no, nv_next);
4461 
4462 	ni->count--;
4463 }
4464 
4465 uint32_t
4466 ipfw_objhash_count(struct namedobj_instance *ni)
4467 {
4468 
4469 	return (ni->count);
4470 }
4471 
4472 uint32_t
4473 ipfw_objhash_count_type(struct namedobj_instance *ni, uint16_t type)
4474 {
4475 	struct named_object *no;
4476 	uint32_t count;
4477 	int i;
4478 
4479 	count = 0;
4480 	for (i = 0; i < ni->nn_size; i++) {
4481 		TAILQ_FOREACH(no, &ni->names[i], nn_next) {
4482 			if (no->etlv == type)
4483 				count++;
4484 		}
4485 	}
4486 	return (count);
4487 }
4488 
4489 /*
4490  * Runs @func for each found named object.
4491  * It is safe to delete objects from callback
4492  */
4493 int
4494 ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg)
4495 {
4496 	struct named_object *no, *no_tmp;
4497 	int i, ret;
4498 
4499 	for (i = 0; i < ni->nn_size; i++) {
4500 		TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
4501 			ret = f(ni, no, arg);
4502 			if (ret != 0)
4503 				return (ret);
4504 		}
4505 	}
4506 	return (0);
4507 }
4508 
4509 /*
4510  * Runs @f for each found named object with type @type.
4511  * It is safe to delete objects from callback
4512  */
4513 int
4514 ipfw_objhash_foreach_type(struct namedobj_instance *ni, objhash_cb_t *f,
4515     void *arg, uint16_t type)
4516 {
4517 	struct named_object *no, *no_tmp;
4518 	int i, ret;
4519 
4520 	for (i = 0; i < ni->nn_size; i++) {
4521 		TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
4522 			if (no->etlv != type)
4523 				continue;
4524 			ret = f(ni, no, arg);
4525 			if (ret != 0)
4526 				return (ret);
4527 		}
4528 	}
4529 	return (0);
4530 }
4531 
4532 /*
4533  * Removes index from given set.
4534  * Returns 0 on success.
4535  */
4536 int
4537 ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx)
4538 {
4539 	u_long *mask;
4540 	int i, v;
4541 
4542 	i = idx / BLOCK_ITEMS;
4543 	v = idx % BLOCK_ITEMS;
4544 
4545 	if (i >= ni->max_blocks)
4546 		return (1);
4547 
4548 	mask = &ni->idx_mask[i];
4549 
4550 	if ((*mask & ((u_long)1 << v)) != 0)
4551 		return (1);
4552 
4553 	/* Mark as free */
4554 	*mask |= (u_long)1 << v;
4555 
4556 	/* Update free offset */
4557 	if (ni->free_off[0] > i)
4558 		ni->free_off[0] = i;
4559 
4560 	return (0);
4561 }
4562 
4563 /*
4564  * Allocate new index in given instance and stores in in @pidx.
4565  * Returns 0 on success.
4566  */
4567 int
4568 ipfw_objhash_alloc_idx(void *n, uint16_t *pidx)
4569 {
4570 	struct namedobj_instance *ni;
4571 	u_long *mask;
4572 	int i, off, v;
4573 
4574 	ni = (struct namedobj_instance *)n;
4575 
4576 	off = ni->free_off[0];
4577 	mask = &ni->idx_mask[off];
4578 
4579 	for (i = off; i < ni->max_blocks; i++, mask++) {
4580 		if ((v = ffsl(*mask)) == 0)
4581 			continue;
4582 
4583 		/* Mark as busy */
4584 		*mask &= ~ ((u_long)1 << (v - 1));
4585 
4586 		ni->free_off[0] = i;
4587 
4588 		v = BLOCK_ITEMS * i + v - 1;
4589 
4590 		*pidx = v;
4591 		return (0);
4592 	}
4593 
4594 	return (1);
4595 }
4596 
4597 /* end of file */
4598