#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include "kernel.h"
#include "./packer/packit.h"
#include "las_pcap_recv.h"

#ifndef PACKER
  extern struct pack_vect		*packs2bsnt;	/* Packets to be sent structure */
  extern struct header_hash_table 	**head_hash;	/* header hash table */
  extern u_int16_t			noh;		/* Number of headers */
#endif

/*
 *  Sums the ASCII values of each caracter in a string
 */
u_int32_t string2int(char *name){
  int		len,i;
  u_int32_t	sum = 0;

  if(name == NULL){
    printf("Ooops! there isn't any string here!!\n");
    return 0;
  }else{
     len = strlen(name);
     for(i=0;i<len;i++){
       sum += name[i];
     }
     return sum;
   }
}

/* 
 * Returns the number of digits that the number 'N' contains
 */
int digits(int N){
  int i = 1;
  int x = 0;

  while(N%i != N){
    ++x;
    i *= 10;
  }
  return x;
}

u_int32_t pot10(u_int32_t x){
  int d, i;
  
  d = 1;
  for(i=0;i<x;i++){
    d *= 10;
  }
  return d;
}

/*
 *  Square de number N and take m_digits digits of the middle of the number
 */
u_int32_t mid_square(u_int32_t N, u_int8_t m_digits){
  int t_digits;
  char number[10];
  int i,m;
  u_int32_t the_number = 0;

  N %= 65536;
  N *= N;
  t_digits = digits(N);
  m = t_digits/2 - (m_digits-1)/2;
  if(m_digits <= t_digits){
    sprintf(number,"%d",N);
    for(i=m;i<m_digits+m;i++){
      the_number += (number[i]-48)*pot10((m_digits-1) - (i-m));
    }
    return the_number;
  }else return N;
}

/*
 *  It's a very simple hashing algorithm
 */
u_int32_t insert_hash(key,hsh,max,pos)
char 		*key;
struct hash	**hsh;
u_int32_t	max;
u_int32_t	pos;
{
  int num_key = string2int(key);
  int place,keyLen,residentKeyLen,placed,hashResult,key_size;

  keyLen = strlen(key);
  placed = 0;
  hashResult = mid_square(num_key, digits(max))%max;
  place = hashResult;
  while(!placed){
    if(hsh[place] == NULL){
      hsh[place] = (struct hash*) malloc(sizeof(struct hash));
      hsh[place]->pos = pos;
      hsh[place]->key = (char*)malloc(keyLen+1);
      memset(hsh[place]->key,0,keyLen+1);
      memcpy(hsh[place]->key,key,keyLen);
      placed = 1;
      //printf("Placed @%d\n",place);
    }else{
       residentKeyLen = strlen(hsh[place]->key);
       key_size = (residentKeyLen>keyLen)?(residentKeyLen):(keyLen);
       if(strncmp(key,hsh[place]->key,key_size) == 0){
         return -1; /* This Key already exists */
       }else{
         place++;
         place %= max;
        }
     }
  }
  return place;
}

/*
 *  Checks whether the State has already been created
 */

int16_t check_state(state,hsh,max)
char *state;
struct hash **hsh;
u_int32_t max;
{
  int num_key = string2int(state);
  int place,keyLen,residentKeyLen,placed,hashResult,key_size;

  hashResult = mid_square(num_key, digits(max))%max;
  keyLen = strlen(state);
  place = hashResult;
//printf("to be placed @%d\n",place);

  while(1){
    if(hsh[place] == NULL){
      return -1;
    }else{
       residentKeyLen = strlen(hsh[place]->key);
       key_size = (residentKeyLen>keyLen)?(residentKeyLen):(keyLen);
       if(strncmp(state,hsh[place]->key,key_size)==0){
         return place;
       }else{
         place++;
         place %= max;
        }
     }
  }
}

/*
 *  Links the hashing table to the state vector
 */
