1/*
2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* IPFW2 Backward Compatibility */
29
30/* Convert to and from IPFW2 structures. */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/errno.h>
35#include <sys/socket.h>
36#include <sys/socketvar.h>
37
38#include <sys/types.h>
39
40#include <net/if.h>
41#include <netinet/in.h>
42#include <netinet/in_systm.h>
43#include <netinet/ip.h>
44#include <netinet/ip_icmp.h>
45#include <netinet/ip_fw.h>
46#include <netinet/tcp.h>
47
48#include "ip_fw2_compat.h"
49
50#define FW2_DEBUG_VERBOSE 0
51
52/*
53 * _s_x is a structure that stores a string <-> token pairs, used in
54 * various places in the parser. Entries are stored in arrays,
55 * with an entry with s=NULL as terminator.
56 * The search routines are match_token() and match_value().
57 * Often, an element with x=0 contains an error string.
58 *
59 */
60struct _s_x {
61	char const *s;
62	int x;
63};
64
65#define NO_VERSION_STR "IP_FW_VERSION_NONE"
66#define VERSION_ZERO_STR "IP_FW_VERSION_0"
67#define VERSION_ONE_STR "IP_FW_VERSION_1"
68#define CURRENT_API_VERSION_STR "IP_FW_CURRENT_API_VERSION"
69
70#if FW2_DEBUG_VERBOSE
71
72static struct _s_x f_tcpflags[] = {
73	{ "syn", TH_SYN },
74	{ "fin", TH_FIN },
75	{ "ack", TH_ACK },
76	{ "psh", TH_PUSH },
77	{ "rst", TH_RST },
78	{ "urg", TH_URG },
79	{ "tcp flag", 0 },
80	{ NULL,	0 }
81};
82
83static struct _s_x f_tcpopts[] = {
84	{ "mss",	IP_FW_TCPOPT_MSS },
85	{ "maxseg",	IP_FW_TCPOPT_MSS },
86	{ "window",	IP_FW_TCPOPT_WINDOW },
87	{ "sack",	IP_FW_TCPOPT_SACK },
88	{ "ts",		IP_FW_TCPOPT_TS },
89	{ "timestamp",	IP_FW_TCPOPT_TS },
90	{ "cc",		IP_FW_TCPOPT_CC },
91	{ "tcp option",	0 },
92	{ NULL,	0 }
93};
94
95
96/*
97 * IP options span the range 0 to 255 so we need to remap them
98 * (though in fact only the low 5 bits are significant).
99 */
100static struct _s_x f_ipopts[] = {
101	{ "ssrr",	IP_FW_IPOPT_SSRR},
102	{ "lsrr",	IP_FW_IPOPT_LSRR},
103	{ "rr",		IP_FW_IPOPT_RR},
104	{ "ts",		IP_FW_IPOPT_TS},
105	{ "ip option",	0 },
106	{ NULL,	0 }
107};
108
109static struct _s_x f_iptos[] = {
110	{ "lowdelay",	IPTOS_LOWDELAY},
111	{ "throughput",	IPTOS_THROUGHPUT},
112	{ "reliability", IPTOS_RELIABILITY},
113	{ "mincost",	IPTOS_MINCOST},
114	{ "congestion",	IPTOS_CE},
115	{ "ecntransport", IPTOS_ECT},
116	{ "ip tos option", 0},
117	{ NULL,	0 }
118};
119
120static struct _s_x limit_masks[] = {
121	{"all",		DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
122	{"src-addr",	DYN_SRC_ADDR},
123	{"src-port",	DYN_SRC_PORT},
124	{"dst-addr",	DYN_DST_ADDR},
125	{"dst-port",	DYN_DST_PORT},
126	{NULL,		0}
127};
128
129#endif /* !FW2_DEBUG_VERBOSE */
130
131#if 0 /* version #1 */
132
133static void
134ipfw_print_fw_flags(u_int flags)
135{
136	/* print action */
137	switch (flags & IP_FW_F_COMMAND_COMPAT) {
138		case IP_FW_F_ACCEPT_COMPAT:
139			printf("IP_FW_F_ACCEPT_COMPAT\n");
140			break;
141		case IP_FW_F_COUNT_COMPAT:
142			printf("IP_FW_F_COUNT_COMPAT\n");
143			break;
144		case IP_FW_F_PIPE_COMPAT:
145			printf("IP_FW_F_PIPE_COMPAT\n");
146			break;
147		case IP_FW_F_QUEUE_COMPAT:
148			printf("IP_FW_F_QUEUE_COMPAT\n");
149			break;
150		case IP_FW_F_SKIPTO_COMPAT:
151			printf("IP_FW_F_SKIPTO_COMPAT\n");
152			break;
153		case IP_FW_F_DIVERT_COMPAT:
154			printf("IP_FW_F_DIVERT_COMPAT\n");
155			break;
156		case IP_FW_F_TEE_COMPAT:
157			printf("IP_FW_F_TEE_COMPAT\n");
158			break;
159		case IP_FW_F_FWD_COMPAT:
160			printf("IP_FW_F_FWD_COMPAT\n");
161			break;
162		case IP_FW_F_DENY_COMPAT:
163			printf("IP_FW_F_DENY_COMPAT\n");
164			break;
165		case IP_FW_F_REJECT_COMPAT:
166			printf("IP_FW_F_REJECT_COMPAT\n");
167			break;
168		case IP_FW_F_CHECK_S_COMPAT:
169			printf("IP_FW_F_CHECK_S_COMPAT\n");
170			break;
171		default:
172			printf("No action given\n");
173			break;
174	}
175
176	/* print commands */
177	if (flags & IP_FW_F_IN_COMPAT) {
178		printf("IP_FW_F_IN_COMPAT\n");
179	}
180	if (flags & IP_FW_F_OUT_COMPAT) {
181		printf("IP_FW_F_OUT_COMPAT\n");
182	}
183	if (flags & IP_FW_F_IIFACE_COMPAT) {
184		printf("IP_FW_F_IIFACE_COMPAT\n");
185	}
186	if (flags & IP_FW_F_OIFACE_COMPAT) {
187		printf("IP_FW_F_OIFACE_COMPAT\n");
188	}
189	if (flags & IP_FW_F_PRN_COMPAT) {
190		printf("IP_FW_F_PRN_COMPAT\n");
191	}
192	if (flags & IP_FW_F_SRNG_COMPAT) {
193		printf("IP_FW_F_SRNG_COMPAT\n");
194	}
195	if (flags & IP_FW_F_DRNG_COMPAT) {
196		printf("IP_FW_F_DRNG_COMPAT\n");
197	}
198	if (flags & IP_FW_F_FRAG_COMPAT) {
199		printf("IP_FW_F_FRAG_COMPAT\n");
200	}
201	if (flags & IP_FW_F_IIFNAME_COMPAT) {
202		printf("IP_FW_F_IIFNAME_COMPAT\n");
203	}
204	if (flags & IP_FW_F_OIFNAME_COMPAT) {
205		printf("IP_FW_F_OIFNAME_COMPAT\n");
206	}
207	if (flags & IP_FW_F_INVSRC_COMPAT) {
208		printf("IP_FW_F_INVSRC_COMPAT\n");
209	}
210	if (flags & IP_FW_F_INVDST_COMPAT) {
211		printf("IP_FW_F_INVDST_COMPAT\n");
212	}
213	if (flags & IP_FW_F_ICMPBIT_COMPAT) {
214		printf("IP_FW_F_ICMPBIT_COMPAT\n");
215	}
216	if (flags & IP_FW_F_UID_COMPAT) {
217		printf("IP_FW_F_UID_COMPAT\n");
218	}
219	if (flags & IP_FW_F_RND_MATCH_COMPAT) {
220		printf("IP_FW_F_RND_MATCH_COMPAT\n");
221	}
222	if (flags & IP_FW_F_SMSK_COMPAT) {
223		printf("IP_FW_F_SMSK_COMPAT\n");
224	}
225	if (flags & IP_FW_F_DMSK_COMPAT) {
226		printf("IP_FW_F_DMSK_COMPAT\n");
227	}
228	if (flags & IP_FW_BRIDGED_COMPAT) {
229		printf("IP_FW_BRIDGED_COMPAT\n");
230	}
231	if (flags & IP_FW_F_KEEP_S_COMPAT) {
232		printf("IP_FW_F_KEEP_S_COMPAT\n");
233	}
234	if (flags & IP_FW_F_CHECK_S_COMPAT) {
235		printf("IP_FW_F_CHECK_S_COMPAT\n");
236	}
237	if (flags & IP_FW_F_SME_COMPAT) {
238		printf("IP_FW_F_SME_COMPAT\n");
239	}
240	if (flags & IP_FW_F_DME_COMPAT) {
241		printf("IP_FW_F_DME_COMPAT\n");
242	}
243}
244
245static void
246print_fw_version(u_int32_t api_version)
247{
248	switch (api_version) {
249		case IP_FW_VERSION_0:
250			printf("Version: %s\n", VERSION_ZERO_STR);
251			break;
252		case IP_FW_VERSION_1:
253			printf("Version: %s\n", VERSION_ONE_STR);
254			break;
255		case IP_FW_CURRENT_API_VERSION:
256			printf("Version: %s\n", CURRENT_API_VERSION_STR);
257			break;
258		case IP_FW_VERSION_NONE:
259			printf("Version: %s\n", NO_VERSION_STR);
260			break;
261		default:
262			printf("Unrecognized version\n");
263			break;
264	}
265}
266
267static void
268print_icmptypes(ipfw_insn_u32 *cmd)
269{
270	int i;
271	char sep= ' ';
272
273	printf(" icmptypes");
274	for (i = 0; i < 32; i++) {
275		if ( (cmd->d[0] & (1 << (i))) == 0)
276			continue;
277		printf("%c%d", sep, i);
278		sep = ',';
279	}
280}
281
282/*
283 * print flags set/clear in the two bitmasks passed as parameters.
284 * There is a specialized check for f_tcpflags.
285 */
286static void
287print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
288{
289	char const *comma = "";
290	int i;
291	uint8_t set = cmd->arg1 & 0xff;
292	uint8_t clear = (cmd->arg1 >> 8) & 0xff;
293
294	if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {
295		printf(" setup");
296		return;
297	}
298
299	printf(" %s ", name);
300	for (i=0; list[i].x != 0; i++) {
301		if (set & list[i].x) {
302			set &= ~list[i].x;
303			printf("%s%s", comma, list[i].s);
304			comma = ",";
305		}
306		if (clear & list[i].x) {
307			clear &= ~list[i].x;
308			printf("%s!%s", comma, list[i].s);
309			comma = ",";
310		}
311	}
312}
313
314static int
315contigmask(uint8_t *p, int len)
316{
317	int i, n;
318
319	for (i=0; i<len ; i++)
320		if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
321			break;
322	for (n=i+1; n < len; n++)
323		if ( (p[n/8] & (1 << (7 - (n%8)))) != 0)
324			return -1; /* mask not contiguous */
325	return i;
326}
327
328/*
329 * Print the ip address contained in a command.
330 */
331static void
332print_ip(ipfw_insn_ip *cmd)
333{
334	int len = F_LEN((ipfw_insn *)cmd);
335	uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
336	char ipv4str[MAX_IPv4_STR_LEN];
337
338	printf("%s ", cmd->o.len & F_NOT ? " not": "");
339
340	if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
341		printf("me");
342		return;
343	}
344
345	/*
346	 * len == 2 indicates a single IP, whereas lists of 1 or more
347	 * addr/mask pairs have len = (2n+1). We convert len to n so we
348	 * use that to count the number of entries.
349	 */
350    for (len = len / 2; len > 0; len--, a += 2) {
351	int mb =	/* mask length */
352	    (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ?
353		32 : contigmask((uint8_t *)&(a[1]), 32);
354	if (mb == 0) {	/* any */
355		printf("any");
356	} else {		/* numeric IP followed by some kind of mask */
357		printf("%s", inet_ntop(AF_INET, &a[0], ipv4str, sizeof(ipv4str)));
358		if (mb < 0)
359			printf(":%s", inet_ntop(AF_INET, &a[1], ipv4str, sizeof(ipv4str)));
360		else if (mb < 32)
361			printf("/%d", mb);
362	}
363	if (len > 1)
364		printf(",");
365    }
366}
367
368/*
369 * prints a MAC address/mask pair
370 */
371static void
372print_mac(uint8_t *addr, uint8_t *mask)
373{
374	int l = contigmask(mask, 48);
375
376	if (l == 0)
377		printf(" any");
378	else {
379		printf(" %02x:%02x:%02x:%02x:%02x:%02x",
380		    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
381		if (l == -1)
382			printf("&%02x:%02x:%02x:%02x:%02x:%02x",
383			    mask[0], mask[1], mask[2],
384			    mask[3], mask[4], mask[5]);
385		else if (l < 48)
386			printf("/%d", l);
387	}
388}
389
390#endif /* !version #1 */
391
392#if FW2_DEBUG_VERBOSE
393static void
394ipfw_print_vers2_struct(struct ip_fw *vers2_rule)
395{
396	int			l;
397	ipfw_insn		*cmd;
398	ipfw_insn_log	*logptr = NULL;
399	char			ipv4str[MAX_IPv4_STR_LEN];
400
401	print_fw_version(vers2_rule->version);
402
403	printf("act_ofs: %d\n", vers2_rule->act_ofs);
404	printf("cmd_len: %d\n", vers2_rule->cmd_len);
405	printf("rulenum: %d\n", vers2_rule->rulenum);
406	printf("set: %d\n", vers2_rule->set);
407	printf("pcnt: %llu\n", vers2_rule->pcnt);
408	printf("bcnt: %llu\n", vers2_rule->bcnt);
409	printf("timestamp: %d\n", vers2_rule->timestamp);
410
411	/*
412	 * first print actions
413	 */
414	for (l = vers2_rule->cmd_len - vers2_rule->act_ofs, cmd = ACTION_PTR(vers2_rule);
415			l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
416		switch(cmd->opcode) {
417			case O_CHECK_STATE:
418				printf("check-state");
419				break;
420
421			case O_ACCEPT:
422				printf("allow");
423				break;
424
425			case O_COUNT:
426				printf("count");
427				break;
428
429			case O_DENY:
430				printf("deny");
431				break;
432
433			case O_REJECT:
434				if (cmd->arg1 == ICMP_REJECT_RST)
435					printf("reset");
436				else if (cmd->arg1 == ICMP_UNREACH_HOST)
437					printf("reject");
438				else
439					printf("unreach %u", cmd->arg1);
440				break;
441
442			case O_SKIPTO:
443				printf("skipto %u", cmd->arg1);
444				break;
445
446			case O_PIPE:
447				printf("pipe %u", cmd->arg1);
448				break;
449
450			case O_QUEUE:
451				printf("queue %u", cmd->arg1);
452				break;
453
454			case O_DIVERT:
455				printf("divert %u", cmd->arg1);
456				break;
457
458			case O_TEE:
459				printf("tee %u", cmd->arg1);
460				break;
461
462			case O_FORWARD_IP:
463			{
464				ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
465
466				printf("fwd %s",
467					   inet_ntop(AF_INET, &s->sa.sin_addr, ipv4str,
468					   			 sizeof(ipv4str)));
469				if (s->sa.sin_port)
470					printf(",%d", s->sa.sin_port);
471				break;
472			}
473
474			case O_LOG: /* O_LOG is printed last */
475				logptr = (ipfw_insn_log *)cmd;
476				break;
477
478			default:
479				printf("** unrecognized action %d len %d",
480					cmd->opcode, cmd->len);
481		}
482	}
483	if (logptr) {
484		if (logptr->max_log > 0)
485			printf(" log logamount %d", logptr->max_log);
486		else
487			printf(" log");
488	}
489
490	/*
491	 * then print the body.
492	 */
493	for (l = vers2_rule->act_ofs, cmd = vers2_rule->cmd ;
494		l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
495		/* useful alias */
496		ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
497
498		switch(cmd->opcode) {
499			case O_PROB:
500				break;	/* done already */
501
502			case O_PROBE_STATE:
503				break; /* no need to print anything here */
504
505			case O_MACADDR2:
506			{
507				ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
508
509				if (cmd->len & F_NOT)
510					printf(" not");
511				printf(" MAC");
512				print_mac(m->addr, m->mask);
513				print_mac(m->addr + 6, m->mask + 6);
514				printf("\n");
515				break;
516			}
517			case O_MAC_TYPE:
518			{
519				uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
520				int i;
521
522				for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
523					printf("0x%04x", p[0]);
524					if (p[0] != p[1]) {
525						printf("-");
526						printf("0x%04x", p[1]);
527					}
528					printf(",");
529				}
530				break;
531			}
532			case O_IP_SRC:
533			case O_IP_SRC_MASK:
534			case O_IP_SRC_ME:
535				print_ip((ipfw_insn_ip *)cmd);
536				break;
537
538			case O_IP_DST:
539			case O_IP_DST_MASK:
540			case O_IP_DST_ME:
541				print_ip((ipfw_insn_ip *)cmd);
542				break;
543
544			case O_IP_DSTPORT:
545			case O_IP_SRCPORT:
546			{
547				uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
548				int i;
549
550				for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
551					printf("0x%04x", p[0]);
552					if (p[0] != p[1]) {
553						printf("-");
554						printf("0x%04x", p[1]);
555					}
556					printf(",");
557				}
558				break;
559			}
560			case O_PROTO:
561			{
562				printf("O_PROTO");
563
564				if (cmd->len & F_NOT)
565					printf(" not");
566
567				printf(" %u", cmd->arg1);
568
569				break;
570			}
571
572			default: /*options ... */
573			{
574				if (cmd->len & F_NOT && cmd->opcode != O_IN)
575					printf(" not");
576				switch(cmd->opcode) {
577					case O_FRAG:
578						printf("O_FRAG");
579						break;
580
581					case O_IN:
582						printf(cmd->len & F_NOT ? " out" : " O_IN");
583						break;
584
585					case O_LAYER2:
586						printf(" O_LAYER2");
587						break;
588					case O_XMIT:
589					case O_RECV:
590					case O_VIA:
591					{
592						char const *s;
593						ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
594
595						if (cmd->opcode == O_XMIT)
596							s = "O_XMIT";
597						else if (cmd->opcode == O_RECV)
598							s = "O_RECV";
599						else /* if (cmd->opcode == O_VIA) */
600							s = "O_VIA";
601						if (cmdif->name[0] == '\0') {
602							printf(" %s %s", s,
603								   inet_ntop(AF_INET, &cmdif->p.ip, ipv4str,
604								   			 sizeof(ipv4str)));
605						}
606						else if (cmdif->p.unit == -1)
607							printf(" %s %s*", s, cmdif->name);
608						else
609							printf(" %s %s%d", s, cmdif->name,
610								cmdif->p.unit);
611					}
612						break;
613
614					case O_IPID:
615						if (F_LEN(cmd) == 1)
616							printf(" ipid %u", cmd->arg1 );
617						else {
618							uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
619							int i;
620
621							for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
622								printf("0x%04x", p[0]);
623								if (p[0] != p[1]) {
624									printf("-");
625									printf("0x%04x", p[1]);
626								}
627								printf(",");
628							}
629						}
630
631						break;
632
633					case O_IPTTL:
634						if (F_LEN(cmd) == 1)
635							printf(" ipttl %u", cmd->arg1 );
636						else {
637							uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
638							int i;
639
640							for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
641								printf("0x%04x", p[0]);
642								if (p[0] != p[1]) {
643									printf("-");
644									printf("0x%04x", p[1]);
645								}
646								printf(",");
647							}
648						}
649
650						break;
651
652					case O_IPVER:
653						printf(" ipver %u", cmd->arg1 );
654						break;
655
656					case O_IPPRECEDENCE:
657						printf(" ipprecedence %u", (cmd->arg1) >> 5 );
658						break;
659
660					case O_IPLEN:
661						if (F_LEN(cmd) == 1)
662							printf(" iplen %u", cmd->arg1 );
663						else {
664							uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
665							int i;
666
667							for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
668								printf("0x%04x", p[0]);
669								if (p[0] != p[1]) {
670									printf("-");
671									printf("0x%04x", p[1]);
672								}
673								printf(",");
674							}
675						}
676
677						break;
678
679					case O_IPOPT:
680						print_flags("ipoptions", cmd, f_ipopts);
681						break;
682
683					case O_IPTOS:
684						print_flags("iptos", cmd, f_iptos);
685						break;
686
687					case O_ICMPTYPE:
688						print_icmptypes((ipfw_insn_u32 *)cmd);
689						break;
690
691					case O_ESTAB:
692						printf(" established");
693						break;
694
695					case O_TCPFLAGS:
696						print_flags("tcpflags", cmd, f_tcpflags);
697						break;
698
699					case O_TCPOPTS:
700						print_flags("tcpoptions", cmd, f_tcpopts);
701						break;
702
703					case O_TCPWIN:
704						printf(" tcpwin %d", ntohs(cmd->arg1));
705						break;
706
707					case O_TCPACK:
708						printf(" tcpack %u", ntohl(cmd32->d[0]));
709						break;
710
711					case O_TCPSEQ:
712						printf(" tcpseq %u", ntohl(cmd32->d[0]));
713						break;
714
715					case O_UID:
716						printf(" uid %u", cmd32->d[0]);
717						break;
718
719					case O_GID:
720						printf(" gid %u", cmd32->d[0]);
721						break;
722
723					case O_VERREVPATH:
724						printf(" verrevpath");
725						break;
726
727					case O_IPSEC:
728						printf(" ipsec");
729						break;
730
731					case O_NOP:
732						break;
733
734					case O_KEEP_STATE:
735						printf(" keep-state");
736						break;
737
738					case O_LIMIT:
739					{
740						struct _s_x *p = limit_masks;
741						ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
742						uint8_t x = c->limit_mask;
743						char const *comma = " ";
744
745						printf(" limit");
746						for (; p->x != 0 ; p++)
747							if ((x & p->x) == p->x) {
748								x &= ~p->x;
749								printf("%s%s", comma, p->s);
750								comma = ",";
751							}
752						printf(" %d", c->conn_limit);
753
754						break;
755					}
756
757					default:
758						printf(" [opcode %d len %d]",
759							cmd->opcode, cmd->len);
760				} /* switch */
761			} /* default */
762		} /* switch */
763	} /* for */
764}
765
766#endif /* !FW2_DEBUG_VERBOSE */
767
768
769/*
770 * helper function, updates the pointer to cmd with the length
771 * of the current command, and also cleans up the first word of
772 * the new command in case it has been clobbered before.
773 * from ipfw2.c
774 */
775static ipfw_insn *
776next_cmd(ipfw_insn *cmd)
777{
778	cmd += F_LEN(cmd);
779	bzero(cmd, sizeof(*cmd));
780	return cmd;
781}
782
783/*
784 * A function to fill simple commands of size 1.
785 * Existing flags are preserved.
786 * from ipfw2.c
787 */
788static void
789fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, uint16_t arg)
790{
791	cmd->opcode = opcode;
792	cmd->len =  ((cmd->len) & (F_NOT | F_OR)) | 1;
793	cmd->arg1 = arg;
794}
795
796
797static u_int32_t
798fill_compat_tcpflags(u_int32_t flags) {
799	u_int32_t	flags_compat = 0;
800
801	if (flags & TH_FIN)
802		flags_compat |= IP_FW_TCPF_FIN_COMPAT;
803	if (flags & TH_SYN)
804		flags_compat |= IP_FW_TCPF_SYN_COMPAT;
805	if (flags & TH_RST)
806		flags_compat |= IP_FW_TCPF_RST_COMPAT;
807	if (flags & TH_PUSH)
808		flags_compat |= IP_FW_TCPF_PSH_COMPAT;
809	if (flags & TH_ACK)
810		flags_compat |= IP_FW_TCPF_ACK_COMPAT;
811	if (flags & TH_URG)
812		flags_compat |= IP_FW_TCPF_URG_COMPAT;
813
814	return flags_compat;
815}
816
817
818/* ********************************************
819 * *********** Convert from Latest ************
820 * ********************************************/
821
822/*
823 * Things we're actively ignoring:
824 *	sets, sets of addresses, blocks (NOT, OR)
825 */
826static void
827ipfw_map_from_cmds_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *compat_rule)
828{
829	int 		l;
830	ipfw_insn	*cmd;
831
832	for (l = curr_rule->act_ofs, cmd = curr_rule->cmd ;
833		l > 0 ;
834		l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
835		/* useful alias */
836		ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
837
838		switch (cmd->opcode) {
839			case O_PROTO:
840				/* protocol */
841				compat_rule->fw_prot = cmd->arg1;
842				break;
843
844			case O_IP_SRC_ME:
845				compat_rule->fw_flg |= IP_FW_F_SME_COMPAT;
846				if (cmd->len & F_NOT) {
847					compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
848				}
849				break;
850
851			case O_IP_SRC_MASK:
852			{
853				/* addr/mask */
854				ipfw_insn_ip	*ip = (ipfw_insn_ip *)cmd;
855
856				compat_rule->fw_src = ip->addr;
857				compat_rule->fw_smsk = ip->mask;
858				if (cmd->len & F_NOT) {
859					compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
860				}
861				break;
862			}
863
864			case O_IP_SRC:
865				/* one IP */
866				/* source -
867				 * for now we only deal with one address
868				 * per rule and ignore sets of addresses
869				 */
870				compat_rule->fw_src.s_addr = cmd32->d[0];
871				if (cmd->len & F_NOT) {
872					compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
873				}
874				break;
875
876			case O_IP_SRCPORT:
877			{
878				/* source ports */
879				ipfw_insn_u16	*ports = (ipfw_insn_u16 *)cmd;
880				uint16_t		*p = ports->ports;
881				int				i, j;
882
883				/* copy list of ports */
884				for (i = F_LEN(cmd) - 1, j = 0; i > 0; i--, j++, p += 2) {
885					if (p[0] != p[1]) {
886						/* this is a range */
887						compat_rule->fw_flg |= IP_FW_F_SRNG_COMPAT;
888						compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
889						compat_rule->fw_uar_compat.fw_pts[j] = p[1];
890					} else {
891						compat_rule->fw_uar_compat.fw_pts[j] = p[0];
892					}
893				}
894				IP_FW_SETNSRCP_COMPAT(compat_rule, j);
895
896				break;
897			}
898
899			case O_IP_DST_ME:
900			/* destination */
901				compat_rule->fw_flg |= IP_FW_F_DME_COMPAT;
902				if (cmd->len & F_NOT) {
903					compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
904				}
905				break;
906
907			case O_IP_DST_MASK:
908			{
909				/* addr/mask */
910				ipfw_insn_ip	*ip = (ipfw_insn_ip *)cmd;
911
912				compat_rule->fw_dst = ip->addr;
913				compat_rule->fw_dmsk = ip->mask;
914				if (cmd->len & F_NOT) {
915					compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
916				}
917				break;
918			}
919			case O_IP_DST:
920				/* one IP */
921				/* dest -
922				 * for now we only deal with one address
923				 * per rule, and ignore sets of addresses
924				 */
925				compat_rule->fw_dst.s_addr = cmd32->d[0];
926				if (cmd->len & F_NOT) {
927					compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
928				}
929				break;
930
931			case O_IP_DSTPORT:
932			{
933				/* dest. ports */
934				ipfw_insn_u16	*ports = (ipfw_insn_u16 *)cmd;
935				uint16_t		*p = ports->ports;
936				int				i,
937								j = IP_FW_GETNSRCP_COMPAT(compat_rule);
938
939				/* copy list of ports */
940				for (i = F_LEN(cmd) - 1; i > 0; i--, j++, p += 2) {
941					if (p[0] != p[1]) {
942						/* this is a range */
943						compat_rule->fw_flg |= IP_FW_F_DRNG_COMPAT;
944						compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
945						compat_rule->fw_uar_compat.fw_pts[j] = p[1];
946					} else {
947						compat_rule->fw_uar_compat.fw_pts[j] = p[0];
948					}
949				}
950				IP_FW_SETNDSTP_COMPAT(compat_rule, (j - IP_FW_GETNSRCP_COMPAT(compat_rule)));
951
952				break;
953			}
954
955			case O_LOG:
956			{
957				ipfw_insn_log *c = (ipfw_insn_log *)cmd;
958
959				compat_rule->fw_flg |= IP_FW_F_PRN_COMPAT;
960				compat_rule->fw_logamount = c->max_log;
961				break;
962			}
963			case O_UID:
964				compat_rule->fw_flg |= IP_FW_F_UID_COMPAT;
965				compat_rule->fw_uid = cmd32->d[0];
966				break;
967
968			case O_IN:
969				if (cmd->len & F_NOT) {
970					compat_rule->fw_flg |= IP_FW_F_OUT_COMPAT;
971				} else {
972					compat_rule->fw_flg |= IP_FW_F_IN_COMPAT;
973				}
974				break;
975
976			case O_KEEP_STATE:
977				compat_rule->fw_flg |= IP_FW_F_KEEP_S_COMPAT;
978				break;
979
980			case O_LAYER2:
981				compat_rule->fw_flg |= IP_FW_BRIDGED_COMPAT;
982				break;
983
984			case O_XMIT:
985			{
986				ipfw_insn_if	*ifcmd = (ipfw_insn_if *)cmd;
987				union ip_fw_if_compat	ifu;
988
989				if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
990					/* any */
991					compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
992					ifu.fu_via_ip.s_addr = 0;
993				}
994				else if (ifcmd->p.ip.s_addr != 0) {
995					compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
996					ifu.fu_via_ip = ifcmd->p.ip;
997				} else {
998					compat_rule->fw_flg |= IP_FW_F_OIFNAME_COMPAT;
999					strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1000					ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1001				}
1002				compat_rule->fw_out_if = ifu;
1003
1004				break;
1005			}
1006
1007			case O_RECV:
1008			{
1009				ipfw_insn_if	*ifcmd = (ipfw_insn_if *)cmd;
1010				union ip_fw_if_compat	ifu;
1011
1012				if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1013					/* any */
1014					compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1015					ifu.fu_via_ip.s_addr = 0;
1016				}
1017				else if (ifcmd->p.ip.s_addr != 0) {
1018					compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1019					ifu.fu_via_ip = ifcmd->p.ip;
1020				} else {
1021					compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1022					strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1023					ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1024				}
1025				compat_rule->fw_in_if = ifu;
1026
1027				break;
1028			}
1029
1030			case O_VIA:
1031			{
1032				ipfw_insn_if			*ifcmd = (ipfw_insn_if *)cmd;
1033				union ip_fw_if_compat	ifu;
1034
1035				if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1036					/* any */
1037					ifu.fu_via_ip.s_addr = 0;
1038				}
1039				else if (ifcmd->name[0] != '\0') {
1040					compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1041					strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1042					ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1043				} else {
1044					ifu.fu_via_ip = ifcmd->p.ip;
1045				}
1046				compat_rule->fw_flg |= IF_FW_F_VIAHACK_COMPAT;
1047				compat_rule->fw_out_if = compat_rule->fw_in_if = ifu;
1048
1049				break;
1050			}
1051
1052			case O_FRAG:
1053				compat_rule->fw_flg |= IP_FW_F_FRAG_COMPAT;
1054				break;
1055
1056			case O_IPOPT:
1057				/* IP options */
1058				compat_rule->fw_ipopt = (cmd->arg1 & 0xff);
1059				compat_rule->fw_ipnopt = ((cmd->arg1 >> 8) & 0xff);
1060				break;
1061
1062			case O_TCPFLAGS:
1063				/* check for "setup" */
1064				if ((cmd->arg1 & 0xff) == TH_SYN &&
1065					((cmd->arg1 >> 8) & 0xff) == TH_ACK) {
1066					compat_rule->fw_tcpf = IP_FW_TCPF_SYN_COMPAT;
1067					compat_rule->fw_tcpnf = IP_FW_TCPF_ACK_COMPAT;
1068				}
1069				else {
1070					compat_rule->fw_tcpf = fill_compat_tcpflags(cmd->arg1 & 0xff);
1071					compat_rule->fw_tcpnf = fill_compat_tcpflags((cmd->arg1 >> 8) & 0xff);
1072				}
1073				break;
1074
1075			case O_TCPOPTS:
1076				/* TCP options */
1077				compat_rule->fw_tcpopt = (cmd->arg1 & 0xff);
1078				compat_rule->fw_tcpnopt = ((cmd->arg1 >> 8) & 0xff);
1079				break;
1080
1081			case O_ESTAB:
1082				compat_rule->fw_ipflg |= IP_FW_IF_TCPEST_COMPAT;
1083				break;
1084
1085			case O_ICMPTYPE:
1086			{
1087				/* ICMP */
1088				/* XXX: check this */
1089				int	i, type;
1090
1091				compat_rule->fw_flg |= IP_FW_F_ICMPBIT_COMPAT;
1092				for (i = 0; i < sizeof(uint32_t) ; i++) {
1093					type = cmd32->d[0] & i;
1094
1095					compat_rule->fw_uar_compat.fw_icmptypes[type / (sizeof(unsigned) * 8)] |=
1096						1 << (type % (sizeof(unsigned) * 8));
1097				}
1098				break;
1099			}
1100			default:
1101				break;
1102		} /* switch */
1103	} /* for */
1104}
1105
1106static void
1107ipfw_map_from_cmds_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *compat_rule)
1108{
1109	int 		l;
1110	ipfw_insn	*cmd;
1111	for (l = curr_rule->act_ofs, cmd = curr_rule->cmd ;
1112		l > 0 ;
1113		l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
1114		/* useful alias */
1115		ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
1116
1117		switch (cmd->opcode) {
1118			case O_PROTO:
1119				/* protocol */
1120				compat_rule->fw_prot = cmd->arg1;
1121				break;
1122
1123			case O_IP_SRC_ME:
1124				compat_rule->fw_flg |= IP_FW_F_SME_COMPAT;
1125				if (cmd->len & F_NOT) {
1126					compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
1127				}
1128				break;
1129
1130			case O_IP_SRC_MASK:
1131			{
1132				/* addr/mask */
1133				ipfw_insn_ip	*ip = (ipfw_insn_ip *)cmd;
1134
1135				compat_rule->fw_src = ip->addr;
1136				compat_rule->fw_smsk = ip->mask;
1137				if (cmd->len & F_NOT) {
1138					compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
1139				}
1140				break;
1141			}
1142
1143			case O_IP_SRC:
1144				/* one IP */
1145				/* source -
1146				 * for now we only deal with one address
1147				 * per rule and ignore sets of addresses
1148				 */
1149				compat_rule->fw_src.s_addr = cmd32->d[0];
1150				if (cmd->len & F_NOT) {
1151					compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
1152				}
1153				break;
1154
1155			case O_IP_SRCPORT:
1156			{
1157				/* source ports */
1158				ipfw_insn_u16	*ports = (ipfw_insn_u16 *)cmd;
1159				uint16_t		*p = ports->ports;
1160				int				i, j;
1161
1162				/* copy list of ports */
1163				for (i = F_LEN(cmd) - 1, j = 0; i > 0; i--, j++, p += 2) {
1164					if (p[0] != p[1]) {
1165						/* this is a range */
1166						compat_rule->fw_flg |= IP_FW_F_SRNG_COMPAT;
1167						compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
1168						compat_rule->fw_uar_compat.fw_pts[j] = p[1];
1169					} else {
1170						compat_rule->fw_uar_compat.fw_pts[j] = p[0];
1171					}
1172				}
1173				IP_FW_SETNSRCP_COMPAT(compat_rule, j);
1174
1175				break;
1176			}
1177
1178			case O_IP_DST_ME:
1179			/* destination */
1180				compat_rule->fw_flg |= IP_FW_F_DME_COMPAT;
1181				if (cmd->len & F_NOT) {
1182					compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1183				}
1184				break;
1185
1186			case O_IP_DST_MASK:
1187			{
1188				/* addr/mask */
1189				ipfw_insn_ip	*ip = (ipfw_insn_ip *)cmd;
1190
1191				compat_rule->fw_dst = ip->addr;
1192				compat_rule->fw_dmsk = ip->mask;
1193				if (cmd->len & F_NOT) {
1194					compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1195				}
1196				break;
1197			}
1198			case O_IP_DST:
1199				/* one IP */
1200				/* dest -
1201				 * for now we only deal with one address
1202				 * per rule, and ignore sets of addresses
1203				 */
1204				compat_rule->fw_dst.s_addr = cmd32->d[0];
1205				if (cmd->len & F_NOT) {
1206					compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
1207				}
1208				break;
1209
1210			case O_IP_DSTPORT:
1211			{
1212				/* dest. ports */
1213				ipfw_insn_u16	*ports = (ipfw_insn_u16 *)cmd;
1214				uint16_t		*p = ports->ports;
1215				int				i,
1216								j = IP_FW_GETNSRCP_COMPAT(compat_rule);
1217
1218				/* copy list of ports */
1219				for (i = F_LEN(cmd) - 1; i > 0; i--, j++, p += 2) {
1220					if (p[0] != p[1]) {
1221						/* this is a range */
1222						compat_rule->fw_flg |= IP_FW_F_DRNG_COMPAT;
1223						compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
1224						compat_rule->fw_uar_compat.fw_pts[j] = p[1];
1225					} else {
1226						compat_rule->fw_uar_compat.fw_pts[j] = p[0];
1227					}
1228				}
1229				IP_FW_SETNDSTP_COMPAT(compat_rule, (j - IP_FW_GETNSRCP_COMPAT(compat_rule)));
1230
1231				break;
1232			}
1233
1234			case O_LOG:
1235			{
1236				ipfw_insn_log *c = (ipfw_insn_log *)cmd;
1237
1238				compat_rule->fw_flg |= IP_FW_F_PRN_COMPAT;
1239				compat_rule->fw_logamount = c->max_log;
1240				break;
1241			}
1242			case O_UID:
1243				compat_rule->fw_flg |= IP_FW_F_UID_COMPAT;
1244				compat_rule->fw_uid = cmd32->d[0];
1245				break;
1246
1247			case O_IN:
1248				if (cmd->len & F_NOT) {
1249					compat_rule->fw_flg |= IP_FW_F_OUT_COMPAT;
1250				} else {
1251					compat_rule->fw_flg |= IP_FW_F_IN_COMPAT;
1252				}
1253				break;
1254
1255			case O_KEEP_STATE:
1256				compat_rule->fw_flg |= IP_FW_F_KEEP_S_COMPAT;
1257				break;
1258
1259			case O_LAYER2:
1260				compat_rule->fw_flg |= IP_FW_BRIDGED_COMPAT;
1261				break;
1262
1263			case O_XMIT:
1264			{
1265				ipfw_insn_if	*ifcmd = (ipfw_insn_if *)cmd;
1266				union ip_fw_if_compat	ifu;
1267
1268				if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1269					/* any */
1270					compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
1271					ifu.fu_via_ip.s_addr = 0;
1272				}
1273				else if (ifcmd->p.ip.s_addr != 0) {
1274					compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
1275					ifu.fu_via_ip = ifcmd->p.ip;
1276				} else {
1277					compat_rule->fw_flg |= IP_FW_F_OIFNAME_COMPAT;
1278					strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1279					ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1280				}
1281				compat_rule->fw_out_if = ifu;
1282
1283				break;
1284			}
1285
1286			case O_RECV:
1287			{
1288				ipfw_insn_if	*ifcmd = (ipfw_insn_if *)cmd;
1289				union ip_fw_if_compat	ifu;
1290
1291				if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1292					/* any */
1293					compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1294					ifu.fu_via_ip.s_addr = 0;
1295				}
1296				else if (ifcmd->p.ip.s_addr != 0) {
1297					compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
1298					ifu.fu_via_ip = ifcmd->p.ip;
1299				} else {
1300					compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1301					strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1302					ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1303				}
1304				compat_rule->fw_in_if = ifu;
1305
1306				break;
1307			}
1308
1309			case O_VIA:
1310			{
1311				ipfw_insn_if			*ifcmd = (ipfw_insn_if *)cmd;
1312				union ip_fw_if_compat	ifu;
1313
1314				if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
1315					/* any */
1316					ifu.fu_via_ip.s_addr = 0;
1317				}
1318				else if (ifcmd->name[0] != '\0') {
1319					compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
1320					strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
1321					ifu.fu_via_if_compat.unit = ifcmd->p.unit;
1322				} else {
1323					ifu.fu_via_ip = ifcmd->p.ip;
1324				}
1325				compat_rule->fw_flg |= IF_FW_F_VIAHACK_COMPAT;
1326				compat_rule->fw_out_if = compat_rule->fw_in_if = ifu;
1327
1328				break;
1329			}
1330
1331			case O_FRAG:
1332				compat_rule->fw_flg |= IP_FW_F_FRAG_COMPAT;
1333				break;
1334
1335			case O_IPOPT:
1336				/* IP options */
1337				compat_rule->fw_ipopt = (cmd->arg1 & 0xff);
1338				compat_rule->fw_ipnopt = ((cmd->arg1 >> 8) & 0xff);
1339				break;
1340
1341			case O_TCPFLAGS:
1342				/* check for "setup" */
1343				if ((cmd->arg1 & 0xff) == TH_SYN &&
1344					((cmd->arg1 >> 8) & 0xff) == TH_ACK) {
1345					compat_rule->fw_tcpf = IP_FW_TCPF_SYN_COMPAT;
1346					compat_rule->fw_tcpnf = IP_FW_TCPF_ACK_COMPAT;
1347				}
1348				else {
1349					compat_rule->fw_tcpf = fill_compat_tcpflags(cmd->arg1 & 0xff);
1350					compat_rule->fw_tcpnf = fill_compat_tcpflags((cmd->arg1 >> 8) & 0xff);
1351				}
1352				break;
1353
1354			case O_TCPOPTS:
1355				/* TCP options */
1356				compat_rule->fw_tcpopt = (cmd->arg1 & 0xff);
1357				compat_rule->fw_tcpnopt = ((cmd->arg1 >> 8) & 0xff);
1358				break;
1359
1360			case O_ESTAB:
1361				compat_rule->fw_ipflg |= IP_FW_IF_TCPEST_COMPAT;
1362				break;
1363
1364			case O_ICMPTYPE:
1365			{
1366				/* ICMP */
1367				/* XXX: check this */
1368				int	i, type;
1369
1370				compat_rule->fw_flg |= IP_FW_F_ICMPBIT_COMPAT;
1371				for (i = 0; i < sizeof(uint32_t) ; i++) {
1372					type = cmd32->d[0] & i;
1373
1374					compat_rule->fw_uar_compat.fw_icmptypes[type / (sizeof(unsigned) * 8)] |=
1375						1 << (type % (sizeof(unsigned) * 8));
1376				}
1377				break;
1378			}
1379			default:
1380				break;
1381		} /* switch */
1382	} /* for */
1383}
1384
1385static void
1386ipfw_map_from_actions_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *compat_rule)
1387{
1388	int l;
1389	ipfw_insn	*cmd;
1390
1391	for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
1392			l > 0 ;
1393			l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
1394		switch (cmd->opcode) {
1395			case O_ACCEPT:
1396				compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
1397				break;
1398			case O_COUNT:
1399				compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
1400				break;
1401			case O_PIPE:
1402				compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
1403				compat_rule->fw_divert_port_compat = cmd->arg1;
1404				break;
1405			case O_QUEUE:
1406				compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
1407				compat_rule->fw_divert_port_compat = cmd->arg1;
1408				break;
1409			case O_SKIPTO:
1410				compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
1411				compat_rule->fw_skipto_rule_compat = cmd->arg1;
1412				break;
1413			case O_DIVERT:
1414				compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
1415				compat_rule->fw_divert_port_compat = cmd->arg1;
1416				break;
1417			case O_TEE:
1418				compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
1419				compat_rule->fw_divert_port_compat = cmd->arg1;
1420				break;
1421			case O_FORWARD_IP:
1422			{
1423				ipfw_insn_sa	*p = (ipfw_insn_sa *)cmd;
1424
1425				compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
1426				compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
1427				compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
1428				compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
1429				compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
1430
1431				break;
1432			}
1433			case O_DENY:
1434				compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
1435				break;
1436			case O_REJECT:
1437				compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
1438				compat_rule->fw_reject_code_compat = cmd->arg1;
1439				break;
1440			case O_CHECK_STATE:
1441				compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
1442				break;
1443			default:
1444				break;
1445		}
1446	}
1447}
1448
1449static void
1450ipfw_map_from_actions_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *compat_rule)
1451{
1452	int l;
1453	ipfw_insn	*cmd;
1454	for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
1455			l > 0 ;
1456			l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
1457		switch (cmd->opcode) {
1458			case O_ACCEPT:
1459				compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
1460				break;
1461			case O_COUNT:
1462				compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
1463				break;
1464			case O_PIPE:
1465				compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
1466				compat_rule->fw_divert_port_compat = cmd->arg1;
1467				break;
1468			case O_QUEUE:
1469				compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
1470				compat_rule->fw_divert_port_compat = cmd->arg1;
1471				break;
1472			case O_SKIPTO:
1473				compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
1474				compat_rule->fw_skipto_rule_compat = cmd->arg1;
1475				break;
1476			case O_DIVERT:
1477				compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
1478				compat_rule->fw_divert_port_compat = cmd->arg1;
1479				break;
1480			case O_TEE:
1481				compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
1482				compat_rule->fw_divert_port_compat = cmd->arg1;
1483				break;
1484			case O_FORWARD_IP:
1485			{
1486				ipfw_insn_sa	*p = (ipfw_insn_sa *)cmd;
1487
1488				compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
1489				compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
1490				compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
1491				compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
1492				compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
1493
1494				break;
1495			}
1496			case O_DENY:
1497				compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
1498				break;
1499			case O_REJECT:
1500				compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
1501				compat_rule->fw_reject_code_compat = cmd->arg1;
1502				break;
1503			case O_CHECK_STATE:
1504				compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
1505				break;
1506			default:
1507				break;
1508		}
1509	}
1510}
1511
1512static void
1513ipfw_version_latest_to_one_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *rule_vers1)
1514{
1515	if (!rule_vers1)
1516		return;
1517
1518	bzero(rule_vers1, sizeof(struct ip_fw_compat_32));
1519
1520	rule_vers1->version = IP_FW_VERSION_1;
1521	rule_vers1->context = CAST_DOWN_EXPLICIT(user32_addr_t,curr_rule->context);
1522	rule_vers1->fw_number = curr_rule->rulenum;
1523	rule_vers1->fw_pcnt = curr_rule->pcnt;
1524	rule_vers1->fw_bcnt = curr_rule->bcnt;
1525	rule_vers1->timestamp = curr_rule->timestamp;
1526
1527	/* convert actions */
1528	ipfw_map_from_actions_32(curr_rule, rule_vers1);
1529
1530	/* convert commands */
1531	ipfw_map_from_cmds_32(curr_rule, rule_vers1);
1532
1533#if FW2_DEBUG_VERBOSE
1534	ipfw_print_vers1_struct_32(rule_vers1);
1535#endif
1536}
1537
1538static void
1539ipfw_version_latest_to_one_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *rule_vers1)
1540{
1541	if (!rule_vers1)
1542		return;
1543
1544	bzero(rule_vers1, sizeof(struct ip_fw_compat_64));
1545
1546	rule_vers1->version = IP_FW_VERSION_1;
1547	rule_vers1->context = CAST_DOWN_EXPLICIT(__uint64_t, curr_rule->context);
1548	rule_vers1->fw_number = curr_rule->rulenum;
1549	rule_vers1->fw_pcnt = curr_rule->pcnt;
1550	rule_vers1->fw_bcnt = curr_rule->bcnt;
1551	rule_vers1->timestamp = curr_rule->timestamp;
1552
1553	/* convert actions */
1554	ipfw_map_from_actions_64(curr_rule, rule_vers1);
1555
1556	/* convert commands */
1557	ipfw_map_from_cmds_64(curr_rule, rule_vers1);
1558
1559#if FW2_DEBUG_VERBOSE
1560	ipfw_print_vers1_struct_64(rule_vers1);
1561#endif
1562}
1563
1564/* first convert to version one then to version zero */
1565static void
1566ipfw_version_latest_to_zero(struct ip_fw *curr_rule, struct ip_old_fw *rule_vers0, int is64user)
1567{
1568
1569	if ( is64user ){
1570		struct ip_fw_compat_64	rule_vers1;
1571		ipfw_version_latest_to_one_64((struct ip_fw_64*)curr_rule, &rule_vers1);
1572		bzero(rule_vers0, sizeof(struct ip_old_fw));
1573		bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
1574		bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
1575		bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
1576		bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
1577		rule_vers0->fw_pcnt       = rule_vers1.fw_pcnt;
1578		rule_vers0->fw_bcnt       = rule_vers1.fw_bcnt;
1579		rule_vers0->fw_src        = rule_vers1.fw_src;
1580		rule_vers0->fw_dst        = rule_vers1.fw_dst;
1581		rule_vers0->fw_smsk       = rule_vers1.fw_smsk;
1582		rule_vers0->fw_dmsk       = rule_vers1.fw_dmsk;
1583		rule_vers0->fw_number     = rule_vers1.fw_number;
1584		rule_vers0->fw_flg        = rule_vers1.fw_flg;
1585		rule_vers0->fw_ipopt      = rule_vers1.fw_ipopt;
1586		rule_vers0->fw_ipnopt     = rule_vers1.fw_ipnopt;
1587		rule_vers0->fw_tcpf       = rule_vers1.fw_tcpf;
1588		rule_vers0->fw_tcpnf      = rule_vers1.fw_tcpnf;
1589		rule_vers0->timestamp     = rule_vers1.timestamp;
1590		rule_vers0->fw_prot       = rule_vers1.fw_prot;
1591		rule_vers0->fw_nports     = rule_vers1.fw_nports;
1592		rule_vers0->pipe_ptr      = CAST_DOWN_EXPLICIT(void*, rule_vers1.pipe_ptr);
1593		rule_vers0->next_rule_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.next_rule_ptr);
1594
1595		if (rule_vers1.fw_ipflg & IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
1596	}
1597	else {
1598		struct ip_fw_compat_32	rule_vers1;
1599		ipfw_version_latest_to_one_32( (struct ip_fw_32*)curr_rule, &rule_vers1);
1600		bzero(rule_vers0, sizeof(struct ip_old_fw));
1601		bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
1602		bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
1603		bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
1604		bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
1605		rule_vers0->fw_pcnt       = rule_vers1.fw_pcnt;
1606		rule_vers0->fw_bcnt       = rule_vers1.fw_bcnt;
1607		rule_vers0->fw_src        = rule_vers1.fw_src;
1608		rule_vers0->fw_dst        = rule_vers1.fw_dst;
1609		rule_vers0->fw_smsk       = rule_vers1.fw_smsk;
1610		rule_vers0->fw_dmsk       = rule_vers1.fw_dmsk;
1611		rule_vers0->fw_number     = rule_vers1.fw_number;
1612		rule_vers0->fw_flg        = rule_vers1.fw_flg;
1613		rule_vers0->fw_ipopt      = rule_vers1.fw_ipopt;
1614		rule_vers0->fw_ipnopt     = rule_vers1.fw_ipnopt;
1615		rule_vers0->fw_tcpf       = rule_vers1.fw_tcpf;
1616		rule_vers0->fw_tcpnf      = rule_vers1.fw_tcpnf;
1617		rule_vers0->timestamp     = rule_vers1.timestamp;
1618		rule_vers0->fw_prot       = rule_vers1.fw_prot;
1619		rule_vers0->fw_nports     = rule_vers1.fw_nports;
1620		rule_vers0->pipe_ptr      = CAST_DOWN_EXPLICIT(void*, rule_vers1.pipe_ptr);
1621		rule_vers0->next_rule_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.next_rule_ptr);
1622
1623		if (rule_vers1.fw_ipflg & IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
1624	}
1625
1626}
1627
1628void
1629ipfw_convert_from_latest(struct ip_fw *curr_rule, void *old_rule, u_int32_t api_version, int is64user)
1630{
1631	switch (api_version) {
1632		case IP_FW_VERSION_0:
1633		{
1634			struct ip_old_fw	*rule_vers0 = old_rule;
1635
1636			ipfw_version_latest_to_zero(curr_rule, rule_vers0, is64user);
1637			break;
1638		}
1639		case IP_FW_VERSION_1:
1640		{
1641			if ( is64user )
1642				ipfw_version_latest_to_one_64((struct ip_fw_64*)curr_rule, (struct ip_fw_compat_64 *)old_rule);
1643			else
1644				ipfw_version_latest_to_one_32((struct ip_fw_32*)curr_rule, (struct ip_fw_compat_32 *)old_rule);
1645
1646			break;
1647		}
1648		case IP_FW_CURRENT_API_VERSION:
1649			/* ipfw2 for now, don't need to do anything */
1650			break;
1651
1652		default:
1653			/* unknown version */
1654			break;
1655	}
1656}
1657
1658
1659/* ********************************************
1660 * *********** Convert to Latest **************
1661 * ********************************************/
1662
1663/* from ip_fw.c */
1664static int
1665ipfw_check_vers1_struct_32(struct ip_fw_compat_32 *frwl)
1666{
1667	/* Check for invalid flag bits */
1668	if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
1669		/*
1670		printf(("%s undefined flag bits set (flags=%x)\n",
1671		    err_prefix, frwl->fw_flg));
1672		*/
1673		return (EINVAL);
1674	}
1675	if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
1676		/* check-state */
1677		return 0 ;
1678	}
1679	/* Must apply to incoming or outgoing (or both) */
1680	if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
1681		/*
1682		printf(("%s neither in nor out\n", err_prefix));
1683		*/
1684		return (EINVAL);
1685	}
1686	/* Empty interface name is no good */
1687	if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
1688	      && !*frwl->fw_in_if.fu_via_if_compat.name)
1689	    || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
1690	      && !*frwl->fw_out_if.fu_via_if_compat.name)) {
1691		/*
1692		printf(("%s empty interface name\n", err_prefix));
1693		*/
1694		return (EINVAL);
1695	}
1696	/* Sanity check interface matching */
1697	if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
1698		;		/* allow "via" backwards compatibility */
1699	} else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
1700	    && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
1701		/*
1702		printf(("%s outgoing interface check on incoming\n",
1703		    err_prefix));
1704		*/
1705		return (EINVAL);
1706	}
1707	/* Sanity check port ranges */
1708	if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
1709		/*
1710		printf(("%s src range set but n_src_p=%d\n",
1711		    err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
1712		*/
1713		return (EINVAL);
1714	}
1715	if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
1716		/*
1717		printf(("%s dst range set but n_dst_p=%d\n",
1718		    err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
1719		*/
1720		return (EINVAL);
1721	}
1722	if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
1723		/*
1724		printf(("%s too many ports (%d+%d)\n",
1725		    err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
1726		*/
1727		return (EINVAL);
1728	}
1729	/*
1730	 *	Protocols other than TCP/UDP don't use port range
1731	 */
1732	if ((frwl->fw_prot != IPPROTO_TCP) &&
1733	    (frwl->fw_prot != IPPROTO_UDP) &&
1734	    (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
1735		/*
1736		printf(("%s port(s) specified for non TCP/UDP rule\n",
1737		    err_prefix));
1738		*/
1739		return (EINVAL);
1740	}
1741
1742	/*
1743	 *	Rather than modify the entry to make such entries work,
1744	 *	we reject this rule and require user level utilities
1745	 *	to enforce whatever policy they deem appropriate.
1746	 */
1747	if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
1748		(frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
1749		/*
1750		printf(("%s rule never matches\n", err_prefix));
1751		*/
1752		return (EINVAL);
1753	}
1754
1755	if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
1756		(frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1757		if (frwl->fw_nports) {
1758		/*
1759			printf(("%s cannot mix 'frag' and ports\n", err_prefix));
1760		*/
1761			return (EINVAL);
1762		}
1763		if (frwl->fw_prot == IPPROTO_TCP &&
1764			frwl->fw_tcpf != frwl->fw_tcpnf) {
1765		/*
1766			printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
1767		*/
1768			return (EINVAL);
1769		}
1770	}
1771
1772	/* Check command specific stuff */
1773	switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
1774	{
1775	case IP_FW_F_REJECT_COMPAT:
1776		if (frwl->fw_reject_code_compat >= 0x100
1777		    && !(frwl->fw_prot == IPPROTO_TCP
1778		      && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
1779		/*
1780			printf(("%s unknown reject code\n", err_prefix));
1781		*/
1782			return (EINVAL);
1783		}
1784		break;
1785	case IP_FW_F_DIVERT_COMPAT:		/* Diverting to port zero is invalid */
1786	case IP_FW_F_TEE_COMPAT:
1787	case IP_FW_F_PIPE_COMPAT:              /* piping through 0 is invalid */
1788	case IP_FW_F_QUEUE_COMPAT:             /* piping through 0 is invalid */
1789		if (frwl->fw_divert_port_compat == 0) {
1790		/*
1791			printf(("%s can't divert to port 0\n", err_prefix));
1792		*/
1793			return (EINVAL);
1794		}
1795		break;
1796	case IP_FW_F_DENY_COMPAT:
1797	case IP_FW_F_ACCEPT_COMPAT:
1798	case IP_FW_F_COUNT_COMPAT:
1799	case IP_FW_F_SKIPTO_COMPAT:
1800	case IP_FW_F_FWD_COMPAT:
1801	case IP_FW_F_UID_COMPAT:
1802		break;
1803	default:
1804		/*
1805		printf(("%s invalid command\n", err_prefix));
1806		*/
1807		return (EINVAL);
1808	}
1809
1810	return 0;
1811}
1812
1813static int
1814ipfw_check_vers1_struct_64(struct ip_fw_compat_64 *frwl)
1815{
1816	/* Check for invalid flag bits */
1817	if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
1818		/*
1819		printf(("%s undefined flag bits set (flags=%x)\n",
1820		    err_prefix, frwl->fw_flg));
1821		*/
1822
1823		return (EINVAL);
1824	}
1825	if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
1826		/* check-state */
1827		return 0 ;
1828	}
1829	/* Must apply to incoming or outgoing (or both) */
1830	if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
1831		/*
1832		printf(("%s neither in nor out\n", err_prefix));
1833		*/
1834
1835		return (EINVAL);
1836	}
1837	/* Empty interface name is no good */
1838	if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
1839	      && !*frwl->fw_in_if.fu_via_if_compat.name)
1840	    || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
1841	      && !*frwl->fw_out_if.fu_via_if_compat.name)) {
1842		/*
1843		printf(("%s empty interface name\n", err_prefix));
1844		*/
1845
1846		return (EINVAL);
1847	}
1848	/* Sanity check interface matching */
1849	if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
1850		;		/* allow "via" backwards compatibility */
1851	} else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
1852	    && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
1853		/*
1854		printf(("%s outgoing interface check on incoming\n",
1855		    err_prefix));
1856		*/
1857
1858		return (EINVAL);
1859	}
1860	/* Sanity check port ranges */
1861	if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
1862		/*
1863		printf(("%s src range set but n_src_p=%d\n",
1864		    err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
1865		*/
1866
1867		return (EINVAL);
1868	}
1869	if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
1870		/*
1871		printf(("%s dst range set but n_dst_p=%d\n",
1872		    err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
1873		*/
1874
1875		return (EINVAL);
1876	}
1877	if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
1878		/*
1879		printf(("%s too many ports (%d+%d)\n",
1880		    err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
1881		*/
1882
1883		return (EINVAL);
1884	}
1885	/*
1886	 *	Protocols other than TCP/UDP don't use port range
1887	 */
1888	if ((frwl->fw_prot != IPPROTO_TCP) &&
1889	    (frwl->fw_prot != IPPROTO_UDP) &&
1890	    (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
1891		/*
1892		printf(("%s port(s) specified for non TCP/UDP rule\n",
1893		    err_prefix));
1894		*/
1895
1896		return (EINVAL);
1897	}
1898
1899	/*
1900	 *	Rather than modify the entry to make such entries work,
1901	 *	we reject this rule and require user level utilities
1902	 *	to enforce whatever policy they deem appropriate.
1903	 */
1904	if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
1905		(frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
1906		/*
1907		printf(("%s rule never matches\n", err_prefix));
1908		*/
1909
1910		return (EINVAL);
1911	}
1912
1913	if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
1914		(frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1915		if (frwl->fw_nports) {
1916		/*
1917			printf(("%s cannot mix 'frag' and ports\n", err_prefix));
1918		*/
1919
1920			return (EINVAL);
1921		}
1922		if (frwl->fw_prot == IPPROTO_TCP &&
1923			frwl->fw_tcpf != frwl->fw_tcpnf) {
1924		/*
1925			printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
1926		*/
1927
1928			return (EINVAL);
1929		}
1930	}
1931
1932	/* Check command specific stuff */
1933	switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
1934	{
1935	case IP_FW_F_REJECT_COMPAT:
1936		if (frwl->fw_reject_code_compat >= 0x100
1937		    && !(frwl->fw_prot == IPPROTO_TCP
1938		      && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
1939		/*
1940			printf(("%s unknown reject code\n", err_prefix));
1941		*/
1942
1943			return (EINVAL);
1944		}
1945		break;
1946	case IP_FW_F_DIVERT_COMPAT:		/* Diverting to port zero is invalid */
1947	case IP_FW_F_TEE_COMPAT:
1948	case IP_FW_F_PIPE_COMPAT:              /* piping through 0 is invalid */
1949	case IP_FW_F_QUEUE_COMPAT:             /* piping through 0 is invalid */
1950		if (frwl->fw_divert_port_compat == 0) {
1951		/*
1952			printf(("%s can't divert to port 0\n", err_prefix));
1953		*/
1954
1955			return (EINVAL);
1956		}
1957		break;
1958	case IP_FW_F_DENY_COMPAT:
1959	case IP_FW_F_ACCEPT_COMPAT:
1960	case IP_FW_F_COUNT_COMPAT:
1961	case IP_FW_F_SKIPTO_COMPAT:
1962	case IP_FW_F_FWD_COMPAT:
1963	case IP_FW_F_UID_COMPAT:
1964		break;
1965	default:
1966		/*
1967		printf(("%s invalid command\n", err_prefix));
1968		*/
1969
1970		return (EINVAL);
1971	}
1972
1973	return 0;
1974}
1975
1976static void
1977ipfw_convert_to_cmds_32(struct ip_fw *curr_rule, struct ip_fw_compat_32 *compat_rule)
1978{
1979	int			k;
1980	uint32_t	actbuf[255], cmdbuf[255];
1981	ipfw_insn	*action, *cmd, *src, *dst;
1982	ipfw_insn	*have_state = NULL;	/* track check-state or keep-state */
1983
1984	if (!compat_rule || !curr_rule || !(curr_rule->cmd)) {
1985		return;
1986	}
1987
1988	/* preemptively check the old ip_fw rule to
1989	 * make sure it's valid before starting to copy stuff
1990	 */
1991	if (ipfw_check_vers1_struct_32(compat_rule)) {
1992		/* bad rule */
1993		return;
1994	}
1995
1996	bzero(actbuf, sizeof(actbuf));		/* actions go here */
1997	bzero(cmdbuf, sizeof(cmdbuf));
1998
1999	/* fill in action */
2000	action = (ipfw_insn *)actbuf;
2001	{
2002	u_int	flag = compat_rule->fw_flg;
2003
2004	action->len = 1;	/* default */
2005
2006	if (flag & IP_FW_F_CHECK_S_COMPAT) {
2007		have_state = action;
2008		action->opcode = O_CHECK_STATE;
2009	}
2010	else {
2011		switch (flag & IP_FW_F_COMMAND_COMPAT) {
2012			case IP_FW_F_ACCEPT_COMPAT:
2013				action->opcode = O_ACCEPT;
2014				break;
2015			case IP_FW_F_COUNT_COMPAT:
2016				action->opcode = O_COUNT;
2017				break;
2018			case IP_FW_F_PIPE_COMPAT:
2019				action->opcode = O_PIPE;
2020				action->len = F_INSN_SIZE(ipfw_insn_pipe);
2021				action->arg1 = compat_rule->fw_divert_port_compat;
2022				break;
2023			case IP_FW_F_QUEUE_COMPAT:
2024				action->opcode = O_QUEUE;
2025				action->len = F_INSN_SIZE(ipfw_insn_pipe);
2026				action->arg1 = compat_rule->fw_divert_port_compat;
2027				break;
2028			case IP_FW_F_SKIPTO_COMPAT:
2029				action->opcode = O_SKIPTO;
2030				action->arg1 = compat_rule->fw_skipto_rule_compat;
2031				break;
2032			case IP_FW_F_DIVERT_COMPAT:
2033				action->opcode = O_DIVERT;
2034				action->arg1 = compat_rule->fw_divert_port_compat;
2035				break;
2036			case IP_FW_F_TEE_COMPAT:
2037				action->opcode = O_TEE;
2038				action->arg1 = compat_rule->fw_divert_port_compat;
2039				break;
2040			case IP_FW_F_FWD_COMPAT:
2041			{
2042				ipfw_insn_sa *p = (ipfw_insn_sa *)action;
2043
2044				action->opcode = O_FORWARD_IP;
2045				action->len = F_INSN_SIZE(ipfw_insn_sa);
2046
2047				p->sa.sin_len = compat_rule->fw_fwd_ip_compat.sin_len;
2048				p->sa.sin_family = compat_rule->fw_fwd_ip_compat.sin_family;
2049				p->sa.sin_port = compat_rule->fw_fwd_ip_compat.sin_port;
2050				p->sa.sin_addr = compat_rule->fw_fwd_ip_compat.sin_addr;
2051
2052				break;
2053			}
2054			case IP_FW_F_DENY_COMPAT:
2055				action->opcode = O_DENY;
2056				action->arg1 = 0;
2057				break;
2058			case IP_FW_F_REJECT_COMPAT:
2059				action->opcode = O_REJECT;
2060				action->arg1 = compat_rule->fw_reject_code_compat;
2061				break;
2062			default:
2063				action->opcode = O_NOP;
2064				break;
2065		}
2066	}
2067
2068	/* action is mandatory */
2069	if (action->opcode == O_NOP) {
2070			return;
2071	}
2072
2073	action = next_cmd(action);
2074	} /* end actions */
2075
2076	cmd = (ipfw_insn *)cmdbuf;
2077
2078	/* this is O_CHECK_STATE, we're done */
2079	if (have_state) {
2080			goto done;
2081	}
2082
2083	{
2084	ipfw_insn		*prev = NULL;
2085	u_int			flag = compat_rule->fw_flg;
2086
2087	/* logging */
2088	if (flag & IP_FW_F_PRN_COMPAT) {
2089		ipfw_insn_log *c = (ipfw_insn_log *)cmd;
2090
2091		cmd->opcode = O_LOG;
2092		cmd->len |= F_INSN_SIZE(ipfw_insn_log);
2093		c->max_log = compat_rule->fw_logamount;
2094
2095		prev = cmd;
2096		cmd = next_cmd(cmd);
2097	}
2098
2099	/* protocol */
2100	if (compat_rule->fw_prot != 0) {
2101		fill_cmd(cmd, O_PROTO, compat_rule->fw_prot);
2102		prev = cmd;
2103		cmd = next_cmd(cmd);
2104	}
2105
2106	/* source */
2107	if (flag & IP_FW_F_SME_COMPAT) {
2108		cmd->opcode = O_IP_SRC_ME;
2109		cmd->len |= F_INSN_SIZE(ipfw_insn);
2110		if (flag & IP_FW_F_INVSRC_COMPAT) {
2111			cmd->len ^= F_NOT; /* toggle F_NOT */
2112		}
2113
2114		prev = cmd;
2115		cmd = next_cmd(cmd);
2116	} else {
2117		if (compat_rule->fw_smsk.s_addr != 0) {
2118			/* addr/mask */
2119			ipfw_insn_ip	*ip = (ipfw_insn_ip *)cmd;
2120
2121			ip->addr = compat_rule->fw_src;
2122			ip->mask = compat_rule->fw_smsk;
2123			cmd->opcode = O_IP_SRC_MASK;
2124			cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
2125		} else {
2126			/* one IP */
2127			ipfw_insn_u32	*cmd32 = (ipfw_insn_u32 *)cmd;	/* alias for cmd */
2128
2129			if (compat_rule->fw_src.s_addr == 0) {
2130				/* any */
2131				cmd32->o.len &= ~F_LEN_MASK;	/* zero len */
2132			} else {
2133				cmd32->d[0] = compat_rule->fw_src.s_addr;
2134				cmd32->o.opcode = O_IP_SRC;
2135				cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2136			}
2137		}
2138
2139		if (flag & IP_FW_F_INVSRC_COMPAT) {
2140			cmd->len ^= F_NOT; /* toggle F_NOT */
2141		}
2142
2143		if (F_LEN(cmd) != 0) { /* !any */
2144			prev = cmd;
2145			cmd = next_cmd(cmd);
2146		}
2147	}
2148
2149	/* source ports */
2150	{
2151		ipfw_insn_u16	*ports = (ipfw_insn_u16 *)cmd;
2152		uint16_t		*p = ports->ports;
2153		int				i, j = 0,
2154						nports = IP_FW_GETNSRCP_COMPAT(compat_rule),
2155						have_range = 0;
2156
2157		cmd->opcode = O_IP_SRCPORT;
2158		for (i = 0; i < nports; i++) {
2159			if (((flag & IP_FW_F_SRNG_COMPAT) ||
2160				(flag & IP_FW_F_SMSK_COMPAT)) && !have_range) {
2161				p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
2162				p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2163				have_range = 1;
2164			} else {
2165				p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2166			}
2167			p += 2;
2168			j++;
2169		}
2170
2171		if (j > 0) {
2172			ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
2173		}
2174
2175		prev = cmd;
2176		cmd = next_cmd(cmd);
2177	}
2178
2179	/* destination */
2180	if (flag & IP_FW_F_DME_COMPAT) {
2181		cmd->opcode = O_IP_DST_ME;
2182		cmd->len |= F_INSN_SIZE(ipfw_insn);
2183		if (flag & IP_FW_F_INVDST_COMPAT) {
2184			cmd->len ^= F_NOT; /* toggle F_NOT */
2185		}
2186
2187		prev = cmd;
2188		cmd = next_cmd(cmd);
2189	} else {
2190		if (compat_rule->fw_dmsk.s_addr != 0) {
2191			/* addr/mask */
2192			ipfw_insn_ip	*ip = (ipfw_insn_ip *)cmd;
2193
2194			ip->addr = compat_rule->fw_dst;
2195			ip->mask = compat_rule->fw_dmsk;
2196			cmd->opcode = O_IP_DST_MASK;
2197			cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
2198		} else {
2199			/* one IP */
2200			ipfw_insn_u32	*cmd32 = (ipfw_insn_u32 *)cmd;	/* alias for cmd */
2201
2202			if (compat_rule->fw_dst.s_addr == 0) {
2203				/* any */
2204				cmd32->o.len &= ~F_LEN_MASK;	/* zero len */
2205			} else {
2206				cmd32->d[0] = compat_rule->fw_dst.s_addr;
2207				cmd32->o.opcode = O_IP_DST;
2208				cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2209			}
2210		}
2211
2212		if (flag & IP_FW_F_INVDST_COMPAT) {
2213			cmd->len ^= F_NOT; /* toggle F_NOT */
2214		}
2215
2216		if (F_LEN(cmd) != 0) { /* !any */
2217			prev = cmd;
2218			cmd = next_cmd(cmd);
2219		}
2220	}
2221
2222	/* dest. ports */
2223	{
2224		ipfw_insn_u16	*ports = (ipfw_insn_u16 *)cmd;
2225		uint16_t		*p = ports->ports;
2226		int				i = IP_FW_GETNSRCP_COMPAT(compat_rule),
2227						j = 0,
2228						nports = (IP_FW_GETNDSTP_COMPAT(compat_rule) + i),
2229						have_range = 0;
2230
2231		cmd->opcode = O_IP_DSTPORT;
2232		for (; i < nports; i++, p += 2) {
2233			if (((flag & IP_FW_F_DRNG_COMPAT) ||
2234				(flag & IP_FW_F_DMSK_COMPAT)) && !have_range) {
2235				/* range */
2236				p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
2237				p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2238				have_range = 1;
2239			} else {
2240				p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2241			}
2242			j++;
2243		}
2244
2245		if (j > 0) {
2246			ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
2247		}
2248
2249		prev = cmd;
2250		cmd = next_cmd(cmd);
2251	}
2252
2253	if (flag & IP_FW_F_UID_COMPAT) {
2254		ipfw_insn_u32	*cmd32 = (ipfw_insn_u32 *)cmd;	/* alias for cmd */
2255
2256		cmd32->o.opcode = O_UID;
2257		cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2258		cmd32->d[0] = compat_rule->fw_uid;
2259
2260		prev = cmd;
2261		cmd = next_cmd(cmd);
2262	}
2263
2264	if (flag & IP_FW_F_KEEP_S_COMPAT) {
2265		have_state = cmd;
2266		fill_cmd(cmd, O_KEEP_STATE, 0);
2267
2268		prev = cmd;
2269		cmd = next_cmd(cmd);
2270	}
2271	if (flag & IP_FW_BRIDGED_COMPAT) {
2272		fill_cmd(cmd, O_LAYER2, 0);
2273
2274		prev = cmd;
2275		cmd = next_cmd(cmd);
2276	}
2277
2278	if ((flag & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
2279		/* via */
2280		ipfw_insn_if			*ifcmd = (ipfw_insn_if *)cmd;
2281		union ip_fw_if_compat	ifu = compat_rule->fw_in_if;
2282
2283		cmd->opcode = O_VIA;
2284		ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2285
2286		if (ifu.fu_via_ip.s_addr == 0) {
2287			/* "any" */
2288			ifcmd->name[0] = '\0';
2289			ifcmd->o.len = 0;
2290		}
2291		else if (compat_rule->fw_flg & IP_FW_F_IIFNAME_COMPAT) {
2292			/* by name */
2293			strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2294			ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2295		} else {
2296			/* by addr */
2297			ifcmd->p.ip = ifu.fu_via_ip;
2298		}
2299
2300		prev = cmd;
2301		cmd = next_cmd(cmd);
2302	} else {
2303		if (flag & IP_FW_F_IN_COMPAT) {
2304			fill_cmd(cmd, O_IN, 0);
2305
2306			prev = cmd;
2307			cmd = next_cmd(cmd);
2308		}
2309		if (flag & IP_FW_F_OUT_COMPAT) {
2310			/* if the previous command was O_IN, and this
2311			 * is being set as well, it's equivalent to not
2312			 * having either command, so let's back up prev
2313			 * to the cmd before it and move cmd to prev.
2314			 */
2315			if (prev->opcode == O_IN) {
2316				cmd = prev;
2317				bzero(cmd, sizeof(*cmd));
2318			} else {
2319				cmd->len ^= F_NOT; /* toggle F_NOT */
2320				fill_cmd(cmd, O_IN, 0);
2321
2322				prev = cmd;
2323				cmd = next_cmd(cmd);
2324			}
2325		}
2326		if (flag & IP_FW_F_OIFACE_COMPAT) {
2327			/* xmit */
2328			ipfw_insn_if	*ifcmd = (ipfw_insn_if *)cmd;
2329			union ip_fw_if_compat	ifu = compat_rule->fw_out_if;
2330
2331			cmd->opcode = O_XMIT;
2332			ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2333
2334			if (ifu.fu_via_ip.s_addr == 0) {
2335				/* "any" */
2336				ifcmd->name[0] = '\0';
2337				ifcmd->o.len = 0;
2338			}
2339			else if (flag & IP_FW_F_OIFNAME_COMPAT) {
2340				/* by name */
2341				strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2342				ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2343			} else {
2344				/* by addr */
2345				ifcmd->p.ip = ifu.fu_via_ip;
2346			}
2347
2348			prev = cmd;
2349			cmd = next_cmd(cmd);
2350		}
2351		else if (flag & IP_FW_F_IIFACE_COMPAT) {
2352			/* recv */
2353			ipfw_insn_if	*ifcmd = (ipfw_insn_if *)cmd;
2354			union ip_fw_if_compat	ifu = compat_rule->fw_in_if;
2355
2356			cmd->opcode = O_RECV;
2357			ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2358
2359			if (ifu.fu_via_ip.s_addr == 0) {
2360				/* "any" */
2361				ifcmd->name[0] = '\0';
2362				ifcmd->o.len = 0;
2363			}
2364			else if (flag & IP_FW_F_IIFNAME_COMPAT) {
2365				/* by name */
2366				strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2367				ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2368			} else {
2369				/* by addr */
2370				ifcmd->p.ip = ifu.fu_via_ip;
2371			}
2372
2373			prev = cmd;
2374			cmd = next_cmd(cmd);
2375		}
2376	}
2377
2378	if (flag & IP_FW_F_FRAG_COMPAT) {
2379		fill_cmd(cmd, O_FRAG, 0);
2380
2381		prev = cmd;
2382		cmd = next_cmd(cmd);
2383	}
2384
2385	/* IP options */
2386	if (compat_rule->fw_ipopt != 0 || compat_rule->fw_ipnopt != 0) {
2387		fill_cmd(cmd, O_IPOPT, (compat_rule->fw_ipopt & 0xff) |
2388								(compat_rule->fw_ipnopt & 0xff) << 8);
2389
2390		prev = cmd;
2391		cmd = next_cmd(cmd);
2392	}
2393
2394	if (compat_rule->fw_prot == IPPROTO_TCP) {
2395		if (compat_rule->fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
2396			fill_cmd(cmd, O_ESTAB, 0);
2397
2398			prev = cmd;
2399			cmd = next_cmd(cmd);
2400		}
2401
2402		/* TCP options and flags */
2403		if (compat_rule->fw_tcpf != 0 || compat_rule->fw_tcpnf != 0) {
2404			if ((compat_rule->fw_tcpf & IP_FW_TCPF_SYN_COMPAT) &&
2405				compat_rule->fw_tcpnf & IP_FW_TCPF_ACK_COMPAT) {
2406				fill_cmd(cmd, O_TCPFLAGS, (TH_SYN) | ( (TH_ACK) & 0xff) <<8);
2407
2408				prev = cmd;
2409				cmd = next_cmd(cmd);
2410			}
2411			else {
2412				fill_cmd(cmd, O_TCPFLAGS, (compat_rule->fw_tcpf & 0xff) |
2413											(compat_rule->fw_tcpnf & 0xff) << 8);
2414
2415				prev = cmd;
2416				cmd = next_cmd(cmd);
2417			}
2418		}
2419		if (compat_rule->fw_tcpopt != 0 || compat_rule->fw_tcpnopt != 0) {
2420			fill_cmd(cmd, O_TCPOPTS, (compat_rule->fw_tcpopt & 0xff) |
2421										(compat_rule->fw_tcpnopt & 0xff) << 8);
2422
2423			prev = cmd;
2424			cmd = next_cmd(cmd);
2425		}
2426	}
2427
2428	/* ICMP */
2429	/* XXX: check this */
2430	if (flag & IP_FW_F_ICMPBIT_COMPAT) {
2431		int	i;
2432		ipfw_insn_u32	*cmd32 = (ipfw_insn_u32 *)cmd;	/* alias for cmd */
2433
2434		cmd32->o.opcode = O_ICMPTYPE;
2435		cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2436
2437		for (i = 0; i < IP_FW_ICMPTYPES_DIM_COMPAT; i++) {
2438			cmd32->d[0] |= compat_rule->fw_uar_compat.fw_icmptypes[i];
2439		}
2440
2441		prev = cmd;
2442		cmd = next_cmd(cmd);
2443	}
2444	} /* end commands */
2445
2446done:
2447	/* finally, copy everything into the current
2448	 * rule buffer in the right order.
2449	 */
2450	dst = curr_rule->cmd;
2451
2452	/* first, do match probability */
2453	if (compat_rule->fw_flg & IP_FW_F_RND_MATCH_COMPAT) {
2454		dst->opcode = O_PROB;
2455		dst->len = 2;
2456		*((int32_t *)(dst+1)) = compat_rule->pipe_ptr;
2457		dst += dst->len;
2458	}
2459
2460	/* generate O_PROBE_STATE if necessary */
2461	if (have_state && have_state->opcode != O_CHECK_STATE) {
2462		fill_cmd(dst, O_PROBE_STATE, 0);
2463		dst = next_cmd(dst);
2464	}
2465
2466	/*
2467	 * copy all commands but O_LOG, O_KEEP_STATE
2468	 */
2469	for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
2470		k = F_LEN(src);
2471
2472		switch (src->opcode) {
2473		case O_LOG:
2474		case O_KEEP_STATE:
2475			break;
2476		default:
2477			bcopy(src, dst, k * sizeof(uint32_t));
2478			dst += k;
2479		}
2480	}
2481
2482	/*
2483	 * put back the have_state command as last opcode
2484	 */
2485	if (have_state && have_state->opcode != O_CHECK_STATE) {
2486		k = F_LEN(have_state);
2487		bcopy(have_state, dst, k * sizeof(uint32_t));
2488		dst += k;
2489	}
2490
2491	/*
2492	 * start action section
2493	 */
2494	curr_rule->act_ofs = dst - curr_rule->cmd;
2495
2496	/*
2497	 * put back O_LOG if necessary
2498	 */
2499	src = (ipfw_insn *)cmdbuf;
2500	if (src->opcode == O_LOG) {
2501		k = F_LEN(src);
2502		bcopy(src, dst, k * sizeof(uint32_t));
2503		dst += k;
2504	}
2505
2506	/*
2507	 * copy all other actions
2508	 */
2509	for (src = (ipfw_insn *)actbuf; src != action; src += k) {
2510		k = F_LEN(src);
2511		bcopy(src, dst, k * sizeof(uint32_t));
2512		dst += k;
2513	}
2514
2515	curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
2516
2517	return;
2518}
2519
2520static void
2521ipfw_convert_to_cmds_64(struct ip_fw *curr_rule, struct ip_fw_compat_64 *compat_rule)
2522{
2523	int			k;
2524	uint32_t	actbuf[255], cmdbuf[255];
2525	ipfw_insn	*action, *cmd, *src, *dst;
2526	ipfw_insn	*have_state = NULL;	/* track check-state or keep-state */
2527
2528	if (!compat_rule || !curr_rule || !(curr_rule->cmd)) {
2529		return;
2530	}
2531
2532	/* preemptively check the old ip_fw rule to
2533	 * make sure it's valid before starting to copy stuff
2534	 */
2535	if (ipfw_check_vers1_struct_64(compat_rule)) {
2536		/* bad rule */
2537		return;
2538	}
2539
2540	bzero(actbuf, sizeof(actbuf));		/* actions go here */
2541	bzero(cmdbuf, sizeof(cmdbuf));
2542	/* fill in action */
2543	action = (ipfw_insn *)actbuf;
2544	{
2545	u_int	flag = compat_rule->fw_flg;
2546
2547	action->len = 1;	/* default */
2548
2549	if (flag & IP_FW_F_CHECK_S_COMPAT) {
2550		have_state = action;
2551		action->opcode = O_CHECK_STATE;
2552	}
2553	else {
2554		switch (flag & IP_FW_F_COMMAND_COMPAT) {
2555			case IP_FW_F_ACCEPT_COMPAT:
2556				action->opcode = O_ACCEPT;
2557				break;
2558			case IP_FW_F_COUNT_COMPAT:
2559				action->opcode = O_COUNT;
2560				break;
2561			case IP_FW_F_PIPE_COMPAT:
2562				action->opcode = O_PIPE;
2563				action->len = F_INSN_SIZE(ipfw_insn_pipe);
2564				action->arg1 = compat_rule->fw_divert_port_compat;
2565				break;
2566			case IP_FW_F_QUEUE_COMPAT:
2567				action->opcode = O_QUEUE;
2568				action->len = F_INSN_SIZE(ipfw_insn_pipe);
2569				action->arg1 = compat_rule->fw_divert_port_compat;
2570				break;
2571			case IP_FW_F_SKIPTO_COMPAT:
2572				action->opcode = O_SKIPTO;
2573				action->arg1 = compat_rule->fw_skipto_rule_compat;
2574				break;
2575			case IP_FW_F_DIVERT_COMPAT:
2576				action->opcode = O_DIVERT;
2577				action->arg1 = compat_rule->fw_divert_port_compat;
2578				break;
2579			case IP_FW_F_TEE_COMPAT:
2580				action->opcode = O_TEE;
2581				action->arg1 = compat_rule->fw_divert_port_compat;
2582				break;
2583			case IP_FW_F_FWD_COMPAT:
2584			{
2585				ipfw_insn_sa *p = (ipfw_insn_sa *)action;
2586
2587				action->opcode = O_FORWARD_IP;
2588				action->len = F_INSN_SIZE(ipfw_insn_sa);
2589
2590				p->sa.sin_len = compat_rule->fw_fwd_ip_compat.sin_len;
2591				p->sa.sin_family = compat_rule->fw_fwd_ip_compat.sin_family;
2592				p->sa.sin_port = compat_rule->fw_fwd_ip_compat.sin_port;
2593				p->sa.sin_addr = compat_rule->fw_fwd_ip_compat.sin_addr;
2594
2595				break;
2596			}
2597			case IP_FW_F_DENY_COMPAT:
2598				action->opcode = O_DENY;
2599				action->arg1 = 0;
2600				break;
2601			case IP_FW_F_REJECT_COMPAT:
2602				action->opcode = O_REJECT;
2603				action->arg1 = compat_rule->fw_reject_code_compat;
2604				break;
2605			default:
2606				action->opcode = O_NOP;
2607				break;
2608		}
2609	}
2610
2611	/* action is mandatory */
2612	if (action->opcode == O_NOP) {
2613			return;
2614	}
2615
2616	action = next_cmd(action);
2617	} /* end actions */
2618
2619	cmd = (ipfw_insn *)cmdbuf;
2620
2621	/* this is O_CHECK_STATE, we're done */
2622	if (have_state) {
2623			goto done;
2624	}
2625
2626	{
2627	ipfw_insn		*prev = NULL;
2628	u_int			flag = compat_rule->fw_flg;
2629
2630	/* logging */
2631	if (flag & IP_FW_F_PRN_COMPAT) {
2632		ipfw_insn_log *c = (ipfw_insn_log *)cmd;
2633
2634		cmd->opcode = O_LOG;
2635		cmd->len |= F_INSN_SIZE(ipfw_insn_log);
2636		c->max_log = compat_rule->fw_logamount;
2637
2638		prev = cmd;
2639		cmd = next_cmd(cmd);
2640	}
2641
2642	/* protocol */
2643	if (compat_rule->fw_prot != 0) {
2644		fill_cmd(cmd, O_PROTO, compat_rule->fw_prot);
2645		prev = cmd;
2646		cmd = next_cmd(cmd);
2647	}
2648
2649	/* source */
2650	if (flag & IP_FW_F_SME_COMPAT) {
2651		cmd->opcode = O_IP_SRC_ME;
2652		cmd->len |= F_INSN_SIZE(ipfw_insn);
2653		if (flag & IP_FW_F_INVSRC_COMPAT) {
2654			cmd->len ^= F_NOT; /* toggle F_NOT */
2655		}
2656
2657		prev = cmd;
2658		cmd = next_cmd(cmd);
2659	} else {
2660		if (compat_rule->fw_smsk.s_addr != 0) {
2661			/* addr/mask */
2662			ipfw_insn_ip	*ip = (ipfw_insn_ip *)cmd;
2663
2664			ip->addr = compat_rule->fw_src;
2665			ip->mask = compat_rule->fw_smsk;
2666			cmd->opcode = O_IP_SRC_MASK;
2667			cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
2668		} else {
2669			/* one IP */
2670			ipfw_insn_u32	*cmd32 = (ipfw_insn_u32 *)cmd;	/* alias for cmd */
2671
2672			if (compat_rule->fw_src.s_addr == 0) {
2673				/* any */
2674				cmd32->o.len &= ~F_LEN_MASK;	/* zero len */
2675			} else {
2676				cmd32->d[0] = compat_rule->fw_src.s_addr;
2677				cmd32->o.opcode = O_IP_SRC;
2678				cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2679			}
2680		}
2681
2682		if (flag & IP_FW_F_INVSRC_COMPAT) {
2683			cmd->len ^= F_NOT; /* toggle F_NOT */
2684		}
2685
2686		if (F_LEN(cmd) != 0) { /* !any */
2687			prev = cmd;
2688			cmd = next_cmd(cmd);
2689		}
2690	}
2691
2692	/* source ports */
2693	{
2694		ipfw_insn_u16	*ports = (ipfw_insn_u16 *)cmd;
2695		uint16_t		*p = ports->ports;
2696		int				i, j = 0,
2697						nports = IP_FW_GETNSRCP_COMPAT(compat_rule),
2698						have_range = 0;
2699
2700		cmd->opcode = O_IP_SRCPORT;
2701		for (i = 0; i < nports; i++) {
2702			if (((flag & IP_FW_F_SRNG_COMPAT) ||
2703				(flag & IP_FW_F_SMSK_COMPAT)) && !have_range) {
2704				p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
2705				p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2706				have_range = 1;
2707			} else {
2708				p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2709			}
2710			p += 2;
2711			j++;
2712		}
2713
2714		if (j > 0) {
2715			ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
2716		}
2717
2718		prev = cmd;
2719		cmd = next_cmd(cmd);
2720	}
2721
2722	/* destination */
2723	if (flag & IP_FW_F_DME_COMPAT) {
2724		cmd->opcode = O_IP_DST_ME;
2725		cmd->len |= F_INSN_SIZE(ipfw_insn);
2726		if (flag & IP_FW_F_INVDST_COMPAT) {
2727			cmd->len ^= F_NOT; /* toggle F_NOT */
2728		}
2729
2730		prev = cmd;
2731		cmd = next_cmd(cmd);
2732	} else {
2733		if (compat_rule->fw_dmsk.s_addr != 0) {
2734			/* addr/mask */
2735			ipfw_insn_ip	*ip = (ipfw_insn_ip *)cmd;
2736
2737			ip->addr = compat_rule->fw_dst;
2738			ip->mask = compat_rule->fw_dmsk;
2739			cmd->opcode = O_IP_DST_MASK;
2740			cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
2741		} else {
2742			/* one IP */
2743			ipfw_insn_u32	*cmd32 = (ipfw_insn_u32 *)cmd;	/* alias for cmd */
2744
2745			if (compat_rule->fw_dst.s_addr == 0) {
2746				/* any */
2747				cmd32->o.len &= ~F_LEN_MASK;	/* zero len */
2748			} else {
2749				cmd32->d[0] = compat_rule->fw_dst.s_addr;
2750				cmd32->o.opcode = O_IP_DST;
2751				cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2752			}
2753		}
2754
2755		if (flag & IP_FW_F_INVDST_COMPAT) {
2756			cmd->len ^= F_NOT; /* toggle F_NOT */
2757		}
2758
2759		if (F_LEN(cmd) != 0) { /* !any */
2760			prev = cmd;
2761			cmd = next_cmd(cmd);
2762		}
2763	}
2764
2765	/* dest. ports */
2766	{
2767		ipfw_insn_u16	*ports = (ipfw_insn_u16 *)cmd;
2768		uint16_t		*p = ports->ports;
2769		int				i = IP_FW_GETNSRCP_COMPAT(compat_rule),
2770						j = 0,
2771						nports = (IP_FW_GETNDSTP_COMPAT(compat_rule) + i),
2772						have_range = 0;
2773
2774		cmd->opcode = O_IP_DSTPORT;
2775		for (; i < nports; i++, p += 2) {
2776			if (((flag & IP_FW_F_DRNG_COMPAT) ||
2777				(flag & IP_FW_F_DMSK_COMPAT)) && !have_range) {
2778				/* range */
2779				p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
2780				p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2781				have_range = 1;
2782			} else {
2783				p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
2784			}
2785			j++;
2786		}
2787
2788		if (j > 0) {
2789			ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
2790		}
2791
2792		prev = cmd;
2793		cmd = next_cmd(cmd);
2794	}
2795
2796	if (flag & IP_FW_F_UID_COMPAT) {
2797		ipfw_insn_u32	*cmd32 = (ipfw_insn_u32 *)cmd;	/* alias for cmd */
2798
2799		cmd32->o.opcode = O_UID;
2800		cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2801		cmd32->d[0] = compat_rule->fw_uid;
2802
2803		prev = cmd;
2804		cmd = next_cmd(cmd);
2805	}
2806
2807	if (flag & IP_FW_F_KEEP_S_COMPAT) {
2808		have_state = cmd;
2809		fill_cmd(cmd, O_KEEP_STATE, 0);
2810
2811		prev = cmd;
2812		cmd = next_cmd(cmd);
2813	}
2814	if (flag & IP_FW_BRIDGED_COMPAT) {
2815		fill_cmd(cmd, O_LAYER2, 0);
2816
2817		prev = cmd;
2818		cmd = next_cmd(cmd);
2819	}
2820
2821	if ((flag & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
2822		/* via */
2823		ipfw_insn_if			*ifcmd = (ipfw_insn_if *)cmd;
2824		union ip_fw_if_compat	ifu = compat_rule->fw_in_if;
2825
2826		cmd->opcode = O_VIA;
2827		ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2828
2829		if (ifu.fu_via_ip.s_addr == 0) {
2830			/* "any" */
2831			ifcmd->name[0] = '\0';
2832			ifcmd->o.len = 0;
2833		}
2834		else if (compat_rule->fw_flg & IP_FW_F_IIFNAME_COMPAT) {
2835			/* by name */
2836			strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2837			ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2838		} else {
2839			/* by addr */
2840			ifcmd->p.ip = ifu.fu_via_ip;
2841		}
2842
2843		prev = cmd;
2844		cmd = next_cmd(cmd);
2845	} else {
2846		if (flag & IP_FW_F_IN_COMPAT) {
2847			fill_cmd(cmd, O_IN, 0);
2848
2849			prev = cmd;
2850			cmd = next_cmd(cmd);
2851		}
2852		if (flag & IP_FW_F_OUT_COMPAT) {
2853			/* if the previous command was O_IN, and this
2854			 * is being set as well, it's equivalent to not
2855			 * having either command, so let's back up prev
2856			 * to the cmd before it and move cmd to prev.
2857			 */
2858			if (prev->opcode == O_IN) {
2859				cmd = prev;
2860				bzero(cmd, sizeof(*cmd));
2861			} else {
2862				cmd->len ^= F_NOT; /* toggle F_NOT */
2863				fill_cmd(cmd, O_IN, 0);
2864
2865				prev = cmd;
2866				cmd = next_cmd(cmd);
2867			}
2868		}
2869		if (flag & IP_FW_F_OIFACE_COMPAT) {
2870			/* xmit */
2871			ipfw_insn_if	*ifcmd = (ipfw_insn_if *)cmd;
2872			union ip_fw_if_compat	ifu = compat_rule->fw_out_if;
2873
2874			cmd->opcode = O_XMIT;
2875			ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2876
2877			if (ifu.fu_via_ip.s_addr == 0) {
2878				/* "any" */
2879				ifcmd->name[0] = '\0';
2880				ifcmd->o.len = 0;
2881			}
2882			else if (flag & IP_FW_F_OIFNAME_COMPAT) {
2883				/* by name */
2884				strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2885				ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2886			} else {
2887				/* by addr */
2888				ifcmd->p.ip = ifu.fu_via_ip;
2889			}
2890
2891			prev = cmd;
2892			cmd = next_cmd(cmd);
2893		}
2894		else if (flag & IP_FW_F_IIFACE_COMPAT) {
2895			/* recv */
2896			ipfw_insn_if	*ifcmd = (ipfw_insn_if *)cmd;
2897			union ip_fw_if_compat	ifu = compat_rule->fw_in_if;
2898
2899			cmd->opcode = O_RECV;
2900			ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2901
2902			if (ifu.fu_via_ip.s_addr == 0) {
2903				/* "any" */
2904				ifcmd->name[0] = '\0';
2905				ifcmd->o.len = 0;
2906			}
2907			else if (flag & IP_FW_F_IIFNAME_COMPAT) {
2908				/* by name */
2909				strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
2910				ifcmd->p.unit = ifu.fu_via_if_compat.unit;
2911			} else {
2912				/* by addr */
2913				ifcmd->p.ip = ifu.fu_via_ip;
2914			}
2915
2916			prev = cmd;
2917			cmd = next_cmd(cmd);
2918		}
2919	}
2920
2921	if (flag & IP_FW_F_FRAG_COMPAT) {
2922		fill_cmd(cmd, O_FRAG, 0);
2923
2924		prev = cmd;
2925		cmd = next_cmd(cmd);
2926	}
2927
2928	/* IP options */
2929	if (compat_rule->fw_ipopt != 0 || compat_rule->fw_ipnopt != 0) {
2930		fill_cmd(cmd, O_IPOPT, (compat_rule->fw_ipopt & 0xff) |
2931								(compat_rule->fw_ipnopt & 0xff) << 8);
2932
2933		prev = cmd;
2934		cmd = next_cmd(cmd);
2935	}
2936
2937	if (compat_rule->fw_prot == IPPROTO_TCP) {
2938		if (compat_rule->fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
2939			fill_cmd(cmd, O_ESTAB, 0);
2940
2941			prev = cmd;
2942			cmd = next_cmd(cmd);
2943		}
2944
2945		/* TCP options and flags */
2946		if (compat_rule->fw_tcpf != 0 || compat_rule->fw_tcpnf != 0) {
2947			if ((compat_rule->fw_tcpf & IP_FW_TCPF_SYN_COMPAT) &&
2948				compat_rule->fw_tcpnf & IP_FW_TCPF_ACK_COMPAT) {
2949				fill_cmd(cmd, O_TCPFLAGS, (TH_SYN) | ( (TH_ACK) & 0xff) <<8);
2950
2951				prev = cmd;
2952				cmd = next_cmd(cmd);
2953			}
2954			else {
2955				fill_cmd(cmd, O_TCPFLAGS, (compat_rule->fw_tcpf & 0xff) |
2956											(compat_rule->fw_tcpnf & 0xff) << 8);
2957
2958				prev = cmd;
2959				cmd = next_cmd(cmd);
2960			}
2961		}
2962		if (compat_rule->fw_tcpopt != 0 || compat_rule->fw_tcpnopt != 0) {
2963			fill_cmd(cmd, O_TCPOPTS, (compat_rule->fw_tcpopt & 0xff) |
2964										(compat_rule->fw_tcpnopt & 0xff) << 8);
2965
2966			prev = cmd;
2967			cmd = next_cmd(cmd);
2968		}
2969	}
2970
2971	/* ICMP */
2972	/* XXX: check this */
2973	if (flag & IP_FW_F_ICMPBIT_COMPAT) {
2974		int	i;
2975		ipfw_insn_u32	*cmd32 = (ipfw_insn_u32 *)cmd;	/* alias for cmd */
2976		cmd32->o.opcode = O_ICMPTYPE;
2977		cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2978
2979		for (i = 0; i < IP_FW_ICMPTYPES_DIM_COMPAT; i++) {
2980			cmd32->d[0] |= compat_rule->fw_uar_compat.fw_icmptypes[i];
2981		}
2982
2983		prev = cmd;
2984		cmd = next_cmd(cmd);
2985	}
2986	} /* end commands */
2987done:
2988	/* finally, copy everything into the current
2989	 * rule buffer in the right order.
2990	 */
2991	dst = curr_rule->cmd;
2992
2993	/* first, do match probability */
2994	if (compat_rule->fw_flg & IP_FW_F_RND_MATCH_COMPAT) {
2995		dst->opcode = O_PROB;
2996		dst->len = 2;
2997		*((int32_t *)(dst+1)) = compat_rule->pipe_ptr;
2998		dst += dst->len;
2999	}
3000
3001	/* generate O_PROBE_STATE if necessary */
3002	if (have_state && have_state->opcode != O_CHECK_STATE) {
3003		fill_cmd(dst, O_PROBE_STATE, 0);
3004		dst = next_cmd(dst);
3005	}
3006
3007	/*
3008	 * copy all commands but O_LOG, O_KEEP_STATE
3009	 */
3010	for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
3011		k = F_LEN(src);
3012		switch (src->opcode) {
3013		case O_LOG:
3014		case O_KEEP_STATE:
3015			break;
3016		default:
3017			bcopy(src, dst, k * sizeof(uint32_t));
3018			dst += k;
3019		}
3020	}
3021
3022	/*
3023	 * put back the have_state command as last opcode
3024	 */
3025	if (have_state && have_state->opcode != O_CHECK_STATE) {
3026		k = F_LEN(have_state);
3027		bcopy(have_state, dst, k * sizeof(uint32_t));
3028		dst += k;
3029	}
3030
3031	/*
3032	 * start action section
3033	 */
3034	curr_rule->act_ofs = dst - curr_rule->cmd;
3035
3036	/*
3037	 * put back O_LOG if necessary
3038	 */
3039	src = (ipfw_insn *)cmdbuf;
3040	if (src->opcode == O_LOG) {
3041		k = F_LEN(src);
3042		bcopy(src, dst, k * sizeof(uint32_t));
3043		dst += k;
3044	}
3045
3046	/*
3047	 * copy all other actions
3048	 */
3049	for (src = (ipfw_insn *)actbuf; src != action; src += k) {
3050		k = F_LEN(src);
3051		bcopy(src, dst, k * sizeof(uint32_t));
3052		dst += k;
3053	}
3054
3055	curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
3056	return;
3057}
3058
3059static int
3060ipfw_version_one_to_version_two_32(struct sockopt *sopt, struct ip_fw *curr_rule,
3061								struct ip_fw_compat_32 *rule_vers1)
3062{
3063	int	err = EINVAL;
3064	struct ip_fw_compat_32	*rule_ptr;
3065	struct ip_fw_compat_32	rule;
3066
3067	if (rule_vers1) {
3068		rule_ptr = rule_vers1;
3069		err = 0;
3070	} else {
3071		/* do some basic size checking here, more extensive checking later */
3072		if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat_32))
3073			return err;
3074
3075		if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat_32),
3076							sizeof(struct ip_fw_compat_32)))) {
3077			return err;
3078		}
3079
3080		rule_ptr = &rule;
3081	}
3082
3083	/* deal with commands */
3084	ipfw_convert_to_cmds_32(curr_rule, rule_ptr);
3085
3086	curr_rule->version = IP_FW_CURRENT_API_VERSION;
3087	curr_rule->context = CAST_DOWN_EXPLICIT(void*, rule_ptr->context);
3088	curr_rule->rulenum = rule_ptr->fw_number;
3089	curr_rule->pcnt = rule_ptr->fw_pcnt;
3090	curr_rule->bcnt = rule_ptr->fw_bcnt;
3091	curr_rule->timestamp = rule_ptr->timestamp;
3092
3093
3094#if FW2_DEBUG_VERBOSE
3095	ipfw_print_vers2_struct(curr_rule);
3096#endif
3097
3098	return err;
3099}
3100
3101static int
3102ipfw_version_one_to_version_two_64(struct sockopt *sopt, struct ip_fw *curr_rule,
3103								struct ip_fw_compat_64 *rule_vers1)
3104{
3105	int	err = EINVAL;
3106	struct ip_fw_compat_64	*rule_ptr;
3107	struct ip_fw_compat_64	rule;
3108
3109	if (rule_vers1) {
3110		rule_ptr = rule_vers1;
3111		err = 0;
3112	} else {
3113		/* do some basic size checking here, more extensive checking later */
3114		if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat_64))
3115			return err;
3116
3117		if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat_64),
3118							sizeof(struct ip_fw_compat_64)))) {
3119			return err;
3120		}
3121		rule_ptr = &rule;
3122	}
3123
3124	/* deal with commands */
3125	ipfw_convert_to_cmds_64(curr_rule, rule_ptr);
3126
3127	curr_rule->version = IP_FW_CURRENT_API_VERSION;
3128	curr_rule->context = CAST_DOWN_EXPLICIT( void *, rule_ptr->context);
3129	curr_rule->rulenum = rule_ptr->fw_number;
3130	curr_rule->pcnt = rule_ptr->fw_pcnt;
3131	curr_rule->bcnt = rule_ptr->fw_bcnt;
3132	curr_rule->timestamp = rule_ptr->timestamp;
3133
3134
3135#if FW2_DEBUG_VERBOSE
3136	ipfw_print_vers2_struct(curr_rule);
3137#endif
3138
3139	return err;
3140}
3141
3142/* This converts to whatever the latest version is. Currently the
3143 * latest version of the firewall is ipfw2.
3144 */
3145static int
3146ipfw_version_one_to_latest_32(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat_32 *rule_vers1)
3147{
3148	int err;
3149
3150	/* if rule_vers1 is not null then this is coming from
3151	 * ipfw_version_zero_to_latest(), so pass that along;
3152	 * otherwise let ipfw_version_one_to_version_two()
3153	 * get the rule from sopt.
3154	 */
3155	err = ipfw_version_one_to_version_two_32(sopt, curr_rule, rule_vers1);
3156
3157	return err;
3158}
3159
3160static int
3161ipfw_version_one_to_latest_64(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat_64 *rule_vers1)
3162{
3163	int err;
3164
3165	/* if rule_vers1 is not null then this is coming from
3166	 * ipfw_version_zero_to_latest(), so pass that along;
3167	 * otherwise let ipfw_version_one_to_version_two()
3168	 * get the rule from sopt.
3169	 */
3170	err = ipfw_version_one_to_version_two_64(sopt, curr_rule, rule_vers1);
3171
3172	return err;
3173}
3174
3175
3176#if 0
3177
3178/*
3179 * XXX - ipfw_version_zero_to_one
3180 *
3181 * This function is only used in version #1 of ipfw, which is now deprecated.
3182 *
3183 */
3184
3185static void
3186ipfw_version_zero_to_one(struct ip_old_fw *rule_vers0, struct ip_fw_compat *rule_vers1)
3187{
3188	bzero(rule_vers1, sizeof(struct ip_fw_compat));
3189	bcopy(&rule_vers0->fw_uar, &rule_vers1->fw_uar_compat, sizeof(rule_vers0->fw_uar));
3190	bcopy(&rule_vers0->fw_in_if, &rule_vers1->fw_in_if, sizeof(rule_vers0->fw_in_if));
3191	bcopy(&rule_vers0->fw_out_if, &rule_vers1->fw_out_if, sizeof(rule_vers0->fw_out_if));
3192	bcopy(&rule_vers0->fw_un, &rule_vers1->fw_un_compat, sizeof(rule_vers0->fw_un));
3193
3194	rule_vers1->version       = 10;
3195	rule_vers1->fw_pcnt       = rule_vers0->fw_pcnt;
3196	rule_vers1->fw_bcnt       = rule_vers0->fw_bcnt;
3197	rule_vers1->fw_src        = rule_vers0->fw_src;
3198	rule_vers1->fw_dst        = rule_vers0->fw_dst;
3199	rule_vers1->fw_smsk       = rule_vers0->fw_smsk;
3200	rule_vers1->fw_dmsk       = rule_vers0->fw_dmsk;
3201	rule_vers1->fw_number     = rule_vers0->fw_number;
3202	rule_vers1->fw_flg        = rule_vers0->fw_flg;
3203	rule_vers1->fw_ipopt      = rule_vers0->fw_ipopt;
3204	rule_vers1->fw_ipnopt     = rule_vers0->fw_ipnopt;
3205	rule_vers1->fw_tcpf       = rule_vers0->fw_tcpf & ~IP_OLD_FW_TCPF_ESTAB;
3206	rule_vers1->fw_tcpnf      = rule_vers0->fw_tcpnf;
3207	rule_vers1->timestamp     = rule_vers0->timestamp;
3208	rule_vers1->fw_prot       = rule_vers0->fw_prot;
3209	rule_vers1->fw_nports     = rule_vers0->fw_nports;
3210	rule_vers1->pipe_ptr      = rule_vers0->pipe_ptr;
3211	rule_vers1->next_rule_ptr = rule_vers0->next_rule_ptr;
3212	rule_vers1->fw_ipflg      = (rule_vers0->fw_tcpf & IP_OLD_FW_TCPF_ESTAB) ? IP_FW_IF_TCPEST_COMPAT : 0;
3213}
3214
3215#endif /* !ipfw_version_zero_to_one  */
3216
3217/* rule is a u_int32_t buffer[255] into which the converted
3218 * (if necessary) rules go.
3219 */
3220int
3221ipfw_convert_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, int api_version, int is64user)
3222{
3223	int	err = 0;
3224
3225	/* the following functions copy the rules passed in and
3226	 * convert to latest structures based on version
3227	 */
3228	switch (api_version) {
3229		case IP_FW_VERSION_0:
3230			/* we're not supporting VERSION 0 */
3231			err = EOPNOTSUPP;
3232			break;
3233
3234		case IP_FW_VERSION_1:
3235			/* this is the version supported in Panther */
3236			if ( is64user )
3237				err = ipfw_version_one_to_latest_64(sopt, curr_rule, NULL);
3238			else
3239				err = ipfw_version_one_to_latest_32(sopt, curr_rule, NULL);
3240			break;
3241
3242		case IP_FW_CURRENT_API_VERSION:
3243			/* IPFW2 for now */
3244			/* do nothing here... */
3245			break;
3246
3247		default:
3248			/* unrecognized/unsupported version */
3249			err = EINVAL;
3250			break;
3251	}
3252
3253	return err;
3254}
3255
3256int
3257ipfw_get_command_and_version(struct sockopt *sopt, int *command, u_int32_t *api_version)
3258{
3259	int cmd;
3260	int err = 0;
3261	u_int32_t	vers = IP_FW_VERSION_NONE;
3262
3263	/* first deal with the oldest version */
3264	if (sopt->sopt_name == IP_OLD_FW_GET) {
3265		vers = IP_FW_VERSION_0;
3266		cmd = IP_FW_GET;
3267	}
3268	else if (sopt->sopt_name == IP_OLD_FW_FLUSH) {
3269		vers = IP_FW_VERSION_0;
3270		cmd = IP_FW_FLUSH;
3271	}
3272	else if (sopt->sopt_name == IP_OLD_FW_ZERO) {
3273		vers = IP_FW_VERSION_0;
3274		cmd = IP_FW_ZERO;
3275	}
3276	else if (sopt->sopt_name == IP_OLD_FW_ADD) {
3277		vers = IP_FW_VERSION_0;
3278		cmd = IP_FW_ADD;
3279	}
3280	else if (sopt->sopt_name == IP_OLD_FW_DEL) {
3281		vers = IP_FW_VERSION_0;
3282		cmd = IP_FW_DEL;
3283	}
3284	else if (sopt->sopt_name == IP_OLD_FW_RESETLOG) {
3285		vers = IP_FW_VERSION_0;
3286		cmd = IP_FW_RESETLOG;
3287	}
3288	else {
3289		cmd = sopt->sopt_name;
3290	}
3291
3292	if (vers == IP_FW_VERSION_NONE) {
3293		/* working off the fact that the offset
3294		 * is the same in both structs.
3295		 */
3296		struct ip_fw_64 rule;
3297                size_t  copyinsize;
3298
3299                if (proc_is64bit(sopt->sopt_p))
3300                        copyinsize = sizeof(struct ip_fw_64);
3301                else
3302                        copyinsize = sizeof(struct ip_fw_32);
3303
3304		if (!sopt->sopt_val || sopt->sopt_valsize < copyinsize)
3305			return EINVAL;
3306		if ((err = sooptcopyin(sopt, &rule, copyinsize, copyinsize))) {
3307			return err;
3308		}
3309
3310		vers = rule.version;
3311	}
3312
3313	if (command) {
3314		*command = cmd;
3315	}
3316	if (api_version) {
3317		*api_version = vers;
3318	}
3319
3320	return err;
3321}
3322
3323