/*
 * parse.c - parsing of pcap packages
 *
 * author: hackbard@hackdaworld.dyndns.org
 *
 */

#include "parse.h"
#include "main.h"

/* all the parsing stuff will go here
 *
 * different protocols should get to seperated files though ...
 */

unsigned int int_s(unsigned int val) {

  unsigned int swapped;

  swapped=(val&0x000000ff)<<24;
  swapped|=(val&0x0000ff00)<<8;
  swapped|=(val&0x00ff0000)>>8;
  swapped|=(val&0xff000000)>>24;

  return swapped;
}

int switch_active_state(char *state) {

  switch(*state) {
    case '-':
      *state='\\';
      break;
    case '\\':
      *state='|';
      break;
    case '|':
      *state='/';
      break;
    default:
      *state='-';
      break;
  }

  return 23;
}

void parse_package(unsigned char *ptr,const struct pcap_pkthdr *pcap_header,const unsigned char *pkg) {

  t_info *info;
  int i;
  t_sta new_sta;
  t_sta *cmp_sta;
  t_sta *sta;
  unsigned char *package=NULL;
  t_frame4_hdr *f4hdr;
  t_frame3_hdr *f3hdr;
  //t_frame2_hdr *f2hdr;
  //t_frame1_hdr *f1hdr;
  t_beacon_fb *beacon_fb;
  unsigned char *data;
  t_prism_hdr *prismhdr=NULL;
  int ret;
  char string[MESSAGE_MAX];
  char sc[MAX_SYSCALL_CHARS];
  unsigned char new;
  unsigned char foo;

  info=(t_info *)ptr;

  info->count++;

  memset(&new_sta,0,sizeof(t_sta));
  new=0;
  foo=0;

  /* prism or ieee802.11 header ? */
  if(info->mode&MODE_IEEE80211) {
    package=(unsigned char *)pkg;
    prismhdr=NULL;
  }
  else if(info->mode&MODE_PRISM) {
    package=(unsigned char *)pkg+sizeof(t_prism_hdr);
    prismhdr=(t_prism_hdr *)pkg;
  }

  /* management */
  if(FCTL_TYPE(package[0])==FCTL_TYPE_MGMT) {
    info->count_m++;

    /* beacon frames */
    if(FCTL_STYPE(package[0])==FCTL_STYPE_BEACON) {
      f3hdr=(t_frame3_hdr *)package;
      beacon_fb=(t_beacon_fb *)(package+sizeof(t_frame3_hdr));
      // check sta
      memcpy(new_sta.addr,f3hdr->addr2,ADDR_LEN);
      memcpy(new_sta.bssid,f3hdr->addr3,ADDR_LEN);
      ret=list_search_data(&(info->sniffed_sta),&new_sta,ADDR_LEN);
      if((ret==L_EMPTY_LIST)|(ret==L_NO_SUCH_ELEMENT)) {
        list_add_element(&(info->sniffed_sta),&new_sta,sizeof(t_sta));
        sta=(t_sta *)info->sniffed_sta.current->data;
        new=1;
      }
      else sta=(t_sta *)info->sniffed_sta.current->data;
      // fill in stuff ...
      memcpy(sta->ssid,beacon_fb->ssid,beacon_fb->ssid_length);
      if((CAP_INFO_ESS(beacon_fb->cap_info))&
         (CAP_INFO_IBSS(beacon_fb->cap_info)==0)) sta->ap=AP;
      if(CAP_INFO_PRIVACY(beacon_fb->cap_info)) sta->wep=WEP;
      sta->count_mgmt++;
      switch_active_state(&(sta->active));
      if(info->mode&MODE_IEEE80211) sta->sq=0;
      else if(info->mode&MODE_PRISM)
        sta->sq=(prismhdr->signal.data)-(prismhdr->noise.data);
      strncpy(string,"last: beacon, source: ",MESSAGE_MAX);
      for(i=0;i<ADDR_LEN;i++)
        snprintf(&string[22+3*i],4,"%02x%c",sta->addr[i],
                 (i==ADDR_LEN-1)?'.':':');
      string[22+3*ADDR_LEN+1]=0;
      display_console(info,string);
      if(new) {
        snprintf(sc,MAX_SYSCALL_CHARS,
                 "flite 'access point found: %s'",
                 sta->ssid);
        system(sc);
        if(sta->wep&WEP) strncpy(sc,"flite ' crypted'",MAX_SYSCALL_CHARS);
        else strncpy(sc,"flite 'not crypted'",MAX_SYSCALL_CHARS);
        system(sc);
      } 
    }

  }

  /* control */
  else if(FCTL_TYPE(package[0])==FCTL_TYPE_CTRL) {
    info->count_c++;
    display_console(info,"last: got control frame");
  }

  /* data */
  else if(FCTL_TYPE(package[0])==FCTL_TYPE_DATA) {
    info->count_d++;

    //if(FCTL_STYPE(package[0])==FCTL_STYPE_DATA) {
      if(FCTL_TODS(package[0])&FCTL_FROMDS(package[0])) {
        f4hdr=(t_frame4_hdr *)package;
        data=package+sizeof(t_frame4_hdr);
        memcpy(new_sta.addr,f4hdr->addr4,ADDR_LEN);
        foo=1;
      }
      else {
        f3hdr=(t_frame3_hdr *)package;
        data=package+sizeof(t_frame3_hdr);
        if(FCTL_TODS(package[0])) {
          memcpy(new_sta.addr,f3hdr->addr2,ADDR_LEN);
          memcpy(new_sta.bssid,f3hdr->addr1,ADDR_LEN);
        }
        else if(FCTL_FROMDS(package[0])) {
          memcpy(new_sta.addr,f3hdr->addr3,ADDR_LEN);
          memcpy(new_sta.bssid,f3hdr->addr2,ADDR_LEN);
        }
        else {
          memcpy(new_sta.addr,f3hdr->addr2,ADDR_LEN);
          memcpy(new_sta.bssid,f3hdr->addr3,ADDR_LEN);
        }
      }

      ret=list_search_data(&(info->sniffed_sta),&new_sta,ADDR_LEN);
      if((ret==L_EMPTY_LIST)|(ret==L_NO_SUCH_ELEMENT)) {
        list_add_element(&(info->sniffed_sta),&new_sta,sizeof(t_sta));
        sta=(t_sta *)info->sniffed_sta.current->data;
        new=1;
      }
      else sta=(t_sta *)info->sniffed_sta.current->data;
      if(!(sta->ap)) {
        ret=list_count(&(info->sniffed_sta));
        list_reset(&(info->sniffed_sta));
        for(i=0;i<ret;i++) {
          cmp_sta=(t_sta *)info->sniffed_sta.current->data;
          if(!memcmp(cmp_sta->bssid,sta->bssid,ADDR_LEN)) {
            if(FCTL_FROMDS(package[0]))
              snprintf(sta->ssid,MAX_SSID_LEN,"<- %s",cmp_sta->ssid);
            else if(FCTL_TODS(package[0]))
              snprintf(sta->ssid,MAX_SSID_LEN,"-> %s",cmp_sta->ssid);
            else
              snprintf(sta->ssid,MAX_SSID_LEN,"<> %s",cmp_sta->ssid);
            break;
          }
          list_next(&(info->sniffed_sta));
        }
      }
      // fill in stuff ...
      sta->count_data++;
      switch_active_state(&(sta->active));
      if(info->mode&MODE_IEEE80211) sta->sq=0;
      else if(info->mode&MODE_PRISM)
        sta->sq=(prismhdr->signal.data)-(prismhdr->noise.data);
      if(new) {
        strcpy(sc,"flite 'station found by data package'");
        system(sc);
        if(foo) {
          sta->wds=1;
          strcpy(sc,"flite 'wds package'");
          system(sc);
        }
        memcpy(sta->snap,data,10);
        if((data[0]==0xaa)&(data[1]==0xaa)&(data[2]==0x03)&
           (data[3]==0x00)&(data[4]==0x00)&(data[5]==0x00)) {
          sta->wep=0;
          strcpy(sc,"flite 'not crypted'");
          system(sc);
        }
        else {
          sta->wep=WEP;
          strcpy(sc,"flite ' crypted'");
          system(sc);
        }
      }
         
    //}

    display_console(info,"last: got data frame");
  }

  if(info->dump_handle!=NULL) pcap_dump((unsigned char *)(info->dump_handle),pcap_header,pkg);

}