u_int8_t link_h2sv(hsh,cell,hsh_pos)
struct hash **hsh;
struct base **cell;
u_int32_t hsh_pos;
{
  int cell_pos = hsh[hsh_pos]->pos;
  int name_len = strlen(hsh[hsh_pos]->key);

  if(cell[cell_pos] == NULL){
    cell[cell_pos] = (struct base*)malloc(sizeof(struct base));
  }
  cell[cell_pos]->state_id = cell_pos;
  cell[cell_pos]->state_name = (char*)malloc(name_len+1);
  memcpy(cell[cell_pos]->state_name,hsh[hsh_pos]->key,name_len+1);
  cell[cell_pos]->action = NOT_SPEC;
  cell[cell_pos]->arg = NULL;
  cell[cell_pos]->next = -1;
}

#ifndef PACKER

/* 
 * Binds the action "SEND PACKET #pckt_id" to the state pointed by CELL[C_POS] 
 */
u_int8_t action_send(cell,c_pos,pckt_id,next,nobt,but_chainl)
struct base 	**cell;		/* State Vector */
u_int32_t 	c_pos;		/* Working state */
u_int32_t 	pckt_id;	/* Packet to send */
u_int32_t 	next;		/* Next state */
u_int16_t	nobt;		/* Number of buts */
struct but_in 	*but_chainl;	/* Changes in the packet */
{
  struct send 		snd;
  struct but_in		*baux,*bstart = but_chainl;
  int 			snd_len = sizeof(struct send);
  int			the_recv,off,status_1,status_2;
  int			i,nobti = nobt;
  int			waiting_packs;
  u_int32_t		arg_1,arg_2,result;
  
  snd.packet_id = pckt_id;
  if(cell[c_pos] == NULL){
    printf("HOUSTON WE GOT A little PROBLEM(a)!!\n"); /*It can't happen!*/
    return -1;
  }
  snd.but = NULL;
  snd.nobt = nobt;
  snd.pack = (u_char *)malloc((packs2bsnt[pckt_id-1].psize/8)+1);
  memcpy(snd.pack,packs2bsnt[pckt_id-1].data,packs2bsnt[pckt_id-1].psize/8);
  snd.psize = packs2bsnt[pckt_id-1].psize;
  
