xref: /freebsd/sys/netpfil/ipfw/ip_fw_sockopt.c (revision 55620f43deef5c0eb5b4b0f675de18b30c8d1c2d)
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 		case O_PROTO:
1683 		case O_IP_SRC_ME:
1684 		case O_IP_DST_ME:
1685 		case O_LAYER2:
1686 		case O_IN:
1687 		case O_FRAG:
1688 		case O_DIVERTED:
1689 		case O_IPOPT:
1690 		case O_IPTOS:
1691 		case O_IPPRECEDENCE:
1692 		case O_IPVER:
1693 		case O_SOCKARG:
1694 		case O_TCPFLAGS:
1695 		case O_TCPOPTS:
1696 		case O_ESTAB:
1697 		case O_VERREVPATH:
1698 		case O_VERSRCREACH:
1699 		case O_ANTISPOOF:
1700 		case O_IPSEC:
1701 #ifdef INET6
1702 		case O_IP6_SRC_ME:
1703 		case O_IP6_DST_ME:
1704 		case O_EXT_HDR:
1705 		case O_IP6:
1706 #endif
1707 		case O_IP4:
1708 		case O_TAG:
1709 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1710 				goto bad_size;
1711 			break;
1712 
1713 		case O_EXTERNAL_ACTION:
1714 			if (cmd->arg1 == 0 ||
1715 			    cmdlen != F_INSN_SIZE(ipfw_insn)) {
1716 				printf("ipfw: invalid external "
1717 				    "action opcode\n");
1718 				return (EINVAL);
1719 			}
1720 			ci->object_opcodes++;
1721 			/* Do we have O_EXTERNAL_INSTANCE opcode? */
1722 			if (l != cmdlen) {
1723 				l -= cmdlen;
1724 				cmd += cmdlen;
1725 				cmdlen = F_LEN(cmd);
1726 				if (cmd->opcode != O_EXTERNAL_INSTANCE) {
1727 					printf("ipfw: invalid opcode "
1728 					    "next to external action %u\n",
1729 					    cmd->opcode);
1730 					return (EINVAL);
1731 				}
1732 				if (cmd->arg1 == 0 ||
1733 				    cmdlen != F_INSN_SIZE(ipfw_insn)) {
1734 					printf("ipfw: invalid external "
1735 					    "action instance opcode\n");
1736 					return (EINVAL);
1737 				}
1738 				ci->object_opcodes++;
1739 			}
1740 			goto check_action;
1741 
1742 		case O_FIB:
1743 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1744 				goto bad_size;
1745 			if (cmd->arg1 >= rt_numfibs) {
1746 				printf("ipfw: invalid fib number %d\n",
1747 					cmd->arg1);
1748 				return EINVAL;
1749 			}
1750 			break;
1751 
1752 		case O_SETFIB:
1753 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1754 				goto bad_size;
1755 			if ((cmd->arg1 != IP_FW_TARG) &&
1756 			    ((cmd->arg1 & 0x7FFF) >= rt_numfibs)) {
1757 				printf("ipfw: invalid fib number %d\n",
1758 					cmd->arg1 & 0x7FFF);
1759 				return EINVAL;
1760 			}
1761 			goto check_action;
1762 
1763 		case O_UID:
1764 		case O_GID:
1765 		case O_JAIL:
1766 		case O_IP_SRC:
1767 		case O_IP_DST:
1768 		case O_TCPSEQ:
1769 		case O_TCPACK:
1770 		case O_PROB:
1771 		case O_ICMPTYPE:
1772 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1773 				goto bad_size;
1774 			break;
1775 
1776 		case O_LIMIT:
1777 			if (cmdlen != F_INSN_SIZE(ipfw_insn_limit))
1778 				goto bad_size;
1779 			break;
1780 
1781 		case O_LOG:
1782 			if (cmdlen != F_INSN_SIZE(ipfw_insn_log))
1783 				goto bad_size;
1784 
1785 			((ipfw_insn_log *)cmd)->log_left =
1786 			    ((ipfw_insn_log *)cmd)->max_log;
1787 
1788 			break;
1789 
1790 		case O_IP_SRC_MASK:
1791 		case O_IP_DST_MASK:
1792 			/* only odd command lengths */
1793 			if ((cmdlen & 1) == 0)
1794 				goto bad_size;
1795 			break;
1796 
1797 		case O_IP_SRC_SET:
1798 		case O_IP_DST_SET:
1799 			if (cmd->arg1 == 0 || cmd->arg1 > 256) {
1800 				printf("ipfw: invalid set size %d\n",
1801 					cmd->arg1);
1802 				return EINVAL;
1803 			}
1804 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
1805 			    (cmd->arg1+31)/32 )
1806 				goto bad_size;
1807 			break;
1808 
1809 		case O_IP_SRC_LOOKUP:
1810 		case O_IP_DST_LOOKUP:
1811 			if (cmd->arg1 >= V_fw_tables_max) {
1812 				printf("ipfw: invalid table number %d\n",
1813 				    cmd->arg1);
1814 				return (EINVAL);
1815 			}
1816 			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
1817 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
1818 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1819 				goto bad_size;
1820 			ci->object_opcodes++;
1821 			break;
1822 		case O_IP_FLOW_LOOKUP:
1823 			if (cmd->arg1 >= V_fw_tables_max) {
1824 				printf("ipfw: invalid table number %d\n",
1825 				    cmd->arg1);
1826 				return (EINVAL);
1827 			}
1828 			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
1829 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1830 				goto bad_size;
1831 			ci->object_opcodes++;
1832 			break;
1833 		case O_MACADDR2:
1834 			if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
1835 				goto bad_size;
1836 			break;
1837 
1838 		case O_NOP:
1839 		case O_IPID:
1840 		case O_IPTTL:
1841 		case O_IPLEN:
1842 		case O_TCPDATALEN:
1843 		case O_TCPWIN:
1844 		case O_TAGGED:
1845 			if (cmdlen < 1 || cmdlen > 31)
1846 				goto bad_size;
1847 			break;
1848 
1849 		case O_DSCP:
1850 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1)
1851 				goto bad_size;
1852 			break;
1853 
1854 		case O_MAC_TYPE:
1855 		case O_IP_SRCPORT:
1856 		case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
1857 			if (cmdlen < 2 || cmdlen > 31)
1858 				goto bad_size;
1859 			break;
1860 
1861 		case O_RECV:
1862 		case O_XMIT:
1863 		case O_VIA:
1864 			if (cmdlen != F_INSN_SIZE(ipfw_insn_if))
1865 				goto bad_size;
1866 			ci->object_opcodes++;
1867 			break;
1868 
1869 		case O_ALTQ:
1870 			if (cmdlen != F_INSN_SIZE(ipfw_insn_altq))
1871 				goto bad_size;
1872 			break;
1873 
1874 		case O_PIPE:
1875 		case O_QUEUE:
1876 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1877 				goto bad_size;
1878 			goto check_action;
1879 
1880 		case O_FORWARD_IP:
1881 			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa))
1882 				goto bad_size;
1883 			goto check_action;
1884 #ifdef INET6
1885 		case O_FORWARD_IP6:
1886 			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6))
1887 				goto bad_size;
1888 			goto check_action;
1889 #endif /* INET6 */
1890 
1891 		case O_DIVERT:
1892 		case O_TEE:
1893 			if (ip_divert_ptr == NULL)
1894 				return EINVAL;
1895 			else
1896 				goto check_size;
1897 		case O_NETGRAPH:
1898 		case O_NGTEE:
1899 			if (ng_ipfw_input_p == NULL)
1900 				return EINVAL;
1901 			else
1902 				goto check_size;
1903 		case O_NAT:
1904 			if (!IPFW_NAT_LOADED)
1905 				return EINVAL;
1906 			if (cmdlen != F_INSN_SIZE(ipfw_insn_nat))
1907  				goto bad_size;
1908  			goto check_action;
1909 		case O_FORWARD_MAC: /* XXX not implemented yet */
1910 		case O_CHECK_STATE:
1911 		case O_COUNT:
1912 		case O_ACCEPT:
1913 		case O_DENY:
1914 		case O_REJECT:
1915 		case O_SETDSCP:
1916 #ifdef INET6
1917 		case O_UNREACH6:
1918 #endif
1919 		case O_SKIPTO:
1920 		case O_REASS:
1921 		case O_CALLRETURN:
1922 check_size:
1923 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1924 				goto bad_size;
1925 check_action:
1926 			if (have_action) {
1927 				printf("ipfw: opcode %d, multiple actions"
1928 					" not allowed\n",
1929 					cmd->opcode);
1930 				return (EINVAL);
1931 			}
1932 			have_action = 1;
1933 			if (l != cmdlen) {
1934 				printf("ipfw: opcode %d, action must be"
1935 					" last opcode\n",
1936 					cmd->opcode);
1937 				return (EINVAL);
1938 			}
1939 			break;
1940 #ifdef INET6
1941 		case O_IP6_SRC:
1942 		case O_IP6_DST:
1943 			if (cmdlen != F_INSN_SIZE(struct in6_addr) +
1944 			    F_INSN_SIZE(ipfw_insn))
1945 				goto bad_size;
1946 			break;
1947 
1948 		case O_FLOW6ID:
1949 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
1950 			    ((ipfw_insn_u32 *)cmd)->o.arg1)
1951 				goto bad_size;
1952 			break;
1953 
1954 		case O_IP6_SRC_MASK:
1955 		case O_IP6_DST_MASK:
1956 			if ( !(cmdlen & 1) || cmdlen > 127)
1957 				goto bad_size;
1958 			break;
1959 		case O_ICMP6TYPE:
1960 			if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
1961 				goto bad_size;
1962 			break;
1963 #endif
1964 
1965 		default:
1966 			switch (cmd->opcode) {
1967 #ifndef INET6
1968 			case O_IP6_SRC_ME:
1969 			case O_IP6_DST_ME:
1970 			case O_EXT_HDR:
1971 			case O_IP6:
1972 			case O_UNREACH6:
1973 			case O_IP6_SRC:
1974 			case O_IP6_DST:
1975 			case O_FLOW6ID:
1976 			case O_IP6_SRC_MASK:
1977 			case O_IP6_DST_MASK:
1978 			case O_ICMP6TYPE:
1979 				printf("ipfw: no IPv6 support in kernel\n");
1980 				return (EPROTONOSUPPORT);
1981 #endif
1982 			default:
1983 				printf("ipfw: opcode %d, unknown opcode\n",
1984 					cmd->opcode);
1985 				return (EINVAL);
1986 			}
1987 		}
1988 	}
1989 	if (have_action == 0) {
1990 		printf("ipfw: missing action\n");
1991 		return (EINVAL);
1992 	}
1993 	return 0;
1994 
1995 bad_size:
1996 	printf("ipfw: opcode %d size %d wrong\n",
1997 		cmd->opcode, cmdlen);
1998 	return (EINVAL);
1999 }
2000 
2001 
2002 /*
2003  * Translation of requests for compatibility with FreeBSD 7.2/8.
2004  * a static variable tells us if we have an old client from userland,
2005  * and if necessary we translate requests and responses between the
2006  * two formats.
2007  */
2008 static int is7 = 0;
2009 
2010 struct ip_fw7 {
2011 	struct ip_fw7	*next;		/* linked list of rules     */
2012 	struct ip_fw7	*next_rule;	/* ptr to next [skipto] rule    */
2013 	/* 'next_rule' is used to pass up 'set_disable' status      */
2014 
2015 	uint16_t	act_ofs;	/* offset of action in 32-bit units */
2016 	uint16_t	cmd_len;	/* # of 32-bit words in cmd */
2017 	uint16_t	rulenum;	/* rule number          */
2018 	uint8_t		set;		/* rule set (0..31)     */
2019 	// #define RESVD_SET   31  /* set for default and persistent rules */
2020 	uint8_t		_pad;		/* padding          */
2021 	// uint32_t        id;             /* rule id, only in v.8 */
2022 	/* These fields are present in all rules.           */
2023 	uint64_t	pcnt;		/* Packet counter       */
2024 	uint64_t	bcnt;		/* Byte counter         */
2025 	uint32_t	timestamp;	/* tv_sec of last match     */
2026 
2027 	ipfw_insn	cmd[1];		/* storage for commands     */
2028 };
2029 
2030 static int convert_rule_to_7(struct ip_fw_rule0 *rule);
2031 static int convert_rule_to_8(struct ip_fw_rule0 *rule);
2032 
2033 #ifndef RULESIZE7
2034 #define RULESIZE7(rule)  (sizeof(struct ip_fw7) + \
2035 	((struct ip_fw7 *)(rule))->cmd_len * 4 - 4)
2036 #endif
2037 
2038 
2039 /*
2040  * Copy the static and dynamic rules to the supplied buffer
2041  * and return the amount of space actually used.
2042  * Must be run under IPFW_UH_RLOCK
2043  */
2044 static size_t
2045 ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
2046 {
2047 	char *bp = buf;
2048 	char *ep = bp + space;
2049 	struct ip_fw *rule;
2050 	struct ip_fw_rule0 *dst;
2051 	int error, i, l, warnflag;
2052 	time_t	boot_seconds;
2053 
2054 	warnflag = 0;
2055 
2056         boot_seconds = boottime.tv_sec;
2057 	for (i = 0; i < chain->n_rules; i++) {
2058 		rule = chain->map[i];
2059 
2060 		if (is7) {
2061 		    /* Convert rule to FreeBSd 7.2 format */
2062 		    l = RULESIZE7(rule);
2063 		    if (bp + l + sizeof(uint32_t) <= ep) {
2064 			bcopy(rule, bp, l + sizeof(uint32_t));
2065 			error = set_legacy_obj_kidx(chain,
2066 			    (struct ip_fw_rule0 *)bp);
2067 			if (error != 0)
2068 				return (0);
2069 			error = convert_rule_to_7((struct ip_fw_rule0 *) bp);
2070 			if (error)
2071 				return 0; /*XXX correct? */
2072 			/*
2073 			 * XXX HACK. Store the disable mask in the "next"
2074 			 * pointer in a wild attempt to keep the ABI the same.
2075 			 * Why do we do this on EVERY rule?
2076 			 */
2077 			bcopy(&V_set_disable,
2078 				&(((struct ip_fw7 *)bp)->next_rule),
2079 				sizeof(V_set_disable));
2080 			if (((struct ip_fw7 *)bp)->timestamp)
2081 			    ((struct ip_fw7 *)bp)->timestamp += boot_seconds;
2082 			bp += l;
2083 		    }
2084 		    continue; /* go to next rule */
2085 		}
2086 
2087 		l = RULEUSIZE0(rule);
2088 		if (bp + l > ep) { /* should not happen */
2089 			printf("overflow dumping static rules\n");
2090 			break;
2091 		}
2092 		dst = (struct ip_fw_rule0 *)bp;
2093 		export_rule0(rule, dst, l);
2094 		error = set_legacy_obj_kidx(chain, dst);
2095 
2096 		/*
2097 		 * XXX HACK. Store the disable mask in the "next"
2098 		 * pointer in a wild attempt to keep the ABI the same.
2099 		 * Why do we do this on EVERY rule?
2100 		 *
2101 		 * XXX: "ipfw set show" (ab)uses IP_FW_GET to read disabled mask
2102 		 * so we need to fail _after_ saving at least one mask.
2103 		 */
2104 		bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable));
2105 		if (dst->timestamp)
2106 			dst->timestamp += boot_seconds;
2107 		bp += l;
2108 
2109 		if (error != 0) {
2110 			if (error == 2) {
2111 				/* Non-fatal table rewrite error. */
2112 				warnflag = 1;
2113 				continue;
2114 			}
2115 			printf("Stop on rule %d. Fail to convert table\n",
2116 			    rule->rulenum);
2117 			break;
2118 		}
2119 	}
2120 	if (warnflag != 0)
2121 		printf("ipfw: process %s is using legacy interfaces,"
2122 		    " consider rebuilding\n", "");
2123 	ipfw_get_dynamic(chain, &bp, ep); /* protected by the dynamic lock */
2124 	return (bp - (char *)buf);
2125 }
2126 
2127 
2128 struct dump_args {
2129 	uint32_t	b;	/* start rule */
2130 	uint32_t	e;	/* end rule */
2131 	uint32_t	rcount;	/* number of rules */
2132 	uint32_t	rsize;	/* rules size */
2133 	uint32_t	tcount;	/* number of tables */
2134 	int		rcounters;	/* counters */
2135 };
2136 
2137 void
2138 ipfw_export_obj_ntlv(struct named_object *no, ipfw_obj_ntlv *ntlv)
2139 {
2140 
2141 	ntlv->head.type = no->etlv;
2142 	ntlv->head.length = sizeof(*ntlv);
2143 	ntlv->idx = no->kidx;
2144 	strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
2145 }
2146 
2147 /*
2148  * Export named object info in instance @ni, identified by @kidx
2149  * to ipfw_obj_ntlv. TLV is allocated from @sd space.
2150  *
2151  * Returns 0 on success.
2152  */
2153 static int
2154 export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
2155     struct sockopt_data *sd)
2156 {
2157 	struct named_object *no;
2158 	ipfw_obj_ntlv *ntlv;
2159 
2160 	no = ipfw_objhash_lookup_kidx(ni, kidx);
2161 	KASSERT(no != NULL, ("invalid object kernel index passed"));
2162 
2163 	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
2164 	if (ntlv == NULL)
2165 		return (ENOMEM);
2166 
2167 	ipfw_export_obj_ntlv(no, ntlv);
2168 	return (0);
2169 }
2170 
2171 /*
2172  * Dumps static rules with table TLVs in buffer @sd.
2173  *
2174  * Returns 0 on success.
2175  */
2176 static int
2177 dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
2178     uint32_t *bmask, struct sockopt_data *sd)
2179 {
2180 	int error;
2181 	int i, l;
2182 	uint32_t tcount;
2183 	ipfw_obj_ctlv *ctlv;
2184 	struct ip_fw *krule;
2185 	struct namedobj_instance *ni;
2186 	caddr_t dst;
2187 
2188 	/* Dump table names first (if any) */
2189 	if (da->tcount > 0) {
2190 		/* Header first */
2191 		ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
2192 		if (ctlv == NULL)
2193 			return (ENOMEM);
2194 		ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
2195 		ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) +
2196 		    sizeof(*ctlv);
2197 		ctlv->count = da->tcount;
2198 		ctlv->objsize = sizeof(ipfw_obj_ntlv);
2199 	}
2200 
2201 	i = 0;
2202 	tcount = da->tcount;
2203 	ni = ipfw_get_table_objhash(chain);
2204 	while (tcount > 0) {
2205 		if ((bmask[i / 32] & (1 << (i % 32))) == 0) {
2206 			i++;
2207 			continue;
2208 		}
2209 
2210 		/* Jump to shared named object bitmask */
2211 		if (i >= IPFW_TABLES_MAX) {
2212 			ni = CHAIN_TO_SRV(chain);
2213 			i -= IPFW_TABLES_MAX;
2214 			bmask += IPFW_TABLES_MAX / 32;
2215 		}
2216 
2217 		if ((error = export_objhash_ntlv(ni, i, sd)) != 0)
2218 			return (error);
2219 
2220 		i++;
2221 		tcount--;
2222 	}
2223 
2224 	/* Dump rules */
2225 	ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
2226 	if (ctlv == NULL)
2227 		return (ENOMEM);
2228 	ctlv->head.type = IPFW_TLV_RULE_LIST;
2229 	ctlv->head.length = da->rsize + sizeof(*ctlv);
2230 	ctlv->count = da->rcount;
2231 
2232 	for (i = da->b; i < da->e; i++) {
2233 		krule = chain->map[i];
2234 
2235 		l = RULEUSIZE1(krule) + sizeof(ipfw_obj_tlv);
2236 		if (da->rcounters != 0)
2237 			l += sizeof(struct ip_fw_bcounter);
2238 		dst = (caddr_t)ipfw_get_sopt_space(sd, l);
2239 		if (dst == NULL)
2240 			return (ENOMEM);
2241 
2242 		export_rule1(krule, dst, l, da->rcounters);
2243 	}
2244 
2245 	return (0);
2246 }
2247 
2248 /*
2249  * Marks every object index used in @rule with bit in @bmask.
2250  * Used to generate bitmask of referenced tables/objects for given ruleset
2251  * or its part.
2252  *
2253  * Returns number of newly-referenced objects.
2254  */
2255 static int
2256 mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
2257     uint32_t *bmask)
2258 {
2259 	struct opcode_obj_rewrite *rw;
2260 	ipfw_insn *cmd;
2261 	int bidx, cmdlen, l, count;
2262 	uint16_t kidx;
2263 	uint8_t subtype;
2264 
2265 	l = rule->cmd_len;
2266 	cmd = rule->cmd;
2267 	cmdlen = 0;
2268 	count = 0;
2269 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2270 		cmdlen = F_LEN(cmd);
2271 
2272 		rw = find_op_rw(cmd, &kidx, &subtype);
2273 		if (rw == NULL)
2274 			continue;
2275 
2276 		bidx = kidx / 32;
2277 		/*
2278 		 * Maintain separate bitmasks for table and
2279 		 * non-table objects.
2280 		 */
2281 		if (rw->etlv != IPFW_TLV_TBL_NAME)
2282 			bidx += IPFW_TABLES_MAX / 32;
2283 
2284 		if ((bmask[bidx] & (1 << (kidx % 32))) == 0)
2285 			count++;
2286 
2287 		bmask[bidx] |= 1 << (kidx % 32);
2288 	}
2289 
2290 	return (count);
2291 }
2292 
2293 /*
2294  * Dumps requested objects data
2295  * Data layout (version 0)(current):
2296  * Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags
2297  *   size = ipfw_cfg_lheader.size
2298  * Reply: [ ipfw_cfg_lheader
2299  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
2300  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST)
2301  *     ipfw_obj_tlv(IPFW_TLV_RULE_ENT) [ ip_fw_bcounter (optional) ip_fw_rule ]
2302  *   ] (optional)
2303  *   [ ipfw_obj_ctlv(IPFW_TLV_STATE_LIST) ipfw_obj_dyntlv x N ] (optional)
2304  * ]
2305  * * NOTE IPFW_TLV_STATE_LIST has the single valid field: objsize.
2306  * The rest (size, count) are set to zero and needs to be ignored.
2307  *
2308  * Returns 0 on success.
2309  */
2310 static int
2311 dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2312     struct sockopt_data *sd)
2313 {
2314 	ipfw_cfg_lheader *hdr;
2315 	struct ip_fw *rule;
2316 	size_t sz, rnum;
2317 	uint32_t hdr_flags;
2318 	int error, i;
2319 	struct dump_args da;
2320 	uint32_t *bmask;
2321 
2322 	hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
2323 	if (hdr == NULL)
2324 		return (EINVAL);
2325 
2326 	error = 0;
2327 	bmask = NULL;
2328 	/* Allocate needed state. Note we allocate 2xspace mask, for table&srv  */
2329 	if (hdr->flags & IPFW_CFG_GET_STATIC)
2330 		bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO);
2331 
2332 	IPFW_UH_RLOCK(chain);
2333 
2334 	/*
2335 	 * STAGE 1: Determine size/count for objects in range.
2336 	 * Prepare used tables bitmask.
2337 	 */
2338 	sz = sizeof(ipfw_cfg_lheader);
2339 	memset(&da, 0, sizeof(da));
2340 
2341 	da.b = 0;
2342 	da.e = chain->n_rules;
2343 
2344 	if (hdr->end_rule != 0) {
2345 		/* Handle custom range */
2346 		if ((rnum = hdr->start_rule) > IPFW_DEFAULT_RULE)
2347 			rnum = IPFW_DEFAULT_RULE;
2348 		da.b = ipfw_find_rule(chain, rnum, 0);
2349 		rnum = hdr->end_rule;
2350 		rnum = (rnum < IPFW_DEFAULT_RULE) ? rnum+1 : IPFW_DEFAULT_RULE;
2351 		da.e = ipfw_find_rule(chain, rnum, 0) + 1;
2352 	}
2353 
2354 	if (hdr->flags & IPFW_CFG_GET_STATIC) {
2355 		for (i = da.b; i < da.e; i++) {
2356 			rule = chain->map[i];
2357 			da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv);
2358 			da.rcount++;
2359 			/* Update bitmask of used objects for given range */
2360 			da.tcount += mark_object_kidx(chain, rule, bmask);
2361 		}
2362 		/* Add counters if requested */
2363 		if (hdr->flags & IPFW_CFG_GET_COUNTERS) {
2364 			da.rsize += sizeof(struct ip_fw_bcounter) * da.rcount;
2365 			da.rcounters = 1;
2366 		}
2367 
2368 		if (da.tcount > 0)
2369 			sz += da.tcount * sizeof(ipfw_obj_ntlv) +
2370 			    sizeof(ipfw_obj_ctlv);
2371 		sz += da.rsize + sizeof(ipfw_obj_ctlv);
2372 	}
2373 
2374 	if (hdr->flags & IPFW_CFG_GET_STATES)
2375 		sz += ipfw_dyn_get_count() * sizeof(ipfw_obj_dyntlv) +
2376 		     sizeof(ipfw_obj_ctlv);
2377 
2378 
2379 	/*
2380 	 * Fill header anyway.
2381 	 * Note we have to save header fields to stable storage
2382 	 * buffer inside @sd can be flushed after dumping rules
2383 	 */
2384 	hdr->size = sz;
2385 	hdr->set_mask = ~V_set_disable;
2386 	hdr_flags = hdr->flags;
2387 	hdr = NULL;
2388 
2389 	if (sd->valsize < sz) {
2390 		error = ENOMEM;
2391 		goto cleanup;
2392 	}
2393 
2394 	/* STAGE2: Store actual data */
2395 	if (hdr_flags & IPFW_CFG_GET_STATIC) {
2396 		error = dump_static_rules(chain, &da, bmask, sd);
2397 		if (error != 0)
2398 			goto cleanup;
2399 	}
2400 
2401 	if (hdr_flags & IPFW_CFG_GET_STATES)
2402 		error = ipfw_dump_states(chain, sd);
2403 
2404 cleanup:
2405 	IPFW_UH_RUNLOCK(chain);
2406 
2407 	if (bmask != NULL)
2408 		free(bmask, M_TEMP);
2409 
2410 	return (error);
2411 }
2412 
2413 int
2414 ipfw_check_object_name_generic(const char *name)
2415 {
2416 	int nsize;
2417 
2418 	nsize = sizeof(((ipfw_obj_ntlv *)0)->name);
2419 	if (strnlen(name, nsize) == nsize)
2420 		return (EINVAL);
2421 	if (name[0] == '\0')
2422 		return (EINVAL);
2423 	return (0);
2424 }
2425 
2426 /*
2427  * Creates non-existent objects referenced by rule.
2428  *
2429  * Return 0 on success.
2430  */
2431 int
2432 create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd,
2433     struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti)
2434 {
2435 	struct opcode_obj_rewrite *rw;
2436 	struct obj_idx *p;
2437 	uint16_t kidx;
2438 	int error;
2439 
2440 	/*
2441 	 * Compatibility stuff: do actual creation for non-existing,
2442 	 * but referenced objects.
2443 	 */
2444 	for (p = oib; p < pidx; p++) {
2445 		if (p->kidx != 0)
2446 			continue;
2447 
2448 		ti->uidx = p->uidx;
2449 		ti->type = p->type;
2450 		ti->atype = 0;
2451 
2452 		rw = find_op_rw(cmd + p->off, NULL, NULL);
2453 		KASSERT(rw != NULL, ("Unable to find handler for op %d",
2454 		    (cmd + p->off)->opcode));
2455 
2456 		if (rw->create_object == NULL)
2457 			error = EOPNOTSUPP;
2458 		else
2459 			error = rw->create_object(ch, ti, &kidx);
2460 		if (error == 0) {
2461 			p->kidx = kidx;
2462 			continue;
2463 		}
2464 
2465 		/*
2466 		 * Error happened. We have to rollback everything.
2467 		 * Drop all already acquired references.
2468 		 */
2469 		IPFW_UH_WLOCK(ch);
2470 		unref_oib_objects(ch, cmd, oib, pidx);
2471 		IPFW_UH_WUNLOCK(ch);
2472 
2473 		return (error);
2474 	}
2475 
2476 	return (0);
2477 }
2478 
2479 /*
2480  * Compatibility function for old ipfw(8) binaries.
2481  * Rewrites table/nat kernel indices with userland ones.
2482  * Convert tables matching '/^\d+$/' to their atoi() value.
2483  * Use number 65535 for other tables.
2484  *
2485  * Returns 0 on success.
2486  */
2487 static int
2488 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule)
2489 {
2490 	struct opcode_obj_rewrite *rw;
2491 	struct named_object *no;
2492 	ipfw_insn *cmd;
2493 	char *end;
2494 	long val;
2495 	int cmdlen, error, l;
2496 	uint16_t kidx, uidx;
2497 	uint8_t subtype;
2498 
2499 	error = 0;
2500 
2501 	l = rule->cmd_len;
2502 	cmd = rule->cmd;
2503 	cmdlen = 0;
2504 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2505 		cmdlen = F_LEN(cmd);
2506 
2507 		/* Check if is index in given opcode */
2508 		rw = find_op_rw(cmd, &kidx, &subtype);
2509 		if (rw == NULL)
2510 			continue;
2511 
2512 		/* Try to find referenced kernel object */
2513 		no = rw->find_bykidx(ch, kidx);
2514 		if (no == NULL)
2515 			continue;
2516 
2517 		val = strtol(no->name, &end, 10);
2518 		if (*end == '\0' && val < 65535) {
2519 			uidx = val;
2520 		} else {
2521 
2522 			/*
2523 			 * We are called via legacy opcode.
2524 			 * Save error and show table as fake number
2525 			 * not to make ipfw(8) hang.
2526 			 */
2527 			uidx = 65535;
2528 			error = 2;
2529 		}
2530 
2531 		rw->update(cmd, uidx);
2532 	}
2533 
2534 	return (error);
2535 }
2536 
2537 
2538 /*
2539  * Unreferences all already-referenced objects in given @cmd rule,
2540  * using information in @oib.
2541  *
2542  * Used to rollback partially converted rule on error.
2543  */
2544 static void
2545 unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib,
2546     struct obj_idx *end)
2547 {
2548 	struct opcode_obj_rewrite *rw;
2549 	struct named_object *no;
2550 	struct obj_idx *p;
2551 
2552 	IPFW_UH_WLOCK_ASSERT(ch);
2553 
2554 	for (p = oib; p < end; p++) {
2555 		if (p->kidx == 0)
2556 			continue;
2557 
2558 		rw = find_op_rw(cmd + p->off, NULL, NULL);
2559 		KASSERT(rw != NULL, ("Unable to find handler for op %d",
2560 		    (cmd + p->off)->opcode));
2561 
2562 		/* Find & unref by existing idx */
2563 		no = rw->find_bykidx(ch, p->kidx);
2564 		KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx));
2565 		no->refcnt--;
2566 	}
2567 }
2568 
2569 /*
2570  * Remove references from every object used in @rule.
2571  * Used at rule removal code.
2572  */
2573 static void
2574 unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule)
2575 {
2576 	struct opcode_obj_rewrite *rw;
2577 	struct named_object *no;
2578 	ipfw_insn *cmd;
2579 	int cmdlen, l;
2580 	uint16_t kidx;
2581 	uint8_t subtype;
2582 
2583 	IPFW_UH_WLOCK_ASSERT(ch);
2584 
2585 	l = rule->cmd_len;
2586 	cmd = rule->cmd;
2587 	cmdlen = 0;
2588 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2589 		cmdlen = F_LEN(cmd);
2590 
2591 		rw = find_op_rw(cmd, &kidx, &subtype);
2592 		if (rw == NULL)
2593 			continue;
2594 		no = rw->find_bykidx(ch, kidx);
2595 
2596 		KASSERT(no != NULL, ("table id %d not found", kidx));
2597 		KASSERT(no->subtype == subtype,
2598 		    ("wrong type %d (%d) for table id %d",
2599 		    no->subtype, subtype, kidx));
2600 		KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
2601 		    kidx, no->refcnt));
2602 
2603 		if (no->refcnt == 1 && rw->destroy_object != NULL)
2604 			rw->destroy_object(ch, no);
2605 		else
2606 			no->refcnt--;
2607 	}
2608 }
2609 
2610 
2611 /*
2612  * Find and reference object (if any) stored in instruction @cmd.
2613  *
2614  * Saves object info in @pidx, sets
2615  *  - @unresolved to 1 if object should exists but not found
2616  *
2617  * Returns non-zero value in case of error.
2618  */
2619 static int
2620 ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti,
2621     struct obj_idx *pidx, int *unresolved)
2622 {
2623 	struct named_object *no;
2624 	struct opcode_obj_rewrite *rw;
2625 	int error;
2626 
2627 	/* Check if this opcode is candidate for rewrite */
2628 	rw = find_op_rw(cmd, &ti->uidx, &ti->type);
2629 	if (rw == NULL)
2630 		return (0);
2631 
2632 	/* Need to rewrite. Save necessary fields */
2633 	pidx->uidx = ti->uidx;
2634 	pidx->type = ti->type;
2635 
2636 	/* Try to find referenced kernel object */
2637 	error = rw->find_byname(ch, ti, &no);
2638 	if (error != 0)
2639 		return (error);
2640 	if (no == NULL) {
2641 		/*
2642 		 * Report about unresolved object for automaic
2643 		 * creation.
2644 		 */
2645 		*unresolved = 1;
2646 		return (0);
2647 	}
2648 
2649 	/* Found. Bump refcount and update kidx. */
2650 	no->refcnt++;
2651 	rw->update(cmd, no->kidx);
2652 	return (0);
2653 }
2654 
2655 /*
2656  * Finds and bumps refcount for objects referenced by given @rule.
2657  * Auto-creates non-existing tables.
2658  * Fills in @oib array with userland/kernel indexes.
2659  *
2660  * Returns 0 on success.
2661  */
2662 static int
2663 ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
2664     struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti)
2665 {
2666 	struct obj_idx *pidx;
2667 	ipfw_insn *cmd;
2668 	int cmdlen, error, l, unresolved;
2669 
2670 	pidx = oib;
2671 	l = rule->cmd_len;
2672 	cmd = rule->cmd;
2673 	cmdlen = 0;
2674 	error = 0;
2675 
2676 	IPFW_UH_WLOCK(ch);
2677 
2678 	/* Increase refcount on each existing referenced table. */
2679 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2680 		cmdlen = F_LEN(cmd);
2681 		unresolved = 0;
2682 
2683 		error = ref_opcode_object(ch, cmd, ti, pidx, &unresolved);
2684 		if (error != 0)
2685 			break;
2686 		/*
2687 		 * Compatibility stuff for old clients:
2688 		 * prepare to automaitcally create non-existing objects.
2689 		 */
2690 		if (unresolved != 0) {
2691 			pidx->off = rule->cmd_len - l;
2692 			pidx++;
2693 		}
2694 	}
2695 
2696 	if (error != 0) {
2697 		/* Unref everything we have already done */
2698 		unref_oib_objects(ch, rule->cmd, oib, pidx);
2699 		IPFW_UH_WUNLOCK(ch);
2700 		return (error);
2701 	}
2702 	IPFW_UH_WUNLOCK(ch);
2703 
2704 	/* Perform auto-creation for non-existing objects */
2705 	if (pidx != oib)
2706 		error = create_objects_compat(ch, rule->cmd, oib, pidx, ti);
2707 
2708 	/* Calculate real number of dynamic objects */
2709 	ci->object_opcodes = (uint16_t)(pidx - oib);
2710 
2711 	return (error);
2712 }
2713 
2714 /*
2715  * Checks is opcode is referencing table of appropriate type.
2716  * Adds reference count for found table if true.
2717  * Rewrites user-supplied opcode values with kernel ones.
2718  *
2719  * Returns 0 on success and appropriate error code otherwise.
2720  */
2721 static int
2722 rewrite_rule_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci)
2723 {
2724 	int error;
2725 	ipfw_insn *cmd;
2726 	uint8_t type;
2727 	struct obj_idx *p, *pidx_first, *pidx_last;
2728 	struct tid_info ti;
2729 
2730 	/*
2731 	 * Prepare an array for storing opcode indices.
2732 	 * Use stack allocation by default.
2733 	 */
2734 	if (ci->object_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
2735 		/* Stack */
2736 		pidx_first = ci->obuf;
2737 	} else
2738 		pidx_first = malloc(
2739 		    ci->object_opcodes * sizeof(struct obj_idx),
2740 		    M_IPFW, M_WAITOK | M_ZERO);
2741 
2742 	error = 0;
2743 	type = 0;
2744 	memset(&ti, 0, sizeof(ti));
2745 
2746 	/* Use set rule is assigned to. */
2747 	ti.set = ci->krule->set;
2748 	if (ci->ctlv != NULL) {
2749 		ti.tlvs = (void *)(ci->ctlv + 1);
2750 		ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
2751 	}
2752 
2753 	/* Reference all used tables and other objects */
2754 	error = ref_rule_objects(chain, ci->krule, ci, pidx_first, &ti);
2755 	if (error != 0)
2756 		goto free;
2757 	/*
2758 	 * Note that ref_rule_objects() might have updated ci->object_opcodes
2759 	 * to reflect actual number of object opcodes.
2760 	 */
2761 
2762 	/* Perform rewrite of remaining opcodes */
2763 	p = pidx_first;
2764 	pidx_last = pidx_first + ci->object_opcodes;
2765 	for (p = pidx_first; p < pidx_last; p++) {
2766 		cmd = ci->krule->cmd + p->off;
2767 		update_opcode_kidx(cmd, p->kidx);
2768 	}
2769 
2770 free:
2771 	if (pidx_first != ci->obuf)
2772 		free(pidx_first, M_IPFW);
2773 
2774 	return (error);
2775 }
2776 
2777 /*
2778  * Adds one or more rules to ipfw @chain.
2779  * Data layout (version 0)(current):
2780  * Request:
2781  * [
2782  *   ip_fw3_opheader
2783  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1)
2784  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3)
2785  * ]
2786  * Reply:
2787  * [
2788  *   ip_fw3_opheader
2789  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
2790  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ]
2791  * ]
2792  *
2793  * Rules in reply are modified to store their actual ruleset number.
2794  *
2795  * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending
2796  * according to their idx field and there has to be no duplicates.
2797  * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending.
2798  * (*3) Each ip_fw structure needs to be aligned to u64 boundary.
2799  *
2800  * Returns 0 on success.
2801  */
2802 static int
2803 add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2804     struct sockopt_data *sd)
2805 {
2806 	ipfw_obj_ctlv *ctlv, *rtlv, *tstate;
2807 	ipfw_obj_ntlv *ntlv;
2808 	int clen, error, idx;
2809 	uint32_t count, read;
2810 	struct ip_fw_rule *r;
2811 	struct rule_check_info rci, *ci, *cbuf;
2812 	int i, rsize;
2813 
2814 	op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize);
2815 	ctlv = (ipfw_obj_ctlv *)(op3 + 1);
2816 
2817 	read = sizeof(ip_fw3_opheader);
2818 	rtlv = NULL;
2819 	tstate = NULL;
2820 	cbuf = NULL;
2821 	memset(&rci, 0, sizeof(struct rule_check_info));
2822 
2823 	if (read + sizeof(*ctlv) > sd->valsize)
2824 		return (EINVAL);
2825 
2826 	if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
2827 		clen = ctlv->head.length;
2828 		/* Check size and alignment */
2829 		if (clen > sd->valsize || clen < sizeof(*ctlv))
2830 			return (EINVAL);
2831 		if ((clen % sizeof(uint64_t)) != 0)
2832 			return (EINVAL);
2833 
2834 		/*
2835 		 * Some table names or other named objects.
2836 		 * Check for validness.
2837 		 */
2838 		count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv);
2839 		if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv))
2840 			return (EINVAL);
2841 
2842 		/*
2843 		 * Check each TLV.
2844 		 * Ensure TLVs are sorted ascending and
2845 		 * there are no duplicates.
2846 		 */
2847 		idx = -1;
2848 		ntlv = (ipfw_obj_ntlv *)(ctlv + 1);
2849 		while (count > 0) {
2850 			if (ntlv->head.length != sizeof(ipfw_obj_ntlv))
2851 				return (EINVAL);
2852 
2853 			error = ipfw_check_object_name_generic(ntlv->name);
2854 			if (error != 0)
2855 				return (error);
2856 
2857 			if (ntlv->idx <= idx)
2858 				return (EINVAL);
2859 
2860 			idx = ntlv->idx;
2861 			count--;
2862 			ntlv++;
2863 		}
2864 
2865 		tstate = ctlv;
2866 		read += ctlv->head.length;
2867 		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
2868 	}
2869 
2870 	if (read + sizeof(*ctlv) > sd->valsize)
2871 		return (EINVAL);
2872 
2873 	if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
2874 		clen = ctlv->head.length;
2875 		if (clen + read > sd->valsize || clen < sizeof(*ctlv))
2876 			return (EINVAL);
2877 		if ((clen % sizeof(uint64_t)) != 0)
2878 			return (EINVAL);
2879 
2880 		/*
2881 		 * TODO: Permit adding multiple rules at once
2882 		 */
2883 		if (ctlv->count != 1)
2884 			return (ENOTSUP);
2885 
2886 		clen -= sizeof(*ctlv);
2887 
2888 		if (ctlv->count > clen / sizeof(struct ip_fw_rule))
2889 			return (EINVAL);
2890 
2891 		/* Allocate state for each rule or use stack */
2892 		if (ctlv->count == 1) {
2893 			memset(&rci, 0, sizeof(struct rule_check_info));
2894 			cbuf = &rci;
2895 		} else
2896 			cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP,
2897 			    M_WAITOK | M_ZERO);
2898 		ci = cbuf;
2899 
2900 		/*
2901 		 * Check each rule for validness.
2902 		 * Ensure numbered rules are sorted ascending
2903 		 * and properly aligned
2904 		 */
2905 		idx = 0;
2906 		r = (struct ip_fw_rule *)(ctlv + 1);
2907 		count = 0;
2908 		error = 0;
2909 		while (clen > 0) {
2910 			rsize = roundup2(RULESIZE(r), sizeof(uint64_t));
2911 			if (rsize > clen || ctlv->count <= count) {
2912 				error = EINVAL;
2913 				break;
2914 			}
2915 
2916 			ci->ctlv = tstate;
2917 			error = check_ipfw_rule1(r, rsize, ci);
2918 			if (error != 0)
2919 				break;
2920 
2921 			/* Check sorting */
2922 			if (r->rulenum != 0 && r->rulenum < idx) {
2923 				printf("rulenum %d idx %d\n", r->rulenum, idx);
2924 				error = EINVAL;
2925 				break;
2926 			}
2927 			idx = r->rulenum;
2928 
2929 			ci->urule = (caddr_t)r;
2930 
2931 			rsize = roundup2(rsize, sizeof(uint64_t));
2932 			clen -= rsize;
2933 			r = (struct ip_fw_rule *)((caddr_t)r + rsize);
2934 			count++;
2935 			ci++;
2936 		}
2937 
2938 		if (ctlv->count != count || error != 0) {
2939 			if (cbuf != &rci)
2940 				free(cbuf, M_TEMP);
2941 			return (EINVAL);
2942 		}
2943 
2944 		rtlv = ctlv;
2945 		read += ctlv->head.length;
2946 		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
2947 	}
2948 
2949 	if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) {
2950 		if (cbuf != NULL && cbuf != &rci)
2951 			free(cbuf, M_TEMP);
2952 		return (EINVAL);
2953 	}
2954 
2955 	/*
2956 	 * Passed rules seems to be valid.
2957 	 * Allocate storage and try to add them to chain.
2958 	 */
2959 	for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) {
2960 		clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule);
2961 		ci->krule = ipfw_alloc_rule(chain, clen);
2962 		import_rule1(ci);
2963 	}
2964 
2965 	if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) {
2966 		/* Free allocate krules */
2967 		for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++)
2968 			free_rule(ci->krule);
2969 	}
2970 
2971 	if (cbuf != NULL && cbuf != &rci)
2972 		free(cbuf, M_TEMP);
2973 
2974 	return (error);
2975 }
2976 
2977 /*
2978  * Lists all sopts currently registered.
2979  * Data layout (v0)(current):
2980  * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
2981  * Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ]
2982  *
2983  * Returns 0 on success
2984  */
2985 static int
2986 dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2987     struct sockopt_data *sd)
2988 {
2989 	struct _ipfw_obj_lheader *olh;
2990 	ipfw_sopt_info *i;
2991 	struct ipfw_sopt_handler *sh;
2992 	uint32_t count, n, size;
2993 
2994 	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
2995 	if (olh == NULL)
2996 		return (EINVAL);
2997 	if (sd->valsize < olh->size)
2998 		return (EINVAL);
2999 
3000 	CTL3_LOCK();
3001 	count = ctl3_hsize;
3002 	size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader);
3003 
3004 	/* Fill in header regadless of buffer size */
3005 	olh->count = count;
3006 	olh->objsize = sizeof(ipfw_sopt_info);
3007 
3008 	if (size > olh->size) {
3009 		olh->size = size;
3010 		CTL3_UNLOCK();
3011 		return (ENOMEM);
3012 	}
3013 	olh->size = size;
3014 
3015 	for (n = 1; n <= count; n++) {
3016 		i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i));
3017 		KASSERT(i != NULL, ("previously checked buffer is not enough"));
3018 		sh = &ctl3_handlers[n];
3019 		i->opcode = sh->opcode;
3020 		i->version = sh->version;
3021 		i->refcnt = sh->refcnt;
3022 	}
3023 	CTL3_UNLOCK();
3024 
3025 	return (0);
3026 }
3027 
3028 /*
3029  * Compares two opcodes.
3030  * Used both in qsort() and bsearch().
3031  *
3032  * Returns 0 if match is found.
3033  */
3034 static int
3035 compare_opcodes(const void *_a, const void *_b)
3036 {
3037 	const struct opcode_obj_rewrite *a, *b;
3038 
3039 	a = (const struct opcode_obj_rewrite *)_a;
3040 	b = (const struct opcode_obj_rewrite *)_b;
3041 
3042 	if (a->opcode < b->opcode)
3043 		return (-1);
3044 	else if (a->opcode > b->opcode)
3045 		return (1);
3046 
3047 	return (0);
3048 }
3049 
3050 /*
3051  * XXX: Rewrite bsearch()
3052  */
3053 static int
3054 find_op_rw_range(uint16_t op, struct opcode_obj_rewrite **plo,
3055     struct opcode_obj_rewrite **phi)
3056 {
3057 	struct opcode_obj_rewrite *ctl3_max, *lo, *hi, h, *rw;
3058 
3059 	memset(&h, 0, sizeof(h));
3060 	h.opcode = op;
3061 
3062 	rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters,
3063 	    ctl3_rsize, sizeof(h), compare_opcodes);
3064 	if (rw == NULL)
3065 		return (1);
3066 
3067 	/* Find the first element matching the same opcode */
3068 	lo = rw;
3069 	for ( ; lo > ctl3_rewriters && (lo - 1)->opcode == op; lo--)
3070 		;
3071 
3072 	/* Find the last element matching the same opcode */
3073 	hi = rw;
3074 	ctl3_max = ctl3_rewriters + ctl3_rsize;
3075 	for ( ; (hi + 1) < ctl3_max && (hi + 1)->opcode == op; hi++)
3076 		;
3077 
3078 	*plo = lo;
3079 	*phi = hi;
3080 
3081 	return (0);
3082 }
3083 
3084 /*
3085  * Finds opcode object rewriter based on @code.
3086  *
3087  * Returns pointer to handler or NULL.
3088  */
3089 static struct opcode_obj_rewrite *
3090 find_op_rw(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
3091 {
3092 	struct opcode_obj_rewrite *rw, *lo, *hi;
3093 	uint16_t uidx;
3094 	uint8_t subtype;
3095 
3096 	if (find_op_rw_range(cmd->opcode, &lo, &hi) != 0)
3097 		return (NULL);
3098 
3099 	for (rw = lo; rw <= hi; rw++) {
3100 		if (rw->classifier(cmd, &uidx, &subtype) == 0) {
3101 			if (puidx != NULL)
3102 				*puidx = uidx;
3103 			if (ptype != NULL)
3104 				*ptype = subtype;
3105 			return (rw);
3106 		}
3107 	}
3108 
3109 	return (NULL);
3110 }
3111 int
3112 classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx)
3113 {
3114 
3115 	if (find_op_rw(cmd, puidx, NULL) == 0)
3116 		return (1);
3117 	return (0);
3118 }
3119 
3120 void
3121 update_opcode_kidx(ipfw_insn *cmd, uint16_t idx)
3122 {
3123 	struct opcode_obj_rewrite *rw;
3124 
3125 	rw = find_op_rw(cmd, NULL, NULL);
3126 	KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode));
3127 	rw->update(cmd, idx);
3128 }
3129 
3130 void
3131 ipfw_init_obj_rewriter()
3132 {
3133 
3134 	ctl3_rewriters = NULL;
3135 	ctl3_rsize = 0;
3136 }
3137 
3138 void
3139 ipfw_destroy_obj_rewriter()
3140 {
3141 
3142 	if (ctl3_rewriters != NULL)
3143 		free(ctl3_rewriters, M_IPFW);
3144 	ctl3_rewriters = NULL;
3145 	ctl3_rsize = 0;
3146 }
3147 
3148 /*
3149  * Adds one or more opcode object rewrite handlers to the global array.
3150  * Function may sleep.
3151  */
3152 void
3153 ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
3154 {
3155 	size_t sz;
3156 	struct opcode_obj_rewrite *tmp;
3157 
3158 	CTL3_LOCK();
3159 
3160 	for (;;) {
3161 		sz = ctl3_rsize + count;
3162 		CTL3_UNLOCK();
3163 		tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO);
3164 		CTL3_LOCK();
3165 		if (ctl3_rsize + count <= sz)
3166 			break;
3167 
3168 		/* Retry */
3169 		free(tmp, M_IPFW);
3170 	}
3171 
3172 	/* Merge old & new arrays */
3173 	sz = ctl3_rsize + count;
3174 	memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw));
3175 	memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw));
3176 	qsort(tmp, sz, sizeof(*rw), compare_opcodes);
3177 	/* Switch new and free old */
3178 	if (ctl3_rewriters != NULL)
3179 		free(ctl3_rewriters, M_IPFW);
3180 	ctl3_rewriters = tmp;
3181 	ctl3_rsize = sz;
3182 
3183 	CTL3_UNLOCK();
3184 }
3185 
3186 /*
3187  * Removes one or more object rewrite handlers from the global array.
3188  */
3189 int
3190 ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
3191 {
3192 	size_t sz;
3193 	struct opcode_obj_rewrite *ctl3_max, *ktmp, *lo, *hi;
3194 	int i;
3195 
3196 	CTL3_LOCK();
3197 
3198 	for (i = 0; i < count; i++) {
3199 		if (find_op_rw_range(rw[i].opcode, &lo, &hi) != 0)
3200 			continue;
3201 
3202 		for (ktmp = lo; ktmp <= hi; ktmp++) {
3203 			if (ktmp->classifier != rw[i].classifier)
3204 				continue;
3205 
3206 			ctl3_max = ctl3_rewriters + ctl3_rsize;
3207 			sz = (ctl3_max - (ktmp + 1)) * sizeof(*ktmp);
3208 			memmove(ktmp, ktmp + 1, sz);
3209 			ctl3_rsize--;
3210 			break;
3211 		}
3212 
3213 	}
3214 
3215 	if (ctl3_rsize == 0) {
3216 		if (ctl3_rewriters != NULL)
3217 			free(ctl3_rewriters, M_IPFW);
3218 		ctl3_rewriters = NULL;
3219 	}
3220 
3221 	CTL3_UNLOCK();
3222 
3223 	return (0);
3224 }
3225 
3226 static int
3227 export_objhash_ntlv_internal(struct namedobj_instance *ni,
3228     struct named_object *no, void *arg)
3229 {
3230 	struct sockopt_data *sd;
3231 	ipfw_obj_ntlv *ntlv;
3232 
3233 	sd = (struct sockopt_data *)arg;
3234 	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
3235 	if (ntlv == NULL)
3236 		return (ENOMEM);
3237 	ipfw_export_obj_ntlv(no, ntlv);
3238 	return (0);
3239 }
3240 
3241 /*
3242  * Lists all service objects.
3243  * Data layout (v0)(current):
3244  * Request: [ ipfw_obj_lheader ] size = ipfw_obj_lheader.size
3245  * Reply: [ ipfw_obj_lheader [ ipfw_obj_ntlv x N ] (optional) ]
3246  * Returns 0 on success
3247  */
3248 static int
3249 dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
3250     struct sockopt_data *sd)
3251 {
3252 	ipfw_obj_lheader *hdr;
3253 	int count;
3254 
3255 	hdr = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
3256 	if (hdr == NULL)
3257 		return (EINVAL);
3258 
3259 	IPFW_UH_RLOCK(chain);
3260 	count = ipfw_objhash_count(CHAIN_TO_SRV(chain));
3261 	hdr->size = sizeof(ipfw_obj_lheader) + count * sizeof(ipfw_obj_ntlv);
3262 	if (sd->valsize < hdr->size) {
3263 		IPFW_UH_RUNLOCK(chain);
3264 		return (ENOMEM);
3265 	}
3266 	hdr->count = count;
3267 	hdr->objsize = sizeof(ipfw_obj_ntlv);
3268 	if (count > 0)
3269 		ipfw_objhash_foreach(CHAIN_TO_SRV(chain),
3270 		    export_objhash_ntlv_internal, sd);
3271 	IPFW_UH_RUNLOCK(chain);
3272 	return (0);
3273 }
3274 
3275 /*
3276  * Compares two sopt handlers (code, version and handler ptr).
3277  * Used both as qsort() and bsearch().
3278  * Does not compare handler for latter case.
3279  *
3280  * Returns 0 if match is found.
3281  */
3282 static int
3283 compare_sh(const void *_a, const void *_b)
3284 {
3285 	const struct ipfw_sopt_handler *a, *b;
3286 
3287 	a = (const struct ipfw_sopt_handler *)_a;
3288 	b = (const struct ipfw_sopt_handler *)_b;
3289 
3290 	if (a->opcode < b->opcode)
3291 		return (-1);
3292 	else if (a->opcode > b->opcode)
3293 		return (1);
3294 
3295 	if (a->version < b->version)
3296 		return (-1);
3297 	else if (a->version > b->version)
3298 		return (1);
3299 
3300 	/* bsearch helper */
3301 	if (a->handler == NULL)
3302 		return (0);
3303 
3304 	if ((uintptr_t)a->handler < (uintptr_t)b->handler)
3305 		return (-1);
3306 	else if ((uintptr_t)a->handler > (uintptr_t)b->handler)
3307 		return (1);
3308 
3309 	return (0);
3310 }
3311 
3312 /*
3313  * Finds sopt handler based on @code and @version.
3314  *
3315  * Returns pointer to handler or NULL.
3316  */
3317 static struct ipfw_sopt_handler *
3318 find_sh(uint16_t code, uint8_t version, sopt_handler_f *handler)
3319 {
3320 	struct ipfw_sopt_handler *sh, h;
3321 
3322 	memset(&h, 0, sizeof(h));
3323 	h.opcode = code;
3324 	h.version = version;
3325 	h.handler = handler;
3326 
3327 	sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers,
3328 	    ctl3_hsize, sizeof(h), compare_sh);
3329 
3330 	return (sh);
3331 }
3332 
3333 static int
3334 find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh)
3335 {
3336 	struct ipfw_sopt_handler *sh;
3337 
3338 	CTL3_LOCK();
3339 	if ((sh = find_sh(opcode, version, NULL)) == NULL) {
3340 		CTL3_UNLOCK();
3341 		printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n",
3342 		    opcode, version);
3343 		return (EINVAL);
3344 	}
3345 	sh->refcnt++;
3346 	ctl3_refct++;
3347 	/* Copy handler data to requested buffer */
3348 	*psh = *sh;
3349 	CTL3_UNLOCK();
3350 
3351 	return (0);
3352 }
3353 
3354 static void
3355 find_unref_sh(struct ipfw_sopt_handler *psh)
3356 {
3357 	struct ipfw_sopt_handler *sh;
3358 
3359 	CTL3_LOCK();
3360 	sh = find_sh(psh->opcode, psh->version, NULL);
3361 	KASSERT(sh != NULL, ("ctl3 handler disappeared"));
3362 	sh->refcnt--;
3363 	ctl3_refct--;
3364 	CTL3_UNLOCK();
3365 }
3366 
3367 void
3368 ipfw_init_sopt_handler()
3369 {
3370 
3371 	CTL3_LOCK_INIT();
3372 	IPFW_ADD_SOPT_HANDLER(1, scodes);
3373 }
3374 
3375 void
3376 ipfw_destroy_sopt_handler()
3377 {
3378 
3379 	IPFW_DEL_SOPT_HANDLER(1, scodes);
3380 	CTL3_LOCK_DESTROY();
3381 }
3382 
3383 /*
3384  * Adds one or more sockopt handlers to the global array.
3385  * Function may sleep.
3386  */
3387 void
3388 ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
3389 {
3390 	size_t sz;
3391 	struct ipfw_sopt_handler *tmp;
3392 
3393 	CTL3_LOCK();
3394 
3395 	for (;;) {
3396 		sz = ctl3_hsize + count;
3397 		CTL3_UNLOCK();
3398 		tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO);
3399 		CTL3_LOCK();
3400 		if (ctl3_hsize + count <= sz)
3401 			break;
3402 
3403 		/* Retry */
3404 		free(tmp, M_IPFW);
3405 	}
3406 
3407 	/* Merge old & new arrays */
3408 	sz = ctl3_hsize + count;
3409 	memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh));
3410 	memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh));
3411 	qsort(tmp, sz, sizeof(*sh), compare_sh);
3412 	/* Switch new and free old */
3413 	if (ctl3_handlers != NULL)
3414 		free(ctl3_handlers, M_IPFW);
3415 	ctl3_handlers = tmp;
3416 	ctl3_hsize = sz;
3417 	ctl3_gencnt++;
3418 
3419 	CTL3_UNLOCK();
3420 }
3421 
3422 /*
3423  * Removes one or more sockopt handlers from the global array.
3424  */
3425 int
3426 ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
3427 {
3428 	size_t sz;
3429 	struct ipfw_sopt_handler *tmp, *h;
3430 	int i;
3431 
3432 	CTL3_LOCK();
3433 
3434 	for (i = 0; i < count; i++) {
3435 		tmp = &sh[i];
3436 		h = find_sh(tmp->opcode, tmp->version, tmp->handler);
3437 		if (h == NULL)
3438 			continue;
3439 
3440 		sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h);
3441 		memmove(h, h + 1, sz);
3442 		ctl3_hsize--;
3443 	}
3444 
3445 	if (ctl3_hsize == 0) {
3446 		if (ctl3_handlers != NULL)
3447 			free(ctl3_handlers, M_IPFW);
3448 		ctl3_handlers = NULL;
3449 	}
3450 
3451 	ctl3_gencnt++;
3452 
3453 	CTL3_UNLOCK();
3454 
3455 	return (0);
3456 }
3457 
3458 /*
3459  * Writes data accumulated in @sd to sockopt buffer.
3460  * Zeroes internal @sd buffer.
3461  */
3462 static int
3463 ipfw_flush_sopt_data(struct sockopt_data *sd)
3464 {
3465 	struct sockopt *sopt;
3466 	int error;
3467 	size_t sz;
3468 
3469 	sz = sd->koff;
3470 	if (sz == 0)
3471 		return (0);
3472 
3473 	sopt = sd->sopt;
3474 
3475 	if (sopt->sopt_dir == SOPT_GET) {
3476 		error = copyout(sd->kbuf, sopt->sopt_val, sz);
3477 		if (error != 0)
3478 			return (error);
3479 	}
3480 
3481 	memset(sd->kbuf, 0, sd->ksize);
3482 	sd->ktotal += sz;
3483 	sd->koff = 0;
3484 	if (sd->ktotal + sd->ksize < sd->valsize)
3485 		sd->kavail = sd->ksize;
3486 	else
3487 		sd->kavail = sd->valsize - sd->ktotal;
3488 
3489 	/* Update sopt buffer data */
3490 	sopt->sopt_valsize = sd->ktotal;
3491 	sopt->sopt_val = sd->sopt_val + sd->ktotal;
3492 
3493 	return (0);
3494 }
3495 
3496 /*
3497  * Ensures that @sd buffer has contiguous @neeeded number of
3498  * bytes.
3499  *
3500  * Returns pointer to requested space or NULL.
3501  */
3502 caddr_t
3503 ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed)
3504 {
3505 	int error;
3506 	caddr_t addr;
3507 
3508 	if (sd->kavail < needed) {
3509 		/*
3510 		 * Flush data and try another time.
3511 		 */
3512 		error = ipfw_flush_sopt_data(sd);
3513 
3514 		if (sd->kavail < needed || error != 0)
3515 			return (NULL);
3516 	}
3517 
3518 	addr = sd->kbuf + sd->koff;
3519 	sd->koff += needed;
3520 	sd->kavail -= needed;
3521 	return (addr);
3522 }
3523 
3524 /*
3525  * Requests @needed contiguous bytes from @sd buffer.
3526  * Function is used to notify subsystem that we are
3527  * interesed in first @needed bytes (request header)
3528  * and the rest buffer can be safely zeroed.
3529  *
3530  * Returns pointer to requested space or NULL.
3531  */
3532 caddr_t
3533 ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed)
3534 {
3535 	caddr_t addr;
3536 
3537 	if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL)
3538 		return (NULL);
3539 
3540 	if (sd->kavail > 0)
3541 		memset(sd->kbuf + sd->koff, 0, sd->kavail);
3542 
3543 	return (addr);
3544 }
3545 
3546 /*
3547  * New sockopt handler.
3548  */
3549 int
3550 ipfw_ctl3(struct sockopt *sopt)
3551 {
3552 	int error, locked;
3553 	size_t size, valsize;
3554 	struct ip_fw_chain *chain;
3555 	char xbuf[256];
3556 	struct sockopt_data sdata;
3557 	struct ipfw_sopt_handler h;
3558 	ip_fw3_opheader *op3 = NULL;
3559 
3560 	error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
3561 	if (error != 0)
3562 		return (error);
3563 
3564 	if (sopt->sopt_name != IP_FW3)
3565 		return (ipfw_ctl(sopt));
3566 
3567 	chain = &V_layer3_chain;
3568 	error = 0;
3569 
3570 	/* Save original valsize before it is altered via sooptcopyin() */
3571 	valsize = sopt->sopt_valsize;
3572 	memset(&sdata, 0, sizeof(sdata));
3573 	/* Read op3 header first to determine actual operation */
3574 	op3 = (ip_fw3_opheader *)xbuf;
3575 	error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3));
3576 	if (error != 0)
3577 		return (error);
3578 	sopt->sopt_valsize = valsize;
3579 
3580 	/*
3581 	 * Find and reference command.
3582 	 */
3583 	error = find_ref_sh(op3->opcode, op3->version, &h);
3584 	if (error != 0)
3585 		return (error);
3586 
3587 	/*
3588 	 * Disallow modifications in really-really secure mode, but still allow
3589 	 * the logging counters to be reset.
3590 	 */
3591 	if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) {
3592 		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
3593 		if (error != 0) {
3594 			find_unref_sh(&h);
3595 			return (error);
3596 		}
3597 	}
3598 
3599 	/*
3600 	 * Fill in sockopt_data structure that may be useful for
3601 	 * IP_FW3 get requests.
3602 	 */
3603 	locked = 0;
3604 	if (valsize <= sizeof(xbuf)) {
3605 		/* use on-stack buffer */
3606 		sdata.kbuf = xbuf;
3607 		sdata.ksize = sizeof(xbuf);
3608 		sdata.kavail = valsize;
3609 	} else {
3610 
3611 		/*
3612 		 * Determine opcode type/buffer size:
3613 		 * allocate sliding-window buf for data export or
3614 		 * contiguous buffer for special ops.
3615 		 */
3616 		if ((h.dir & HDIR_SET) != 0) {
3617 			/* Set request. Allocate contigous buffer. */
3618 			if (valsize > CTL3_LARGEBUF) {
3619 				find_unref_sh(&h);
3620 				return (EFBIG);
3621 			}
3622 
3623 			size = valsize;
3624 		} else {
3625 			/* Get request. Allocate sliding window buffer */
3626 			size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF;
3627 
3628 			if (size < valsize) {
3629 				/* We have to wire user buffer */
3630 				error = vslock(sopt->sopt_val, valsize);
3631 				if (error != 0)
3632 					return (error);
3633 				locked = 1;
3634 			}
3635 		}
3636 
3637 		sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
3638 		sdata.ksize = size;
3639 		sdata.kavail = size;
3640 	}
3641 
3642 	sdata.sopt = sopt;
3643 	sdata.sopt_val = sopt->sopt_val;
3644 	sdata.valsize = valsize;
3645 
3646 	/*
3647 	 * Copy either all request (if valsize < bsize_max)
3648 	 * or first bsize_max bytes to guarantee most consumers
3649 	 * that all necessary data has been copied).
3650 	 * Anyway, copy not less than sizeof(ip_fw3_opheader).
3651 	 */
3652 	if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize,
3653 	    sizeof(ip_fw3_opheader))) != 0)
3654 		return (error);
3655 	op3 = (ip_fw3_opheader *)sdata.kbuf;
3656 
3657 	/* Finally, run handler */
3658 	error = h.handler(chain, op3, &sdata);
3659 	find_unref_sh(&h);
3660 
3661 	/* Flush state and free buffers */
3662 	if (error == 0)
3663 		error = ipfw_flush_sopt_data(&sdata);
3664 	else
3665 		ipfw_flush_sopt_data(&sdata);
3666 
3667 	if (locked != 0)
3668 		vsunlock(sdata.sopt_val, valsize);
3669 
3670 	/* Restore original pointer and set number of bytes written */
3671 	sopt->sopt_val = sdata.sopt_val;
3672 	sopt->sopt_valsize = sdata.ktotal;
3673 	if (sdata.kbuf != xbuf)
3674 		free(sdata.kbuf, M_TEMP);
3675 
3676 	return (error);
3677 }
3678 
3679 /**
3680  * {set|get}sockopt parser.
3681  */
3682 int
3683 ipfw_ctl(struct sockopt *sopt)
3684 {
3685 #define	RULE_MAXSIZE	(512*sizeof(u_int32_t))
3686 	int error;
3687 	size_t size, valsize;
3688 	struct ip_fw *buf;
3689 	struct ip_fw_rule0 *rule;
3690 	struct ip_fw_chain *chain;
3691 	u_int32_t rulenum[2];
3692 	uint32_t opt;
3693 	struct rule_check_info ci;
3694 	IPFW_RLOCK_TRACKER;
3695 
3696 	chain = &V_layer3_chain;
3697 	error = 0;
3698 
3699 	/* Save original valsize before it is altered via sooptcopyin() */
3700 	valsize = sopt->sopt_valsize;
3701 	opt = sopt->sopt_name;
3702 
3703 	/*
3704 	 * Disallow modifications in really-really secure mode, but still allow
3705 	 * the logging counters to be reset.
3706 	 */
3707 	if (opt == IP_FW_ADD ||
3708 	    (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) {
3709 		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
3710 		if (error != 0)
3711 			return (error);
3712 	}
3713 
3714 	switch (opt) {
3715 	case IP_FW_GET:
3716 		/*
3717 		 * pass up a copy of the current rules. Static rules
3718 		 * come first (the last of which has number IPFW_DEFAULT_RULE),
3719 		 * followed by a possibly empty list of dynamic rule.
3720 		 * The last dynamic rule has NULL in the "next" field.
3721 		 *
3722 		 * Note that the calculated size is used to bound the
3723 		 * amount of data returned to the user.  The rule set may
3724 		 * change between calculating the size and returning the
3725 		 * data in which case we'll just return what fits.
3726 		 */
3727 		for (;;) {
3728 			int len = 0, want;
3729 
3730 			size = chain->static_len;
3731 			size += ipfw_dyn_len();
3732 			if (size >= sopt->sopt_valsize)
3733 				break;
3734 			buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
3735 			IPFW_UH_RLOCK(chain);
3736 			/* check again how much space we need */
3737 			want = chain->static_len + ipfw_dyn_len();
3738 			if (size >= want)
3739 				len = ipfw_getrules(chain, buf, size);
3740 			IPFW_UH_RUNLOCK(chain);
3741 			if (size >= want)
3742 				error = sooptcopyout(sopt, buf, len);
3743 			free(buf, M_TEMP);
3744 			if (size >= want)
3745 				break;
3746 		}
3747 		break;
3748 
3749 	case IP_FW_FLUSH:
3750 		/* locking is done within del_entry() */
3751 		error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
3752 		break;
3753 
3754 	case IP_FW_ADD:
3755 		rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);
3756 		error = sooptcopyin(sopt, rule, RULE_MAXSIZE,
3757 			sizeof(struct ip_fw7) );
3758 
3759 		memset(&ci, 0, sizeof(struct rule_check_info));
3760 
3761 		/*
3762 		 * If the size of commands equals RULESIZE7 then we assume
3763 		 * a FreeBSD7.2 binary is talking to us (set is7=1).
3764 		 * is7 is persistent so the next 'ipfw list' command
3765 		 * will use this format.
3766 		 * NOTE: If wrong version is guessed (this can happen if
3767 		 *       the first ipfw command is 'ipfw [pipe] list')
3768 		 *       the ipfw binary may crash or loop infinitly...
3769 		 */
3770 		size = sopt->sopt_valsize;
3771 		if (size == RULESIZE7(rule)) {
3772 		    is7 = 1;
3773 		    error = convert_rule_to_8(rule);
3774 		    if (error) {
3775 			free(rule, M_TEMP);
3776 			return error;
3777 		    }
3778 		    size = RULESIZE(rule);
3779 		} else
3780 		    is7 = 0;
3781 		if (error == 0)
3782 			error = check_ipfw_rule0(rule, size, &ci);
3783 		if (error == 0) {
3784 			/* locking is done within add_rule() */
3785 			struct ip_fw *krule;
3786 			krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule));
3787 			ci.urule = (caddr_t)rule;
3788 			ci.krule = krule;
3789 			import_rule0(&ci);
3790 			error = commit_rules(chain, &ci, 1);
3791 			if (error != 0)
3792 				free_rule(ci.krule);
3793 			else if (sopt->sopt_dir == SOPT_GET) {
3794 				if (is7) {
3795 					error = convert_rule_to_7(rule);
3796 					size = RULESIZE7(rule);
3797 					if (error) {
3798 						free(rule, M_TEMP);
3799 						return error;
3800 					}
3801 				}
3802 				error = sooptcopyout(sopt, rule, size);
3803 			}
3804 		}
3805 		free(rule, M_TEMP);
3806 		break;
3807 
3808 	case IP_FW_DEL:
3809 		/*
3810 		 * IP_FW_DEL is used for deleting single rules or sets,
3811 		 * and (ab)used to atomically manipulate sets. Argument size
3812 		 * is used to distinguish between the two:
3813 		 *    sizeof(u_int32_t)
3814 		 *	delete single rule or set of rules,
3815 		 *	or reassign rules (or sets) to a different set.
3816 		 *    2*sizeof(u_int32_t)
3817 		 *	atomic disable/enable sets.
3818 		 *	first u_int32_t contains sets to be disabled,
3819 		 *	second u_int32_t contains sets to be enabled.
3820 		 */
3821 		error = sooptcopyin(sopt, rulenum,
3822 			2*sizeof(u_int32_t), sizeof(u_int32_t));
3823 		if (error)
3824 			break;
3825 		size = sopt->sopt_valsize;
3826 		if (size == sizeof(u_int32_t) && rulenum[0] != 0) {
3827 			/* delete or reassign, locking done in del_entry() */
3828 			error = del_entry(chain, rulenum[0]);
3829 		} else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */
3830 			IPFW_UH_WLOCK(chain);
3831 			V_set_disable =
3832 			    (V_set_disable | rulenum[0]) & ~rulenum[1] &
3833 			    ~(1<<RESVD_SET); /* set RESVD_SET always enabled */
3834 			IPFW_UH_WUNLOCK(chain);
3835 		} else
3836 			error = EINVAL;
3837 		break;
3838 
3839 	case IP_FW_ZERO:
3840 	case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */
3841 		rulenum[0] = 0;
3842 		if (sopt->sopt_val != 0) {
3843 		    error = sooptcopyin(sopt, rulenum,
3844 			    sizeof(u_int32_t), sizeof(u_int32_t));
3845 		    if (error)
3846 			break;
3847 		}
3848 		error = zero_entry(chain, rulenum[0],
3849 			sopt->sopt_name == IP_FW_RESETLOG);
3850 		break;
3851 
3852 	/*--- TABLE opcodes ---*/
3853 	case IP_FW_TABLE_ADD:
3854 	case IP_FW_TABLE_DEL:
3855 		{
3856 			ipfw_table_entry ent;
3857 			struct tentry_info tei;
3858 			struct tid_info ti;
3859 			struct table_value v;
3860 
3861 			error = sooptcopyin(sopt, &ent,
3862 			    sizeof(ent), sizeof(ent));
3863 			if (error)
3864 				break;
3865 
3866 			memset(&tei, 0, sizeof(tei));
3867 			tei.paddr = &ent.addr;
3868 			tei.subtype = AF_INET;
3869 			tei.masklen = ent.masklen;
3870 			ipfw_import_table_value_legacy(ent.value, &v);
3871 			tei.pvalue = &v;
3872 			memset(&ti, 0, sizeof(ti));
3873 			ti.uidx = ent.tbl;
3874 			ti.type = IPFW_TABLE_CIDR;
3875 
3876 			error = (opt == IP_FW_TABLE_ADD) ?
3877 			    add_table_entry(chain, &ti, &tei, 0, 1) :
3878 			    del_table_entry(chain, &ti, &tei, 0, 1);
3879 		}
3880 		break;
3881 
3882 
3883 	case IP_FW_TABLE_FLUSH:
3884 		{
3885 			u_int16_t tbl;
3886 			struct tid_info ti;
3887 
3888 			error = sooptcopyin(sopt, &tbl,
3889 			    sizeof(tbl), sizeof(tbl));
3890 			if (error)
3891 				break;
3892 			memset(&ti, 0, sizeof(ti));
3893 			ti.uidx = tbl;
3894 			error = flush_table(chain, &ti);
3895 		}
3896 		break;
3897 
3898 	case IP_FW_TABLE_GETSIZE:
3899 		{
3900 			u_int32_t tbl, cnt;
3901 			struct tid_info ti;
3902 
3903 			if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
3904 			    sizeof(tbl))))
3905 				break;
3906 			memset(&ti, 0, sizeof(ti));
3907 			ti.uidx = tbl;
3908 			IPFW_RLOCK(chain);
3909 			error = ipfw_count_table(chain, &ti, &cnt);
3910 			IPFW_RUNLOCK(chain);
3911 			if (error)
3912 				break;
3913 			error = sooptcopyout(sopt, &cnt, sizeof(cnt));
3914 		}
3915 		break;
3916 
3917 	case IP_FW_TABLE_LIST:
3918 		{
3919 			ipfw_table *tbl;
3920 			struct tid_info ti;
3921 
3922 			if (sopt->sopt_valsize < sizeof(*tbl)) {
3923 				error = EINVAL;
3924 				break;
3925 			}
3926 			size = sopt->sopt_valsize;
3927 			tbl = malloc(size, M_TEMP, M_WAITOK);
3928 			error = sooptcopyin(sopt, tbl, size, sizeof(*tbl));
3929 			if (error) {
3930 				free(tbl, M_TEMP);
3931 				break;
3932 			}
3933 			tbl->size = (size - sizeof(*tbl)) /
3934 			    sizeof(ipfw_table_entry);
3935 			memset(&ti, 0, sizeof(ti));
3936 			ti.uidx = tbl->tbl;
3937 			IPFW_RLOCK(chain);
3938 			error = ipfw_dump_table_legacy(chain, &ti, tbl);
3939 			IPFW_RUNLOCK(chain);
3940 			if (error) {
3941 				free(tbl, M_TEMP);
3942 				break;
3943 			}
3944 			error = sooptcopyout(sopt, tbl, size);
3945 			free(tbl, M_TEMP);
3946 		}
3947 		break;
3948 
3949 	/*--- NAT operations are protected by the IPFW_LOCK ---*/
3950 	case IP_FW_NAT_CFG:
3951 		if (IPFW_NAT_LOADED)
3952 			error = ipfw_nat_cfg_ptr(sopt);
3953 		else {
3954 			printf("IP_FW_NAT_CFG: %s\n",
3955 			    "ipfw_nat not present, please load it");
3956 			error = EINVAL;
3957 		}
3958 		break;
3959 
3960 	case IP_FW_NAT_DEL:
3961 		if (IPFW_NAT_LOADED)
3962 			error = ipfw_nat_del_ptr(sopt);
3963 		else {
3964 			printf("IP_FW_NAT_DEL: %s\n",
3965 			    "ipfw_nat not present, please load it");
3966 			error = EINVAL;
3967 		}
3968 		break;
3969 
3970 	case IP_FW_NAT_GET_CONFIG:
3971 		if (IPFW_NAT_LOADED)
3972 			error = ipfw_nat_get_cfg_ptr(sopt);
3973 		else {
3974 			printf("IP_FW_NAT_GET_CFG: %s\n",
3975 			    "ipfw_nat not present, please load it");
3976 			error = EINVAL;
3977 		}
3978 		break;
3979 
3980 	case IP_FW_NAT_GET_LOG:
3981 		if (IPFW_NAT_LOADED)
3982 			error = ipfw_nat_get_log_ptr(sopt);
3983 		else {
3984 			printf("IP_FW_NAT_GET_LOG: %s\n",
3985 			    "ipfw_nat not present, please load it");
3986 			error = EINVAL;
3987 		}
3988 		break;
3989 
3990 	default:
3991 		printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);
3992 		error = EINVAL;
3993 	}
3994 
3995 	return (error);
3996 #undef RULE_MAXSIZE
3997 }
3998 #define	RULE_MAXSIZE	(256*sizeof(u_int32_t))
3999 
4000 /* Functions to convert rules 7.2 <==> 8.0 */
4001 static int
4002 convert_rule_to_7(struct ip_fw_rule0 *rule)
4003 {
4004 	/* Used to modify original rule */
4005 	struct ip_fw7 *rule7 = (struct ip_fw7 *)rule;
4006 	/* copy of original rule, version 8 */
4007 	struct ip_fw_rule0 *tmp;
4008 
4009 	/* Used to copy commands */
4010 	ipfw_insn *ccmd, *dst;
4011 	int ll = 0, ccmdlen = 0;
4012 
4013 	tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
4014 	if (tmp == NULL) {
4015 		return 1; //XXX error
4016 	}
4017 	bcopy(rule, tmp, RULE_MAXSIZE);
4018 
4019 	/* Copy fields */
4020 	//rule7->_pad = tmp->_pad;
4021 	rule7->set = tmp->set;
4022 	rule7->rulenum = tmp->rulenum;
4023 	rule7->cmd_len = tmp->cmd_len;
4024 	rule7->act_ofs = tmp->act_ofs;
4025 	rule7->next_rule = (struct ip_fw7 *)tmp->next_rule;
4026 	rule7->cmd_len = tmp->cmd_len;
4027 	rule7->pcnt = tmp->pcnt;
4028 	rule7->bcnt = tmp->bcnt;
4029 	rule7->timestamp = tmp->timestamp;
4030 
4031 	/* Copy commands */
4032 	for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ;
4033 			ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
4034 		ccmdlen = F_LEN(ccmd);
4035 
4036 		bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
4037 
4038 		if (dst->opcode > O_NAT)
4039 			/* O_REASS doesn't exists in 7.2 version, so
4040 			 * decrement opcode if it is after O_REASS
4041 			 */
4042 			dst->opcode--;
4043 
4044 		if (ccmdlen > ll) {
4045 			printf("ipfw: opcode %d size truncated\n",
4046 				ccmd->opcode);
4047 			return EINVAL;
4048 		}
4049 	}
4050 	free(tmp, M_TEMP);
4051 
4052 	return 0;
4053 }
4054 
4055 static int
4056 convert_rule_to_8(struct ip_fw_rule0 *rule)
4057 {
4058 	/* Used to modify original rule */
4059 	struct ip_fw7 *rule7 = (struct ip_fw7 *) rule;
4060 
4061 	/* Used to copy commands */
4062 	ipfw_insn *ccmd, *dst;
4063 	int ll = 0, ccmdlen = 0;
4064 
4065 	/* Copy of original rule */
4066 	struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
4067 	if (tmp == NULL) {
4068 		return 1; //XXX error
4069 	}
4070 
4071 	bcopy(rule7, tmp, RULE_MAXSIZE);
4072 
4073 	for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ;
4074 			ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
4075 		ccmdlen = F_LEN(ccmd);
4076 
4077 		bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
4078 
4079 		if (dst->opcode > O_NAT)
4080 			/* O_REASS doesn't exists in 7.2 version, so
4081 			 * increment opcode if it is after O_REASS
4082 			 */
4083 			dst->opcode++;
4084 
4085 		if (ccmdlen > ll) {
4086 			printf("ipfw: opcode %d size truncated\n",
4087 			    ccmd->opcode);
4088 			return EINVAL;
4089 		}
4090 	}
4091 
4092 	rule->_pad = tmp->_pad;
4093 	rule->set = tmp->set;
4094 	rule->rulenum = tmp->rulenum;
4095 	rule->cmd_len = tmp->cmd_len;
4096 	rule->act_ofs = tmp->act_ofs;
4097 	rule->next_rule = (struct ip_fw *)tmp->next_rule;
4098 	rule->cmd_len = tmp->cmd_len;
4099 	rule->id = 0; /* XXX see if is ok = 0 */
4100 	rule->pcnt = tmp->pcnt;
4101 	rule->bcnt = tmp->bcnt;
4102 	rule->timestamp = tmp->timestamp;
4103 
4104 	free (tmp, M_TEMP);
4105 	return 0;
4106 }
4107 
4108 /*
4109  * Named object api
4110  *
4111  */
4112 
4113 void
4114 ipfw_init_srv(struct ip_fw_chain *ch)
4115 {
4116 
4117 	ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT);
4118 	ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT,
4119 	    M_IPFW, M_WAITOK | M_ZERO);
4120 }
4121 
4122 void
4123 ipfw_destroy_srv(struct ip_fw_chain *ch)
4124 {
4125 
4126 	free(ch->srvstate, M_IPFW);
4127 	ipfw_objhash_destroy(ch->srvmap);
4128 }
4129 
4130 /*
4131  * Allocate new bitmask which can be used to enlarge/shrink
4132  * named instance index.
4133  */
4134 void
4135 ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks)
4136 {
4137 	size_t size;
4138 	int max_blocks;
4139 	u_long *idx_mask;
4140 
4141 	KASSERT((items % BLOCK_ITEMS) == 0,
4142 	   ("bitmask size needs to power of 2 and greater or equal to %zu",
4143 	    BLOCK_ITEMS));
4144 
4145 	max_blocks = items / BLOCK_ITEMS;
4146 	size = items / 8;
4147 	idx_mask = malloc(size * IPFW_MAX_SETS, M_IPFW, M_WAITOK);
4148 	/* Mark all as free */
4149 	memset(idx_mask, 0xFF, size * IPFW_MAX_SETS);
4150 	*idx_mask &= ~(u_long)1; /* Skip index 0 */
4151 
4152 	*idx = idx_mask;
4153 	*pblocks = max_blocks;
4154 }
4155 
4156 /*
4157  * Copy current bitmask index to new one.
4158  */
4159 void
4160 ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks)
4161 {
4162 	int old_blocks, new_blocks;
4163 	u_long *old_idx, *new_idx;
4164 	int i;
4165 
4166 	old_idx = ni->idx_mask;
4167 	old_blocks = ni->max_blocks;
4168 	new_idx = *idx;
4169 	new_blocks = *blocks;
4170 
4171 	for (i = 0; i < IPFW_MAX_SETS; i++) {
4172 		memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i],
4173 		    old_blocks * sizeof(u_long));
4174 	}
4175 }
4176 
4177 /*
4178  * Swaps current @ni index with new one.
4179  */
4180 void
4181 ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks)
4182 {
4183 	int old_blocks;
4184 	u_long *old_idx;
4185 
4186 	old_idx = ni->idx_mask;
4187 	old_blocks = ni->max_blocks;
4188 
4189 	ni->idx_mask = *idx;
4190 	ni->max_blocks = *blocks;
4191 
4192 	/* Save old values */
4193 	*idx = old_idx;
4194 	*blocks = old_blocks;
4195 }
4196 
4197 void
4198 ipfw_objhash_bitmap_free(void *idx, int blocks)
4199 {
4200 
4201 	free(idx, M_IPFW);
4202 }
4203 
4204 /*
4205  * Creates named hash instance.
4206  * Must be called without holding any locks.
4207  * Return pointer to new instance.
4208  */
4209 struct namedobj_instance *
4210 ipfw_objhash_create(uint32_t items)
4211 {
4212 	struct namedobj_instance *ni;
4213 	int i;
4214 	size_t size;
4215 
4216 	size = sizeof(struct namedobj_instance) +
4217 	    sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE +
4218 	    sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE;
4219 
4220 	ni = malloc(size, M_IPFW, M_WAITOK | M_ZERO);
4221 	ni->nn_size = NAMEDOBJ_HASH_SIZE;
4222 	ni->nv_size = NAMEDOBJ_HASH_SIZE;
4223 
4224 	ni->names = (struct namedobjects_head *)(ni +1);
4225 	ni->values = &ni->names[ni->nn_size];
4226 
4227 	for (i = 0; i < ni->nn_size; i++)
4228 		TAILQ_INIT(&ni->names[i]);
4229 
4230 	for (i = 0; i < ni->nv_size; i++)
4231 		TAILQ_INIT(&ni->values[i]);
4232 
4233 	/* Set default hashing/comparison functions */
4234 	ni->hash_f = objhash_hash_name;
4235 	ni->cmp_f = objhash_cmp_name;
4236 
4237 	/* Allocate bitmask separately due to possible resize */
4238 	ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks);
4239 
4240 	return (ni);
4241 }
4242 
4243 void
4244 ipfw_objhash_destroy(struct namedobj_instance *ni)
4245 {
4246 
4247 	free(ni->idx_mask, M_IPFW);
4248 	free(ni, M_IPFW);
4249 }
4250 
4251 void
4252 ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f,
4253     objhash_cmp_f *cmp_f)
4254 {
4255 
4256 	ni->hash_f = hash_f;
4257 	ni->cmp_f = cmp_f;
4258 }
4259 
4260 static uint32_t
4261 objhash_hash_name(struct namedobj_instance *ni, const void *name, uint32_t set)
4262 {
4263 
4264 	return (fnv_32_str((const char *)name, FNV1_32_INIT));
4265 }
4266 
4267 static int
4268 objhash_cmp_name(struct named_object *no, const void *name, uint32_t set)
4269 {
4270 
4271 	if ((strcmp(no->name, (const char *)name) == 0) && (no->set == set))
4272 		return (0);
4273 
4274 	return (1);
4275 }
4276 
4277 static uint32_t
4278 objhash_hash_idx(struct namedobj_instance *ni, uint32_t val)
4279 {
4280 	uint32_t v;
4281 
4282 	v = val % (ni->nv_size - 1);
4283 
4284 	return (v);
4285 }
4286 
4287 struct named_object *
4288 ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name)
4289 {
4290 	struct named_object *no;
4291 	uint32_t hash;
4292 
4293 	hash = ni->hash_f(ni, name, set) % ni->nn_size;
4294 
4295 	TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
4296 		if (ni->cmp_f(no, name, set) == 0)
4297 			return (no);
4298 	}
4299 
4300 	return (NULL);
4301 }
4302 
4303 /*
4304  * Find named object by @uid.
4305  * Check @tlvs for valid data inside.
4306  *
4307  * Returns pointer to found TLV or NULL.
4308  */
4309 ipfw_obj_ntlv *
4310 ipfw_find_name_tlv_type(void *tlvs, int len, uint16_t uidx, uint32_t etlv)
4311 {
4312 	ipfw_obj_ntlv *ntlv;
4313 	uintptr_t pa, pe;
4314 	int l;
4315 
4316 	pa = (uintptr_t)tlvs;
4317 	pe = pa + len;
4318 	l = 0;
4319 	for (; pa < pe; pa += l) {
4320 		ntlv = (ipfw_obj_ntlv *)pa;
4321 		l = ntlv->head.length;
4322 
4323 		if (l != sizeof(*ntlv))
4324 			return (NULL);
4325 
4326 		if (ntlv->idx != uidx)
4327 			continue;
4328 		/*
4329 		 * When userland has specified zero TLV type, do
4330 		 * not compare it with eltv. In some cases userland
4331 		 * doesn't know what type should it have. Use only
4332 		 * uidx and name for search named_object.
4333 		 */
4334 		if (ntlv->head.type != 0 &&
4335 		    ntlv->head.type != (uint16_t)etlv)
4336 			continue;
4337 
4338 		if (ipfw_check_object_name_generic(ntlv->name) != 0)
4339 			return (NULL);
4340 
4341 		return (ntlv);
4342 	}
4343 
4344 	return (NULL);
4345 }
4346 
4347 /*
4348  * Finds object config based on either legacy index
4349  * or name in ntlv.
4350  * Note @ti structure contains unchecked data from userland.
4351  *
4352  * Returns 0 in success and fills in @pno with found config
4353  */
4354 int
4355 ipfw_objhash_find_type(struct namedobj_instance *ni, struct tid_info *ti,
4356     uint32_t etlv, struct named_object **pno)
4357 {
4358 	char *name;
4359 	ipfw_obj_ntlv *ntlv;
4360 	uint32_t set;
4361 
4362 	if (ti->tlvs == NULL)
4363 		return (EINVAL);
4364 
4365 	ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx, etlv);
4366 	if (ntlv == NULL)
4367 		return (EINVAL);
4368 	name = ntlv->name;
4369 
4370 	/*
4371 	 * Use set provided by @ti instead of @ntlv one.
4372 	 * This is needed due to different sets behavior
4373 	 * controlled by V_fw_tables_sets.
4374 	 */
4375 	set = ti->set;
4376 	*pno = ipfw_objhash_lookup_name(ni, set, name);
4377 	if (*pno == NULL)
4378 		return (ESRCH);
4379 	return (0);
4380 }
4381 
4382 /*
4383  * Find named object by name, considering also its TLV type.
4384  */
4385 struct named_object *
4386 ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set,
4387     uint32_t type, const char *name)
4388 {
4389 	struct named_object *no;
4390 	uint32_t hash;
4391 
4392 	hash = ni->hash_f(ni, name, set) % ni->nn_size;
4393 
4394 	TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
4395 		if (ni->cmp_f(no, name, set) == 0 &&
4396 		    no->etlv == (uint16_t)type)
4397 			return (no);
4398 	}
4399 
4400 	return (NULL);
4401 }
4402 
4403 struct named_object *
4404 ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx)
4405 {
4406 	struct named_object *no;
4407 	uint32_t hash;
4408 
4409 	hash = objhash_hash_idx(ni, kidx);
4410 
4411 	TAILQ_FOREACH(no, &ni->values[hash], nv_next) {
4412 		if (no->kidx == kidx)
4413 			return (no);
4414 	}
4415 
4416 	return (NULL);
4417 }
4418 
4419 int
4420 ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a,
4421     struct named_object *b)
4422 {
4423 
4424 	if ((strcmp(a->name, b->name) == 0) && a->set == b->set)
4425 		return (1);
4426 
4427 	return (0);
4428 }
4429 
4430 void
4431 ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no)
4432 {
4433 	uint32_t hash;
4434 
4435 	hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
4436 	TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next);
4437 
4438 	hash = objhash_hash_idx(ni, no->kidx);
4439 	TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next);
4440 
4441 	ni->count++;
4442 }
4443 
4444 void
4445 ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no)
4446 {
4447 	uint32_t hash;
4448 
4449 	hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
4450 	TAILQ_REMOVE(&ni->names[hash], no, nn_next);
4451 
4452 	hash = objhash_hash_idx(ni, no->kidx);
4453 	TAILQ_REMOVE(&ni->values[hash], no, nv_next);
4454 
4455 	ni->count--;
4456 }
4457 
4458 uint32_t
4459 ipfw_objhash_count(struct namedobj_instance *ni)
4460 {
4461 
4462 	return (ni->count);
4463 }
4464 
4465 uint32_t
4466 ipfw_objhash_count_type(struct namedobj_instance *ni, uint16_t type)
4467 {
4468 	struct named_object *no;
4469 	uint32_t count;
4470 	int i;
4471 
4472 	count = 0;
4473 	for (i = 0; i < ni->nn_size; i++) {
4474 		TAILQ_FOREACH(no, &ni->names[i], nn_next) {
4475 			if (no->etlv == type)
4476 				count++;
4477 		}
4478 	}
4479 	return (count);
4480 }
4481 
4482 /*
4483  * Runs @func for each found named object.
4484  * It is safe to delete objects from callback
4485  */
4486 int
4487 ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg)
4488 {
4489 	struct named_object *no, *no_tmp;
4490 	int i, ret;
4491 
4492 	for (i = 0; i < ni->nn_size; i++) {
4493 		TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
4494 			ret = f(ni, no, arg);
4495 			if (ret != 0)
4496 				return (ret);
4497 		}
4498 	}
4499 	return (0);
4500 }
4501 
4502 /*
4503  * Runs @f for each found named object with type @type.
4504  * It is safe to delete objects from callback
4505  */
4506 int
4507 ipfw_objhash_foreach_type(struct namedobj_instance *ni, objhash_cb_t *f,
4508     void *arg, uint16_t type)
4509 {
4510 	struct named_object *no, *no_tmp;
4511 	int i, ret;
4512 
4513 	for (i = 0; i < ni->nn_size; i++) {
4514 		TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
4515 			if (no->etlv != type)
4516 				continue;
4517 			ret = f(ni, no, arg);
4518 			if (ret != 0)
4519 				return (ret);
4520 		}
4521 	}
4522 	return (0);
4523 }
4524 
4525 /*
4526  * Removes index from given set.
4527  * Returns 0 on success.
4528  */
4529 int
4530 ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx)
4531 {
4532 	u_long *mask;
4533 	int i, v;
4534 
4535 	i = idx / BLOCK_ITEMS;
4536 	v = idx % BLOCK_ITEMS;
4537 
4538 	if (i >= ni->max_blocks)
4539 		return (1);
4540 
4541 	mask = &ni->idx_mask[i];
4542 
4543 	if ((*mask & ((u_long)1 << v)) != 0)
4544 		return (1);
4545 
4546 	/* Mark as free */
4547 	*mask |= (u_long)1 << v;
4548 
4549 	/* Update free offset */
4550 	if (ni->free_off[0] > i)
4551 		ni->free_off[0] = i;
4552 
4553 	return (0);
4554 }
4555 
4556 /*
4557  * Allocate new index in given instance and stores in in @pidx.
4558  * Returns 0 on success.
4559  */
4560 int
4561 ipfw_objhash_alloc_idx(void *n, uint16_t *pidx)
4562 {
4563 	struct namedobj_instance *ni;
4564 	u_long *mask;
4565 	int i, off, v;
4566 
4567 	ni = (struct namedobj_instance *)n;
4568 
4569 	off = ni->free_off[0];
4570 	mask = &ni->idx_mask[off];
4571 
4572 	for (i = off; i < ni->max_blocks; i++, mask++) {
4573 		if ((v = ffsl(*mask)) == 0)
4574 			continue;
4575 
4576 		/* Mark as busy */
4577 		*mask &= ~ ((u_long)1 << (v - 1));
4578 
4579 		ni->free_off[0] = i;
4580 
4581 		v = BLOCK_ITEMS * i + v - 1;
4582 
4583 		*pidx = v;
4584 		return (0);
4585 	}
4586 
4587 	return (1);
4588 }
4589 
4590 /* end of file */
4591