+static int
+Get32static_len()
+{
+ 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()
+{
+ 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);
+}
+
+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);
+ dyn_rule_vers1->id = p->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;
+ dyn_rule_vers1->id = p->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;
+}
+