  if(but_chainl != NULL){ /* chained list --> index  */
    //printf("--> %u\n",packs2bsnt[pckt_id-1].psize/8);
    //show_buffs(snd.pack,packs2bsnt[pckt_id-1].psize/8);
    waiting_packs = 0;
    while(but_chainl != NULL){
      switch(but_chainl->but->operation){
        case NOP:
	  status_1 = get_argument(&snd,cell,but_chainl->but,pckt_id,0,&arg_1,waiting_packs,0);
	  if(!status_1){ /* If status_1 == 0 the argument is put in the packet now,
			  *   otherwise it is left for the player to assemble it.
			  */
	    carry_argument(&snd,but_chainl->but,pckt_id,arg_1);
	    --nobti;
            free_but(&(but_chainl->but));
	  }else{
             switch(status_1){
	       case STORED_PACKET: /* Stored Packets are static, so it's value is already  
				    *   took from the stored packet and the argument is 
				    *   turned into a IMMEDIATE one.
				    */
		 to_immediate(but_chainl->but, 0, arg_1);
	       break;
	       case RECEIVED_PACKET:
	         ++waiting_packs;
	       break;
	       case IMMEDIATE:
	       case THIS_PACKET:
	       case STD_CKSUM:
	       break;
	       default:
	         printf("An internal error has occurred.(That's all I can say... watta sh*t!)\n");
	     }
           }
	break;
	default:
	  if((but_chainl->but->args[0]->type | but_chainl->but->args[1]->type) == RECEIVED_PACKET){
	  /* Both arguments are RECEIVED_PACKET */
	    waiting_packs += 2;
          }else if(((but_chainl->but->args[0]->type  | \
		     but_chainl->but->args[1]->type) & \
		    RECEIVED_PACKET) == RECEIVED_PACKET){
		/* At least one argument is RECEIVED_PACKET */
		  ++waiting_packs;
		  the_recv = (but_chainl->but->args[0]->type == RECEIVED_PACKET)?(0):(1);
		  if(but_chainl->but->args[the_recv^1]->type == STORED_PACKET){
		      status_1 = get_argument(&snd,cell,but_chainl->but,pckt_id,the_recv^1,&arg_1,waiting_packs,0);
		      to_immediate(but_chainl->but, the_recv^1, arg_1);
		  }
	        }else{ 
		 /* None of the arguments is RECEIVED_PACKET */
		   status_1 = get_argument(&snd,cell,but_chainl->but,pckt_id,0,&arg_1,waiting_packs,0);
		   status_2 = get_argument(&snd,cell,but_chainl->but,pckt_id,1,&arg_2,waiting_packs,0);
		   if(!(status_1 | status_2)){
		     calc_args(but_chainl->but->operation,arg_1,arg_2,&result);
		     carry_argument(&snd,but_chainl->but,pckt_id,result);
		     --nobti;
		     free_but(&(but_chainl->but));
		   }else{
		      if(status_1 == STORED_PACKET){
		        to_immediate(but_chainl->but, 0, arg_1);
	              }
		      if(status_2 == STORED_PACKET){
			to_immediate(but_chainl->but, 1, arg_2);
		      }
	            }
		 }
      }
      fflush(stdout);
      but_chainl = but_chainl->next;
    }
    snd.nobt = nobti;
    snd.but = (struct but **)malloc(sizeof(struct but*)*nobti);
    but_chainl = bstart;
    baux = but_chainl;
    i = 0;
    while(but_chainl != NULL){
      if(but_chainl->but != NULL ){
	snd.but[i] = but_chainl->but;
	++i;
      }
      but_chainl = but_chainl->next;
      free(baux);
      baux = but_chainl;
    }
  }
  cell[c_pos]->action = SEND_PACKET;
  cell[c_pos]->arg = (u_int8_t *)malloc(snd_len);
  memcpy(cell[c_pos]->arg,&snd,snd_len);
  cell[c_pos]->next = next;
  return 0;
}

/*
 * Binds the action "WAIT" to the state pointed by CELL[C_POS]
 */
u_int8_t action_wait(cell,c_pos,time,next)
struct base **cell;
u_int32_t c_pos;
u_int32_t time;
u_int32_t next;
{
  struct wait wt;
  int wt_len = sizeof(struct wait);

  wt.usec = time;
  if(cell[c_pos] == NULL){
    printf("HOUSTON WE GOT A little PROBLEM(a)!!\n"); /*It can't happen!*/
    return -1;
  }
  cell[c_pos]->action = WAIT;
  cell[c_pos]->arg = (u_int8_t *)malloc(wt_len);
  memcpy(cell[c_pos]->arg,&wt,wt_len);
  cell[c_pos]->next = next;
  return 0;
}

/*
 * Binds the action "RECV_PACKET" to the state pointed by CELL[C_POS]
 */

u_int8_t action_recv(cell,c_pos,bpf_expr,iface,brch,nob,to)
struct base 	**cell;		/* State Vector 	*/
u_int32_t 	c_pos;		/* Working state 	*/
char 		*bpf_expr;	/* BPF expression	*/
char		*iface;		/* Interface to be used */
struct brch_in 	*brch;		/* Branches structure	*/
u_int16_t 	nob;		/* Number of branches	*/
struct timeout	to;		/* Timeout structure	*/
{
  struct recv *rcv;
  int	brch_i;
 
  if(cell[c_pos] == NULL){
    printf("HOUSTON WE GOT A little PROBLEM(a)!!\n"); /*It can't happen!*/
    return -1;
  }
  cell[c_pos]->action = RECV_PACKET;
 
  rcv = (struct recv *)malloc(sizeof(struct recv));
  //rcv->pd = init_pcap(iface,bpf_expr,&rcv->offset);

  rcv->bpf = strdup(bpf_expr);
  rcv->iface = strdup(iface);
  
  rcv->brnch_struct = (struct branch_recv*)malloc(sizeof(struct branch_recv));
  rcv->brnch_struct->nob = nob;
  rcv->brnch_struct->fld_struct = (struct field_recv**)malloc(sizeof(struct field_recv*)*nob);
  brch_i = 0;
  
