+static int
+Get32static_len(void)
+{
+ int diff;
+ int len = static_len_32;
+ struct ip_fw *rule;
+ char *useraction;
+
+ for (rule = layer3_chain; rule; rule = rule->next) {
+ if (rule->reserved_1 == IPFW_RULE_INACTIVE) {
+ continue;
+ }
+ if (rule->act_ofs) {
+ useraction = (char*)ACTION_PTR( rule );
+ if (((ipfw_insn*)useraction)->opcode == O_QUEUE || ((ipfw_insn*)useraction)->opcode == O_PIPE) {
+ diff = sizeof(ipfw_insn_pipe) - sizeof(ipfw_insn_pipe_32);
+ if (diff) {
+ len -= diff;
+ }
+ }
+ }
+ }
+ return len;
+}
+
+static int
+Get64static_len(void)
+{
+ int diff;
+ int len = static_len_64;
+ struct ip_fw *rule;
+ char *useraction;
+
+ for (rule = layer3_chain; rule; rule = rule->next) {
+ if (rule->reserved_1 == IPFW_RULE_INACTIVE) {
+ continue;
+ }
+ if (rule->act_ofs) {
+ useraction = (char *)ACTION_PTR( rule );
+ if (((ipfw_insn*)useraction)->opcode == O_QUEUE || ((ipfw_insn*)useraction)->opcode == O_PIPE) {
+ diff = sizeof(ipfw_insn_pipe_64) - sizeof(ipfw_insn_pipe);
+ if (diff) {
+ len += diff;
+ }
+ }
+ }
+ }
+ return len;
+}
+
+static void
+copyto32fw_insn( struct ip_fw_32 *fw32, struct ip_fw *user_ip_fw, int cmdsize)
+{
+ char *end;
+ char *fw32action;
+ char *useraction;
+ int justcmdsize;
+ int diff = 0;
+ int actioncopysize;
+
+ end = ((char*)user_ip_fw->cmd) + cmdsize;
+ useraction = (char*)ACTION_PTR( user_ip_fw );
+ fw32action = (char*)fw32->cmd + (user_ip_fw->act_ofs * sizeof(uint32_t));
+ if ((justcmdsize = (fw32action - (char*)fw32->cmd))) {
+ bcopy( user_ip_fw->cmd, fw32->cmd, justcmdsize);
+ }
+ while (useraction < end) {
+ if (((ipfw_insn*)useraction)->opcode == O_QUEUE || ((ipfw_insn*)useraction)->opcode == O_PIPE) {
+ actioncopysize = sizeof(ipfw_insn_pipe_32);
+ ((ipfw_insn*)fw32action)->opcode = ((ipfw_insn*)useraction)->opcode;
+ ((ipfw_insn*)fw32action)->arg1 = ((ipfw_insn*)useraction)->arg1;
+ ((ipfw_insn*)fw32action)->len = F_INSN_SIZE(ipfw_insn_pipe_32);
+ diff = ((ipfw_insn*)useraction)->len - ((ipfw_insn*)fw32action)->len;
+ if (diff) {
+ fw32->cmd_len -= diff;
+ }
+ } else {
+ actioncopysize = (F_LEN((ipfw_insn*)useraction) ? (F_LEN((ipfw_insn*)useraction)) : 1) * sizeof(uint32_t);
+ bcopy( useraction, fw32action, actioncopysize );
+ }
+ useraction += (F_LEN((ipfw_insn*)useraction) ? (F_LEN((ipfw_insn*)useraction)) : 1) * sizeof(uint32_t);
+ fw32action += actioncopysize;
+ }
+}
+
+static void
+copyto64fw_insn( struct ip_fw_64 *fw64, struct ip_fw *user_ip_fw, int cmdsize)
+{
+ char *end;
+ char *fw64action;
+ char *useraction;
+ int justcmdsize;
+ int diff;
+ int actioncopysize;
+
+ end = ((char *)user_ip_fw->cmd) + cmdsize;
+ useraction = (char*)ACTION_PTR( user_ip_fw );
+ if ((justcmdsize = (useraction - (char*)user_ip_fw->cmd))) {
+ bcopy( user_ip_fw->cmd, fw64->cmd, justcmdsize);
+ }
+ fw64action = (char*)fw64->cmd + justcmdsize;
+ while (useraction < end) {
+ if (((ipfw_insn*)user_ip_fw)->opcode == O_QUEUE || ((ipfw_insn*)user_ip_fw)->opcode == O_PIPE) {
+ actioncopysize = sizeof(ipfw_insn_pipe_64);
+ ((ipfw_insn*)fw64action)->opcode = ((ipfw_insn*)useraction)->opcode;
+ ((ipfw_insn*)fw64action)->arg1 = ((ipfw_insn*)useraction)->arg1;
+ ((ipfw_insn*)fw64action)->len = F_INSN_SIZE(ipfw_insn_pipe_64);
+ diff = ((ipfw_insn*)fw64action)->len - ((ipfw_insn*)useraction)->len;
+ if (diff) {
+ fw64->cmd_len += diff;
+ }
+ } else {
+ actioncopysize = (F_LEN((ipfw_insn*)useraction) ? (F_LEN((ipfw_insn*)useraction)) : 1) * sizeof(uint32_t);
+ bcopy( useraction, fw64action, actioncopysize );
+ }
+ useraction += (F_LEN((ipfw_insn*)useraction) ? (F_LEN((ipfw_insn*)useraction)) : 1) * sizeof(uint32_t);
+ fw64action += actioncopysize;
+ }
+}
+
+static void
+copyto32fw( struct ip_fw *user_ip_fw, struct ip_fw_32 *fw32, __unused size_t copysize)
+{
+ size_t rulesize, cmdsize;
+
+ fw32->version = user_ip_fw->version;
+ fw32->context = CAST_DOWN_EXPLICIT( user32_addr_t, user_ip_fw->context);
+ fw32->next = CAST_DOWN_EXPLICIT(user32_addr_t, user_ip_fw->next);
+ fw32->next_rule = CAST_DOWN_EXPLICIT(user32_addr_t, user_ip_fw->next_rule);
+ fw32->act_ofs = user_ip_fw->act_ofs;
+ fw32->cmd_len = user_ip_fw->cmd_len;
+ fw32->rulenum = user_ip_fw->rulenum;
+ fw32->set = user_ip_fw->set;
+ fw32->set_masks[0] = user_ip_fw->set_masks[0];
+ fw32->set_masks[1] = user_ip_fw->set_masks[1];
+ fw32->pcnt = user_ip_fw->pcnt;
+ fw32->bcnt = user_ip_fw->bcnt;
+ fw32->timestamp = user_ip_fw->timestamp;
+ fw32->reserved_1 = user_ip_fw->reserved_1;
+ fw32->reserved_2 = user_ip_fw->reserved_2;
+ rulesize = sizeof(struct ip_fw_32) + (user_ip_fw->cmd_len * sizeof(ipfw_insn) - 4);
+ cmdsize = user_ip_fw->cmd_len * sizeof(u_int32_t);
+ copyto32fw_insn( fw32, user_ip_fw, cmdsize );
+}
+
+static void
+copyto64fw( struct ip_fw *user_ip_fw, struct ip_fw_64 *fw64, size_t copysize)
+{
+ size_t rulesize, cmdsize;
+
+ fw64->version = user_ip_fw->version;
+ fw64->context = CAST_DOWN_EXPLICIT(__uint64_t, user_ip_fw->context);
+ fw64->next = CAST_DOWN_EXPLICIT(user64_addr_t, user_ip_fw->next);
+ fw64->next_rule = CAST_DOWN_EXPLICIT(user64_addr_t, user_ip_fw->next_rule);
+ fw64->act_ofs = user_ip_fw->act_ofs;
+ fw64->cmd_len = user_ip_fw->cmd_len;
+ fw64->rulenum = user_ip_fw->rulenum;
+ fw64->set = user_ip_fw->set;
+ fw64->set_masks[0] = user_ip_fw->set_masks[0];
+ fw64->set_masks[1] = user_ip_fw->set_masks[1];
+ fw64->pcnt = user_ip_fw->pcnt;
+ fw64->bcnt = user_ip_fw->bcnt;
+ fw64->timestamp = user_ip_fw->timestamp;
+ fw64->reserved_1 = user_ip_fw->reserved_1;
+ fw64->reserved_2 = user_ip_fw->reserved_2;
+ rulesize = sizeof(struct ip_fw_64) + (user_ip_fw->cmd_len * sizeof(ipfw_insn) - 4);
+ if (rulesize > copysize) {
+ cmdsize = copysize - sizeof(struct ip_fw_64) + 4;
+ } else {
+ cmdsize = user_ip_fw->cmd_len * sizeof(u_int32_t);
+ }
+ copyto64fw_insn( fw64, user_ip_fw, cmdsize);
+}
+
+static int
+copyfrom32fw_insn( struct ip_fw_32 *fw32, struct ip_fw *user_ip_fw, int cmdsize)
+{
+ char *end;
+ char *fw32action;
+ char *useraction;
+ int justcmdsize;
+ int diff;
+ int actioncopysize;
+
+ end = ((char*)fw32->cmd) + cmdsize;
+ fw32action = (char*)ACTION_PTR( fw32 );
+ if ((justcmdsize = (fw32action - (char*)fw32->cmd))) {
+ bcopy( fw32->cmd, user_ip_fw->cmd, justcmdsize);
+ }
+ useraction = (char*)user_ip_fw->cmd + justcmdsize;
+ while (fw32action < end) {
+ if (((ipfw_insn*)fw32action)->opcode == O_QUEUE || ((ipfw_insn*)fw32action)->opcode == O_PIPE) {
+ actioncopysize = sizeof(ipfw_insn_pipe);
+ ((ipfw_insn*)useraction)->opcode = ((ipfw_insn*)fw32action)->opcode;
+ ((ipfw_insn*)useraction)->arg1 = ((ipfw_insn*)fw32action)->arg1;
+ ((ipfw_insn*)useraction)->len = F_INSN_SIZE(ipfw_insn_pipe);
+ diff = ((ipfw_insn*)useraction)->len - ((ipfw_insn*)fw32action)->len;
+ if (diff) {
+ /* readjust the cmd_len */
+ user_ip_fw->cmd_len += diff;
+ }
+ } else {
+ actioncopysize = (F_LEN((ipfw_insn*)fw32action) ? (F_LEN((ipfw_insn*)fw32action)) : 1) * sizeof(uint32_t);
+ bcopy( fw32action, useraction, actioncopysize );
+ }
+ fw32action += (F_LEN((ipfw_insn*)fw32action) ? (F_LEN((ipfw_insn*)fw32action)) : 1) * sizeof(uint32_t);
+ useraction += actioncopysize;
+ }
+
+ return useraction - (char*)user_ip_fw->cmd;
+}
+
+static int
+copyfrom64fw_insn( struct ip_fw_64 *fw64, struct ip_fw *user_ip_fw, int cmdsize)
+{
+ char *end;
+ char *fw64action;
+ char *useraction;
+ int justcmdsize;
+ int diff;
+ int actioncopysize;
+
+ end = ((char *)fw64->cmd) + cmdsize;
+ fw64action = (char*)ACTION_PTR( fw64 );
+ if ((justcmdsize = (fw64action - (char*)fw64->cmd))) {
+ bcopy( fw64->cmd, user_ip_fw->cmd, justcmdsize);
+ }
+ useraction = (char*)user_ip_fw->cmd + justcmdsize;
+ while (fw64action < end) {
+ if (((ipfw_insn*)fw64action)->opcode == O_QUEUE || ((ipfw_insn*)fw64action)->opcode == O_PIPE) {
+ actioncopysize = sizeof(ipfw_insn_pipe);
+ ((ipfw_insn*)useraction)->opcode = ((ipfw_insn*)fw64action)->opcode;
+ ((ipfw_insn*)useraction)->arg1 = ((ipfw_insn*)fw64action)->arg1;
+ ((ipfw_insn*)useraction)->len = F_INSN_SIZE(ipfw_insn_pipe);
+ diff = ((ipfw_insn*)fw64action)->len - ((ipfw_insn*)useraction)->len;
+ if (diff) {
+ /* readjust the cmd_len */
+ user_ip_fw->cmd_len -= diff;
+ }
+ } else {
+ actioncopysize = (F_LEN((ipfw_insn*)fw64action) ? (F_LEN((ipfw_insn*)fw64action)) : 1) * sizeof(uint32_t);
+ bcopy( fw64action, useraction, actioncopysize );
+ }
+ fw64action += (F_LEN((ipfw_insn*)fw64action) ? (F_LEN((ipfw_insn*)fw64action)) : 1) * sizeof(uint32_t);
+ useraction += actioncopysize;
+ }
+ return useraction - (char*)user_ip_fw->cmd;
+}
+
+static size_t
+copyfrom32fw( struct ip_fw_32 *fw32, struct ip_fw *user_ip_fw, size_t copysize)
+{
+ size_t rulesize, cmdsize;
+
+ user_ip_fw->version = fw32->version;
+ user_ip_fw->context = CAST_DOWN(void *, fw32->context);
+ user_ip_fw->next = CAST_DOWN(struct ip_fw*, fw32->next);
+ user_ip_fw->next_rule = CAST_DOWN_EXPLICIT(struct ip_fw*, fw32->next_rule);
+ user_ip_fw->act_ofs = fw32->act_ofs;
+ user_ip_fw->cmd_len = fw32->cmd_len;
+ user_ip_fw->rulenum = fw32->rulenum;
+ user_ip_fw->set = fw32->set;
+ user_ip_fw->set_masks[0] = fw32->set_masks[0];
+ user_ip_fw->set_masks[1] = fw32->set_masks[1];
+ user_ip_fw->pcnt = fw32->pcnt;
+ user_ip_fw->bcnt = fw32->bcnt;
+ user_ip_fw->timestamp = fw32->timestamp;
+ user_ip_fw->reserved_1 = fw32->reserved_1;
+ user_ip_fw->reserved_2 = fw32->reserved_2;
+ rulesize = sizeof(struct ip_fw_32) + (fw32->cmd_len * sizeof(ipfw_insn) - 4);
+ if (rulesize > copysize) {
+ cmdsize = copysize - sizeof(struct ip_fw_32) - 4;
+ } else {
+ cmdsize = fw32->cmd_len * sizeof(ipfw_insn);
+ }
+ cmdsize = copyfrom32fw_insn( fw32, user_ip_fw, cmdsize);
+ return sizeof(struct ip_fw) + cmdsize - 4;
+}
+
+static size_t
+copyfrom64fw( struct ip_fw_64 *fw64, struct ip_fw *user_ip_fw, size_t copysize)
+{
+ size_t rulesize, cmdsize;
+
+ user_ip_fw->version = fw64->version;
+ user_ip_fw->context = CAST_DOWN_EXPLICIT( void *, fw64->context);
+ user_ip_fw->next = CAST_DOWN_EXPLICIT(struct ip_fw*, fw64->next);
+ user_ip_fw->next_rule = CAST_DOWN_EXPLICIT(struct ip_fw*, fw64->next_rule);
+ user_ip_fw->act_ofs = fw64->act_ofs;
+ user_ip_fw->cmd_len = fw64->cmd_len;
+ user_ip_fw->rulenum = fw64->rulenum;
+ user_ip_fw->set = fw64->set;
+ user_ip_fw->set_masks[0] = fw64->set_masks[0];
+ user_ip_fw->set_masks[1] = fw64->set_masks[1];
+ user_ip_fw->pcnt = fw64->pcnt;
+ user_ip_fw->bcnt = fw64->bcnt;
+ user_ip_fw->timestamp = fw64->timestamp;
+ user_ip_fw->reserved_1 = fw64->reserved_1;
+ user_ip_fw->reserved_2 = fw64->reserved_2;
+ //bcopy( fw64->cmd, user_ip_fw->cmd, fw64->cmd_len * sizeof(ipfw_insn));
+ rulesize = sizeof(struct ip_fw_64) + (fw64->cmd_len * sizeof(ipfw_insn) - 4);
+ if (rulesize > copysize) {
+ cmdsize = copysize - sizeof(struct ip_fw_64) - 4;
+ } else {
+ cmdsize = fw64->cmd_len * sizeof(ipfw_insn);
+ }
+ cmdsize = copyfrom64fw_insn( fw64, user_ip_fw, cmdsize);
+ return sizeof(struct ip_fw) + cmdsize - 4;
+}
+
+void
+externalize_flow_id(struct ipfw_flow_id *dst, struct ip_flow_id *src);
+void
+externalize_flow_id(struct ipfw_flow_id *dst, struct ip_flow_id *src)
+{
+ dst->dst_ip = src->dst_ip;
+ dst->src_ip = src->src_ip;
+ dst->dst_port = src->dst_port;
+ dst->src_port = src->src_port;
+ dst->proto = src->proto;
+ dst->flags = src->flags;
+}
+
+static
+void
+cp_dyn_to_comp_32( struct ipfw_dyn_rule_compat_32 *dyn_rule_vers1, int *len)
+{
+ struct ipfw_dyn_rule_compat_32 *dyn_last = NULL;
+ ipfw_dyn_rule *p;
+ int i;
+
+ if (ipfw_dyn_v) {
+ for (i = 0; i < curr_dyn_buckets; i++) {
+ for (p = ipfw_dyn_v[i]; p != NULL; p = p->next) {
+ dyn_rule_vers1->chain = (user32_addr_t)(p->rule->rulenum);
+ externalize_flow_id(&dyn_rule_vers1->id, &p->id);
+ externalize_flow_id(&dyn_rule_vers1->mask, &p->id);
+ dyn_rule_vers1->type = p->dyn_type;
+ dyn_rule_vers1->expire = p->expire;
+ dyn_rule_vers1->pcnt = p->pcnt;
+ dyn_rule_vers1->bcnt = p->bcnt;
+ dyn_rule_vers1->bucket = p->bucket;
+ dyn_rule_vers1->state = p->state;
+
+ dyn_rule_vers1->next = CAST_DOWN_EXPLICIT( user32_addr_t, p->next);
+ dyn_last = dyn_rule_vers1;
+
+ *len += sizeof(*dyn_rule_vers1);
+ dyn_rule_vers1++;
+ }
+ }
+
+ if (dyn_last != NULL) {
+ dyn_last->next = ((user32_addr_t)0);
+ }
+ }
+}
+
+
+static
+void
+cp_dyn_to_comp_64( struct ipfw_dyn_rule_compat_64 *dyn_rule_vers1, int *len)
+{
+ struct ipfw_dyn_rule_compat_64 *dyn_last = NULL;
+ ipfw_dyn_rule *p;
+ int i;
+
+ if (ipfw_dyn_v) {
+ for (i = 0; i < curr_dyn_buckets; i++) {
+ for (p = ipfw_dyn_v[i]; p != NULL; p = p->next) {
+ dyn_rule_vers1->chain = (user64_addr_t) p->rule->rulenum;
+ externalize_flow_id(&dyn_rule_vers1->id, &p->id);
+ externalize_flow_id(&dyn_rule_vers1->mask, &p->id);
+ dyn_rule_vers1->type = p->dyn_type;
+ dyn_rule_vers1->expire = p->expire;
+ dyn_rule_vers1->pcnt = p->pcnt;
+ dyn_rule_vers1->bcnt = p->bcnt;
+ dyn_rule_vers1->bucket = p->bucket;
+ dyn_rule_vers1->state = p->state;
+
+ dyn_rule_vers1->next = CAST_DOWN(user64_addr_t, p->next);
+ dyn_last = dyn_rule_vers1;
+
+ *len += sizeof(*dyn_rule_vers1);
+ dyn_rule_vers1++;
+ }
+ }
+
+ if (dyn_last != NULL) {
+ dyn_last->next = CAST_DOWN(user64_addr_t, NULL);
+ }
+ }
+}
+
+static int
+sooptcopyin_fw( struct sockopt *sopt, struct ip_fw *user_ip_fw, size_t *size )
+{
+ size_t valsize, copyinsize = 0;
+ int error = 0;
+
+ valsize = sopt->sopt_valsize;
+ if (size) {
+ copyinsize = *size;
+ }
+ if (proc_is64bit(sopt->sopt_p)) {
+ struct ip_fw_64 *fw64 = NULL;
+
+ if (valsize < sizeof(struct ip_fw_64)) {
+ return EINVAL;
+ }
+ if (!copyinsize) {
+ copyinsize = sizeof(struct ip_fw_64);
+ }
+ if (valsize > copyinsize) {
+ sopt->sopt_valsize = valsize = copyinsize;
+ }
+
+ if (sopt->sopt_p != 0) {
+ fw64 = _MALLOC(copyinsize, M_TEMP, M_WAITOK);
+ if (fw64 == NULL) {
+ return ENOBUFS;
+ }
+ if ((error = copyin(sopt->sopt_val, fw64, valsize)) != 0) {
+ _FREE(fw64, M_TEMP);
+ return error;
+ }
+ } else {
+ bcopy(CAST_DOWN(caddr_t, sopt->sopt_val), fw64, valsize);
+ }
+ valsize = copyfrom64fw( fw64, user_ip_fw, valsize );
+ _FREE( fw64, M_TEMP);
+ } else {
+ struct ip_fw_32 *fw32 = NULL;
+
+ if (valsize < sizeof(struct ip_fw_32)) {
+ return EINVAL;
+ }
+ if (!copyinsize) {
+ copyinsize = sizeof(struct ip_fw_32);
+ }
+ if (valsize > copyinsize) {
+ sopt->sopt_valsize = valsize = copyinsize;
+ }
+
+ if (sopt->sopt_p != 0) {
+ fw32 = _MALLOC(copyinsize, M_TEMP, M_WAITOK);
+ if (fw32 == NULL) {
+ return ENOBUFS;
+ }
+ if ((error = copyin(sopt->sopt_val, fw32, valsize)) != 0) {
+ _FREE( fw32, M_TEMP);
+ return error;
+ }
+ } else {
+ bcopy(CAST_DOWN(caddr_t, sopt->sopt_val), fw32, valsize);
+ }
+ valsize = copyfrom32fw( fw32, user_ip_fw, valsize);
+ _FREE( fw32, M_TEMP);
+ }
+ if (size) {
+ *size = valsize;
+ }
+ return error;
+}
+