]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/ip_fw2_compat.c
xnu-3789.1.32.tar.gz
[apple/xnu.git] / bsd / netinet / ip_fw2_compat.c
index eb7eb43fe57a0704a79253ea027f15188a27653f..c4f1bf576cd0a599274a68661601cdb339db1555 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -67,6 +67,8 @@ struct _s_x {
 #define VERSION_ONE_STR "IP_FW_VERSION_1"
 #define CURRENT_API_VERSION_STR "IP_FW_CURRENT_API_VERSION"
 
+#if FW2_DEBUG_VERBOSE
+
 static struct _s_x f_tcpflags[] = {
        { "syn", TH_SYN },
        { "fin", TH_FIN },
@@ -90,6 +92,7 @@ static struct _s_x f_tcpopts[] = {
        { NULL, 0 }
 };
 
+
 /*
  * IP options span the range 0 to 255 so we need to remap them
  * (though in fact only the low 5 bits are significant).
@@ -123,6 +126,10 @@ static struct _s_x limit_masks[] = {
        {NULL,          0}
 };
 
+#endif /* !FW2_DEBUG_VERBOSE */
+
+#if 0 /* version #1 */
+
 static void
 ipfw_print_fw_flags(u_int flags)
 {
@@ -257,115 +264,6 @@ print_fw_version(u_int32_t api_version)
        }
 }
 
-static void
-ipfw_print_vers1_struct(struct ip_fw_compat *vers1_rule)
-{
-       char ipv4str[MAX_IPv4_STR_LEN];
-       print_fw_version(vers1_rule->version);
-       printf("Rule #%d\n", vers1_rule->fw_number);
-       
-       ipfw_print_fw_flags(vers1_rule->fw_flg);
-       
-       printf("fw_pcnt: %llu\n", vers1_rule->fw_pcnt);
-       printf("fw_bcnt: %llu\n", vers1_rule->fw_bcnt);
-       printf("fw_src: %s\n",
-               inet_ntop(AF_INET, &vers1_rule->fw_src, ipv4str, sizeof(ipv4str)));
-       printf("fw_dst: %s\n",
-               inet_ntop(AF_INET, &vers1_rule->fw_dst, ipv4str, sizeof(ipv4str)));
-       printf("fw_smsk: %s\n",
-               inet_ntop(AF_INET, &vers1_rule->fw_smsk, ipv4str, sizeof(ipv4str)));
-       printf("fw_dmsk: %s\n",
-               inet_ntop(AF_INET, &vers1_rule->fw_dmsk, ipv4str, sizeof(ipv4str)));
-       
-       if (vers1_rule->fw_flg & IP_FW_F_ICMPBIT_COMPAT) {
-               int type_index;
-               int first = 1;
-
-               printf(" icmptype");
-
-               for (type_index = 0; 
-                               type_index < (IP_FW_ICMPTYPES_DIM_COMPAT * sizeof(unsigned) * 8); 
-                               ++type_index) {
-                       if (vers1_rule->fw_uar_compat.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
-                               (1U << (type_index % (sizeof(unsigned) * 8)))) {
-                               printf("%c%d", first == 1 ? ' ' : ',', type_index);
-                               first = 0;
-                       }
-               }
-       } else {
-               int i, nsp, ndp;
-               
-               nsp = IP_FW_GETNSRCP_COMPAT(vers1_rule);
-               for (i = 0; i < nsp; i++) {
-                       printf("source ports: fw_uar_compat.fw_pts: %04x", vers1_rule->fw_uar_compat.fw_pts[i]);
-                       if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_SRNG_COMPAT))
-                               printf("-");
-                       else if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_SMSK_COMPAT))
-                               printf(":");
-                       else
-                               printf(",");
-               }
-               
-               printf("\n");
-               
-               ndp = IP_FW_GETNDSTP_COMPAT(vers1_rule);
-               for (i = 0; i < ndp; i++) {
-                       printf("source ports: fw_uar_compat.fw_pts: %04x", vers1_rule->fw_uar_compat.fw_pts[nsp+i]);
-                       if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_DRNG_COMPAT))
-                               printf("-");
-                       else if (i == 0 && (vers1_rule->fw_flg & IP_FW_F_DMSK_COMPAT))
-                               printf(":");
-                       else
-                               printf(",");
-               }
-
-               printf("\n");
-       }
-       
-       printf("fw_ipflg: %d\n", vers1_rule->fw_ipflg);
-       printf("fw_ipopt: %d\n", vers1_rule->fw_ipopt);
-       printf("fw_ipnopt: %d\n", vers1_rule->fw_ipnopt);
-       printf("fw_tcpopt: %d\n", vers1_rule->fw_tcpopt);
-       printf("fw_tcpnopt: %d\n", vers1_rule->fw_tcpnopt);
-       printf("fw_tcpf: %d\n", vers1_rule->fw_tcpf);
-       printf("fw_tcpnf: %d\n", vers1_rule->fw_tcpnf);
-       printf("timestamp: %ld\n", vers1_rule->timestamp);
-
-       if ((vers1_rule->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
-               printf("fw_in_if: ");
-               inet_ntop(AF_INET, &vers1_rule->fw_in_if.fu_via_ip, ipv4str,
-                                 sizeof(ipv4str));
-               printf("fu_via_ip: %s\n", ipv4str);
-               printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_in_if.fu_via_if_compat.name);
-               printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_in_if.fu_via_if_compat.unit);
-       } else {
-               if (vers1_rule->fw_flg & IP_FW_F_IIFACE_COMPAT) {
-                       printf("fw_in_if: ");
-                       printf("fu_via_ip: %s\n",
-                                  inet_ntop(AF_INET, &vers1_rule->fw_in_if.fu_via_ip, ipv4str,
-                                                        sizeof(ipv4str)));
-                       printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_in_if.fu_via_if_compat.name);
-                       printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_in_if.fu_via_if_compat.unit);
-               }
-               if (vers1_rule->fw_flg & IP_FW_F_OIFACE_COMPAT) {
-                       printf("fw_out_if: ");
-                       printf("fu_via_ip: %s\n",
-                                  inet_ntop(AF_INET, &vers1_rule->fw_out_if.fu_via_ip,
-                                                        ipv4str, sizeof(ipv4str)));
-                       printf("fu_via_if_compat.name: %s\n", vers1_rule->fw_out_if.fu_via_if_compat.name);
-                       printf("fu_via_if_compat.unit: %d\n", vers1_rule->fw_out_if.fu_via_if_compat.unit);
-               }
-       }
-       
-       printf("fw_prot: %d\n", vers1_rule->fw_prot);
-       printf("fw_nports: %d\n", vers1_rule->fw_nports);
-       printf("pipe_ptr: %p\n", vers1_rule->pipe_ptr);
-       printf("next_rule_ptr: %p\n", vers1_rule->next_rule_ptr);
-       printf("fw_uid: %d\n", vers1_rule->fw_uid);
-       printf("fw_logamount: %d\n", vers1_rule->fw_logamount);
-       printf("fw_loghighest: %llu\n", vers1_rule->fw_loghighest);
-}
-
 static void
 print_icmptypes(ipfw_insn_u32 *cmd)
 {
@@ -489,6 +387,9 @@ print_mac(uint8_t *addr, uint8_t *mask)
        }
 }
 
+#endif /* !version #1 */
+
+#if FW2_DEBUG_VERBOSE
 static void
 ipfw_print_vers2_struct(struct ip_fw *vers2_rule)
 {
@@ -862,6 +763,9 @@ ipfw_print_vers2_struct(struct ip_fw *vers2_rule)
        } /* for */
 }
 
+#endif /* !FW2_DEBUG_VERBOSE */
+
+
 /*
  * helper function, updates the pointer to cmd with the length
  * of the current command, and also cleans up the first word of
@@ -920,7 +824,7 @@ fill_compat_tcpflags(u_int32_t flags) {
  *     sets, sets of addresses, blocks (NOT, OR)
  */
 static void
-ipfw_map_from_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
+ipfw_map_from_cmds_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *compat_rule)
 {
        int             l;
        ipfw_insn       *cmd;
@@ -1200,166 +1104,714 @@ ipfw_map_from_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
 }
 
 static void