  while(brch != NULL){
    rcv->brnch_struct->fld_struct[brch_i] = &(brch->info);
    brch_i++;
    brch = (struct brch_in *)brch->next;
  }
  memcpy(&(rcv->to),&(to),sizeof(to));
  rcv->plen = 0;
  rcv->recvpack = NULL;
  cell[c_pos]->next = -2;
  cell[c_pos]->arg = (u_int8_t *)rcv;
  return 0;
}

/*
 *   Binds the action "SHELL" to the state pointed by CELL[C_POS]
 */
u_int8_t action_shell(cell,c_pos,sh)
  struct base     	**cell;         /* State Vector         */
  u_int32_t       	c_pos;          /* Working state        */
  struct shell		sh;		/* Shell structure	*/
{
  struct shell		*shl;

  if(cell[c_pos] == NULL){
    printf("HOUSTON WE GOT A little PROBLEM(a)!!\n"); /*It can't happen!*/
    return -1;
  }
  
  cell[c_pos]->action = SHELL;
  shl = (struct shell*)malloc(sizeof(struct shell));
  shl->command = sh.command;
  cell[c_pos]->arg = (u_int8_t *)shl;
  cell[c_pos]->next = sh.next_state;
  return 0;
}

/*
 *   Binds the action "FINISH" to the state pointed by CELL[C_POS]
 */
u_int8_t action_finish(cell,c_pos)
struct base **cell;
u_int32_t c_pos;
{
  if(cell[c_pos] == NULL){
    printf("HOUSTON WE GOT A little PROBLEM(a)!!\n"); /*It can't happen!*/
    return -1;
  }
  cell[c_pos]->action = FINISH;
  cell[c_pos]->arg = NULL;
  cell[c_pos]->next = -3;
  return 0;
}

/*
 * Shows the state table
 */
