/*
    This file is part of AirSnort.

    AirSnort is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    AirSnort is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AirSnort; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "bssidlist.h"
#include "crc-32.h"
#include "capture.h"
#include "crack.h"

BssidList *head = 0;
BssidList *tail = 0;

extern int listCount;

int isResolved(const unsigned char *p) {
   unsigned char sum;
   if (p[1] == 255 && p[0] > 2 && p[0] < 16) return 1;
   sum = p[0] + p[1];
   if (sum == 1 && (p[2] <= 0x0A || p[2] == 0xFF)) return 1;
   if (sum <= 0x0C && (p[2] >= 0xF2 && p[2] <= 0xFE && p[2] != 0xFD)) return 1;
   return 0;
//   return p[1] == 255 && p[0] > 2 && p[0] < 16;
}

char *ivtostr(const unsigned char *iv) {
   static char ivstr[10];
   sprintf(ivstr, "%2.2X:%2.2X:%2.2X", iv[0], iv[1], iv[2]);
   return ivstr;
}

char *bssidtostr(const unsigned char *bssid) {
   static char bssidstr[20];
   sprintf(bssidstr, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", 
                    bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
   return bssidstr;
}

int bssidMatch(const unsigned char *bssid1, const unsigned char *bssid2) {
   int i = 5;
   for (; i >= 0; i--) {
      if (bssid1[i] != bssid2[i]) return 0;
   }
   return 1;
}

BssidList *bssidFind(const unsigned char *bssid) {
   BssidList *temp = head;
   for (; temp; temp = temp->next) {
      if (bssidMatch(temp->bssid, bssid)) {
         break;
      }
   }
   return temp;
}

BssidList *rowFind(int row) {
   BssidList *temp = head;
   for (; temp; temp = temp->next) {
      if (row == temp->rownum) {
         break;
      }
   }
   return temp;
}

//ap should be a valid BssidList node
void addPacket(BssidList *apNode, CaptureRec *cap, int isData) {
   PacketInfo *pi = cap->pInfo;
   if (!apNode) {
      apNode = bssidFind(cap->bssid);
      if (!apNode) {   
         apNode = addBssid(cap);
//fprintf(stdout, "added %s, fc = %02X\n", bssidtostr(cap->bssid), pi->raw[0]);
      }
   }
   if (!apNode->usingWep && cap->pInfo->wep) {
      addWep(apNode);
   }
   if (pi->channel > 0) {
      apNode->channel = pi->channel;
   }
   if (apNode->usingWep && isData) {
      memcpy(apNode->lastiv, cap->iv, 3);
      apNode->numEncrypted++;
      if (pi->pack) {
         if (!apNode->ap->cracked) {
            enqueuePacket(apNode->ap, pi->pack);
            apNode->queueLen++;
            if ((apNode->queueLen % 10) == 0) {
               sem_post(&(apNode->crackSem));
               apNode->queueLen = 0;
            }
         }
      }
   }
   apNode->numPackets++;
}

void addWep(BssidList *apNode) {
   apNode->usingWep = 1;
   apNode->ap = newCrackNode(apNode);
   sem_init(&(apNode->crackSem), 0, 0);
   pthread_create(&apNode->crackerThread, NULL, cracker, apNode->ap);
}

//check for non-existence of bssid prior to calling this please
BssidList *addBssid(CaptureRec *cap) {
   BssidList *temp = (BssidList*) calloc(1, sizeof(BssidList));
   memcpy(temp->bssid, cap->bssid, 6);
   temp->channel = cap->pInfo->channel;
   temp->name = cap->pInfo->name;
   temp->rownum = tail ? tail->rownum + 1 : 0;
   if (tail) {
      tail = tail->next = temp;
   }
   else {
      head = tail = temp;
   }
   if (cap->pInfo->wep) {
      temp->usingWep = 1;
      temp->ap = newCrackNode(temp);
      sem_init(&(temp->crackSem), 0, 0);
      pthread_create(&temp->crackerThread, NULL, cracker, temp->ap);
   }
   return temp;
}

void clearList() {
   BssidList *temp = head, *next;
   void *result;
   for (; temp; temp = next) {
      next = temp->next;
      if (temp->crackerThread) {
         temp->ap->die = 1;
         sem_post(&(temp->crackSem));
         pthread_join(temp->crackerThread, &result);
         destroyCrackNode(temp->ap);
      }
      free(temp->name);
      free(temp);
   }
   listCount = 0;
   head = tail = NULL;
}