-ipfw_map_from_actions(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
+ipfw_map_from_cmds_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *compat_rule)
 {
-       int l;
+       int             l;
        ipfw_insn       *cmd;
-       
-       for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
-                       l > 0 ; 
-                       l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
+       for (l = curr_rule->act_ofs, cmd = curr_rule->cmd ;
+               l > 0 ; 
+               l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
+               /* useful alias */
+               ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
+
                switch (cmd->opcode) {
-                       case O_ACCEPT:
-                               compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
-                               break;
-                       case O_COUNT:
-                               compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
+                       case O_PROTO:
+                               /* protocol */
+                               compat_rule->fw_prot = cmd->arg1;
                                break;
-                       case O_PIPE:
-                               compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
-                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                       
+                       case O_IP_SRC_ME:
+                               compat_rule->fw_flg |= IP_FW_F_SME_COMPAT;
+                               if (cmd->len & F_NOT) {
+                                       compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
+                               }
                                break;
-                       case O_QUEUE:
-                               compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
-                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                       
+                       case O_IP_SRC_MASK:
+                       {
+                               /* addr/mask */
+                               ipfw_insn_ip    *ip = (ipfw_insn_ip *)cmd;
+                               
+                               compat_rule->fw_src = ip->addr;
+                               compat_rule->fw_smsk = ip->mask;
+                               if (cmd->len & F_NOT) {
+                                       compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
+                               }
                                break;
-                       case O_SKIPTO:
-                               compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
-                               compat_rule->fw_skipto_rule_compat = cmd->arg1;
+                       }
+                       
+                       case O_IP_SRC:
+                               /* one IP */
+                               /* source - 
+                                * for now we only deal with one address
+                                * per rule and ignore sets of addresses
+                                */
+                               compat_rule->fw_src.s_addr = cmd32->d[0];
+                               if (cmd->len & F_NOT) {
+                                       compat_rule->fw_flg |= IP_FW_F_INVSRC_COMPAT;
+                               }
                                break;
-                       case O_DIVERT:
-                               compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
-                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                       
+                       case O_IP_SRCPORT:
+                       {
+                               /* source ports */
+                               ipfw_insn_u16   *ports = (ipfw_insn_u16 *)cmd;
+                               uint16_t                *p = ports->ports;
+                               int                             i, j;
+                               
+                               /* copy list of ports */
+                               for (i = F_LEN(cmd) - 1, j = 0; i > 0; i--, j++, p += 2) {
+                                       if (p[0] != p[1]) {
+                                               /* this is a range */
+                                               compat_rule->fw_flg |= IP_FW_F_SRNG_COMPAT;
+                                               compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
+                                               compat_rule->fw_uar_compat.fw_pts[j] = p[1];
+                                       } else {
+                                               compat_rule->fw_uar_compat.fw_pts[j] = p[0];
+                                       }
+                               }
+                               IP_FW_SETNSRCP_COMPAT(compat_rule, j);
+                               
                                break;
-                       case O_TEE:
-                               compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
-                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                       }
+
+                       case O_IP_DST_ME:
+                       /* destination */
+                               compat_rule->fw_flg |= IP_FW_F_DME_COMPAT;
+                               if (cmd->len & F_NOT) {
+                                       compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
+                               }
                                break;
-                       case O_FORWARD_IP:
+
+                       case O_IP_DST_MASK:
                        {
-                               ipfw_insn_sa    *p = (ipfw_insn_sa *)cmd;
+                               /* addr/mask */
+                               ipfw_insn_ip    *ip = (ipfw_insn_ip *)cmd;
                                
-                               compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
-                               compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
-                               compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
-                               compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
-                               compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
-
+                               compat_rule->fw_dst = ip->addr;
+                               compat_rule->fw_dmsk = ip->mask;
+                               if (cmd->len & F_NOT) {
+                                       compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
+                               }
                                break;
                        }
-                       case O_DENY:
-                               compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
+                       case O_IP_DST:
+                               /* one IP */
+                               /* dest - 
+                                * for now we only deal with one address
+                                * per rule, and ignore sets of addresses
+                                */
+                               compat_rule->fw_dst.s_addr = cmd32->d[0];
+                               if (cmd->len & F_NOT) {
+                                       compat_rule->fw_flg |= IP_FW_F_INVDST_COMPAT;
+                               }
                                break;
-                       case O_REJECT:
-                               compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
-                               compat_rule->fw_reject_code_compat = cmd->arg1;
+                               
+                       case O_IP_DSTPORT:
+                       {
+                               /* dest. ports */
+                               ipfw_insn_u16   *ports = (ipfw_insn_u16 *)cmd;
+                               uint16_t                *p = ports->ports;
+                               int                             i, 
+                                                               j = IP_FW_GETNSRCP_COMPAT(compat_rule);
+                               
+                               /* copy list of ports */
+                               for (i = F_LEN(cmd) - 1; i > 0; i--, j++, p += 2) {
+                                       if (p[0] != p[1]) {
+                                               /* this is a range */
+                                               compat_rule->fw_flg |= IP_FW_F_DRNG_COMPAT;
+                                               compat_rule->fw_uar_compat.fw_pts[j++] = p[0];
+                                               compat_rule->fw_uar_compat.fw_pts[j] = p[1];
+                                       } else {
+                                               compat_rule->fw_uar_compat.fw_pts[j] = p[0];
+                                       }
+                               }
+                               IP_FW_SETNDSTP_COMPAT(compat_rule, (j - IP_FW_GETNSRCP_COMPAT(compat_rule)));
+                               
                                break;
-                       case O_CHECK_STATE:
-                               compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
+                       }
+                       
+                       case O_LOG:
+                       {
+                               ipfw_insn_log *c = (ipfw_insn_log *)cmd;
+                               
+                               compat_rule->fw_flg |= IP_FW_F_PRN_COMPAT;
+                               compat_rule->fw_logamount = c->max_log;
                                break;
-                       default:
+                       }       
+                       case O_UID:
+                               compat_rule->fw_flg |= IP_FW_F_UID_COMPAT;
+                               compat_rule->fw_uid = cmd32->d[0];
                                break;
-               }
-       }
-}
-
-static void
-ipfw_version_latest_to_one(struct ip_fw *curr_rule, struct ip_fw_compat *rule_vers1)
-{
-       if (!rule_vers1)
-               return;
-               
-       bzero(rule_vers1, sizeof(struct ip_fw_compat));
-       
-       rule_vers1->version = IP_FW_VERSION_1;
-       rule_vers1->context = curr_rule->context;
-       rule_vers1->fw_number = curr_rule->rulenum;
-       rule_vers1->fw_pcnt = curr_rule->pcnt;
-       rule_vers1->fw_bcnt = curr_rule->bcnt;
-       rule_vers1->timestamp = curr_rule->timestamp;
-       
-       /* convert actions */
-       ipfw_map_from_actions(curr_rule, rule_vers1);
-
-       /* convert commands */
-       ipfw_map_from_cmds(curr_rule, rule_vers1);
-       
-#if FW2_DEBUG_VERBOSE
-       ipfw_print_vers1_struct(rule_vers1);
-#endif
-}
-
-/* first convert to version one then to version zero */
-static void
-ipfw_version_latest_to_zero(struct ip_fw *curr_rule, struct ip_old_fw *rule_vers0)
-{
-       struct ip_fw_compat     rule_vers1;
-       
-       ipfw_version_latest_to_one(curr_rule, &rule_vers1);
-
-       bzero(rule_vers0, sizeof(struct ip_old_fw));
-       bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
-       bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
-       bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
-       bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
-
-       rule_vers0->fw_pcnt       = rule_vers1.fw_pcnt;
-       rule_vers0->fw_bcnt       = rule_vers1.fw_bcnt;
-       rule_vers0->fw_src        = rule_vers1.fw_src;
-       rule_vers0->fw_dst        = rule_vers1.fw_dst;
-       rule_vers0->fw_smsk       = rule_vers1.fw_smsk;
-       rule_vers0->fw_dmsk       = rule_vers1.fw_dmsk;
-       rule_vers0->fw_number     = rule_vers1.fw_number;
-       rule_vers0->fw_flg        = rule_vers1.fw_flg;
-       rule_vers0->fw_ipopt      = rule_vers1.fw_ipopt;
-       rule_vers0->fw_ipnopt     = rule_vers1.fw_ipnopt;
-       rule_vers0->fw_tcpf       = rule_vers1.fw_tcpf;
-       rule_vers0->fw_tcpnf      = rule_vers1.fw_tcpnf;
-       rule_vers0->timestamp     = rule_vers1.timestamp;
-       rule_vers0->fw_prot       = rule_vers1.fw_prot;
-       rule_vers0->fw_nports     = rule_vers1.fw_nports;
-       rule_vers0->pipe_ptr      = rule_vers1.pipe_ptr;
-       rule_vers0->next_rule_ptr = rule_vers1.next_rule_ptr;
-
-       if (rule_vers1.fw_ipflg && IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
-}
-
-void
-ipfw_convert_from_latest(struct ip_fw *curr_rule, void *old_rule, u_int32_t api_version)
-{
-       switch (api_version) {
-               case IP_FW_VERSION_0:
-               {
-                       struct ip_old_fw        *rule_vers0 = old_rule;
                        
-                       ipfw_version_latest_to_zero(curr_rule, rule_vers0);
-                       break;
-               }
-               case IP_FW_VERSION_1:
-               {
-                       struct ip_fw_compat     *rule_vers1 = old_rule;
+                       case O_IN:
+                               if (cmd->len & F_NOT) {
+                                       compat_rule->fw_flg |= IP_FW_F_OUT_COMPAT;
+                               } else {
+                                       compat_rule->fw_flg |= IP_FW_F_IN_COMPAT;
+                               }
+                               break;
                        
-                       ipfw_version_latest_to_one(curr_rule, rule_vers1);
-                       break;
-               }
-               case IP_FW_CURRENT_API_VERSION:
-                       /* ipfw2 for now, don't need to do anything */
-                       break;
-               
-               default:
-                       /* unknown version */
-                       break;
-       }
-}
-
-
-/* ********************************************
- * *********** Convert to Latest **************
- * ********************************************/
+                       case O_KEEP_STATE:
+                               compat_rule->fw_flg |= IP_FW_F_KEEP_S_COMPAT;
+                               break;
+
+                       case O_LAYER2:
+                               compat_rule->fw_flg |= IP_FW_BRIDGED_COMPAT;
+                               break;
+                       
+                       case O_XMIT:
+                       {
+                               ipfw_insn_if    *ifcmd = (ipfw_insn_if *)cmd;
+                               union ip_fw_if_compat   ifu;
+                               
+                               if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
+                                       /* any */
+                                       compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
+                                       ifu.fu_via_ip.s_addr = 0;
+                               }
+                               else if (ifcmd->p.ip.s_addr != 0) {
+                                       compat_rule->fw_flg |= IP_FW_F_OIFACE_COMPAT;
+                                       ifu.fu_via_ip = ifcmd->p.ip;
+                               } else {
+                                       compat_rule->fw_flg |= IP_FW_F_OIFNAME_COMPAT;
+                                       strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
+                                       ifu.fu_via_if_compat.unit = ifcmd->p.unit;
+                               }
+                               compat_rule->fw_out_if = ifu;
+                               
+                               break;
+                       }
+                       
+                       case O_RECV:
+                       {
+                               ipfw_insn_if    *ifcmd = (ipfw_insn_if *)cmd;
+                               union ip_fw_if_compat   ifu;
+                               
+                               if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
+                                       /* any */
+                                       compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
+                                       ifu.fu_via_ip.s_addr = 0;
+                               }
+                               else if (ifcmd->p.ip.s_addr != 0) {
+                                       compat_rule->fw_flg |= IP_FW_F_IIFACE_COMPAT;
+                                       ifu.fu_via_ip = ifcmd->p.ip;
+                               } else {
+                                       compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
+                                       strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
+                                       ifu.fu_via_if_compat.unit = ifcmd->p.unit;
+                               }
+                               compat_rule->fw_in_if = ifu;
+                               
+                               break;
+                       }
+                       
+                       case O_VIA:
+                       {
+                               ipfw_insn_if                    *ifcmd = (ipfw_insn_if *)cmd;
+                               union ip_fw_if_compat   ifu;
+                               
+                               if ((ifcmd->o.len == 0) && (ifcmd->name[0] == '\0')) {
+                                       /* any */
+                                       ifu.fu_via_ip.s_addr = 0;
+                               }
+                               else if (ifcmd->name[0] != '\0') {
+                                       compat_rule->fw_flg |= IP_FW_F_IIFNAME_COMPAT;
+                                       strncpy(ifu.fu_via_if_compat.name, ifcmd->name, sizeof(ifu.fu_via_if_compat.name));
+                                       ifu.fu_via_if_compat.unit = ifcmd->p.unit;
+                               } else {
+                                       ifu.fu_via_ip = ifcmd->p.ip;
+                               }
+                               compat_rule->fw_flg |= IF_FW_F_VIAHACK_COMPAT;
+                               compat_rule->fw_out_if = compat_rule->fw_in_if = ifu;
+                               
+                               break;
+                       }
+
+                       case O_FRAG:
+                               compat_rule->fw_flg |= IP_FW_F_FRAG_COMPAT;
+                               break;
+                       
+                       case O_IPOPT:
+                               /* IP options */
+                               compat_rule->fw_ipopt = (cmd->arg1 & 0xff);
+                               compat_rule->fw_ipnopt = ((cmd->arg1 >> 8) & 0xff);
+                               break;
+                               
+                       case O_TCPFLAGS:
+                               /* check for "setup" */
+                               if ((cmd->arg1 & 0xff) == TH_SYN &&
+                                       ((cmd->arg1 >> 8) & 0xff) == TH_ACK) {
+                                       compat_rule->fw_tcpf = IP_FW_TCPF_SYN_COMPAT;
+                                       compat_rule->fw_tcpnf = IP_FW_TCPF_ACK_COMPAT;
+                               }
+                               else {
+                                       compat_rule->fw_tcpf = fill_compat_tcpflags(cmd->arg1 & 0xff);
+                                       compat_rule->fw_tcpnf = fill_compat_tcpflags((cmd->arg1 >> 8) & 0xff);
+                               }
+                               break;
+                               
+                       case O_TCPOPTS:
+                               /* TCP options */
+                               compat_rule->fw_tcpopt = (cmd->arg1 & 0xff);
+                               compat_rule->fw_tcpnopt = ((cmd->arg1 >> 8) & 0xff);
+                               break;
+                       
+                       case O_ESTAB:
+                               compat_rule->fw_ipflg |= IP_FW_IF_TCPEST_COMPAT;
+                               break;
+                       
+                       case O_ICMPTYPE:
+                       {
+                               /* ICMP */
+                               /* XXX: check this */
+                               int     i, type;
+                               
+                               compat_rule->fw_flg |= IP_FW_F_ICMPBIT_COMPAT;
+                               for (i = 0; i < sizeof(uint32_t) ; i++) {
+                                       type = cmd32->d[0] & i;
+                                       
+                                       compat_rule->fw_uar_compat.fw_icmptypes[type / (sizeof(unsigned) * 8)] |= 
+                                               1 << (type % (sizeof(unsigned) * 8));
+                               }
+                               break;
+                       }
+                       default:
+                               break;
+               } /* switch */
+       } /* for */
+}
+
+static void
+ipfw_map_from_actions_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *compat_rule)
+{
+       int l;
+       ipfw_insn       *cmd;
+       
+       for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
+                       l > 0 ; 
+                       l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
+               switch (cmd->opcode) {
+                       case O_ACCEPT:
+                               compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
+                               break;
+                       case O_COUNT:
+                               compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
+                               break;
+                       case O_PIPE:
+                               compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
+                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                               break;
+                       case O_QUEUE:
+                               compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
+                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                               break;
+                       case O_SKIPTO:
+                               compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
+                               compat_rule->fw_skipto_rule_compat = cmd->arg1;
+                               break;
+                       case O_DIVERT:
+                               compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
+                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                               break;
+                       case O_TEE:
+                               compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
+                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                               break;
+                       case O_FORWARD_IP:
+                       {
+                               ipfw_insn_sa    *p = (ipfw_insn_sa *)cmd;
+                               
+                               compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
+                               compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
+                               compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
+                               compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
+                               compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
+
+                               break;
+                       }
+                       case O_DENY:
+                               compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
+                               break;
+                       case O_REJECT:
+                               compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
+                               compat_rule->fw_reject_code_compat = cmd->arg1;
+                               break;
+                       case O_CHECK_STATE:
+                               compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
+static void
+ipfw_map_from_actions_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *compat_rule)
+{
+       int l;
+       ipfw_insn       *cmd;
+       for (l = curr_rule->cmd_len - curr_rule->act_ofs, cmd = ACTION_PTR(curr_rule);
+                       l > 0 ; 
+                       l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
+               switch (cmd->opcode) {
+                       case O_ACCEPT:
+                               compat_rule->fw_flg |= IP_FW_F_ACCEPT_COMPAT;
+                               break;
+                       case O_COUNT:
+                               compat_rule->fw_flg |= IP_FW_F_COUNT_COMPAT;
+                               break;
+                       case O_PIPE:
+                               compat_rule->fw_flg |= IP_FW_F_PIPE_COMPAT;
+                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                               break;
+                       case O_QUEUE:
+                               compat_rule->fw_flg |= IP_FW_F_QUEUE_COMPAT;
+                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                               break;
+                       case O_SKIPTO:
+                               compat_rule->fw_flg |= IP_FW_F_SKIPTO_COMPAT;
+                               compat_rule->fw_skipto_rule_compat = cmd->arg1;
+                               break;
+                       case O_DIVERT:
+                               compat_rule->fw_flg |= IP_FW_F_DIVERT_COMPAT;
+                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                               break;
+                       case O_TEE:
+                               compat_rule->fw_flg |= IP_FW_F_TEE_COMPAT;
+                               compat_rule->fw_divert_port_compat = cmd->arg1;
+                               break;
+                       case O_FORWARD_IP:
+                       {
+                               ipfw_insn_sa    *p = (ipfw_insn_sa *)cmd;
+                               
+                               compat_rule->fw_flg |= IP_FW_F_FWD_COMPAT;
+                               compat_rule->fw_fwd_ip_compat.sin_len = p->sa.sin_len;
+                               compat_rule->fw_fwd_ip_compat.sin_family = p->sa.sin_family;
+                               compat_rule->fw_fwd_ip_compat.sin_port = p->sa.sin_port;
+                               compat_rule->fw_fwd_ip_compat.sin_addr = p->sa.sin_addr;
+
+                               break;
+                       }
+                       case O_DENY:
+                               compat_rule->fw_flg |= IP_FW_F_DENY_COMPAT;
+                               break;
+                       case O_REJECT:
+                               compat_rule->fw_flg |= IP_FW_F_REJECT_COMPAT;
+                               compat_rule->fw_reject_code_compat = cmd->arg1;
+                               break;
+                       case O_CHECK_STATE:
+                               compat_rule->fw_flg |= IP_FW_F_CHECK_S_COMPAT;
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
+static void
+ipfw_version_latest_to_one_32(struct ip_fw_32 *curr_rule, struct ip_fw_compat_32 *rule_vers1)
+{
+       if (!rule_vers1)
+               return;
+               
+       bzero(rule_vers1, sizeof(struct ip_fw_compat_32));
+       
+       rule_vers1->version = IP_FW_VERSION_1;
+       rule_vers1->context = CAST_DOWN_EXPLICIT(user32_addr_t,curr_rule->context);
+       rule_vers1->fw_number = curr_rule->rulenum;
+       rule_vers1->fw_pcnt = curr_rule->pcnt;
+       rule_vers1->fw_bcnt = curr_rule->bcnt;
+       rule_vers1->timestamp = curr_rule->timestamp;
+       
+       /* convert actions */
+       ipfw_map_from_actions_32(curr_rule, rule_vers1);
+
+       /* convert commands */
+       ipfw_map_from_cmds_32(curr_rule, rule_vers1);
+       
+#if FW2_DEBUG_VERBOSE
+       ipfw_print_vers1_struct_32(rule_vers1);
+#endif
+}
+
+static void
+ipfw_version_latest_to_one_64(struct ip_fw_64 *curr_rule, struct ip_fw_compat_64 *rule_vers1)
+{
+       if (!rule_vers1)
+               return;
+               
+       bzero(rule_vers1, sizeof(struct ip_fw_compat_64));
+       
+       rule_vers1->version = IP_FW_VERSION_1;
+       rule_vers1->context = CAST_DOWN_EXPLICIT(__uint64_t, curr_rule->context);
+       rule_vers1->fw_number = curr_rule->rulenum;
+       rule_vers1->fw_pcnt = curr_rule->pcnt;
+       rule_vers1->fw_bcnt = curr_rule->bcnt;
+       rule_vers1->timestamp = curr_rule->timestamp;
+       
+       /* convert actions */
+       ipfw_map_from_actions_64(curr_rule, rule_vers1);
+
+       /* convert commands */
+       ipfw_map_from_cmds_64(curr_rule, rule_vers1);
+       
+#if FW2_DEBUG_VERBOSE
+       ipfw_print_vers1_struct_64(rule_vers1);
+#endif
+}
+
+/* first convert to version one then to version zero */
+static void
+ipfw_version_latest_to_zero(struct ip_fw *curr_rule, struct ip_old_fw *rule_vers0, int is64user)
+{
+       
+       if ( is64user ){
+               struct ip_fw_compat_64  rule_vers1;
+               ipfw_version_latest_to_one_64((struct ip_fw_64*)curr_rule, &rule_vers1);
+               bzero(rule_vers0, sizeof(struct ip_old_fw));
+               bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
+               bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
+               bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
+               bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
+               rule_vers0->fw_pcnt       = rule_vers1.fw_pcnt;
+               rule_vers0->fw_bcnt       = rule_vers1.fw_bcnt;
+               rule_vers0->fw_src        = rule_vers1.fw_src;
+               rule_vers0->fw_dst        = rule_vers1.fw_dst;
+               rule_vers0->fw_smsk       = rule_vers1.fw_smsk;
+               rule_vers0->fw_dmsk       = rule_vers1.fw_dmsk;
+               rule_vers0->fw_number     = rule_vers1.fw_number;
+               rule_vers0->fw_flg        = rule_vers1.fw_flg;
+               rule_vers0->fw_ipopt      = rule_vers1.fw_ipopt;
+               rule_vers0->fw_ipnopt     = rule_vers1.fw_ipnopt;
+               rule_vers0->fw_tcpf       = rule_vers1.fw_tcpf;
+               rule_vers0->fw_tcpnf      = rule_vers1.fw_tcpnf;
+               rule_vers0->timestamp     = rule_vers1.timestamp;
+               rule_vers0->fw_prot       = rule_vers1.fw_prot;
+               rule_vers0->fw_nports     = rule_vers1.fw_nports;
+               rule_vers0->pipe_ptr      = CAST_DOWN_EXPLICIT(void*, rule_vers1.pipe_ptr);
+               rule_vers0->next_rule_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.next_rule_ptr);
+
+               if (rule_vers1.fw_ipflg & IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
+       }
+       else {
+               struct ip_fw_compat_32  rule_vers1;
+               ipfw_version_latest_to_one_32( (struct ip_fw_32*)curr_rule, &rule_vers1);
+               bzero(rule_vers0, sizeof(struct ip_old_fw));
+               bcopy(&rule_vers1.fw_uar_compat, &rule_vers0->fw_uar, sizeof(rule_vers1.fw_uar_compat));
+               bcopy(&rule_vers1.fw_in_if, &rule_vers0->fw_in_if, sizeof(rule_vers1.fw_in_if));
+               bcopy(&rule_vers1.fw_out_if, &rule_vers0->fw_out_if, sizeof(rule_vers1.fw_out_if));
+               bcopy(&rule_vers1.fw_un_compat, &rule_vers0->fw_un, sizeof(rule_vers1.fw_un_compat));
+               rule_vers0->fw_pcnt       = rule_vers1.fw_pcnt;
+               rule_vers0->fw_bcnt       = rule_vers1.fw_bcnt;
+               rule_vers0->fw_src        = rule_vers1.fw_src;
+               rule_vers0->fw_dst        = rule_vers1.fw_dst;
+               rule_vers0->fw_smsk       = rule_vers1.fw_smsk;
+               rule_vers0->fw_dmsk       = rule_vers1.fw_dmsk;
+               rule_vers0->fw_number     = rule_vers1.fw_number;
+               rule_vers0->fw_flg        = rule_vers1.fw_flg;
+               rule_vers0->fw_ipopt      = rule_vers1.fw_ipopt;
+               rule_vers0->fw_ipnopt     = rule_vers1.fw_ipnopt;
+               rule_vers0->fw_tcpf       = rule_vers1.fw_tcpf;
+               rule_vers0->fw_tcpnf      = rule_vers1.fw_tcpnf;
+               rule_vers0->timestamp     = rule_vers1.timestamp;
+               rule_vers0->fw_prot       = rule_vers1.fw_prot;
+               rule_vers0->fw_nports     = rule_vers1.fw_nports;
+               rule_vers0->pipe_ptr      = CAST_DOWN_EXPLICIT(void*, rule_vers1.pipe_ptr);
+               rule_vers0->next_rule_ptr = CAST_DOWN_EXPLICIT(void*, rule_vers1.next_rule_ptr);
+
+               if (rule_vers1.fw_ipflg & IP_FW_IF_TCPEST_COMPAT) rule_vers0->fw_tcpf |= IP_OLD_FW_TCPF_ESTAB;
+       }
+
+}
+
+void
+ipfw_convert_from_latest(struct ip_fw *curr_rule, void *old_rule, u_int32_t api_version, int is64user)
+{
+       switch (api_version) {
+               case IP_FW_VERSION_0:
+               {
+                       struct ip_old_fw        *rule_vers0 = old_rule;
+                       
+                       ipfw_version_latest_to_zero(curr_rule, rule_vers0, is64user);
+                       break;
+               }
+               case IP_FW_VERSION_1:
+               {                       
+                       if ( is64user )
+                               ipfw_version_latest_to_one_64((struct ip_fw_64*)curr_rule, (struct ip_fw_compat_64 *)old_rule);
+                       else
+                               ipfw_version_latest_to_one_32((struct ip_fw_32*)curr_rule, (struct ip_fw_compat_32 *)old_rule);
+
+                       break;
+               }
+               case IP_FW_CURRENT_API_VERSION:
+                       /* ipfw2 for now, don't need to do anything */
+                       break;
+               
+               default:
+                       /* unknown version */
+                       break;
+       }
+}
+
+
+/* ********************************************
+ * *********** Convert to Latest **************
+ * ********************************************/
 
 /* from ip_fw.c */
 static int
-ipfw_check_vers1_struct(struct ip_fw_compat *frwl)
+ipfw_check_vers1_struct_32(struct ip_fw_compat_32 *frwl)
+{
+       /* Check for invalid flag bits */
+       if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
+               /* 
+               printf(("%s undefined flag bits set (flags=%x)\n",
+                   err_prefix, frwl->fw_flg));
+               */
+               return (EINVAL);
+       }
+       if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
+               /* check-state */
+               return 0 ;
+       }
+       /* Must apply to incoming or outgoing (or both) */
+       if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
+               /*
+               printf(("%s neither in nor out\n", err_prefix));
+               */
+               return (EINVAL);
+       }
+       /* Empty interface name is no good */
+       if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
+             && !*frwl->fw_in_if.fu_via_if_compat.name)
+           || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
+             && !*frwl->fw_out_if.fu_via_if_compat.name)) {
+               /*
+               printf(("%s empty interface name\n", err_prefix));
+               */
+               return (EINVAL);
+       }
+       /* Sanity check interface matching */
+       if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
+               ;               /* allow "via" backwards compatibility */
+       } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
+           && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
+               /*
+               printf(("%s outgoing interface check on incoming\n",
+                   err_prefix));
+               */
+               return (EINVAL);
+       }
+       /* Sanity check port ranges */
+       if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
+               /*
+               printf(("%s src range set but n_src_p=%d\n",
+                   err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
+               */
+               return (EINVAL);
+       }
+       if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
+               /*
+               printf(("%s dst range set but n_dst_p=%d\n",
+                   err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
+               */
+               return (EINVAL);
+       }
+       if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
+               /*
+               printf(("%s too many ports (%d+%d)\n",
+                   err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
+               */
+               return (EINVAL);
+       }
+       /*
+        *      Protocols other than TCP/UDP don't use port range
+        */
+       if ((frwl->fw_prot != IPPROTO_TCP) &&
+           (frwl->fw_prot != IPPROTO_UDP) &&
+           (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
+               /*
+               printf(("%s port(s) specified for non TCP/UDP rule\n",
+                   err_prefix));
+               */
+               return (EINVAL);
+       }
+
+       /*
+        *      Rather than modify the entry to make such entries work, 
+        *      we reject this rule and require user level utilities
+        *      to enforce whatever policy they deem appropriate.
+        */
+       if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || 
+               (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
+               /*
+               printf(("%s rule never matches\n", err_prefix));
+               */
+               return (EINVAL);
+       }
+
+       if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
+               (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
+               if (frwl->fw_nports) {
+               /*
+                       printf(("%s cannot mix 'frag' and ports\n", err_prefix));
+               */
+                       return (EINVAL);
+               }
+               if (frwl->fw_prot == IPPROTO_TCP &&
+                       frwl->fw_tcpf != frwl->fw_tcpnf) {
+               /*
+                       printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
+               */
+                       return (EINVAL);
+               }
+       }
+
+       /* Check command specific stuff */
+       switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
+       {
+       case IP_FW_F_REJECT_COMPAT:
+               if (frwl->fw_reject_code_compat >= 0x100
+                   && !(frwl->fw_prot == IPPROTO_TCP
+                     && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
+               /*
+                       printf(("%s unknown reject code\n", err_prefix));
+               */
+                       return (EINVAL);
+               }
+               break;
+       case IP_FW_F_DIVERT_COMPAT:             /* Diverting to port zero is invalid */
+       case IP_FW_F_TEE_COMPAT:
+       case IP_FW_F_PIPE_COMPAT:              /* piping through 0 is invalid */
+       case IP_FW_F_QUEUE_COMPAT:             /* piping through 0 is invalid */
+               if (frwl->fw_divert_port_compat == 0) {
+               /*
+                       printf(("%s can't divert to port 0\n", err_prefix));
+               */
+                       return (EINVAL);
+               }
+               break;
+       case IP_FW_F_DENY_COMPAT:
+       case IP_FW_F_ACCEPT_COMPAT:
+       case IP_FW_F_COUNT_COMPAT:
+       case IP_FW_F_SKIPTO_COMPAT:
+       case IP_FW_F_FWD_COMPAT:
+       case IP_FW_F_UID_COMPAT:
+               break;
+       default:
+               /*
+               printf(("%s invalid command\n", err_prefix));
+               */
+               return (EINVAL);
+       }
+
+       return 0;
+}
+
+static int
+ipfw_check_vers1_struct_64(struct ip_fw_compat_64 *frwl)
 {
        /* Check for invalid flag bits */
        if ((frwl->fw_flg & ~IP_FW_F_MASK_COMPAT) != 0) {
@@ -1367,169 +1819,726 @@ ipfw_check_vers1_struct(struct ip_fw_compat *frwl)
                printf(("%s undefined flag bits set (flags=%x)\n",
                    err_prefix, frwl->fw_flg));
                */
+                
+               return (EINVAL);
+       }
+       if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
+               /* check-state */
+               return 0 ;
+       }
+       /* Must apply to incoming or outgoing (or both) */
+       if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
+               /*
+               printf(("%s neither in nor out\n", err_prefix));
+               */
+               
+               return (EINVAL);
+       }
+       /* Empty interface name is no good */
+       if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
+             && !*frwl->fw_in_if.fu_via_if_compat.name)
+           || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
+             && !*frwl->fw_out_if.fu_via_if_compat.name)) {
+               /*
+               printf(("%s empty interface name\n", err_prefix));
+               */
+               
+               return (EINVAL);
+       }
+       /* Sanity check interface matching */
+       if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
+               ;               /* allow "via" backwards compatibility */
+       } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
+           && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
+               /*
+               printf(("%s outgoing interface check on incoming\n",
+                   err_prefix));
+               */
+               
+               return (EINVAL);
+       }
+       /* Sanity check port ranges */
+       if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
+               /*
+               printf(("%s src range set but n_src_p=%d\n",
+                   err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
+               */
+               
+               return (EINVAL);
+       }
+       if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
+               /*
+               printf(("%s dst range set but n_dst_p=%d\n",
+                   err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
+               */
+
+               return (EINVAL);
+       }
+       if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
+               /*
+               printf(("%s too many ports (%d+%d)\n",
+                   err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
+               */
+               
+               return (EINVAL);
+       }
+       /*
+        *      Protocols other than TCP/UDP don't use port range
+        */
+       if ((frwl->fw_prot != IPPROTO_TCP) &&
+           (frwl->fw_prot != IPPROTO_UDP) &&
+           (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
+               /*
+               printf(("%s port(s) specified for non TCP/UDP rule\n",
+                   err_prefix));
+               */
+               
+               return (EINVAL);
+       }
+
+       /*
+        *      Rather than modify the entry to make such entries work, 
+        *      we reject this rule and require user level utilities
+        *      to enforce whatever policy they deem appropriate.
+        */
+       if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || 
+               (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
+               /*
+               printf(("%s rule never matches\n", err_prefix));
+               */
+               
+               return (EINVAL);
+       }
+
+       if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
+               (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
+               if (frwl->fw_nports) {
+               /*
+                       printf(("%s cannot mix 'frag' and ports\n", err_prefix));
+               */
+               
+                       return (EINVAL);
+               }
+               if (frwl->fw_prot == IPPROTO_TCP &&
+                       frwl->fw_tcpf != frwl->fw_tcpnf) {
+               /*
+                       printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
+               */
+               
+                       return (EINVAL);
+               }
+       }
+
+       /* Check command specific stuff */
+       switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
+       {
+       case IP_FW_F_REJECT_COMPAT:
+               if (frwl->fw_reject_code_compat >= 0x100
+                   && !(frwl->fw_prot == IPPROTO_TCP
+                     && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
+               /*
+                       printf(("%s unknown reject code\n", err_prefix));
+               */
+               
+                       return (EINVAL);
+               }
+               break;
+       case IP_FW_F_DIVERT_COMPAT:             /* Diverting to port zero is invalid */
+       case IP_FW_F_TEE_COMPAT:
+       case IP_FW_F_PIPE_COMPAT:              /* piping through 0 is invalid */
+       case IP_FW_F_QUEUE_COMPAT:             /* piping through 0 is invalid */
+               if (frwl->fw_divert_port_compat == 0) {
+               /*
+                       printf(("%s can't divert to port 0\n", err_prefix));
+               */
+               
+                       return (EINVAL);
+               }
+               break;
+       case IP_FW_F_DENY_COMPAT:
+       case IP_FW_F_ACCEPT_COMPAT:
+       case IP_FW_F_COUNT_COMPAT:
+       case IP_FW_F_SKIPTO_COMPAT:
+       case IP_FW_F_FWD_COMPAT:
+       case IP_FW_F_UID_COMPAT:
+               break;
+       default:
+               /*
+               printf(("%s invalid command\n", err_prefix));
+               */
+               
                return (EINVAL);
        }
-       if (frwl->fw_flg == IP_FW_F_CHECK_S_COMPAT) {
-               /* check-state */
-               return 0 ;
+
+       return 0;
+}
+
+static void
+ipfw_convert_to_cmds_32(struct ip_fw *curr_rule, struct ip_fw_compat_32 *compat_rule)
+{
+       int                     k;      
+       uint32_t        actbuf[255], cmdbuf[255];
+       ipfw_insn       *action, *cmd, *src, *dst;
+       ipfw_insn       *have_state = NULL;     /* track check-state or keep-state */
+       
+       if (!compat_rule || !curr_rule) {
+               return;
+       }
+
+       /* preemptively check the old ip_fw rule to
+        * make sure it's valid before starting to copy stuff
+        */
+       if (ipfw_check_vers1_struct_32(compat_rule)) {
+               /* bad rule */
+               return;
+       }
+       
+       bzero(actbuf, sizeof(actbuf));          /* actions go here */
+       bzero(cmdbuf, sizeof(cmdbuf));
+
+       /* fill in action */
+       action = (ipfw_insn *)actbuf;
+       {
+       u_int   flag = compat_rule->fw_flg;
+       
+       action->len = 1;        /* default */
+       
+       if (flag & IP_FW_F_CHECK_S_COMPAT) {
+               have_state = action;
+               action->opcode = O_CHECK_STATE;
+       } 
+       else {
+               switch (flag & IP_FW_F_COMMAND_COMPAT) {
+                       case IP_FW_F_ACCEPT_COMPAT:
+                               action->opcode = O_ACCEPT;
+                               break;
+                       case IP_FW_F_COUNT_COMPAT:
+                               action->opcode = O_COUNT;
+                               break;
+                       case IP_FW_F_PIPE_COMPAT:
+                               action->opcode = O_PIPE;
+                               action->len = F_INSN_SIZE(ipfw_insn_pipe);
+                               action->arg1 = compat_rule->fw_divert_port_compat;
+                               break;
+                       case IP_FW_F_QUEUE_COMPAT:
+                               action->opcode = O_QUEUE;
+                               action->len = F_INSN_SIZE(ipfw_insn_pipe);
+                               action->arg1 = compat_rule->fw_divert_port_compat;
+                               break;
+                       case IP_FW_F_SKIPTO_COMPAT:
+                               action->opcode = O_SKIPTO;
+                               action->arg1 = compat_rule->fw_skipto_rule_compat;
+                               break;
+                       case IP_FW_F_DIVERT_COMPAT:
+                               action->opcode = O_DIVERT;
+                               action->arg1 = compat_rule->fw_divert_port_compat;
+                               break;
+                       case IP_FW_F_TEE_COMPAT:
+                               action->opcode = O_TEE;
+                               action->arg1 = compat_rule->fw_divert_port_compat;
+                               break;
+                       case IP_FW_F_FWD_COMPAT:
+                       {
+                               ipfw_insn_sa *p = (ipfw_insn_sa *)action;
+                               
+                               action->opcode = O_FORWARD_IP;
+                               action->len = F_INSN_SIZE(ipfw_insn_sa);
+                               
+                               p->sa.sin_len = compat_rule->fw_fwd_ip_compat.sin_len;
+                               p->sa.sin_family = compat_rule->fw_fwd_ip_compat.sin_family;
+                               p->sa.sin_port = compat_rule->fw_fwd_ip_compat.sin_port;
+                               p->sa.sin_addr = compat_rule->fw_fwd_ip_compat.sin_addr;
+                               
+                               break;
+                       }
+                       case IP_FW_F_DENY_COMPAT:
+                               action->opcode = O_DENY;
+                               action->arg1 = 0;
+                               break;
+                       case IP_FW_F_REJECT_COMPAT:
+                               action->opcode = O_REJECT;
+                               action->arg1 = compat_rule->fw_reject_code_compat;
+                               break;
+                       default:
+                               action->opcode = O_NOP;
+                               break;
+               }
+       }
+       
+       /* action is mandatory */
+       if (action->opcode == O_NOP) {
+                       return;
+       }
+       
+       action = next_cmd(action);
+       } /* end actions */
+       
+       cmd = (ipfw_insn *)cmdbuf;
+
+       /* this is O_CHECK_STATE, we're done */
+       if (have_state) {
+                       goto done;
+       }
+
+       {
+       ipfw_insn               *prev = NULL;
+       u_int                   flag = compat_rule->fw_flg;
+       
+       /* logging */
+       if (flag & IP_FW_F_PRN_COMPAT) {
+               ipfw_insn_log *c = (ipfw_insn_log *)cmd;
+               
+               cmd->opcode = O_LOG;
+               cmd->len |= F_INSN_SIZE(ipfw_insn_log);
+               c->max_log = compat_rule->fw_logamount;
+
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       }
+
+       /* protocol */
+       if (compat_rule->fw_prot != 0) {
+               fill_cmd(cmd, O_PROTO, compat_rule->fw_prot);
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       }
+       
+       /* source */
+       if (flag & IP_FW_F_SME_COMPAT) {
+               cmd->opcode = O_IP_SRC_ME;
+               cmd->len |= F_INSN_SIZE(ipfw_insn);
+               if (flag & IP_FW_F_INVSRC_COMPAT) {
+                       cmd->len ^= F_NOT; /* toggle F_NOT */                   
+               }
+               
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       } else {
+               if (compat_rule->fw_smsk.s_addr != 0) {
+                       /* addr/mask */
+                       ipfw_insn_ip    *ip = (ipfw_insn_ip *)cmd;
+                       
+                       ip->addr = compat_rule->fw_src;
+                       ip->mask = compat_rule->fw_smsk;
+                       cmd->opcode = O_IP_SRC_MASK;
+                       cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
+               } else {
+                       /* one IP */
+                       ipfw_insn_u32   *cmd32 = (ipfw_insn_u32 *)cmd;  /* alias for cmd */
+                       
+                       if (compat_rule->fw_src.s_addr == 0) {
+                               /* any */
+                               cmd32->o.len &= ~F_LEN_MASK;    /* zero len */
+                       } else {
+                               cmd32->d[0] = compat_rule->fw_src.s_addr;
+                               cmd32->o.opcode = O_IP_SRC;
+                               cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+                       }
+               }
+               
+               if (flag & IP_FW_F_INVSRC_COMPAT) {
+                       cmd->len ^= F_NOT; /* toggle F_NOT */                   
+               }
+
+               if (F_LEN(cmd) != 0) { /* !any */
+                       prev = cmd;
+                       cmd = next_cmd(cmd);
+               }
+       }
+       
+       /* source ports */
+       {
+               ipfw_insn_u16   *ports = (ipfw_insn_u16 *)cmd;
+               uint16_t                *p = ports->ports;
+               int                             i, j = 0, 
+                                               nports = IP_FW_GETNSRCP_COMPAT(compat_rule),
+                                               have_range = 0;
+               
+               cmd->opcode = O_IP_SRCPORT;
+               for (i = 0; i < nports; i++) {
+                       if (((flag & IP_FW_F_SRNG_COMPAT) ||
+                               (flag & IP_FW_F_SMSK_COMPAT)) && !have_range) {
+                               p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
+                               p[1] = compat_rule->fw_uar_compat.fw_pts[i];
+                               have_range = 1;
+                       } else {
+                               p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
+                       }
+                       p += 2;
+                       j++;
+               }
+               
+               if (j > 0) {
+                       ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
+               }
+               
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       }
+       
+       /* destination */
+       if (flag & IP_FW_F_DME_COMPAT) {
+               cmd->opcode = O_IP_DST_ME;
+               cmd->len |= F_INSN_SIZE(ipfw_insn);
+               if (flag & IP_FW_F_INVDST_COMPAT) {
+                       cmd->len ^= F_NOT; /* toggle F_NOT */                   
+               }
+
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       } else {
+               if (compat_rule->fw_dmsk.s_addr != 0) {
+                       /* addr/mask */
+                       ipfw_insn_ip    *ip = (ipfw_insn_ip *)cmd;
+                       
+                       ip->addr = compat_rule->fw_dst;
+                       ip->mask = compat_rule->fw_dmsk;
+                       cmd->opcode = O_IP_DST_MASK;
+                       cmd->len |= F_INSN_SIZE(ipfw_insn_ip); /* double check this */
+               } else {
+                       /* one IP */
+                       ipfw_insn_u32   *cmd32 = (ipfw_insn_u32 *)cmd;  /* alias for cmd */
+                       
+                       if (compat_rule->fw_dst.s_addr == 0) {
+                               /* any */
+                               cmd32->o.len &= ~F_LEN_MASK;    /* zero len */
+                       } else {
+                               cmd32->d[0] = compat_rule->fw_dst.s_addr;
+                               cmd32->o.opcode = O_IP_DST;
+                               cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+                       }
+               }
+               
+               if (flag & IP_FW_F_INVDST_COMPAT) {
+                       cmd->len ^= F_NOT; /* toggle F_NOT */                   
+               }
+
+               if (F_LEN(cmd) != 0) { /* !any */
+                       prev = cmd;
+                       cmd = next_cmd(cmd);
+               }
+       }
+       
+       /* dest. ports */
+       {
+               ipfw_insn_u16   *ports = (ipfw_insn_u16 *)cmd;
+               uint16_t                *p = ports->ports;
+               int                             i = IP_FW_GETNSRCP_COMPAT(compat_rule), 
+                                               j = 0, 
+                                               nports = (IP_FW_GETNDSTP_COMPAT(compat_rule) + i),
+                                               have_range = 0;
+               
+               cmd->opcode = O_IP_DSTPORT;
+               for (; i < nports; i++, p += 2) {
+                       if (((flag & IP_FW_F_DRNG_COMPAT) ||
+                               (flag & IP_FW_F_DMSK_COMPAT)) && !have_range) {
+                               /* range */
+                               p[0] = compat_rule->fw_uar_compat.fw_pts[i++];
+                               p[1] = compat_rule->fw_uar_compat.fw_pts[i];
+                               have_range = 1;
+                       } else {
+                               p[0] = p[1] = compat_rule->fw_uar_compat.fw_pts[i];
+                       }
+                       j++;
+               }
+               
+               if (j > 0) {
+                       ports->o.len |= j+1; /* leave F_NOT and F_OR untouched */
+               }
+               
+               prev = cmd;
+               cmd = next_cmd(cmd);
        }
-       /* Must apply to incoming or outgoing (or both) */
-       if (!(frwl->fw_flg & (IP_FW_F_IN_COMPAT | IP_FW_F_OUT_COMPAT))) {
-               /*
-               printf(("%s neither in nor out\n", err_prefix));
-               */
-               return (EINVAL);
+       
+       if (flag & IP_FW_F_UID_COMPAT) {
+               ipfw_insn_u32   *cmd32 = (ipfw_insn_u32 *)cmd;  /* alias for cmd */
+                       
+               cmd32->o.opcode = O_UID;
+               cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+               cmd32->d[0] = compat_rule->fw_uid;
+
+               prev = cmd;
+               cmd = next_cmd(cmd);
        }
-       /* Empty interface name is no good */
-       if (((frwl->fw_flg & IP_FW_F_IIFNAME_COMPAT)
-             && !*frwl->fw_in_if.fu_via_if_compat.name)
-           || ((frwl->fw_flg & IP_FW_F_OIFNAME_COMPAT)
-             && !*frwl->fw_out_if.fu_via_if_compat.name)) {
-               /*
-               printf(("%s empty interface name\n", err_prefix));
-               */
-               return (EINVAL);
+       
+       if (flag & IP_FW_F_KEEP_S_COMPAT) {
+               have_state = cmd;
+               fill_cmd(cmd, O_KEEP_STATE, 0);
+
+               prev = cmd;
+               cmd = next_cmd(cmd);
        }
-       /* Sanity check interface matching */
-       if ((frwl->fw_flg & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
-               ;               /* allow "via" backwards compatibility */
-       } else if ((frwl->fw_flg & IP_FW_F_IN_COMPAT)
-           && (frwl->fw_flg & IP_FW_F_OIFACE_COMPAT)) {
-               /*
-               printf(("%s outgoing interface check on incoming\n",
-                   err_prefix));
-               */
-               return (EINVAL);
+       if (flag & IP_FW_BRIDGED_COMPAT) {
+               fill_cmd(cmd, O_LAYER2, 0);
+
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       }
+       
+       if ((flag & IF_FW_F_VIAHACK_COMPAT) == IF_FW_F_VIAHACK_COMPAT) {
+               /* via */
+               ipfw_insn_if                    *ifcmd = (ipfw_insn_if *)cmd;
+               union ip_fw_if_compat   ifu = compat_rule->fw_in_if;
+               
+               cmd->opcode = O_VIA;
+               ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
+               
+               if (ifu.fu_via_ip.s_addr == 0) {
+                       /* "any" */
+                       ifcmd->name[0] = '\0';
+                       ifcmd->o.len = 0;
+               }
+               else if (compat_rule->fw_flg & IP_FW_F_IIFNAME_COMPAT) {
+                       /* by name */
+                       strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
+                       ifcmd->p.unit = ifu.fu_via_if_compat.unit;
+               } else {
+                       /* by addr */
+                       ifcmd->p.ip = ifu.fu_via_ip;
+               }
+
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       } else {
+               if (flag & IP_FW_F_IN_COMPAT) {
+                       fill_cmd(cmd, O_IN, 0);
+       
+                       prev = cmd;
+                       cmd = next_cmd(cmd);
+               }
+               if (flag & IP_FW_F_OUT_COMPAT) {
+                       /* if the previous command was O_IN, and this
+                        * is being set as well, it's equivalent to not
+                        * having either command, so let's back up prev 
+                        * to the cmd before it and move cmd to prev.
+                        */
+                       if (prev->opcode == O_IN) {
+                               cmd = prev;
+                               bzero(cmd, sizeof(*cmd));
+                       } else {
+                               cmd->len ^= F_NOT; /* toggle F_NOT */
+                               fill_cmd(cmd, O_IN, 0);
+               
+                               prev = cmd;
+                               cmd = next_cmd(cmd);
+                       }
+               }
+               if (flag & IP_FW_F_OIFACE_COMPAT) {
+                       /* xmit */
+                       ipfw_insn_if    *ifcmd = (ipfw_insn_if *)cmd;
+                       union ip_fw_if_compat   ifu = compat_rule->fw_out_if;
+                       
+                       cmd->opcode = O_XMIT;
+                       ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
+       
+                       if (ifu.fu_via_ip.s_addr == 0) {
+                               /* "any" */
+                               ifcmd->name[0] = '\0';
+                               ifcmd->o.len = 0;
+                       }
+                       else if (flag & IP_FW_F_OIFNAME_COMPAT) {
+                               /* by name */
+                               strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
+                               ifcmd->p.unit = ifu.fu_via_if_compat.unit;
+                       } else {
+                               /* by addr */
+                               ifcmd->p.ip = ifu.fu_via_ip;
+                       }
+       
+                       prev = cmd;
+                       cmd = next_cmd(cmd);
+               } 
+               else if (flag & IP_FW_F_IIFACE_COMPAT) {
+                       /* recv */
+                       ipfw_insn_if    *ifcmd = (ipfw_insn_if *)cmd;
+                       union ip_fw_if_compat   ifu = compat_rule->fw_in_if;
+                       
+                       cmd->opcode = O_RECV;
+                       ifcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
+       
+                       if (ifu.fu_via_ip.s_addr == 0) {
+                               /* "any" */
+                               ifcmd->name[0] = '\0';
+                               ifcmd->o.len = 0;
+                       }
+                       else if (flag & IP_FW_F_IIFNAME_COMPAT) {
+                               /* by name */
+                               strncpy(ifcmd->name, ifu.fu_via_if_compat.name, sizeof(ifcmd->name));
+                               ifcmd->p.unit = ifu.fu_via_if_compat.unit;
+                       } else {
+                               /* by addr */
+                               ifcmd->p.ip = ifu.fu_via_ip;
+                       }
+       
+                       prev = cmd;
+                       cmd = next_cmd(cmd);
+               }
+       }
+       
+       if (flag & IP_FW_F_FRAG_COMPAT) {
+               fill_cmd(cmd, O_FRAG, 0);
+
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       }
+       
+       /* IP options */
+       if (compat_rule->fw_ipopt != 0 || compat_rule->fw_ipnopt != 0) {
+               fill_cmd(cmd, O_IPOPT, (compat_rule->fw_ipopt & 0xff) |
+                                                               (compat_rule->fw_ipnopt & 0xff) << 8);
+               
+               prev = cmd;
+               cmd = next_cmd(cmd);
+       }
+       
+       if (compat_rule->fw_prot == IPPROTO_TCP) {
+               if (compat_rule->fw_ipflg & IP_FW_IF_TCPEST_COMPAT) {
+                       fill_cmd(cmd, O_ESTAB, 0);
+       
+                       prev = cmd;
+                       cmd = next_cmd(cmd);
+               }
+       
+               /* TCP options and flags */
+               if (compat_rule->fw_tcpf != 0 || compat_rule->fw_tcpnf != 0) {
+                       if ((compat_rule->fw_tcpf & IP_FW_TCPF_SYN_COMPAT) &&
+                               compat_rule->fw_tcpnf & IP_FW_TCPF_ACK_COMPAT) {
+                               fill_cmd(cmd, O_TCPFLAGS, (TH_SYN) | ( (TH_ACK) & 0xff) <<8);
+                               
+                               prev = cmd;
+                               cmd = next_cmd(cmd);
+                       }
+                       else {
+                               fill_cmd(cmd, O_TCPFLAGS, (compat_rule->fw_tcpf & 0xff) |
+                                                                                       (compat_rule->fw_tcpnf & 0xff) << 8);
+                               
+                               prev = cmd;
+                               cmd = next_cmd(cmd);
+                       }
+               }
+               if (compat_rule->fw_tcpopt != 0 || compat_rule->fw_tcpnopt != 0) {
+                       fill_cmd(cmd, O_TCPOPTS, (compat_rule->fw_tcpopt & 0xff) |
+                                                                               (compat_rule->fw_tcpnopt & 0xff) << 8);
+                       
+                       prev = cmd;
+                       cmd = next_cmd(cmd);
+               }
        }
-       /* Sanity check port ranges */
-       if ((frwl->fw_flg & IP_FW_F_SRNG_COMPAT) && IP_FW_GETNSRCP_COMPAT(frwl) < 2) {
-               /*
-               printf(("%s src range set but n_src_p=%d\n",
-                   err_prefix, IP_FW_GETNSRCP_COMPAT(frwl)));
-               */
-               return (EINVAL);
+       
+       /* ICMP */
+       /* XXX: check this */
+       if (flag & IP_FW_F_ICMPBIT_COMPAT) {
+               int     i;
+               ipfw_insn_u32   *cmd32 = (ipfw_insn_u32 *)cmd;  /* alias for cmd */
+               
+               cmd32->o.opcode = O_ICMPTYPE;
+               cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+               
+               for (i = 0; i < IP_FW_ICMPTYPES_DIM_COMPAT; i++) {
+                       cmd32->d[0] |= compat_rule->fw_uar_compat.fw_icmptypes[i];
+               }
+
+               prev = cmd;
+               cmd = next_cmd(cmd);
        }
-       if ((frwl->fw_flg & IP_FW_F_DRNG_COMPAT) && IP_FW_GETNDSTP_COMPAT(frwl) < 2) {
-               /*
-               printf(("%s dst range set but n_dst_p=%d\n",
-                   err_prefix, IP_FW_GETNDSTP_COMPAT(frwl)));
-               */
-               return (EINVAL);
+       } /* end commands */
+       
+done:
+       /* finally, copy everything into the current 
+        * rule buffer in the right order.
+        */
+       dst = curr_rule->cmd;
+       
+       /* first, do match probability */
+       if (compat_rule->fw_flg & IP_FW_F_RND_MATCH_COMPAT) {
+               dst->opcode = O_PROB;
+               dst->len = 2;
+               *((int32_t *)(dst+1)) = compat_rule->pipe_ptr;
+               dst += dst->len;
        }
-       if (IP_FW_GETNSRCP_COMPAT(frwl) + IP_FW_GETNDSTP_COMPAT(frwl) > IP_FW_MAX_PORTS_COMPAT) {
-               /*
-               printf(("%s too many ports (%d+%d)\n",
-                   err_prefix, IP_FW_GETNSRCP_COMPAT(frwl), IP_FW_GETNDSTP_COMPAT(frwl)));
-               */
-               return (EINVAL);
+       
+       /* generate O_PROBE_STATE if necessary */
+       if (have_state && have_state->opcode != O_CHECK_STATE) {
+               fill_cmd(dst, O_PROBE_STATE, 0);
+               dst = next_cmd(dst);
        }
+       
        /*
-        *      Protocols other than TCP/UDP don't use port range
+        * copy all commands but O_LOG, O_KEEP_STATE
         */
-       if ((frwl->fw_prot != IPPROTO_TCP) &&
-           (frwl->fw_prot != IPPROTO_UDP) &&
-           (IP_FW_GETNSRCP_COMPAT(frwl) || IP_FW_GETNDSTP_COMPAT(frwl))) {
-               /*
-               printf(("%s port(s) specified for non TCP/UDP rule\n",
-                   err_prefix));
-               */
-               return (EINVAL);
+       for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
+               k = F_LEN(src);
+
+               switch (src->opcode) {
+               case O_LOG:
+               case O_KEEP_STATE:
+                       break;
+               default:
+                       bcopy(src, dst, k * sizeof(uint32_t));
+                       dst += k;
+               }
        }
 
        /*
-        *      Rather than modify the entry to make such entries work, 
-        *      we reject this rule and require user level utilities
-        *      to enforce whatever policy they deem appropriate.
+        * put back the have_state command as last opcode
         */
-       if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || 
-               (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
-               /*
-               printf(("%s rule never matches\n", err_prefix));
-               */
-               return (EINVAL);
+       if (have_state && have_state->opcode != O_CHECK_STATE) {
+               k = F_LEN(have_state);
+               bcopy(have_state, dst, k * sizeof(uint32_t));
+               dst += k;
        }
+       
+       /*
+        * start action section
+        */
+       curr_rule->act_ofs = dst - curr_rule->cmd;
 
-       if ((frwl->fw_flg & IP_FW_F_FRAG_COMPAT) &&
-               (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
-               if (frwl->fw_nports) {
-               /*
-                       printf(("%s cannot mix 'frag' and ports\n", err_prefix));
-               */
-                       return (EINVAL);
-               }
-               if (frwl->fw_prot == IPPROTO_TCP &&
-                       frwl->fw_tcpf != frwl->fw_tcpnf) {
-               /*
-                       printf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
-               */
-                       return (EINVAL);
-               }
+       /*
+        * put back O_LOG if necessary
+        */
+       src = (ipfw_insn *)cmdbuf;
+       if (src->opcode == O_LOG) {
+               k = F_LEN(src);
+               bcopy(src, dst, k * sizeof(uint32_t));
+               dst += k;
        }
-
-       /* Check command specific stuff */
-       switch (frwl->fw_flg & IP_FW_F_COMMAND_COMPAT)
-       {
-       case IP_FW_F_REJECT_COMPAT:
-               if (frwl->fw_reject_code_compat >= 0x100
-                   && !(frwl->fw_prot == IPPROTO_TCP
-                     && frwl->fw_reject_code_compat == IP_FW_REJECT_RST_COMPAT)) {
-               /*
-                       printf(("%s unknown reject code\n", err_prefix));
-               */
-                       return (EINVAL);
-               }
-               break;
-       case IP_FW_F_DIVERT_COMPAT:             /* Diverting to port zero is invalid */
-       case IP_FW_F_TEE_COMPAT:
-       case IP_FW_F_PIPE_COMPAT:              /* piping through 0 is invalid */
-       case IP_FW_F_QUEUE_COMPAT:             /* piping through 0 is invalid */
-               if (frwl->fw_divert_port_compat == 0) {
-               /*
-                       printf(("%s can't divert to port 0\n", err_prefix));
-               */
-                       return (EINVAL);
-               }
-               break;
-       case IP_FW_F_DENY_COMPAT:
-       case IP_FW_F_ACCEPT_COMPAT:
-       case IP_FW_F_COUNT_COMPAT:
-       case IP_FW_F_SKIPTO_COMPAT:
-       case IP_FW_F_FWD_COMPAT:
-       case IP_FW_F_UID_COMPAT:
-               break;
-       default:
-               /*
-               printf(("%s invalid command\n", err_prefix));
-               */
-               return (EINVAL);
+       
+       /*
+        * copy all other actions
+        */
+       for (src = (ipfw_insn *)actbuf; src != action; src += k) {
+               k = F_LEN(src);
+               bcopy(src, dst, k * sizeof(uint32_t));
+               dst += k;
        }
 
-       return 0;
+       curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
+       
+       return;
 }
 
 static void
-ipfw_convert_to_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
+ipfw_convert_to_cmds_64(struct ip_fw *curr_rule, struct ip_fw_compat_64 *compat_rule)
 {
        int                     k;      
        uint32_t        actbuf[255], cmdbuf[255];
        ipfw_insn       *action, *cmd, *src, *dst;
        ipfw_insn       *have_state = NULL;     /* track check-state or keep-state */
        
-       if (!compat_rule || !curr_rule || !(curr_rule->cmd)) {
+       if (!compat_rule || !curr_rule) {
                return;
        }
 
        /* preemptively check the old ip_fw rule to
         * make sure it's valid before starting to copy stuff
         */
-       if (ipfw_check_vers1_struct(compat_rule)) {
+       if (ipfw_check_vers1_struct_64(compat_rule)) {
                /* bad rule */
                return;
        }
        
        bzero(actbuf, sizeof(actbuf));          /* actions go here */
        bzero(cmdbuf, sizeof(cmdbuf));
-
        /* fill in action */
        action = (ipfw_insn *)actbuf;
        {
@@ -1964,7 +2973,6 @@ ipfw_convert_to_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
        if (flag & IP_FW_F_ICMPBIT_COMPAT) {
                int     i;
                ipfw_insn_u32   *cmd32 = (ipfw_insn_u32 *)cmd;  /* alias for cmd */
-               
                cmd32->o.opcode = O_ICMPTYPE;
                cmd32->o.len |= F_INSN_SIZE(ipfw_insn_u32);
                
@@ -1976,7 +2984,6 @@ ipfw_convert_to_cmds(struct ip_fw *curr_rule, struct ip_fw_compat *compat_rule)
                cmd = next_cmd(cmd);
        }
        } /* end commands */
-       
 done:
        /* finally, copy everything into the current 
         * rule buffer in the right order.
@@ -2002,7 +3009,6 @@ done:
         */
        for (src = (ipfw_insn *)cmdbuf; src != cmd; src += k) {
                k = F_LEN(src);
-
                switch (src->opcode) {
                case O_LOG:
                case O_KEEP_STATE:
@@ -2047,28 +3053,27 @@ done:
        }
 
        curr_rule->cmd_len = (uint32_t *)dst - (uint32_t *)(curr_rule->cmd);
-       
        return;
 }
 
 static int
-ipfw_version_one_to_version_two(struct sockopt *sopt, struct ip_fw *curr_rule, 
-                                                               struct ip_fw_compat *rule_vers1)
+ipfw_version_one_to_version_two_32(struct sockopt *sopt, struct ip_fw *curr_rule, 
+                                                               struct ip_fw_compat_32 *rule_vers1)
 {
        int     err = EINVAL;
-       struct ip_fw_compat     *rule_ptr;
-       struct ip_fw_compat     rule;
+       struct ip_fw_compat_32  *rule_ptr;
+       struct ip_fw_compat_32  rule;
        
        if (rule_vers1) {
                rule_ptr = rule_vers1;
                err = 0;
        } else {
                /* do some basic size checking here, more extensive checking later */
-               if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat))
+               if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat_32))
                        return err;
        
-               if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat), 
-                                                       sizeof(struct ip_fw_compat)))) {
+               if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat_32), 
+                                                       sizeof(struct ip_fw_compat_32)))) {
                        return err;
                }
                
@@ -2076,10 +3081,51 @@ ipfw_version_one_to_version_two(struct sockopt *sopt, struct ip_fw *curr_rule,
        }
 
        /* deal with commands */
-       ipfw_convert_to_cmds(curr_rule, rule_ptr);
+       ipfw_convert_to_cmds_32(curr_rule, rule_ptr);
+
+       curr_rule->version = IP_FW_CURRENT_API_VERSION;
+       curr_rule->context = CAST_DOWN_EXPLICIT(void*, rule_ptr->context);
+       curr_rule->rulenum = rule_ptr->fw_number;
+       curr_rule->pcnt = rule_ptr->fw_pcnt;
+       curr_rule->bcnt = rule_ptr->fw_bcnt;
+       curr_rule->timestamp = rule_ptr->timestamp;
+
+       
+#if FW2_DEBUG_VERBOSE
+       ipfw_print_vers2_struct(curr_rule);
+#endif
+       
+       return err;
+}
+
+static int
+ipfw_version_one_to_version_two_64(struct sockopt *sopt, struct ip_fw *curr_rule, 
+                                                               struct ip_fw_compat_64 *rule_vers1)
+{
+       int     err = EINVAL;
+       struct ip_fw_compat_64  *rule_ptr;
+       struct ip_fw_compat_64  rule;
+       
+       if (rule_vers1) {
+               rule_ptr = rule_vers1;
+               err = 0;
+       } else {
+               /* do some basic size checking here, more extensive checking later */
+               if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw_compat_64))
+                       return err;
+       
+               if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw_compat_64), 
+                                                       sizeof(struct ip_fw_compat_64)))) {
+                       return err;
+               }
+               rule_ptr = &rule;
+       }
+
+       /* deal with commands */
+       ipfw_convert_to_cmds_64(curr_rule, rule_ptr);
 
        curr_rule->version = IP_FW_CURRENT_API_VERSION;
-       curr_rule->context = rule_ptr->context;
+       curr_rule->context = CAST_DOWN_EXPLICIT( void *, rule_ptr->context);
        curr_rule->rulenum = rule_ptr->fw_number;
        curr_rule->pcnt = rule_ptr->fw_pcnt;
        curr_rule->bcnt = rule_ptr->fw_bcnt;
@@ -2088,7 +3134,7 @@ ipfw_version_one_to_version_two(struct sockopt *sopt, struct ip_fw *curr_rule,
        
 #if FW2_DEBUG_VERBOSE
        ipfw_print_vers2_struct(curr_rule);
-#endif /* FW2_DEBUG_VERBOSE */
+#endif
        
        return err;
 }
@@ -2097,7 +3143,22 @@ ipfw_version_one_to_version_two(struct sockopt *sopt, struct ip_fw *curr_rule,
  * latest version of the firewall is ipfw2.
  */
 static int
-ipfw_version_one_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat *rule_vers1)
+ipfw_version_one_to_latest_32(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat_32 *rule_vers1)
+{
+       int err;
+       
+       /* if rule_vers1 is not null then this is coming from
+        * ipfw_version_zero_to_latest(), so pass that along;
+        * otherwise let ipfw_version_one_to_version_two()
+        * get the rule from sopt.
+        */
+       err = ipfw_version_one_to_version_two_32(sopt, curr_rule, rule_vers1);
+       
+       return err;
+}
+
+static int
+ipfw_version_one_to_latest_64(struct sockopt *sopt, struct ip_fw *curr_rule, struct ip_fw_compat_64 *rule_vers1)
 {
        int err;
        
@@ -2106,11 +3167,21 @@ ipfw_version_one_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, struct
         * otherwise let ipfw_version_one_to_version_two()
         * get the rule from sopt.
         */
-       err = ipfw_version_one_to_version_two(sopt, curr_rule, rule_vers1);
+       err = ipfw_version_one_to_version_two_64(sopt, curr_rule, rule_vers1);
        
        return err;
 }
 
+
+#if 0
+
+/* 
+ * XXX - ipfw_version_zero_to_one
+ * 
+ * This function is only used in version #1 of ipfw, which is now deprecated.
+ *
+ */ 
+
 static void
 ipfw_version_zero_to_one(struct ip_old_fw *rule_vers0, struct ip_fw_compat *rule_vers1)
 {
@@ -2141,46 +3212,13 @@ ipfw_version_zero_to_one(struct ip_old_fw *rule_vers0, struct ip_fw_compat *rule
        rule_vers1->fw_ipflg      = (rule_vers0->fw_tcpf & IP_OLD_FW_TCPF_ESTAB) ? IP_FW_IF_TCPEST_COMPAT : 0;
 }
 
-/* first convert to version one, then to version two */
-static int
-ipfw_version_zero_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule)
-{
-       int             err;
-       struct ip_old_fw        rule_vers0;
-       struct ip_fw_compat     rule_vers1;
-
-       if (sopt->sopt_name == IP_OLD_FW_GET || 
-               sopt->sopt_name == IP_OLD_FW_FLUSH || 
-               sopt->sopt_val == USER_ADDR_NULL) {
-               /* In the old-style API, it was legal to not pass in a rule 
-                * structure for certain firewall operations (e.g. flush, 
-                * reset log).  If that's the situation, we pretend we received 
-                * a blank structure. */
-               bzero(curr_rule, sizeof(struct ip_fw));
-               curr_rule->version = 10;
-       }
-       else {
-               if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_old_fw)) {
-                       return EINVAL;
-               }
-
-               err = sooptcopyin(sopt, &rule_vers0, sizeof(struct ip_old_fw), 
-                                       sizeof(struct ip_old_fw));
-               if (err) {
-                       return err;
-               }
-               
-               ipfw_version_zero_to_one(&rule_vers0, &rule_vers1);
-       }
-       
-       return (ipfw_version_one_to_latest(sopt, curr_rule, &rule_vers1));
-}
+#endif /* !ipfw_version_zero_to_one  */
 
 /* rule is a u_int32_t buffer[255] into which the converted 
  * (if necessary) rules go.
  */
 int