void show_state(cell,cell_pos)
struct base **cell;
u_int32_t cell_pos;
{
  struct send	snd;
  struct wait	wt;
  struct recv	*rcv;
  struct shell 	sh;
  int i,j,k;
  
  if(cell[cell_pos] == NULL){
    printf("Cell position #%u: %sEMPTY%s.\n",cell_pos,L_RED,L_GRAY);
  }else{
     printf("Cell position #%u: %sFILLED%s.\n",cell_pos,L_GREEN,L_GRAY);
     printf("\tState ID:\t%u\n",cell[cell_pos]->state_id);
     printf("\tState Name:\t%s%s%s\n",L_BLUE,cell[cell_pos]->state_name,L_GRAY);
     printf("\tState Action:\t");
     switch(cell[cell_pos]->action){
       case FINISH:
           printf("FINISH.\n");
         break;
       case SEND_PACKET:
           memcpy(&snd,cell[cell_pos]->arg,sizeof(snd));
           printf("SEND PACKET #%d\n",snd.packet_id);
	   if(snd.nobt > 0){
	     printf("\t\tBut...:\n");
	     for(i=0;i<snd.nobt;i++){
	       show_but(snd.but[i]);
	       printf("\n");
	     }
	   }
	   printf("\n");
         break;
       case WAIT:
           memcpy(&wt,cell[cell_pos]->arg,sizeof(wt));
           printf("WAIT: %u microseconds\n",wt.usec);
         break;
       case SHELL:
	   memcpy(&sh,cell[cell_pos]->arg,sizeof(sh));
	   printf("SHELL: \"%s\"\n",sh.command);
	 break;
       case RECV_PACKET:
	   rcv = (struct recv *)cell[cell_pos]->arg;
	   printf("RECEIVE PACKET:\n");
	   if(rcv->to.time != 0)
	     printf("\t\t\t   Timeout: %uus, otherwise -> %s%s%s\n",rcv->to.time,\
			      D_CYAN,cell[rcv->to.nxt]->state_name,L_GRAY);
           for(i=0;i<rcv->brnch_struct->nob;i++){
             printf("\t\t\t   %sbranch #%d%s takes to state: %s%s%s\n",WHITE,i,L_GRAY,D_CYAN,\
			     cell[rcv->brnch_struct->fld_struct[i]->next_state]->state_name,\
			     L_GRAY);
             for(j=0;j<rcv->brnch_struct->fld_struct[i]->nof;j++){
               printf("\t\t\t     Information at layer %u ",\
			      rcv->brnch_struct->fld_struct[i]->fld_vct[j].layer);
	       if(rcv->brnch_struct->fld_struct[i]->fld_vct[j].layer>1){
	         printf("-> Encapsulation information:\n ");
		 for(k=0;k<rcv->brnch_struct->fld_struct[i]->fld_vct[j].layer-1;k++){
		   printf("\t\t\t\t layer %d - ",k+1);
		   printf("offset: %u \t size: %u\n",\
		          rcv->brnch_struct->fld_struct[i]->fld_vct[j].pheaders[k]->off,\
			  rcv->brnch_struct->fld_struct[i]->fld_vct[j].pheaders[k]->size);
		 }
	       }else
		  printf("\n");
	       printf("\t\t\t\t --> offset (%u) size (%u) information (%#x)\n",\
			       rcv->brnch_struct->fld_struct[i]->fld_vct[j].offset,\
			       rcv->brnch_struct->fld_struct[i]->fld_vct[j].size,\
			       rcv->brnch_struct->fld_struct[i]->fld_vct[j].info);	       
             }
           }
         break;
       case NOT_SPEC:
           printf("ACTION UNDEFINED!\n");
         break;
       default:
         printf("State #%s's printer is not defined yet\n",cell[cell_pos]->state_name);
     }
     printf("\tNext State:\t%s",YELLOW);
     switch(cell[cell_pos]->next){
       case -1:
	 printf("UNDEFINED!");
       break;
       case -2:
         printf("To be assigned.");
       break;
       case -3:
	 printf("There's no next state.");
       break;
       default:
         printf("%s",cell[cell[cell_pos]->next]->state_name);
     }
     printf("%s\n\n",L_GRAY);
   }
}

void show_arg(struct but_args *arg){
  int i;
  switch(arg->type){
    case IMMEDIATE:
      printf("%#x",arg->bi_arg->value);
    break;
    case THIS_PACKET:
      printf("This packet ");
      for(i=0;i<arg->bp_arg->field.layer-1;i++){
        printf("[%u:%u]",arg->bp_arg->field.pheaders[i]->off,\
 		         arg->bp_arg->field.pheaders[i]->size);
      }
      printf(" layer(%u) offset(%u) size(%u) ",arg->bp_arg->field.layer,\
  		                                arg->bp_arg->field.offset,\
					        arg->bp_arg->field.size);
    break;
    case STORED_PACKET:
      printf("Stored Packet number %u: ",arg->bp_arg->pnum);
      for(i=0;i<arg->bp_arg->field.layer-1;i++){
        printf("[%u:%u]",arg->bp_arg->field.pheaders[i]->off,\
 		         arg->bp_arg->field.pheaders[i]->size);
	}
      printf("layer(%u) offset(%u) size(%u) ",arg->bp_arg->field.layer,\
		                               arg->bp_arg->field.offset,\
				    	       arg->bp_arg->field.size);
    break;
    case RECEIVED_PACKET:
      printf("Received packet %u: ",arg->bp_arg->pnum);
      for(i=0;i<arg->bp_arg->field.layer-1;i++){
        printf("[%u:%u]",arg->bp_arg->field.pheaders[i]->off,\
	     	         arg->bp_arg->field.pheaders[i]->size);
	}
      printf("layer(%u) offset(%u) size(%u) ",arg->bp_arg->field.layer,\
		                               arg->bp_arg->field.offset,\
					       arg->bp_arg->field.size);
    break;
    case STD_CKSUM:
      printf("Standart Checksum for header \"%s\"",arg->bc_arg->header);
    break;
  }				  
}

void show_but(struct but *arg){
  int i;
  printf("\t\t");
  for(i=0;i<arg->field->layer-1;i++){
    printf("[%u:%u]",arg->field->pheaders[i]->off,arg->field->pheaders[i]->size);
  }
  printf("> off(%u) size(%u) =\n",arg->field->offset,arg->field->size);
  printf("\t\t\t << ");
  show_arg(arg->args[0]);
  printf(" >> ");
  switch(arg->operation){
    case NOP:
      return;
    break;
    case ADD:
      printf("+\n");
    break;
    case SUB:
      printf("-\n");
    break;
    case MUL:
      printf("*\n");
    break;
    case DIV:
      printf("/\n");
    break;
    case AND:
      printf("AND\n");
    break;
    case OR:
      printf("OR\n");
    break;
    case XOR:
      printf("XOR\n");
    break;
    default:
      printf("Ooops! This was not supposed do show up!\n");
  }
  printf("\t\t\t << ");
  show_arg(arg->args[1]);
  printf(" >> \n");
  return; 
}

void show_all(cell,num)
struct base **cell;
u_int32_t num;
{
  int i;
  for(i=0;i<num;i++){
    show_state(cell,i);
  }
}

u_int32_t calc_tcp_cksum_len(u_char *pack, u_int32_t psize){
  u_int32_t aux,off = 0;

  unpack_it(pack,psize,&aux,16,16);
  off = htons(aux);
  unpack_it(pack,psize,&aux,0,4);
  off -= aux<<2;
  return off;
}

u_int32_t calc_icmp_cksum_len(u_char *pack, u_int32_t psize){
  u_int32_t aux,off = 0;

  unpack_it(pack,psize,&aux,16,16);
  off = htons(aux);
  unpack_it(pack,psize,&aux,0,4);
  off -= aux<<2;
	
  return off;
}

int calc_args(oper,arg_1,arg_2,result)
u_int8_t	oper;
u_int32_t	arg_1;
u_int32_t	arg_2;
u_int32_t	*result;
{
  switch(oper){
    case ADD:
      *result = arg_1 + arg_2;
      return 0;
    break;
    case SUB:
      *result = arg_1 - arg_2;
      return 0;
    break;
    case MUL:
      *result = arg_1 * arg_2;
      return 0;
    break;
    case DIV:
      if(arg_2 == 0){
	printf("Division by zero!\n");
	*result = 0;
	return -2;
      }else{
	 *result = arg_1 / arg_2;
	 return 0;
       }
    break;
    case AND:
      *result = arg_1 & arg_2;
      return 0;
    break;
    case OR:
      *result = arg_1 | arg_2;
      return 0;
    break;
    case XOR:
      *result = arg_1 ^ arg_2;
      return 0;
    break;
    default:
      printf("I can't execute such operation!\n");
      return -1;
  }
}