-ipfw_convert_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, int api_version)
+ipfw_convert_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, int api_version, int is64user)
 {
        int     err = 0;
        
@@ -2189,13 +3227,16 @@ ipfw_convert_to_latest(struct sockopt *sopt, struct ip_fw *curr_rule, int api_ve
         */
        switch (api_version) {
                case IP_FW_VERSION_0:
-                       /* this is the oldest version we support */
-                       err = ipfw_version_zero_to_latest(sopt, curr_rule);
+                       /* we're not supporting VERSION 0 */
+                       err = EOPNOTSUPP;
                        break;
                
                case IP_FW_VERSION_1:
                        /* this is the version supported in Panther */
-                       err = ipfw_version_one_to_latest(sopt, curr_rule, NULL);
+                       if ( is64user )
+                               err = ipfw_version_one_to_latest_64(sopt, curr_rule, NULL);
+                       else
+                               err = ipfw_version_one_to_latest_32(sopt, curr_rule, NULL);
                        break;
                
                case IP_FW_CURRENT_API_VERSION:
@@ -2252,13 +3293,17 @@ ipfw_get_command_and_version(struct sockopt *sopt, int *command, u_int32_t *api_
                /* working off the fact that the offset
                 * is the same in both structs.
                 */
-               struct ip_fw    rule;
-               
-               if (!sopt->sopt_val || sopt->sopt_valsize < sizeof(struct ip_fw))
-                       return EINVAL;
+               struct ip_fw_64 rule;
+                size_t  copyinsize;
+
+                if (proc_is64bit(sopt->sopt_p))
+                        copyinsize = sizeof(struct ip_fw_64);
+                else
+                        copyinsize = sizeof(struct ip_fw_32);
        
-               if ((err = sooptcopyin(sopt, &rule, sizeof(struct ip_fw), 
-                                                       sizeof(struct ip_fw)))) {
+               if (!sopt->sopt_val || sopt->sopt_valsize < copyinsize)
+                       return EINVAL;
+               if ((err = sooptcopyin(sopt, &rule, copyinsize, copyinsize))) {
                        return err;
                }
                
@@ -2268,7 +3313,6 @@ ipfw_get_command_and_version(struct sockopt *sopt, int *command, u_int32_t *api_
        if (command) {
                *command = cmd;
        }
-       
        if (api_version) {
                *api_version = vers;
        }