int get_argument(snd, cell, but, pckt_id, arg_id, arg, waiting_packs,stage)
struct send 	*snd;
struct base	**cell;
struct but 	*but;
u_int32_t 	pckt_id;
u_int8_t	arg_id;
u_int32_t	*arg;
u_int16_t	waiting_packs;
u_int8_t	stage;			/* 0 = assemble stage ; 1 = player stage */
{
  u_int32_t 	argument,off,cksum_len;
  int		status;
  struct recv	*rcv;

  switch(but->args[arg_id]->type){
    case IMMEDIATE:
      argument = but->args[arg_id]->bi_arg->value;
      if(waiting_packs){
	*arg = argument;
        return IMMEDIATE;
      }
    break;
    case THIS_PACKET:
      if(waiting_packs){
	*arg = 0;
        return THIS_PACKET;
      }
      off = packs2bsnt[pckt_id-1].layer[but->args[arg_id]->bp_arg->field.layer-1];
      off += but->args[arg_id]->bp_arg->field.offset;
      status = unpack_it(snd->pack,snd->psize,&argument,\
                         off,\
                         but->args[arg_id]->bp_arg->field.size);
      
      if(status > -1){
        if(but->args[0]->bp_arg->field.swap == 1){
          if(but->args[arg_id]->bp_arg->field.size > 16)
	    argument = htonl(argument);
	  else
	    argument = htons(argument);
	}
      }else{
         printf("Could not extract the information\n");
	 exit(0);
      }
    break;
    case STORED_PACKET:
      off = packs2bsnt[but->args[arg_id]->bp_arg->pnum-1].layer[but->args[arg_id]->bp_arg->field.layer-1];
      off += but->args[arg_id]->bp_arg->field.offset;
      status = unpack_it(packs2bsnt[but->args[arg_id]->bp_arg->pnum-1].data,\
                         packs2bsnt[but->args[arg_id]->bp_arg->pnum-1].psize,\
		         &argument,\
                         off,\
                         but->args[arg_id]->bp_arg->field.size);
      if(status > -1){
        if(but->args[arg_id]->bp_arg->field.swap == 1){
          if(but->args[arg_id]->bp_arg->field.size > 16)
            argument = htonl(argument);
          else
            argument = htons(argument);
        }
      }else{
         printf("Could not extract the information\n");
         exit(0);
       }
      if(waiting_packs){
	*arg = argument;
        return STORED_PACKET;
      }
    break;
    case RECEIVED_PACKET:
      if(stage){
	if(cell[but->args[arg_id]->bp_arg->pnum]->action != RECV_PACKET){
	  printf("The state pointed as RECV_PACKET is not!\n");
	  *arg = 0;
	  return RECEIVED_PACKET;
	}
        rcv = (struct recv *)cell[but->args[arg_id]->bp_arg->pnum]->arg;
        if(rcv->recvpack != NULL){
          off = get_offset(rcv->recvpack, rcv->plen,but->args[arg_id]->bp_arg->field);
	  status = unpack_it(rcv->recvpack,\
			     rcv->plen,\
			     &argument,\
			     off,\
			     but->args[arg_id]->bp_arg->field.size);
	  if(status > -1){
            if(but->args[arg_id]->bp_arg->field.swap == 1){
              if(but->args[arg_id]->bp_arg->field.size > 16)
	        argument = htonl(argument);
	      else
		argument = htons(argument);
	    }
	  }else{
             printf("Could not extract the information\n");
	     exit(0);
	   }
	}else{ /* The state machine is ON, but the packet hasn't arrived yet!
		*   So, the RECEIVED_PACKET is returned to the player...
		*/
	  *arg = 0;
          return RECEIVED_PACKET;
         }
      }else{  /* We're assembling the data structure on the memory, so the state machine
	       *  is OFF, then, the RECEIVED_PACKET is returned to the action_send()
	       *  function
	       */
        *arg = 0;
        return RECEIVED_PACKET;
       }
      break;
      
    case STD_CKSUM:
      if(waiting_packs){
        *arg = 0;
	return STD_CKSUM;
      }else{
         if(memcmp(but->args[arg_id]->bc_arg->header,"TCP",3) == 0){
	   cksum_len = calc_tcp_cksum_len(snd->pack, snd->psize);
           argument = do_tcp_checksum(snd->pack + \
		                      packs2bsnt[pckt_id-1].layer[1]/8,\
				      0,\
				      6,\
				      cksum_len,\
				      snd->pack + 12);
	   argument = htons(argument);
         }else if(memcmp(but->args[arg_id]->bc_arg->header,"ICMP",4) == 0){
		 cksum_len = calc_icmp_cksum_len(snd->pack, snd->psize);
		 argument = do_icmp_checksum(snd->pack + packs2bsnt[pckt_id-1].layer[1]/8, cksum_len);
		 argument = htons(argument);
	       }else{
                  printf("I don't know such header's checksum. (%s)\n",but->args[arg_id]->bc_arg->header);
	          argument = 0;
          }
       }
    break;
    default:
      printf("There is not such type of argument: (%#x)",but->args[arg_id]->type);
  }
  *arg = argument;
  return 0;
}

u_int32_t get_offset(u_char *pack, u_int32_t psize, struct field_off_bits field){
  int off;

  off = calc_off(pack,psize,field.layer,field.pheaders);

  off += field.offset;

  return off;
}

int carry_argument(snd,but,pckt_id,argument)
struct send     *snd;
struct but   	*but;
u_int32_t       pckt_id;
u_int32_t	argument;
{
  u_int32_t off;

  off = packs2bsnt[pckt_id-1].layer[but->field->layer-1];
  off += but->field->offset;
  
  if(but->field->swap){
    if(but->field->size > 16)
      pack_it(snd->pack,htonl(argument),off,but->field->size);
    else
      pack_it(snd->pack,htons(argument),off,but->field->size);
  }else
    pack_it(snd->pack,argument,off,but->field->size);

  //printf("[%x]\n",argument);
  //show_buffs(snd->pack,packs2bsnt[pckt_id-1].psize/8);
}

/*
 *	Releases the struct but_args *
 */

void free_args(struct but_args *bargs){
  switch(bargs->type){
    case IMMEDIATE:
      free(bargs->bi_arg);
    break;
    case THIS_PACKET:
    case STORED_PACKET:
    case RECEIVED_PACKET:
      free_phinf(bargs->bp_arg->field.pheaders,\
	         bargs->bp_arg->field.layer);
      free(bargs->bp_arg);
    break;
    case STD_CKSUM:
      free(bargs->bc_arg->header);
      free(bargs->bc_arg);
    break;
  }
  free(bargs);
  bargs = NULL;
}

/*
 * 	Releases the struct but *
 */

void free_but(struct but **but){
  free_phinf((*but)->field->pheaders,(*but)->field->layer);
  free((*but)->field);
  free_args((*but)->args[0]);
  switch((*but)->operation){
    case NOP:
    break;
    case ADD:
    case SUB:
    case MUL:
    case DIV:
    case AND:
    case OR:
    case XOR:
      free_args((*but)->args[1]);
    break;
    default:
      printf("I don't know such operation!\n");
  }
  free((*but)->args);
  free(*but);
  *but = NULL;
}

/*
 * 	Releases the struct phinf **
 */
void free_phinf(struct phinf **hinf, u_int16_t layer){
  int i;
  
  if(hinf != NULL){
    for(i=0;i<layer-1;i++){
      free(hinf[i]);
    }
    free(hinf);
  }
}

/*
 *	Convert arguments to IMMEDIATE type
 */
void to_immediate(struct but *but, u_int32_t arg_id, u_int32_t arg){

  free_phinf(but->args[arg_id]->bp_arg->field.pheaders,\
             but->args[arg_id]->bp_arg->field.layer);
  free(but->args[arg_id]->bp_arg);
  but->args[arg_id]->type = IMMEDIATE;
  but->args[arg_id]->bi_arg=(struct immediate_arg*)malloc(sizeof(struct immediate_arg));
  but->args[arg_id]->bi_arg->value = arg;
}

u_int32_t get_from_local_pack(u_int32_t packnumber, char *hname, char *fname){
  u_int32_t 		off;		/* field offset */
  u_int32_t 		info;		/* The data */
  u_int16_t		layer;		/* field layer */
  struct header_info 	*finfo = NULL;	/* Field information */
  int			status;
  
  finfo = gimme_the_data(hname,fname,head_hash,noh,&layer);
  
  if(finfo == NULL){
    printf("There is not such header/field: %s.%s\n",hname,fname);
    exit(0);
  }
  
  off  = packs2bsnt[packnumber-1].layer[layer-1];
  off += finfo->offset;
  status = unpack_it(packs2bsnt[packnumber-1].data,\
		     packs2bsnt[packnumber-1].psize,\
		     &info,\
		     off,\
		     finfo->size);
  if(status < 0 ){
    printf("Could not extract data.\n");
    exit(0);
  }

  if(finfo->swap){
    if(finfo->size > 16)
      info = htonl(info);
    else
      info = htons(info);
  }
  return info;
}

int get_out(){
  exit(0);
}

int play(){
  return 0;  
}

#endif
