Logo Search packages:      
Sourcecode: aircrack-ng version File versions  Download package

aircrack-ng.c

/*
 *  802.11 WEP / WPA-PSK Key Cracker
 *
 *  Copyright (C) 2006, 2007, 2008, 2009 Thomas d'Otreppe
 *  Copyright (C) 2004, 2005 Christophe Devine
 *
 *  Advanced WEP attacks developed by KoreK
 *  WPA-PSK  attack code developed by Joshua Wright
 *  SHA1 MMX assembly code written by Simon Marechal
 *
 *  This program 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.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU General Public License in all respects
 *  for all of the code used other than OpenSSL. *  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so. *  If you
 *  do not wish to do so, delete this exception statement from your
 *  version. *  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 */

#define _GNU_SOURCE

#include <sys/types.h>
#include <sys/termios.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <getopt.h>
#include <ctype.h>
#include <err.h>
#include <math.h>
#include <limits.h>

#include "version.h"
#include "crypto.h"
#include "pcap.h"
#include "uniqueiv.h"
#include "aircrack-ng.h"
#include "sha1-sse2.h"
#include "osdep/byteorder.h"
#include "common.h"

#ifdef HAVE_SQLITE
#include <sqlite3.h>
sqlite3 *db;
#endif

extern int get_nb_cpus();

static uchar ZERO[32] =
"\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00";

/* stats global data */

struct timeval t_begin;              /* time at start of attack      */
struct timeval t_stats;              /* time since last update       */
struct timeval t_kprev;              /* time at start of window      */
long long int nb_kprev;              /* last  # of keys tried        */
long long int nb_tried;              /* total # of keys tried        */

/* IPC global data */

struct AP_info *ap_1st;              /* first item in linked list    */
pthread_mutex_t mx_apl;              /* lock write access to ap LL   */
pthread_mutex_t mx_eof;              /* lock write access to nb_eof  */
pthread_mutex_t mx_ivb;              /* lock access to ivbuf array   */
pthread_cond_t  cv_eof;              /* read EOF condition variable  */
int  nb_eof = 0;                     /* # of threads who reached eof */
long nb_pkt = 0;                     /* # of packets read so far     */
int mc_pipe[256][2];                 /* master->child control pipe   */
int cm_pipe[256][2];                 /* child->master results pipe   */
int bf_pipe[256][2];                 /* bruteforcer 'queue' pipe   */
int bf_nkeys[256];
uchar bf_wepkey[64];
int wepkey_crack_success = 0;
int close_aircrack = 0;
int id=0;
pthread_t tid[MAX_THREADS];
struct WPA_data wpa_data[MAX_THREADS];
int wpa_wordlists_done = 0;
static pthread_mutex_t mx_nb = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mx_wpastats = PTHREAD_MUTEX_INITIALIZER;


#define     GOT_IV      0x00000001
#define     USE_IV      0x00000002
#define K01_IV    0x00000010
#define K02_IV    0x00000020
#define K03_IV    0x00000040
#define K04_IV    0x00000080
#define K05_IV    0x00000100
#define K06_IV    0x00000200
#define K07_IV    0x00000400
#define K08_IV    0x00000800
#define K09_IV    0x00001000
#define K10_IV    0x00002000
#define K11_IV    0x00004000
#define K12_IV    0x00008000
#define K13_IV    0x00010000
#define K14_IV    0x00020000
#define K15_IV    0x00040000
#define K16_IV    0x00080000
#define K17_IV    0x00100000

typedef struct
{
      int off1;
      int off2;
      void *buf1;
      void *buf2;
}
read_buf;


int K_COEFF[N_ATTACKS] =
{
      15, 13, 12, 12, 12, 5, 5, 5, 3, 4, 3, 4, 3, 13, 4, 4, -20
};

int PTW_DEFAULTWEIGHT[1] = { 256 };
int PTW_DEFAULTBF[PTW_KEYHSBYTES] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

const uchar R[256] =
{
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
      , 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
      , 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
      , 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80
      , 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100
      , 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116
      , 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132
      , 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148
      , 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164
      , 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180
      , 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196
      , 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212
      , 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228
      , 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244
      , 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
};

char usage[] =
"\n"
"  %s - (C) 2006, 2007, 2008, 2009 Thomas d\'Otreppe\n"
"  Original work: Christophe Devine\n"
"  http://www.aircrack-ng.org\n"
"\n"
"  usage: aircrack-ng [options] <.cap / .ivs file(s)>\n"
"\n"
"  Common options:\n"
"\n"
"      -a <amode> : force attack mode (1/WEP, 2/WPA-PSK)\n"
"      -e <essid> : target selection: network identifier\n"
"      -b <bssid> : target selection: access point's MAC\n"
"      -p <nbcpu> : # of CPU to use  (default: all CPUs)\n"
"      -q         : enable quiet mode (no status output)\n"
"      -C <macs>  : merge the given APs to a virtual one\n"
"      -l <file>  : write key to file\n"
"\n"
"  Static WEP cracking options:\n"
"\n"
"      -c         : search alpha-numeric characters only\n"
"      -t         : search binary coded decimal chr only\n"
"      -h         : search the numeric key for Fritz!BOX\n"
"      -d <mask>  : use masking of the key (A1:XX:CF:YY)\n"
"      -m <maddr> : MAC address to filter usable packets\n"
"      -n <nbits> : WEP key length :  64/128/152/256/512\n"
"      -i <index> : WEP key index (1 to 4), default: any\n"
"      -f <fudge> : bruteforce fudge factor,  default: 2\n"
"      -k <korek> : disable one attack method  (1 to 17)\n"
"      -x or -x0  : disable bruteforce for last keybytes\n"
"      -x1        : last keybyte bruteforcing  (default)\n"
"      -x2        : enable last  2 keybytes bruteforcing"
"%s"
"      -y         : experimental  single bruteforce mode\n"
"      -K         : use only old KoreK attacks (pre-PTW)\n"
"      -s         : show the key in ASCII while cracking\n"
"      -M <num>   : specify maximum number of IVs to use\n"
"      -D         : WEP decloak, skips broken keystreams\n"
"      -P <num>   : PTW debug:  1: disable Klein, 2: PTW\n"
"      -1         : run only 1 try to crack key with PTW\n"
"\n"
"  WEP and WPA-PSK cracking options:\n"
"\n"
"      -w <words> : path to wordlist(s) filename(s)\n"
#ifdef HAVE_SQLITE
"      -r <DB>    : path to airolib-ng database\n"
"                   (Cannot be used with -w)\n"
#endif
"\n"
"      --help     : Displays this usage screen\n"
"\n";

char * progname;
int intr_read = 0;

int safe_write( int fd, void *buf, size_t len );

void clean_exit(int ret)
{
      struct AP_info *ap_cur;
      struct AP_info *ap_prv;
      struct AP_info *ap_next;
      int i=0;
//    int j=0, k=0, attack=0;
      int child_pid;

      char tmpbuf[128];
      memset(tmpbuf, 0, 128);

      if(ret && !opt.is_quiet)
      {
            printf("\nQuitting aircrack-ng...\n");
            fflush(stdout);
      }
      close_aircrack = 1;

      for( i = 0; i < opt.nbcpu; i++ )
      {
            #ifdef CYGWIN
            close( mc_pipe[i][1] );
            close( bf_pipe[i][1] );
            #else
            safe_write( mc_pipe[i][1], (void *) "EXIT\r", 5 );
            safe_write( bf_pipe[i][1], (void *) tmpbuf, 64 );
            #endif
        }

      if( opt.amode != 2 )
      {
            for(i=0; i<id; i++)
            {
                  if(pthread_join(tid[i], NULL) != 0)
                  {
//                      printf("Can't join thread %d\n", i);
                  }
            }

      }

      if(wep.ivbuf != NULL)
      {
            free(wep.ivbuf);
            wep.ivbuf = NULL;
      }

      ap_prv = NULL;
      ap_cur = ap_1st;

      while( ap_cur != NULL )
      {
            if( ap_cur->ivbuf != NULL )
            {
                  free(ap_cur->ivbuf);
                  ap_cur->ivbuf = NULL;
            }

            uniqueiv_wipe( ap_cur->uiv_root );

            if( ap_cur->ptw_clean != NULL )
            {
                  if( ap_cur->ptw_clean->allsessions != NULL )
                  {
                        free(ap_cur->ptw_clean->allsessions);
                        ap_cur->ptw_clean->allsessions=NULL;
                  }
                  free(ap_cur->ptw_clean);
                  ap_cur->ptw_clean = NULL;
            }

            if( ap_cur->ptw_vague != NULL )
            {
                  if( ap_cur->ptw_vague->allsessions != NULL )
                  {
                        free(ap_cur->ptw_vague->allsessions);
                        ap_cur->ptw_vague->allsessions = NULL;
                  }
                  free(ap_cur->ptw_vague);
                  ap_cur->ptw_vague = NULL;
            }

            ap_prv = ap_cur;
            ap_cur = ap_cur->next;
      }

      ap_cur = ap_1st;

      while( ap_cur != NULL )
      {
            ap_next = ap_cur->next;

            if( ap_cur != NULL )
                  free(ap_cur);

            ap_cur = ap_next;
      }

//    attack = A_s5_1;
//    printf("Please wait for evaluation...\n");
//    for(i=0; i<(256*256*256); i++)
//    {
//          if((all_ivs[i].used & GOT_IV) && !(all_ivs[i].used & USE_IV))
//                j++;
//
//          if((all_ivs[i].used & GOT_IV) && (all_ivs[i].used & (1<<(attack+4)) ) )
//          {
//                printf("IV %02X:%02X:%02X used for %d\n", (i/(256*256)), ((i&0xFFFF)/(256)), (i&0xFF), attack);
//                k++;
//          }
//    }
//
//    printf("%d unused IVs\n", j);
//    printf("%d used IVs for %d\n", k, attack);

      child_pid=fork();

      if(child_pid==-1)
      {
        /* do error stuff here */
      }
      if(child_pid!=0)
      {
        /* The parent process exits here. */

        exit(0);
      }

      _exit(ret);
}

void sighandler( int signum )
{
      #if ((defined(__INTEL_COMPILER) || defined(__ICC)) && defined(DO_PGO_DUMP))
      _PGOPTI_Prof_Dump();
      #endif
      signal( signum, sighandler );

      if( signum == SIGQUIT )
            clean_exit( SUCCESS );
//          _exit( SUCCESS );

      if( signum == SIGTERM )
            clean_exit( FAILURE );
//          _exit( FAILURE );

      if( signum == SIGINT )
      {
      #if ((defined(__INTEL_COMPILER) || defined(__ICC)) && defined(DO_PGO_DUMP))
            clean_exit( FAILURE );
//          _exit( FAILURE );
      #else
/*          if(intr_read > 0)*/
                  clean_exit( FAILURE );
/*          else
                  intr_read++;*/
      #endif
      }

      if( signum == SIGWINCH )
            printf( "\33[2J\n" );
}

void eof_wait( int *eof_notified )
{
      if( *eof_notified == 0 )
      {
            *eof_notified = 1;

            /* tell the master thread we reached EOF */

            pthread_mutex_lock( &mx_eof );
            nb_eof++;
            pthread_cond_broadcast( &cv_eof );
            pthread_mutex_unlock( &mx_eof );
      }

      usleep( 100000 );
}


inline int wpa_send_passphrase(char *key, struct WPA_data* data, int lock)
{
      pthread_mutex_lock(&data->mutex);

      if ((data->back+1) % data->nkeys == data->front)
      {
            if (lock != 0)
            {
                  // wait until there's room in the queue
                  pthread_cond_wait(&data->cond, &data->mutex);
            }
            else
            {
                  pthread_mutex_unlock(&data->mutex);
                  return 0; // full queue!
            }
      }

      // put one key in the buffer:
      memcpy(data->key_buffer + data->back*128, key, 128);
      data->back = (data->back+1) % data->nkeys;

      pthread_mutex_unlock(&data->mutex);

      return 1;
}


inline int wpa_receive_passphrase(char *key, struct WPA_data* data)
{
      pthread_mutex_lock(&data->mutex);

      if (data->front==data->back)
      {
            pthread_mutex_unlock(&data->mutex);
            return 0; // empty queue!
      }

      // get one key from the buffer:
      memcpy(key, data->key_buffer + data->front*128, 128);
      data->front = (data->front+1) % data->nkeys;

      // signal that there's now room in the queue for more keys
      pthread_cond_signal(&data->cond);
      pthread_mutex_unlock(&data->mutex);

      return 1;
}

int checkbssids(char *bssidlist)
{
      int first = 1;
      int i = 0;
      char *list, *tmp;
      int nbBSSID = 0;

      if(bssidlist == NULL) return -1;

#define IS_X(x) ((x) == 'X' || (x) == 'x')
#define VALID_CHAR(x)   ((IS_X(x)) || hexCharToInt(x) > -1)

#define VALID_SEP(arg)  ( ((arg) == '_') || ((arg) == '-') || ((arg) == ':') )
      list = strdup(bssidlist);
      do
      {
            tmp = strsep(&list, ",");

            if (tmp == NULL)
                  break;

            ++nbBSSID;

            if(strlen(tmp) != 17) return -1;

            //first byte
            if(!VALID_CHAR(tmp[ 0])) return -1;
            if(!VALID_CHAR(tmp[ 1])) return -1;
            if(!VALID_SEP( tmp[ 2])) return -1;

            //second byte
            if(!VALID_CHAR(tmp[ 3])) return -1;
            if(!VALID_CHAR(tmp[ 4])) return -1;
            if(!VALID_SEP( tmp[ 5])) return -1;

            //third byte
            if(!VALID_CHAR(tmp[ 6])) return -1;
            if(!VALID_CHAR(tmp[ 7])) return -1;
            if(!VALID_SEP( tmp[ 8])) return -1;

            //fourth byte
            if(!VALID_CHAR(tmp[ 9])) return -1;
            if(!VALID_CHAR(tmp[10])) return -1;
            if(!VALID_SEP( tmp[11])) return -1;

            //fifth byte
            if(!VALID_CHAR(tmp[12])) return -1;
            if(!VALID_CHAR(tmp[13])) return -1;
            if(!VALID_SEP( tmp[14])) return -1;

            //sixth byte
            if(!VALID_CHAR(tmp[15])) return -1;
            if(!VALID_CHAR(tmp[16])) return -1;


            if(first)
            {
                  for(i=0; i< 17; i++)
                        if( IS_X(tmp[i])) return -1;

                  opt.firstbssid = (unsigned char *) malloc(sizeof(unsigned char));
                  getmac(tmp, 1, opt.firstbssid);
                  first = 0;
            }

      } while(list);

      // Success
      return nbBSSID;
}

int mergebssids(char * bssidlist, unsigned char * bssid)
{
      struct mergeBSSID * list_prev;
      struct mergeBSSID * list_cur;
      char * mac = NULL;
      char * list = NULL;
      char * tmp = NULL;
      char * tmp2 = NULL;
      int next, i, found;

      // Do not convert if equal to first bssid
      if (memcmp(opt.firstbssid, bssid, 6) == 0)
            return 1;

      list_prev = NULL;
      list_cur = opt.bssid_list_1st;

      while (list_cur != NULL)
      {
            if (memcmp(list_cur->bssid, bssid, 6) == 0)
            {
                  if (list_cur->convert)
                        memcpy(bssid, opt.firstbssid, 6);

                  return list_cur->convert;
            }

            list_prev = list_cur;
            list_cur = list_cur->next;
      }

      // Not found, check if it has to be converted
      mac = (char *) malloc(18);

      if (!mac)
      {
            perror( "malloc failed" );
            return -1;
      }

      snprintf(mac, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
            bssid[0], bssid[1], bssid[2],
            bssid[3], bssid[4], bssid[5]);
      mac[17] = 0;

      tmp2 = list = strdup(bssidlist);

      // skip first element (because it doesn't have to be converted
      // It already has the good value
      tmp = strsep(&list, ",");

      next = found = 0;

      do
      {
            next=0;
            tmp = strsep(&list, ",");
            if (tmp == NULL)
                  break;

            // Length already checked, no need to check it again

            for( i = 0; i < 17; ++i)
            {
                  if((IS_X(tmp[i]) || VALID_SEP(tmp[i]))) continue;

                  if(toupper((int)tmp[i]) != (int)mac[i])
                  {
                        // Not found
                        next = 1;
                        break;
                  }
            }

            if(next == 0)
            {
                  found = 1;
                  break;
            }
      }
      while (list);

      // Free memory
      if(mac != NULL)
            free(mac);
      if(tmp2 != NULL)
            free(tmp2);

      // Add the result to the list
      list_cur = (struct mergeBSSID *) malloc(sizeof(struct mergeBSSID));

      if (!list_cur)
      {
                  perror( "malloc failed" );
                  return -1;
      }

      list_cur->convert = found;
      list_cur->next = NULL;
      memcpy(list_cur->bssid, bssid, 6);

      if (opt.bssid_list_1st == NULL)
            opt.bssid_list_1st = list_cur;
      else
            list_prev->next = list_cur;

      // Do not forget to convert if it was successful
      if (list_cur->convert)
            memcpy(bssid, opt.firstbssid, 6);

#undef VALID_CHAR
#undef VALID_SEP
#undef IS_X

      return list_cur->convert;
}

/* fread isn't atomic, sadly */

int atomic_read( read_buf *rb, int fd, int len, void *buf )
{
      int n;

      if( close_aircrack )
            return( CLOSE_IT );

      if( rb->buf1 == NULL )
      {
            rb->buf1 = malloc( 65536 );
            rb->buf2 = malloc( 65536 );

            if( rb->buf1 == NULL || rb->buf2 == NULL )
                  return( 0 );

            rb->off1 = 0;
            rb->off2 = 0;
      }

      if( len > 65536 - rb->off1 )
      {
            rb->off2 -= rb->off1;

            memcpy( rb->buf2, rb->buf1 + rb->off1, rb->off2 );
            memcpy( rb->buf1, rb->buf2, rb->off2 );

            rb->off1 = 0;
      }

      if( rb->off2 - rb->off1 >= len )
      {
            memcpy( buf, rb->buf1 + rb->off1, len );
            rb->off1 += len;
            return( 1 );
      }
      else
      {
            n = read( fd, rb->buf1 + rb->off2, 65536 - rb->off2 );

            if( n <= 0 )
                  return( 0 );

            rb->off2 += n;

            if( rb->off2 - rb->off1 >= len )
            {
                  memcpy( buf, rb->buf1 + rb->off1, len );
                  rb->off1 += len;
                  return( 1 );
            }
      }

      return( 0 );
}

void read_thread( void *arg )
{
      int fd, n, z, fmt;
      int eof_notified = 0;
      read_buf rb;
//    int ret=0;

      uchar bssid[6];
      uchar dest[6];
      uchar stmac[6];
      uchar *buffer;
      uchar *h80211;
      uchar *p;
      int weight[16];

      struct ivs2_pkthdr ivs2;
      struct ivs2_filehdr fivs2;
      struct pcap_pkthdr pkh;
      struct pcap_file_header pfh;
      struct AP_info *ap_prv, *ap_cur;
      struct ST_info *st_prv, *st_cur;

      signal( SIGINT, sighandler);

      memset( &rb, 0, sizeof( rb ) );
      ap_cur = NULL;

      memset(&pfh, 0, sizeof(struct pcap_file_header));

      if( ( buffer = (uchar *) malloc( 65536 ) ) == NULL )
      {
            /* there is no buffer */

            perror( "malloc failed" );
            goto read_fail;
      }

      h80211 = buffer;

      if( ! opt.is_quiet )
            printf( "Opening %s\n", (char *) arg );

      if( strcmp( arg, "-" ) == 0 )
            fd = 0;
      else
      {
            if( ( fd = open( (char *) arg, O_RDONLY | O_BINARY ) ) < 0 )
            {
                  perror( "open failed" );
                  goto read_fail;
            }
      }

      if( ! atomic_read( &rb, fd, 4, &pfh ) )
      {
            perror( "read(file header) failed" );
            goto read_fail;
      }

      fmt = FORMAT_IVS;

      if( memcmp( &pfh, IVSONLY_MAGIC, 4 ) != 0 &&
            memcmp( &pfh, IVS2_MAGIC, 4 ) != 0)
      {
            fmt = FORMAT_CAP;

            if( pfh.magic != TCPDUMP_MAGIC &&
                  pfh.magic != TCPDUMP_CIGAM )
            {
                  fprintf( stderr, "Unsupported file format "
                        "(not a pcap or IVs file).\n" );
                  goto read_fail;
            }

            /* read the rest of the pcap file header */

            if( ! atomic_read( &rb, fd, 20, (uchar *) &pfh + 4 ) )
            {
                  perror( "read(file header) failed" );
                  goto read_fail;
            }

            /* take care of endian issues and check the link type */

            if( pfh.magic == TCPDUMP_CIGAM )
                  SWAP32( pfh.linktype );

            if( pfh.linktype != LINKTYPE_IEEE802_11 &&
                  pfh.linktype != LINKTYPE_PRISM_HEADER &&
                  pfh.linktype != LINKTYPE_RADIOTAP_HDR &&
                  pfh.linktype != LINKTYPE_PPI_HDR)
            {
                  fprintf( stderr, "This file is not a regular "
                        "802.11 (wireless) capture.\n" );
                  goto read_fail;
            }
      }
      else
      {
            if( opt.wep_decloak )
            {
                  errx(1, "Can't use decloak wep mode with ivs\n"); /* XXX */
            }

            if (memcmp( &pfh, IVS2_MAGIC, 4 ) == 0)
            {
                  fmt = FORMAT_IVS2;

                  if( ! atomic_read( &rb, fd, sizeof(struct ivs2_filehdr), (uchar *) &fivs2 ) )
                  {
                        perror( "read(file header) failed" );
                        goto read_fail;
                  }
                  if(fivs2.version > IVS2_VERSION)
                  {
                        printf( "Error, wrong %s version: %d. Supported up to version %d.\n", IVS2_EXTENSION, fivs2.version, IVS2_VERSION );
                        goto read_fail;
                  }
            } else if (opt.do_ptw)
                  errx(1, "Can't do PTW with old IVS files, recapture without --ivs or use airodump-ng >= 1.0\n"); /* XXX */
      }
      /* avoid blocking on reading the file */

      if( fcntl( fd, F_SETFL, O_NONBLOCK ) < 0 )
      {
            perror( "fcntl(O_NONBLOCK) failed" );
            goto read_fail;
      }

      while( 1 )
      {
            if( close_aircrack )
                  break;

            if( fmt == FORMAT_IVS )
            {
                  /* read one IV */

                  while( ! atomic_read( &rb, fd, 1, buffer ) )
                        eof_wait( &eof_notified );

                  if( close_aircrack )
                        break;

                  if( buffer[0] != 0xFF )
                  {
                        /* new access point MAC */

                        bssid[0] = buffer[0];

                        while( ! atomic_read( &rb, fd, 5, bssid + 1 ) )
                              eof_wait( &eof_notified );
                        if( close_aircrack )
                              break;
                  }

                  while( ! atomic_read( &rb, fd, 5, buffer ) )
                        eof_wait( &eof_notified );
                  if( close_aircrack )
                        break;
            }
            else if( fmt == FORMAT_IVS2 )
            {
                  while( ! atomic_read( &rb, fd, sizeof( struct ivs2_pkthdr ), &ivs2 ) )
                        eof_wait( &eof_notified );
                  if( close_aircrack )
                        break;

                  if(ivs2.flags & IVS2_BSSID)
                  {
                        while( ! atomic_read( &rb, fd, 6, bssid ) )
                              eof_wait( &eof_notified );
                        if( close_aircrack )
                              break;
                        ivs2.len -= 6;
                  }

                  while( ! atomic_read( &rb, fd, ivs2.len, buffer ) )
                        eof_wait( &eof_notified );
                  if( close_aircrack )
                        break;
            }
            else
            {
                  while( ! atomic_read( &rb, fd, sizeof( pkh ), &pkh ) )
                        eof_wait( &eof_notified );
                  if( close_aircrack )
                        break;

                  if( pfh.magic == TCPDUMP_CIGAM )
                        SWAP32( pkh.caplen );

                  if( pkh.caplen <= 0 || pkh.caplen > 65535 )
                  {
                        fprintf( stderr, "\nInvalid packet capture length %d - "
                              "corrupted file?\n", pkh.caplen );
                        eof_wait( &eof_notified );
                        _exit( FAILURE );
                  }

                  while( ! atomic_read( &rb, fd, pkh.caplen, buffer ) )
                        eof_wait( &eof_notified );
                  if( close_aircrack )
                        break;

                  h80211 = buffer;

                  if( pfh.linktype == LINKTYPE_PRISM_HEADER )
                  {
                        /* remove the prism header */

                        if( h80211[7] == 0x40 )
                              n = 64;
                        else
                        {
                              n = *(int *)( h80211 + 4 );

                              if( pfh.magic == TCPDUMP_CIGAM )
                                    SWAP32( n );
                        }

                        if( n < 8 || n >= (int) pkh.caplen )
                              continue;

                        h80211 += n; pkh.caplen -= n;
                  }

                  if( pfh.linktype == LINKTYPE_RADIOTAP_HDR )
                  {
                        /* remove the radiotap header */

                        n = *(unsigned short *)( h80211 + 2 );

                        if( n <= 0 || n >= (int) pkh.caplen )
                              continue;

                        h80211 += n; pkh.caplen -= n;
                  }

                  if( pfh.linktype == LINKTYPE_PPI_HDR )
                  {
                        /* Remove the PPI header */

                        n = le16_to_cpu(*(unsigned short *)( h80211 + 2));

                        if( n <= 0 || n>= (int) pkh.caplen )
                              continue;

                        /* for a while Kismet logged broken PPI headers */
                        if ( n == 24 && le16_to_cpu(*(unsigned short *)(h80211 + 8)) == 2 )
                              n = 32;

                        if( n <= 0 || n>= (int) pkh.caplen )
                              continue;

                        h80211 += n; pkh.caplen -= n;
                  }
            }

            /* prevent concurrent access on the linked list */

            pthread_mutex_lock( &mx_apl );

            nb_pkt++;

            if( fmt == FORMAT_CAP )
            {
                  /* skip packets smaller than a 802.11 header */

                  if( pkh.caplen < 24 )
                        goto unlock_mx_apl;

                  /* skip (uninteresting) control frames */

                  if( ( h80211[0] & 0x0C ) == 0x04 )
                        goto unlock_mx_apl;

                  /* locate the access point's MAC address */

                  switch( h80211[1] & 3 )
                  {
                        case  0: memcpy( bssid, h80211 + 16, 6 ); break;  //Adhoc
                        case  1: memcpy( bssid, h80211 +  4, 6 ); break;  //ToDS
                        case  2: memcpy( bssid, h80211 + 10, 6 ); break;  //FromDS
                        case  3: memcpy( bssid, h80211 + 10, 6 ); break;  //WDS -> Transmitter taken as BSSID
                  }

                  switch( h80211[1] & 3 )
                  {
                        case  0: memcpy( dest, h80211 +  4, 6 ); break;  //Adhoc
                        case  1: memcpy( dest, h80211 + 16, 6 ); break;  //ToDS
                        case  2: memcpy( dest, h80211 +  4, 6 ); break;  //FromDS
                        case  3: memcpy( dest, h80211 + 16, 6 ); break;  //WDS -> Transmitter taken as BSSID
                  }

                  //skip corrupted keystreams in wep decloak mode
                  if(opt.wep_decloak)
                  {
                        if(dest[0] == 0x01)
                              goto unlock_mx_apl;
                  }
            }

            if(opt.bssidmerge)
                  mergebssids(opt.bssidmerge, bssid);

            if( memcmp( bssid, BROADCAST, 6 ) == 0 )
                  /* probe request or such - skip the packet */
                  goto unlock_mx_apl;

            if( memcmp( bssid, opt.bssid, 6 ) != 0 )
                  goto unlock_mx_apl;

            if( memcmp( opt.maddr, ZERO,      6 ) != 0 &&
                  memcmp( opt.maddr, BROADCAST, 6 ) != 0 )
            {
                  /* apply the MAC filter */

                  if( memcmp( opt.maddr, h80211 +  4, 6 ) != 0 &&
                        memcmp( opt.maddr, h80211 + 10, 6 ) != 0 &&
                        memcmp( opt.maddr, h80211 + 16, 6 ) != 0 )
                        goto unlock_mx_apl;
            }

            /* search the linked list */

            ap_prv = NULL;
            ap_cur = ap_1st;

            while( ap_cur != NULL )
            {
                  if( ! memcmp( ap_cur->bssid, bssid, 6 ) )
                        break;

                  ap_prv = ap_cur;
                  ap_cur = ap_cur->next;
            }

            /* if it's a new access point, add it */

            if( ap_cur == NULL )
            {
                  if( ! ( ap_cur = (struct AP_info *) malloc(
                        sizeof( struct AP_info ) ) ) )
                  {
                        perror( "malloc failed" );
                        break;
                  }

                  memset( ap_cur, 0, sizeof( struct AP_info ) );

                  if( ap_1st == NULL )
                        ap_1st = ap_cur;
                  else
                        ap_prv->next = ap_cur;

                  memcpy( ap_cur->bssid, bssid, 6 );

                  ap_cur->crypt = -1;

                  if (opt.do_ptw == 1)
                  {
                        ap_cur->ptw_clean = PTW_newattackstate();
                        if (!ap_cur->ptw_clean) {
                              perror("PTW_newattackstate()");
                              free(ap_cur);
                              ap_cur = NULL;
                              break;
                        }
                        ap_cur->ptw_vague = PTW_newattackstate();
                        if (!ap_cur->ptw_vague) {
                              perror("PTW_newattackstate()");
                              free(ap_cur);
                              ap_cur = NULL;
                              break;
                        }
                  }
            }

            if( fmt == FORMAT_IVS )
            {
                  ap_cur->crypt = 2;

                  add_wep_iv:
                  /* check for uniqueness first */

                  if( ap_cur->nb_ivs == 0 )
                        ap_cur->uiv_root = uniqueiv_init();

                  if( uniqueiv_check( ap_cur->uiv_root, buffer ) == 0 )
                  {
                        /* add the IV & first two encrypted bytes */

                        n = ap_cur->nb_ivs * 5;

                        if( n + 5 > ap_cur->ivbuf_size )
                        {
                              /* enlarge the IVs buffer */

                              ap_cur->ivbuf_size += 131072;
                              ap_cur->ivbuf = (uchar *) realloc(
                                    ap_cur->ivbuf, ap_cur->ivbuf_size );

                              if( ap_cur->ivbuf == NULL )
                              {
                                    perror( "realloc failed" );
                                    break;
                              }
                        }

                        memcpy( ap_cur->ivbuf + n, buffer, 5 );
                        uniqueiv_mark( ap_cur->uiv_root, buffer );
                        ap_cur->nb_ivs++;
                  }

                  goto unlock_mx_apl;
            }

            if( fmt == FORMAT_IVS2 )
            {
                  if(ivs2.flags & IVS2_ESSID)
                  {
                        memcpy( ap_cur->essid, buffer, ivs2.len);
                  }
                  else if(ivs2.flags & IVS2_XOR)
                  {
                        ap_cur->crypt = 2;

                        if (opt.do_ptw) {
                              int clearsize;

                              clearsize = ivs2.len;

                              if (clearsize < opt.keylen+3)
                                    goto unlock_mx_apl;

                              if (PTW_addsession(ap_cur->ptw_clean, buffer, buffer+4, PTW_DEFAULTWEIGHT, 1))
                                    ap_cur->nb_ivs_clean++;

                              if (PTW_addsession(ap_cur->ptw_vague, buffer, buffer+4, PTW_DEFAULTWEIGHT, 1))
                                    ap_cur->nb_ivs_vague++;

                              goto unlock_mx_apl;
                        }

                        buffer[3] = buffer[4];
                        buffer[4] = buffer[5];
                        buffer[3] ^= 0xAA;
                        buffer[4] ^= 0xAA;
                        /* check for uniqueness first */

                        if( ap_cur->nb_ivs == 0 )
                              ap_cur->uiv_root = uniqueiv_init();

                        if( uniqueiv_check( ap_cur->uiv_root, buffer ) == 0 )
                        {
                              /* add the IV & first two encrypted bytes */

                              n = ap_cur->nb_ivs * 5;

                              if( n + 5 > ap_cur->ivbuf_size )
                              {
                                    /* enlarge the IVs buffer */

                                    ap_cur->ivbuf_size += 131072;
                                    ap_cur->ivbuf = (uchar *) realloc(
                                          ap_cur->ivbuf, ap_cur->ivbuf_size );

                                    if( ap_cur->ivbuf == NULL )
                                    {
                                          perror( "realloc failed" );
                                          break;
                                    }
                              }


                              memcpy( ap_cur->ivbuf + n, buffer, 5 );
                              uniqueiv_mark( ap_cur->uiv_root, buffer );
                              ap_cur->nb_ivs++;
//                            all_ivs[256*256*buffer[0] + 256*buffer[1] + buffer[2]].used |= GOT_IV;
                        }
                  }
                  else if(ivs2.flags & IVS2_PTW)
                  {
                        ap_cur->crypt = 2;

                        if (opt.do_ptw) {
                              int clearsize;

                              clearsize = ivs2.len;

                              if (buffer[5] < opt.keylen)
                                    goto unlock_mx_apl;
                              if( clearsize < (6 + buffer[4]*32 + 16*(signed)sizeof(int)) )
                                    goto unlock_mx_apl;

                              memcpy(weight, buffer+clearsize-15*sizeof(int), 16*sizeof(int));
//                            printf("weight 1: %d, weight 2: %d\n", weight[0], weight[1]);

                              if (PTW_addsession(ap_cur->ptw_vague, buffer, buffer+6, weight, buffer[4]))
                                    ap_cur->nb_ivs_vague++;

                              goto unlock_mx_apl;
                        }

                        buffer[3] = buffer[6];
                        buffer[4] = buffer[7];
                        buffer[3] ^= 0xAA;
                        buffer[4] ^= 0xAA;
                        /* check for uniqueness first */

                        if( ap_cur->nb_ivs == 0 )
                              ap_cur->uiv_root = uniqueiv_init();

                        if( uniqueiv_check( ap_cur->uiv_root, buffer ) == 0 )
                        {
                              /* add the IV & first two encrypted bytes */

                              n = ap_cur->nb_ivs * 5;

                              if( n + 5 > ap_cur->ivbuf_size )
                              {
                                    /* enlarge the IVs buffer */

                                    ap_cur->ivbuf_size += 131072;
                                    ap_cur->ivbuf = (uchar *) realloc(
                                          ap_cur->ivbuf, ap_cur->ivbuf_size );

                                    if( ap_cur->ivbuf == NULL )
                                    {
                                          perror( "realloc failed" );
                                          break;
                                    }
                              }


                              memcpy( ap_cur->ivbuf + n, buffer, 5 );
                              uniqueiv_mark( ap_cur->uiv_root, buffer );
                              ap_cur->nb_ivs++;
                        }
                  }
                  else if(ivs2.flags & IVS2_WPA)
                  {
                        ap_cur->crypt = 3;
                        memcpy( &ap_cur->wpa, buffer,
                              sizeof( struct WPA_hdsk ) );
                  }
                  goto unlock_mx_apl;
            }

            /* locate the station MAC in the 802.11 header */

            st_cur = NULL;

            switch( h80211[1] & 3 )
            {
                  case  0: memcpy( stmac, h80211 + 10, 6 ); break;
                  case  1: memcpy( stmac, h80211 + 10, 6 ); break;
                  case  2:

                        /* reject broadcast MACs */

                        if( h80211[4] != 0 ) goto skip_station;
                        memcpy( stmac, h80211 +  4, 6 ); break;

                  default: goto skip_station; break;
            }

            st_prv = NULL;
            st_cur = ap_cur->st_1st;

            while( st_cur != NULL )
            {
                  if( ! memcmp( st_cur->stmac, stmac, 6 ) )
                        break;

                  st_prv = st_cur;
                  st_cur = st_cur->next;
            }

            /* if it's a new supplicant, add it */

            if( st_cur == NULL )
            {
                  if( ! ( st_cur = (struct ST_info *) malloc(
                        sizeof( struct ST_info ) ) ) )
                  {
                        perror( "malloc failed" );
                        break;
                  }

                  memset( st_cur, 0, sizeof( struct ST_info ) );

                  if( ap_cur->st_1st == NULL )
                        ap_cur->st_1st = st_cur;
                  else
                        st_prv->next = st_cur;

                  memcpy( st_cur->stmac, stmac, 6 );
            }

            skip_station:

            /* packet parsing: Beacon or Probe Response */

            if( h80211[0] == 0x80 ||
                  h80211[0] == 0x50 )
            {
                  if( ap_cur->crypt < 0 )
                        ap_cur->crypt = ( h80211[34] & 0x10 ) >> 4;

                  p = h80211 + 36;

                  while( p < h80211 + pkh.caplen )
                  {
                        if( p + 2 + p[1] > h80211 + pkh.caplen )
                              break;

                        if( p[0] == 0x00 && p[1] > 0 && p[2] != '\0' )
                        {
                              /* found a non-cloaked ESSID */

                              n = ( p[1] > 32 ) ? 32 : p[1];

                              memset( ap_cur->essid, 0, 33 );
                              memcpy( ap_cur->essid, p + 2, n );
                        }

                        p += 2 + p[1];
                  }
            }

            /* packet parsing: Association Request */

            if( h80211[0] == 0x00 )
            {
                  p = h80211 + 28;

                  while( p < h80211 + pkh.caplen )
                  {
                        if( p + 2 + p[1] > h80211 + pkh.caplen )
                              break;

                        if( p[0] == 0x00 && p[1] > 0 && p[2] != '\0' )
                        {
                              n = ( p[1] > 32 ) ? 32 : p[1];

                              memset( ap_cur->essid, 0, 33 );
                              memcpy( ap_cur->essid, p + 2, n );
                        }

                        p += 2 + p[1];
                  }
            }

            /* packet parsing: Association Response */

            if( h80211[0] == 0x10 )
            {
                  /* reset the WPA handshake state */

                  if( st_cur != NULL )
                        st_cur->wpa.state = 0;
            }

            /* check if data */

            if( ( h80211[0] & 0x0C ) != 0x08 )
                  goto unlock_mx_apl;

            /* check minimum size */

            z = ( ( h80211[1] & 3 ) != 3 ) ? 24 : 30;
            if ( ( h80211[0] & 0x80 ) == 0x80 )
                  z+=2; /* 802.11e QoS */

            if( z + 16 > (int) pkh.caplen )
                  goto unlock_mx_apl;

            /* check the SNAP header to see if data is encrypted */

            if( h80211[z] != h80211[z + 1] || h80211[z + 2] != 0x03 )
            {
                  ap_cur->crypt = 2;       /* encryption = WEP */

                  /* check the extended IV flag */

                  if( ( h80211[z + 3] & 0x20 ) != 0 )
                                                 /* encryption = WPA */
                              ap_cur->crypt = 3;

                  /* check the WEP key index */

                  if( opt.index != 0 &&
                        ( h80211[z + 3] >> 6 ) != opt.index - 1 )
                        goto unlock_mx_apl;

                  if (opt.do_ptw) {
                        unsigned char *body = h80211 + z;
                        int dlen = pkh.caplen - (body-h80211) - 4 -4;
                        unsigned char clear[2048];
                        int clearsize, i, j, k;
                                int weight[16];

                                if((h80211[1] & 0x03) == 0x03) //30byte header
                                {
                                    body += 6;
                                    dlen -=6;
                                }

                        memset(weight, 0, sizeof(weight));
                        memset(clear, 0, sizeof(clear));

                        /* calculate keystream */
                        k = known_clear(clear, &clearsize, weight, h80211, dlen);
                        if (clearsize < (opt.keylen+3))
                              goto unlock_mx_apl;

                                for (j=0; j<k; j++)
                                {
                                    for (i = 0; i < clearsize; i++)
                                            clear[i+(32*j)] ^= body[4+i];
                                }

                                if(k==1)
                                {
                                    if (PTW_addsession(ap_cur->ptw_clean, body, clear, weight, k))
                                            ap_cur->nb_ivs_clean++;
                                }

                                if (PTW_addsession(ap_cur->ptw_vague, body, clear, weight, k))
                                        ap_cur->nb_ivs_vague++;

                        goto unlock_mx_apl;
                  }

                  /* save the IV & first two output bytes */

                  memcpy( buffer    , h80211 + z    , 3 );
                  memcpy( buffer + 3, h80211 + z + 4, 2 );

            /* Special handling for spanning-tree packets */
            if ( memcmp( h80211 +  4, SPANTREE, 6 ) == 0 ||
                memcmp( h80211 + 16, SPANTREE, 6 ) == 0 )
            {
                buffer[3] = (buffer[3] ^ 0x42) ^ 0xAA;
                buffer[4] = (buffer[4] ^ 0x42) ^ 0xAA;
            }

                  goto add_wep_iv;
            }

            if( ap_cur->crypt < 0 )
                  ap_cur->crypt = 0;       /* no encryption */

            /* if ethertype == IPv4, find the LAN address */

            z += 6;

            if( z + 20 < (int) pkh.caplen )
            {
                  if( h80211[z] == 0x08 && h80211[z + 1] == 0x00 &&
                        ( h80211[1] & 3 ) == 0x01 )
                        memcpy( ap_cur->lanip, &h80211[z + 14], 4 );

                  if( h80211[z] == 0x08 && h80211[z + 1] == 0x06 )
                        memcpy( ap_cur->lanip, &h80211[z + 16], 4 );
            }

            /* check ethertype == EAPOL */

            if( h80211[z] != 0x88 || h80211[z + 1] != 0x8E )
                  goto unlock_mx_apl;

            z += 2;

            ap_cur->eapol = 1;

            /* type == 3 (key), desc. == 254 (WPA) or 2 (RSN) */

            if( h80211[z + 1] != 0x03 ||
                  ( h80211[z + 4] != 0xFE && h80211[z + 4] != 0x02 ) )
                  goto unlock_mx_apl;

            ap_cur->eapol = 0;
            ap_cur->crypt = 3;             /* set WPA */

            if( st_cur == NULL )
            {
                  pthread_mutex_unlock( &mx_apl );
                  continue;
            }

            /* frame 1: Pairwise == 1, Install == 0, Ack == 1, MIC == 0 */

            if( ( h80211[z + 6] & 0x08 ) != 0 &&
                  ( h80211[z + 6] & 0x40 ) == 0 &&
                  ( h80211[z + 6] & 0x80 ) != 0 &&
                  ( h80211[z + 5] & 0x01 ) == 0 )
            {
                  memcpy( st_cur->wpa.anonce, &h80211[z + 17], 32 );

                  /* authenticator nonce set */
                  st_cur->wpa.state = 1;
            }

            /* frame 2 or 4: Pairwise == 1, Install == 0, Ack == 0, MIC == 1 */

            if( ( h80211[z + 6] & 0x08 ) != 0 &&
                  ( h80211[z + 6] & 0x40 ) == 0 &&
                  ( h80211[z + 6] & 0x80 ) == 0 &&
                  ( h80211[z + 5] & 0x01 ) != 0 )
            {
                  if( memcmp( &h80211[z + 17], ZERO, 32 ) != 0 )
                  {
                        memcpy( st_cur->wpa.snonce, &h80211[z + 17], 32 );

                                                 /* supplicant nonce set */
                        st_cur->wpa.state |= 2;
                  }

                  if( (st_cur->wpa.state & 4) != 4 )
                  {
                        /* copy the MIC & eapol frame */

                        st_cur->wpa.eapol_size = ( h80211[z + 2] << 8 )
                              +   h80211[z + 3] + 4;

                        memcpy( st_cur->wpa.keymic, &h80211[z + 81], 16 );
                        memcpy( st_cur->wpa.eapol,  &h80211[z], st_cur->wpa.eapol_size );
                        memset( st_cur->wpa.eapol + 81, 0, 16 );

                                                      /* eapol frame & keymic set */
                        st_cur->wpa.state |= 4;

                        /* copy the key descriptor version */

                        st_cur->wpa.keyver = h80211[z + 6] & 7;
                  }
            }

            /* frame 3: Pairwise == 1, Install == 1, Ack == 1, MIC == 1 */

            if( ( h80211[z + 6] & 0x08 ) != 0 &&
                  ( h80211[z + 6] & 0x40 ) != 0 &&
                  ( h80211[z + 6] & 0x80 ) != 0 &&
                  ( h80211[z + 5] & 0x01 ) != 0 )
            {
                  if( memcmp( &h80211[z + 17], ZERO, 32 ) != 0 )
                  {
                        memcpy( st_cur->wpa.anonce, &h80211[z + 17], 32 );

                                                 /* authenticator nonce set */
                        st_cur->wpa.state |= 1;
                  }

                  if( (st_cur->wpa.state & 4) != 4 )
                  {
                        /* copy the MIC & eapol frame */

                        st_cur->wpa.eapol_size = ( h80211[z + 2] << 8 )
                              +   h80211[z + 3] + 4;

                        memcpy( st_cur->wpa.keymic, &h80211[z + 81], 16 );
                        memcpy( st_cur->wpa.eapol,  &h80211[z], st_cur->wpa.eapol_size );
                        memset( st_cur->wpa.eapol + 81, 0, 16 );

                                                      /* eapol frame & keymic set */
                        st_cur->wpa.state |= 4;

                        /* copy the key descriptor version */

                        st_cur->wpa.keyver = h80211[z + 6] & 7;
                  }
            }

            if( st_cur->wpa.state == 7 )
            {
                  /* got one valid handshake */

                  memcpy( st_cur->wpa.stmac, stmac, 6 );
                  memcpy( &ap_cur->wpa, &st_cur->wpa,
                        sizeof( struct WPA_hdsk ) );
            }

            unlock_mx_apl:

            pthread_mutex_unlock( &mx_apl );

            if( ap_cur != NULL )
            {
                  if( ( ap_cur->nb_ivs >= opt.max_ivs) ||
                      ( ap_cur->nb_ivs_clean >= opt.max_ivs ) ||
                      ( ap_cur->nb_ivs_vague >= opt.max_ivs ) )
                  {
                        eof_wait( &eof_notified );
                        return;
                  }
            }
      }

      read_fail:

      if(rb.buf1 != NULL)
      {
            free(rb.buf1);
            rb.buf1=NULL;
      }
      if(rb.buf2 != NULL)
      {
            free(rb.buf2);
            rb.buf2=NULL;
      }
      if(buffer != NULL)
      {
            free(buffer);
            buffer=NULL;
      }

      if(close_aircrack)
            return;

      //everything is going down
      kill( 0, SIGTERM );
      _exit( FAILURE );
}

void check_thread( void *arg )
{
      int fd, n, z, fmt;
      read_buf rb;
//    int ret=0;

      uchar bssid[6];
      uchar dest[6];
      uchar stmac[6];
      uchar *buffer;
      uchar *h80211;
      uchar *p;
      int weight[16];

      struct ivs2_pkthdr ivs2;
      struct ivs2_filehdr fivs2;
      struct pcap_pkthdr pkh;
      struct pcap_file_header pfh;
      struct AP_info *ap_prv, *ap_cur;
      struct ST_info *st_prv, *st_cur;

      memset( &rb, 0, sizeof( rb ) );
      ap_cur = NULL;

      if( ( buffer = (uchar *) malloc( 65536 ) ) == NULL )
      {
            /* there is no buffer */

            perror( "malloc failed" );
            goto read_fail;
      }

      h80211 = buffer;

      if( ! opt.is_quiet )
            printf( "Opening %s\n", (char *) arg );

      if( strcmp( arg, "-" ) == 0 )
            fd = 0;
      else
      {
            if( ( fd = open( (char *) arg, O_RDONLY | O_BINARY ) ) < 0 )
            {
                  perror( "open failed" );
                  goto read_fail;
            }
      }

      if( ! atomic_read( &rb, fd, 4, &pfh ) )
      {
            perror( "read(file header) failed" );
            goto read_fail;
      }

      fmt = FORMAT_IVS;

      if( memcmp( &pfh, IVSONLY_MAGIC, 4 ) != 0 &&
            memcmp( &pfh, IVS2_MAGIC, 4 ) != 0)
      {
            fmt = FORMAT_CAP;

            if( pfh.magic != TCPDUMP_MAGIC &&
                  pfh.magic != TCPDUMP_CIGAM )
            {
                  fprintf( stderr, "Unsupported file format "
                        "(not a pcap or IVs file).\n" );
                  goto read_fail;
            }

            /* read the rest of the pcap file header */

            if( ! atomic_read( &rb, fd, 20, (uchar *) &pfh + 4 ) )
            {
                  perror( "read(file header) failed" );
                  goto read_fail;
            }

            /* take care of endian issues and check the link type */

            if( pfh.magic == TCPDUMP_CIGAM )
                  SWAP32( pfh.linktype );

            if( pfh.linktype != LINKTYPE_IEEE802_11 &&
                  pfh.linktype != LINKTYPE_PRISM_HEADER &&
                  pfh.linktype != LINKTYPE_RADIOTAP_HDR &&
                  pfh.linktype != LINKTYPE_PPI_HDR )
            {
                  fprintf( stderr, "This file is not a regular "
                        "802.11 (wireless) capture.\n" );
                  goto read_fail;
            }
      } else
      {
            if( opt.wep_decloak )
            {
                  errx(1, "Can't use decloak wep mode with ivs\n"); /* XXX */
            }
            if (memcmp( &pfh, IVS2_MAGIC, 4 ) == 0)
            {
                  fmt = FORMAT_IVS2;

                  if( ! atomic_read( &rb, fd, sizeof(struct ivs2_filehdr), (uchar *) &fivs2 ) )
                  {
                        perror( "read(file header) failed" );
                        goto read_fail;
                  }
                  if(fivs2.version > IVS2_VERSION)
                  {
                        printf( "Error, wrong %s version: %d. Supported up to version %d.\n", IVS2_EXTENSION, fivs2.version, IVS2_VERSION );
                        goto read_fail;
                  }
            } else if (opt.do_ptw)
                  errx(1, "Can't do PTW with old IVS files, recapture without --ivs or use airodump-ng >= 1.0\n"); /* XXX */
      }
      /* avoid blocking on reading the file */

      if( fcntl( fd, F_SETFL, O_NONBLOCK ) < 0 )
      {
            perror( "fcntl(O_NONBLOCK) failed" );
            goto read_fail;
      }

      while( 1 )
      {
            if(close_aircrack)
                  break;

            if( fmt == FORMAT_IVS )
            {
                  /* read one IV */

                  while( ! atomic_read( &rb, fd, 1, buffer ) )
                        goto read_fail;

                  if( buffer[0] != 0xFF )
                  {
                        /* new access point MAC */

                        bssid[0] = buffer[0];

                        while( ! atomic_read( &rb, fd, 5, bssid + 1 ) )
                              goto read_fail;
                  }

                  while( ! atomic_read( &rb, fd, 5, buffer ) )
                        goto read_fail;
            }
            else if( fmt == FORMAT_IVS2 )
            {
                  while( ! atomic_read( &rb, fd, sizeof( struct ivs2_pkthdr ), &ivs2 ) )
                        goto read_fail;

                  if(ivs2.flags & IVS2_BSSID)
                  {
                        while( ! atomic_read( &rb, fd, 6, bssid ) )
                              goto read_fail;
                        ivs2.len -= 6;
                  }

                  while( ! atomic_read( &rb, fd, ivs2.len, buffer ) )
                        goto read_fail;
            }
            else
            {
                  while( ! atomic_read( &rb, fd, sizeof( pkh ), &pkh ) )
                        goto read_fail;

                  if( pfh.magic == TCPDUMP_CIGAM )
                        SWAP32( pkh.caplen );

                  if( pkh.caplen <= 0 || pkh.caplen > 65535 )
                  {
                        fprintf( stderr, "\nInvalid packet capture length %d - "
                              "corrupted file?\n", pkh.caplen );
                        goto read_fail;
                        _exit( FAILURE );
                  }

                  while( ! atomic_read( &rb, fd, pkh.caplen, buffer ) )
                        goto read_fail;

                  h80211 = buffer;

                  if( pfh.linktype == LINKTYPE_PRISM_HEADER )
                  {
                        /* remove the prism header */

                        if( h80211[7] == 0x40 )
                              n = 64;
                        else
                        {
                              n = *(int *)( h80211 + 4 );

                              if( pfh.magic == TCPDUMP_CIGAM )
                                    SWAP32( n );
                        }

                        if( n < 8 || n >= (int) pkh.caplen )
                              continue;

                        h80211 += n; pkh.caplen -= n;
                  }

                  if( pfh.linktype == LINKTYPE_RADIOTAP_HDR )
                  {
                        /* remove the radiotap header */

                        n = *(unsigned short *)( h80211 + 2 );

                        if( n <= 0 || n >= (int) pkh.caplen )
                              continue;

                        h80211 += n; pkh.caplen -= n;
                  }

                  if( pfh.linktype == LINKTYPE_PPI_HDR )
                  {
                        /* Remove the PPI header */

                        n = le16_to_cpu(*(unsigned short *)( h80211 + 2));

                        if( n <= 0 || n>= (int) pkh.caplen )
                              continue;

                        /* for a whole Kismet logged broken PPI headers */
                        if ( n == 24 && le16_to_cpu(*(unsigned short *)(h80211 + 8)) == 2 )
                              n = 32;

                        if( n <= 0 || n>= (int) pkh.caplen )
                              continue;

                        h80211 += n; pkh.caplen -= n;
                  }
            }

            /* prevent concurrent access on the linked list */

            pthread_mutex_lock( &mx_apl );

            nb_pkt++;

            if( fmt == FORMAT_CAP )
            {
                  /* skip packets smaller than a 802.11 header */

                  if( pkh.caplen < 24 )
                        goto unlock_mx_apl;

                  /* skip (uninteresting) control frames */

                  if( ( h80211[0] & 0x0C ) == 0x04 )
                        goto unlock_mx_apl;

                  /* locate the access point's MAC address */

                  switch( h80211[1] & 3 )
                  {
                        case  0: memcpy( bssid, h80211 + 16, 6 ); break;  //Adhoc
                        case  1: memcpy( bssid, h80211 +  4, 6 ); break;  //ToDS
                        case  2: memcpy( bssid, h80211 + 10, 6 ); break;  //FromDS
                        case  3: memcpy( bssid, h80211 + 10, 6 ); break;  //WDS -> Transmitter taken as BSSID
                  }

                  switch( h80211[1] & 3 )
                  {
                        case  0: memcpy( dest, h80211 +  4, 6 ); break;  //Adhoc
                        case  1: memcpy( dest, h80211 + 16, 6 ); break;  //ToDS
                        case  2: memcpy( dest, h80211 +  4, 6 ); break;  //FromDS
                        case  3: memcpy( dest, h80211 + 16, 6 ); break;  //WDS -> Transmitter taken as BSSID
                  }

                  //skip corrupted keystreams in wep decloak mode
                  if(opt.wep_decloak)
                  {
                        if(dest[0] == 0x01)
                              goto unlock_mx_apl;
                  }
            }

            if(opt.bssidmerge)
                  mergebssids(opt.bssidmerge, bssid);

            if( memcmp( bssid, BROADCAST, 6 ) == 0 )
                  /* probe request or such - skip the packet */
                  goto unlock_mx_apl;

            if( memcmp( opt.maddr, ZERO,      6 ) != 0 &&
                  memcmp( opt.maddr, BROADCAST, 6 ) != 0 )
            {
                  /* apply the MAC filter */

                  if( memcmp( opt.maddr, h80211 +  4, 6 ) != 0 &&
                        memcmp( opt.maddr, h80211 + 10, 6 ) != 0 &&
                        memcmp( opt.maddr, h80211 + 16, 6 ) != 0 )
                        goto unlock_mx_apl;
            }

            /* search the linked list */

            ap_prv = NULL;
            ap_cur = ap_1st;

            while( ap_cur != NULL )
            {
                  if( ! memcmp( ap_cur->bssid, bssid, 6 ) )
                        break;

                  ap_prv = ap_cur;
                  ap_cur = ap_cur->next;
            }

            /* if it's a new access point, add it */

            if( ap_cur == NULL )
            {
                  if( ! ( ap_cur = (struct AP_info *) malloc(
                        sizeof( struct AP_info ) ) ) )
                  {
                        perror( "malloc failed" );
                        break;
                  }

                  memset( ap_cur, 0, sizeof( struct AP_info ) );

                  if( ap_1st == NULL )
                        ap_1st = ap_cur;
                  else
                        ap_prv->next = ap_cur;

                  memcpy( ap_cur->bssid, bssid, 6 );

                  ap_cur->crypt = -1;
            }

            if( fmt == FORMAT_IVS )
            {
                  ap_cur->crypt = 2;

                  add_wep_iv:
                  /* check for uniqueness first */

                  if( ap_cur->nb_ivs == 0 )
                        ap_cur->uiv_root = uniqueiv_init();

                  if( uniqueiv_check( ap_cur->uiv_root, buffer ) == 0 )
                  {
                        uniqueiv_mark( ap_cur->uiv_root, buffer );
                        ap_cur->nb_ivs++;
                  }

                  goto unlock_mx_apl;
            }

            if( fmt == FORMAT_IVS2 )
            {
                  if(ivs2.flags & IVS2_ESSID)
                  {
                        memcpy( ap_cur->essid, buffer, ivs2.len);
                        if(opt.essid_set && ! strcmp( opt.essid, ap_cur->essid ) )
                              memcpy( opt.bssid, ap_cur->bssid, 6 );
                  }
                  else if(ivs2.flags & IVS2_XOR)
                  {
                        ap_cur->crypt = 2;

                        if (opt.do_ptw) {
                              int clearsize;

                              clearsize = ivs2.len;

                              if (clearsize < opt.keylen+3)
                                    goto unlock_mx_apl;
                        }

                        if( ap_cur->nb_ivs == 0 )
                              ap_cur->uiv_root = uniqueiv_init();

                        if( uniqueiv_check( ap_cur->uiv_root, buffer ) == 0 )
                        {
                              uniqueiv_mark( ap_cur->uiv_root, buffer );
                              ap_cur->nb_ivs++;
                        }
                  }
                  else if(ivs2.flags & IVS2_PTW)
                  {
                        ap_cur->crypt = 2;

                        if (opt.do_ptw) {
                              int clearsize;

                              clearsize = ivs2.len;

                              if (buffer[5] < opt.keylen)
                                    goto unlock_mx_apl;
                              if( clearsize < (6 + buffer[4]*32 + 16*(signed)sizeof(int)) )
                                    goto unlock_mx_apl;
                        }

                        if( ap_cur->nb_ivs == 0 )
                              ap_cur->uiv_root = uniqueiv_init();

                        if( uniqueiv_check( ap_cur->uiv_root, buffer ) == 0 )
                        {
                              uniqueiv_mark( ap_cur->uiv_root, buffer );
                              ap_cur->nb_ivs++;
                        }
                  }
                  else if(ivs2.flags & IVS2_WPA)
                  {
                        ap_cur->crypt = 3;
                        memcpy( &ap_cur->wpa, buffer,
                              sizeof( struct WPA_hdsk ) );
                  }
                  goto unlock_mx_apl;
            }

            /* locate the station MAC in the 802.11 header */

            st_cur = NULL;

            switch( h80211[1] & 3 )
            {
                  case  0: memcpy( stmac, h80211 + 10, 6 ); break;
                  case  1: memcpy( stmac, h80211 + 10, 6 ); break;
                  case  2:

                        /* reject broadcast MACs */

                        if( h80211[4] != 0 ) goto skip_station;
                        memcpy( stmac, h80211 +  4, 6 ); break;

                  default: goto skip_station; break;
            }

            st_prv = NULL;
            st_cur = ap_cur->st_1st;

            while( st_cur != NULL )
            {
                  if( ! memcmp( st_cur->stmac, stmac, 6 ) )
                        break;

                  st_prv = st_cur;
                  st_cur = st_cur->next;
            }

            /* if it's a new supplicant, add it */

            if( st_cur == NULL )
            {
                  if( ! ( st_cur = (struct ST_info *) malloc(
                        sizeof( struct ST_info ) ) ) )
                  {
                        perror( "malloc failed" );
                        break;
                  }

                  memset( st_cur, 0, sizeof( struct ST_info ) );

                  if( ap_cur->st_1st == NULL )
                        ap_cur->st_1st = st_cur;
                  else
                        st_prv->next = st_cur;

                  memcpy( st_cur->stmac, stmac, 6 );
            }

            skip_station:

            /* packet parsing: Beacon or Probe Response */

            if( h80211[0] == 0x80 ||
                  h80211[0] == 0x50 )
            {
                  if( ap_cur->crypt < 0 )
                        ap_cur->crypt = ( h80211[34] & 0x10 ) >> 4;

                  p = h80211 + 36;

                  while( p < h80211 + pkh.caplen )
                  {
                        if( p + 2 + p[1] > h80211 + pkh.caplen )
                              break;

                        if( p[0] == 0x00 && p[1] > 0 && p[2] != '\0' )
                        {
                              /* found a non-cloaked ESSID */

                              n = ( p[1] > 32 ) ? 32 : p[1];

                              memset( ap_cur->essid, 0, 33 );
                              memcpy( ap_cur->essid, p + 2, n );
                              if(opt.essid_set && ! strcmp( opt.essid, ap_cur->essid ) )
                                    memcpy( opt.bssid, ap_cur->bssid, 6 );
                        }

                        p += 2 + p[1];
                  }
            }

            /* packet parsing: Association Request */

            if( h80211[0] == 0x00 )
            {
                  p = h80211 + 28;

                  while( p < h80211 + pkh.caplen )
                  {
                        if( p + 2 + p[1] > h80211 + pkh.caplen )
                              break;

                        if( p[0] == 0x00 && p[1] > 0 && p[2] != '\0' )
                        {
                              n = ( p[1] > 32 ) ? 32 : p[1];

                              memset( ap_cur->essid, 0, 33 );
                              memcpy( ap_cur->essid, p + 2, n );
                              if(opt.essid_set && ! strcmp( opt.essid, ap_cur->essid ) )
                                    memcpy( opt.bssid, ap_cur->bssid, 6 );
                        }

                        p += 2 + p[1];
                  }

                  /* reset the WPA handshake state */

                  if( st_cur != NULL )
                        st_cur->wpa.state = 0;
            }

            /* packet parsing: Association Response */

            if( h80211[0] == 0x10 )
            {
                  /* reset the WPA handshake state */

                  if( st_cur != NULL )
                        st_cur->wpa.state = 0;
            }

            /* check if data */

            if( ( h80211[0] & 0x0C ) != 0x08 )
                  goto unlock_mx_apl;

            /* check minimum size */

            z = ( ( h80211[1] & 3 ) != 3 ) ? 24 : 30;
            if ( ( h80211[0] & 0x80 ) == 0x80 )
                  z+=2; /* 802.11e QoS */

            if( z + 16 > (int) pkh.caplen )
                  goto unlock_mx_apl;

            /* check the SNAP header to see if data is encrypted */

            if( h80211[z] != h80211[z + 1] || h80211[z + 2] != 0x03 )
            {
                  ap_cur->crypt = 2;       /* encryption = WEP */

                  /* check the extended IV flag */

                  if( ( h80211[z + 3] & 0x20 ) != 0 )
                                                 /* encryption = WPA */
                              ap_cur->crypt = 3;

                  /* check the WEP key index */

                  if( opt.index != 0 &&
                        ( h80211[z + 3] >> 6 ) != opt.index - 1 )
                        goto unlock_mx_apl;

                  if (opt.do_ptw) {
                        unsigned char *body = h80211 + z;
                        int dlen = pkh.caplen - (body-h80211) - 4 -4;
                        unsigned char clear[2048];
                        int clearsize, k;

                                if((h80211[1] & 0x03) == 0x03) //30byte header
                                {
                                    body += 6;
                                    dlen -=6;
                                }

                        /* calculate keystream */
                        k = known_clear(clear, &clearsize, weight, h80211, dlen);
                        if (clearsize < (opt.keylen+3))
                              goto unlock_mx_apl;
                  }

                  /* save the IV & first two output bytes */

                  memcpy( buffer    , h80211 + z    , 3 );
                  goto add_wep_iv;
            }

            if( ap_cur->crypt < 0 )
                  ap_cur->crypt = 0;       /* no encryption */

            /* if ethertype == IPv4, find the LAN address */

            z += 6;

            if( z + 20 < (int) pkh.caplen )
            {
                  if( h80211[z] == 0x08 && h80211[z + 1] == 0x00 &&
                        ( h80211[1] & 3 ) == 0x01 )
                        memcpy( ap_cur->lanip, &h80211[z + 14], 4 );

                  if( h80211[z] == 0x08 && h80211[z + 1] == 0x06 )
                        memcpy( ap_cur->lanip, &h80211[z + 16], 4 );
            }

            /* check ethertype == EAPOL */

            if( h80211[z] != 0x88 || h80211[z + 1] != 0x8E )
                  goto unlock_mx_apl;

            z += 2;

            ap_cur->eapol = 1;

            /* type == 3 (key), desc. == 254 (WPA) or 2 (RSN) */

            if( h80211[z + 1] != 0x03 ||
                  ( h80211[z + 4] != 0xFE && h80211[z + 4] != 0x02 ) )
                  goto unlock_mx_apl;

            ap_cur->eapol = 0;
            ap_cur->crypt = 3;             /* set WPA */

            if( st_cur == NULL )
            {
                  pthread_mutex_unlock( &mx_apl );
                  continue;
            }

            /* frame 1: Pairwise == 1, Install == 0, Ack == 1, MIC == 0 */

            if( ( h80211[z + 6] & 0x08 ) != 0 &&
                  ( h80211[z + 6] & 0x40 ) == 0 &&
                  ( h80211[z + 6] & 0x80 ) != 0 &&
                  ( h80211[z + 5] & 0x01 ) == 0 )
            {
                  memcpy( st_cur->wpa.anonce, &h80211[z + 17], 32 );

                  /* authenticator nonce set */
                  st_cur->wpa.state = 1;
            }

            /* frame 2 or 4: Pairwise == 1, Install == 0, Ack == 0, MIC == 1 */

            if( ( h80211[z + 6] & 0x08 ) != 0 &&
                  ( h80211[z + 6] & 0x40 ) == 0 &&
                  ( h80211[z + 6] & 0x80 ) == 0 &&
                  ( h80211[z + 5] & 0x01 ) != 0 )
            {
                  if( memcmp( &h80211[z + 17], ZERO, 32 ) != 0 )
                  {
                        memcpy( st_cur->wpa.snonce, &h80211[z + 17], 32 );

                                                 /* supplicant nonce set */
                        st_cur->wpa.state |= 2;
                  }

                  if( (st_cur->wpa.state & 4) != 4 )
                  {
                        /* copy the MIC & eapol frame */

                        st_cur->wpa.eapol_size = ( h80211[z + 2] << 8 )
                              +   h80211[z + 3] + 4;

                        memcpy( st_cur->wpa.keymic, &h80211[z + 81], 16 );
                        memcpy( st_cur->wpa.eapol,  &h80211[z], st_cur->wpa.eapol_size );
                        memset( st_cur->wpa.eapol + 81, 0, 16 );

                                                      /* eapol frame & keymic set */
                        st_cur->wpa.state |= 4;

                        /* copy the key descriptor version */

                        st_cur->wpa.keyver = h80211[z + 6] & 7;
                  }
            }

            /* frame 3: Pairwise == 1, Install == 1, Ack == 1, MIC == 1 */

            if( ( h80211[z + 6] & 0x08 ) != 0 &&
                  ( h80211[z + 6] & 0x40 ) != 0 &&
                  ( h80211[z + 6] & 0x80 ) != 0 &&
                  ( h80211[z + 5] & 0x01 ) != 0 )
            {
                  if( memcmp( &h80211[z + 17], ZERO, 32 ) != 0 )
                  {
                        memcpy( st_cur->wpa.anonce, &h80211[z + 17], 32 );

                                                 /* authenticator nonce set */
                        st_cur->wpa.state |= 1;
                  }

                  if( (st_cur->wpa.state & 4) != 4 )
                  {
                        /* copy the MIC & eapol frame */

                        st_cur->wpa.eapol_size = ( h80211[z + 2] << 8 )
                              +   h80211[z + 3] + 4;

                        memcpy( st_cur->wpa.keymic, &h80211[z + 81], 16 );
                        memcpy( st_cur->wpa.eapol,  &h80211[z], st_cur->wpa.eapol_size );
                        memset( st_cur->wpa.eapol + 81, 0, 16 );

                                                      /* eapol frame & keymic set */
                        st_cur->wpa.state |= 4;

                        /* copy the key descriptor version */

                        st_cur->wpa.keyver = h80211[z + 6] & 7;
                  }
            }

            if( st_cur->wpa.state == 7 )
            {
                  /* got one valid handshake */

                  memcpy( st_cur->wpa.stmac, stmac, 6 );
                  memcpy( &ap_cur->wpa, &st_cur->wpa,
                        sizeof( struct WPA_hdsk ) );
            }

            unlock_mx_apl:

            pthread_mutex_unlock( &mx_apl );

            if( ap_cur != NULL )
                  if( ap_cur->nb_ivs >= opt.max_ivs )
                        break;

      }

      read_fail:

      if(rb.buf1 != NULL)
      {
            free(rb.buf1);
            rb.buf1 = NULL;
      }
      if(rb.buf2 != NULL)
      {
            free(rb.buf2);
            rb.buf2 = NULL;
      }
      if(buffer != NULL)
      {
            free(buffer);
            buffer = NULL;
      }

      return;
}

/* timing routine */

float chrono( struct timeval *start, int reset )
{
      float delta;
      struct timeval current;

      gettimeofday( &current, NULL );

      delta = ( current.tv_sec  - start->tv_sec  ) + (float)
            ( current.tv_usec - start->tv_usec ) / 1000000;

      if( reset )
            gettimeofday( start, NULL );

      return( delta );
}

/* signal-safe I/O routines */

int safe_read( int fd, void *buf, size_t len )
{
      int n;
      size_t sum = 0;
      char  *off = (char *) buf;

      while( sum < len )
      {
            if( ! ( n = read( fd, (void *) off, len - sum ) ) )
                {
                  return( 0 );
                }
            if( n < 0 && errno == EINTR ) continue;
            if( n < 0 ) return( n );

            sum += n;
            off += n;
      }

      return( sum );
}

int safe_write( int fd, void *buf, size_t len )
{
      int n;
      size_t sum = 0;
      char  *off = (char *) buf;

      while( sum < len )
      {
            if( ( n = write( fd, (void *) off, len - sum ) ) < 0 )
            {
                  if( errno == EINTR ) continue;
                  return( n );
            }

            sum += n;
            off += n;
      }

      return( sum );
}

/* each thread computes the votes over a subset of the IVs */

int crack_wep_thread( void *arg )
{
      long xv, min, max;
      uchar jj[256];
      uchar S[256], Si[256];
      uchar K[64];

      uchar io1, o1, io2, o2;
      uchar Sq, dq, Kq, jq, q;
      uchar S1, S2, J2, t2;

      int i, j, B, cid = (long) arg;
      int votes[N_ATTACKS][256];
      //first: first S-Box Setup; first2:first round with new key; oldB: old B value
      int first=1, first2=1, oldB=0, oldq=0;

      memcpy( S,  R, 256 );
      memcpy( Si, R, 256 );
      while( 1 )
      {
            if(!first) oldB=B;

            if( safe_read( mc_pipe[cid][0], (void *) &B,
                  sizeof( int ) ) != sizeof( int ) )
            {
                  perror( "read failed" );
                  kill( 0, SIGTERM );
                  _exit( FAILURE );
            }
            if( close_aircrack )
                  break;

            first2=1;

            min = 5 * ( ( (     cid ) * wep.nb_ivs ) / opt.nbcpu );
            max = 5 * ( ( ( 1 + cid ) * wep.nb_ivs ) / opt.nbcpu );

            q = 3 + B;

            memcpy( K + 3, wep.key, B );
            memset( votes, 0, sizeof( votes ) );

            /* START: KoreK attacks */

            for( xv = min; xv < max; xv += 5 )
            {
                  if(!first)
                  {
                        for(i=0; i<oldq; i++)
                        {
                              S[i] = Si[i] = i;
                              S[jj[i]] = Si[jj[i]] = jj[i];
//                            Si[i] = i;
//                            Si[jj[i]] = jj[i];
                        }
                  }

                  pthread_mutex_lock( &mx_ivb );

                  memcpy( K, &wep.ivbuf[xv], 3 );

                  for( i = j = 0; i < q; i++ )
                  {
//                      i can never be 3+opt.keylen or exceed it, as i runs from 0 to q and q is defined as 3+B (with B the keybyte to attack)
//                      jj[i] = j = ( j + S[i] + K[i % (3 + opt.keylen)] ) & 0xFF;
                        jj[i] = j = ( j + S[i] + K[i] ) & 0xFF;
                        SWAP( S[i], S[j] );
                  }

                  i = q; do { i--; SWAP(Si[i],Si[jj[i]]); }
                  while( i != 0 );

                  o1 = wep.ivbuf[xv + 3] ^ 0xAA; io1 = Si[o1]; S1 = S[1];
                  o2 = wep.ivbuf[xv + 4] ^ 0xAA; io2 = Si[o2]; S2 = S[2];
                  pthread_mutex_unlock( &mx_ivb );

                  if(first)
                        first=0;
                  if(first2)
                  {
                        oldB=B;
                        oldq = 3+oldB;
                        first2=0;
                  }

                  Sq = S[q]; dq = Sq + jj[q - 1];

                  if( S2 == 0 )
                  {
                        if( ( S1 == 2 ) && ( o1 == 2 ) )
                        {
                              Kq = 1 - dq; votes[A_neg][Kq]++;
                              Kq = 2 - dq; votes[A_neg][Kq]++;
                              //to signal general usage
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
                              //to know which attack used this iv
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_neg);
                        }
                        else if( o2 == 0 )
                        {
                              Kq = 2 - dq; votes[A_neg][Kq]++;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_neg);
                        }
                  }
                  else
                  {
                        if( ( o2 == 0 ) && ( Sq == 0 ) )
                        {
                              Kq = 2 - dq; votes[A_u15][Kq]++;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_u15);
                        }
                  }

                  if( ( S1 == 1 ) && ( o1 == S2 ) )
                  {
                        Kq = 1 - dq; votes[A_neg][Kq]++;
                        Kq = 2 - dq; votes[A_neg][Kq]++;
//                      all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                      all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_neg);
                  }

                  if( ( S1 == 0 ) && ( S[0] == 1 ) && ( o1 == 1 ) )
                  {
                        Kq = 0 - dq; votes[A_neg][Kq]++;
                        Kq = 1 - dq; votes[A_neg][Kq]++;
//                      all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                      all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_neg);
                  }

                  if( S1 == q )
                  {
                        if( o1 == q )
                        {
                              Kq = Si[0] - dq; votes[A_s13][Kq]++;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_s13);
                        }
                        else if( ( ( 1 - q - o1 ) & 0xFF ) == 0 )
                        {
                              Kq = io1 - dq; votes[A_u13_1][Kq]++;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_u13_1);
                        }
                        else if( io1 < q )
                        {
                              jq = Si[( io1 - q ) & 0xFF];

                              if( jq != 1 )
                              {
                                    Kq = jq - dq; votes[A_u5_1][Kq]++;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_u5_1);
                              }
                        }
                  }

                  if( ( io1 == 2 ) && ( S[q] == 1 ) )
                  {
                        Kq = 1 - dq; votes[A_u5_2][Kq]++;
//                      all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                      all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_u5_2);
                  }

                  if( S[q] == q )
                  {
                        if( ( S1 == 0 ) && ( o1 == q ) )
                        {
                              Kq = 1 - dq; votes[A_u13_2][Kq]++;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_u13_2);
                        }
                        else if( ( ( ( 1 - q - S1 ) & 0xFF ) == 0 ) && ( o1 == S1 ) )
                        {
                              Kq = 1 - dq; votes[A_u13_3][Kq]++;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_u13_3);
                        }
                        else if( ( S1 >= ( ( -q ) & 0xFF ) )
                              && ( ( ( q + S1 - io1 ) & 0xFF ) == 0 ) )
                        {
                              Kq = 1 - dq; votes[A_u5_3][Kq]++;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_u5_3);
                        }
                  }

                  if( ( S1 < q ) && ( ( ( S1 + S[S1] - q ) & 0xFF ) == 0 )  &&
                        ( io1 != 1 ) && ( io1 != S[S1] ) )
                  {
                        Kq = io1 - dq; votes[A_s5_1][Kq]++;
//                      all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                      all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_s5_1);
                  }

                  if( ( S1 > q ) && ( ( ( S2 + S1 - q ) & 0xFF ) == 0 ) )
                  {
                        if( o2 == S1 )
                        {
                              jq = Si[(S1 - S2) & 0xFF];

                              if( ( jq != 1 ) && ( jq != 2 ) )
                              {
                                    Kq = jq - dq; votes[A_s5_2][Kq]++;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_s5_2);
                              }
                        }
                        else if( o2 == ( ( 2 - S2 ) & 0xFF ) )
                        {
                              jq = io2;

                              if( ( jq != 1 ) && ( jq != 2 ) )
                              {
                                    Kq = jq - dq; votes[A_s5_3][Kq]++;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_s5_3);
                              }
                        }
                  }

                  if( ( S[1] != 2 ) && ( S[2] != 0 ) )
                  {
                        J2 = S[1] + S[2];

                        if( J2 < q )
                        {
                              t2 = S[J2] + S[2];

                              if( ( t2 == q ) && ( io2 != 1 ) && ( io2 != 2 )
                                    && ( io2 != J2 ) )
                              {
                                    Kq = io2 - dq; votes[A_s3][Kq]++;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_s3);
                              }
                        }
                  }

                  if( S1 == 2 )
                  {
                        if( q == 4 )
                        {
                              if( o2 == 0 )
                              {
                                    Kq = Si[0] - dq; votes[A_4_s13][Kq]++;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                                  all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_4_s13);
                              }
                              else
                              {
                                    if( ( jj[1] == 2 ) && ( io2 == 0 ) )
                                    {
                                          Kq = Si[254] - dq; votes[A_4_u5_1][Kq]++;
//                                        all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                                        all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_4_u5_1);
                                    }
                                    if( ( jj[1] == 2 ) && ( io2 == 2 ) )
                                    {
                                          Kq = Si[255] - dq; votes[A_4_u5_2][Kq]++;
//                                        all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                                        all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_4_u5_2);
                                    }
                              }
                        }
                        else if( ( q > 4 ) && ( ( S[4] + 2 ) == q ) &&
                              ( io2 != 1 ) && ( io2 != 4 ) )
                        {
                              Kq = io2 - dq; votes[A_u5_4][Kq]++;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= USE_IV;
//                            all_ivs[256*256*K[0] + 256*K[1] + K[2]].used |= 1 << (4+A_u5_4);
                        }
                  }
                  if( close_aircrack )
                        break;
            }
            if( close_aircrack )
                  break;
            /* END: KoreK attacks */

            if( safe_write( cm_pipe[cid][1], votes,
                  sizeof( votes ) ) != sizeof( votes ) )
            {
                  perror( "write failed" );
                  kill( 0, SIGTERM );
                  _exit( FAILURE );
            }
      }

      return( 0 );
}

/* display the current votes */

void show_wep_stats( int B, int force, PTW_tableentry table[PTW_KEYHSBYTES][PTW_n], int choices[KEYHSBYTES], int depth[KEYHSBYTES], int prod )
{
      float delta;
      struct winsize ws;
      int i, et_h, et_m, et_s;
      static int is_cleared = 0;

      if( (chrono( &t_stats, 0 ) < 1.51 || wepkey_crack_success) && force == 0 )
            return;

      if( ioctl( 0, TIOCGWINSZ, &ws ) < 0 )
      {
            ws.ws_row = 25;
            ws.ws_col = 80;
      }

      chrono( &t_stats, 1 );

      delta = chrono( &t_begin, 0 );

      et_h =   delta / 3600;
      et_m = ( delta - et_h * 3600 ) / 60;
      et_s =   delta - et_h * 3600 - et_m * 60;

      if( is_cleared == 0 )
      {
            is_cleared++;

            if( opt.l33t )
                  printf( "\33[40m" );

            printf( "\33[2J" );
      }

      if( opt.l33t )
            printf( "\33[34;1m" );

      printf( "\33[2;%dH%s\n\n", (ws.ws_col - 12) / 2,
            progname );

      if( opt.l33t )
            printf( "\33[33;1m" );

      if(table)
            printf( "\33[5;%dH[%02d:%02d:%02d] Tested %d keys (got %ld IVs)\33[K",
                  (ws.ws_col - 44) / 2, et_h, et_m, et_s, prod, opt.ap->nb_ivs );
      else
            printf( "\33[5;%dH[%02d:%02d:%02d] Tested %lld keys (got %ld IVs)\33[K",
                  (ws.ws_col - 44) / 2, et_h, et_m, et_s, nb_tried, wep.nb_ivs_now );

      if( opt.l33t )
            printf( "\33[32;22m" );

      printf( "\33[7;4HKB    depth   byte(vote)\n" );

      for( i = 0; i <= B; i++ )
      {
            int j, k = ( ws.ws_col - 20 ) / 11;

            if(!table)
            {
                  if( opt.l33t )
                        printf( "   %2d  \33[1m%3d\33[22m/%3d   ",
                              i, wep.depth[i], wep.fudge[i] );
                  else
                        printf( "   %2d  %3d/%3d   ",
                              i, wep.depth[i], wep.fudge[i] );
            }
            else
                  printf( "   %2d  %3d/%3d   ",
                        i, depth[i], choices[i] );

            if(table)
            {
                  for( j = depth[i]; j < k + depth[i]; j++ )
                  {
                        if( j >= 256 ) break;

                        if( opt.l33t )
                              printf( "\33[1m%02X\33[22m(%4d) ",
                                    table[i][j].b,
                                    table[i][j].votes );
                        else
                              printf( "%02X(%4d) ",  table[i][j].b,
                                    table[i][j].votes );
                  }
            }
            else
            {
                  for( j = wep.depth[i]; j < k + wep.depth[i]; j++ )
                  {
                        if( j >= 256 ) break;

                        if( wep.poll[i][j].val == 32767 )
                        {
                              if( opt.l33t )
                                    printf( "\33[1m%02X\33[22m(+inf) ",
                                          wep.poll[i][j].idx );
                              else
                                    printf( "%02X(+inf) ", wep.poll[i][j].idx );
                        }
                        else
                        {
                              if( opt.l33t )
                                    printf( "\33[1m%02X\33[22m(%4d) ",
                                          wep.poll[i][j].idx,
                                          wep.poll[i][j].val );
                              else
                                    printf( "%02X(%4d) ",  wep.poll[i][j].idx,
                                          wep.poll[i][j].val );
                        }
                  }
            }
            if (opt.showASCII && !table)
                  if(wep.poll[i][wep.depth[i]].idx>=ASCII_LOW_T && wep.poll[i][wep.depth[i]].idx<=ASCII_HIGH_T)
                        if(wep.poll[i][wep.depth[i]].val>=ASCII_VOTE_STRENGTH_T || ASCII_DISREGARD_STRENGTH )
                              printf( "  %c",wep.poll[i][wep.depth[i]].idx );

            printf( "\n" );
      }

      if( B < opt.keylen - 1 )
            printf( "\33[J" );

      printf( "\n" );
}

static void key_found(unsigned char *wepkey, int keylen, int B)
{
      FILE * keyFile;
      int i, n;
      int nb_ascii = 0;

      for( i = 0; i < keylen; i++ )
            if( wepkey[i] == 0 ||
            ( wepkey[i] >= 32 && wepkey[i] < 127 ) )
                  nb_ascii++;

      wepkey_crack_success = 1;
      memcpy(bf_wepkey, wepkey, keylen);

      if( opt.is_quiet )
            printf( "KEY FOUND! [ " );
      else
      {
            if (B != -1)
                  show_wep_stats( B - 1, 1, NULL, NULL, NULL, 0 );

            if( opt.l33t )
                  printf( "\33[31;1m" );

            n = ( 80 - 14 - keylen * 3 ) / 2;

            if( 100 * nb_ascii > 75 * keylen )
                  n -= ( keylen + 4 ) / 2;

            if( n <= 0 ) n = 0;

            printf( "\33[K\33[%dCKEY FOUND! [ ", n );
      }

      for( i = 0; i < keylen - 1; i++ )
            printf( "%02X:", wepkey[i] );
      printf( "%02X ] ",   wepkey[i] );

      if( nb_ascii == keylen )
      {
            printf( "(ASCII: " );

            for( i = 0; i < keylen; i++ )
                  printf( "%c", ( ( wepkey[i] >  31 && wepkey[i] < 127 ) ||
                        wepkey[i] > 160 ) ? wepkey[i] : '.' );

            printf( " )" );
      }

      if( opt.l33t )
            printf( "\33[32;22m" );

      printf( "\n\tDecrypted correctly: %d%%\n", opt.probability );
      printf( "\n" );

      // Write the key to a file
      if (opt.logKeyToFile != NULL) {
            keyFile = fopen(opt.logKeyToFile, "w");
            if (keyFile != NULL)
            {
                  for( i = 0; i < keylen; i++ )
                        fprintf(keyFile, "%02X", wepkey[i]);
                  fclose(keyFile);
            }
      }
}

/* test if the current WEP key is valid */

int check_wep_key( uchar *wepkey, int B, int keylen )
{
      uchar x1, x2;
      unsigned long xv;
      int i, j, n, bad, tests;

      uchar K[64];
      uchar S[256];

      if (keylen<=0)
            keylen = opt.keylen;

      nb_tried++;
      bad = 0;

      memcpy( K + 3, wepkey, keylen );

      tests = 32;

//    printf("keylen: %d\n", keylen);
//    if(keylen==13)
//          printf("%02X:%02X:%02X:%02X:%02X\n", wepkey[8],wepkey[9],wepkey[10],wepkey[11],wepkey[12]);

      if(opt.dict) tests = wep.nb_ivs;

      if(tests < TEST_MIN_IVS) tests=TEST_MIN_IVS;
      if(tests > TEST_MAX_IVS) tests=TEST_MAX_IVS;

      for( n = 0; n < tests; n++ )
      {
            /* xv = 5 * ( rand() % wep.nb_ivs ); */
            xv = 5 * n;

            pthread_mutex_lock( &mx_ivb );

            memcpy( K, &wep.ivbuf[xv], 3 );
            memcpy( S, R, 256 );

            for( i = j = 0; i < 256; i++ )
            {
                  j = ( j + S[i] + K[i % (3 + keylen)]) & 0xFF;
                  SWAP( S[i], S[j] );
            }

            i = 1; j = ( 0 + S[i] ) & 0xFF; SWAP(S[i], S[j]);
            x1 = wep.ivbuf[xv + 3] ^ S[(S[i] + S[j]) & 0xFF];

            i = 2; j = ( j + S[i] ) & 0xFF; SWAP(S[i], S[j]);
            x2 = wep.ivbuf[xv + 4] ^ S[(S[i] + S[j]) & 0xFF];

            pthread_mutex_unlock( &mx_ivb );

//          printf("xv: %li x1: %02X  x2: %02X\n", (xv/5), x1, x2);

            if( ( x1 != 0xAA || x2 != 0xAA ) &&
                  ( x1 != 0xE0 || x2 != 0xE0 ) &&
                  ( x1 != 0x42 || x2 != 0x42 ) &&
                  ( x1 != 0x02 || x2 != 0xAA ) )                              //llc sub layer management
                  bad++;

            if( bad > ((tests*opt.probability)/100) )
                  return( FAILURE );
      }

      opt.probability = (((tests-bad)*100)/tests);
      key_found(wepkey, keylen, B);

      return( SUCCESS );
}

/* routine used to sort the votes */

int cmp_votes( const void *bs1, const void *bs2 )
{
      if( ((vote *) bs1)->val < ((vote *) bs2)->val )
            return(  1 );

      if( ((vote *) bs1)->val > ((vote *) bs2)->val )
            return( -1 );

      return( 0 );
}

/* sum up the votes and sort them */

int calc_poll( int B )
{
      int i, n, cid, *vi;
      int votes[N_ATTACKS][256];

      memset(&opt.votes, '\0', sizeof(opt.votes));

      /* send the current keybyte # to each thread */

      for( cid = 0; cid < opt.nbcpu; cid++ )
      {
            n = sizeof( int );

            if( safe_write( mc_pipe[cid][1], &B, n ) != n )
            {
                  perror( "write failed" );
                  kill( 0, SIGTERM );
                  _exit( FAILURE );
            }
      }

      /* collect the votes, multiply by the korek coeffs */

      for( i = 0; i < 256; i++ )
      {
            wep.poll[B][i].idx = i;
            wep.poll[B][i].val = 0;
      }

      for( cid = 0; cid < opt.nbcpu; cid++ )
      {
            n = sizeof( votes );

            if( safe_read( cm_pipe[cid][0], votes, n ) != n )
            {
                  perror( "read failed" );
                  kill( 0, SIGTERM );
                  _exit( FAILURE );
            }

            for( n = 0, vi = (int *) votes; n < N_ATTACKS; n++ )
                  for( i = 0; i < 256; i++, vi++ )
                  {
                        wep.poll[B][i].val += *vi * K_COEFF[n];
                        if(K_COEFF[n]) opt.votes[n] += *vi;
                  }
      }

      /* set votes to the max if the keybyte is user-defined */

      if( opt.debug_row[B] )
            wep.poll[B][opt.debug[B]].val = 32767;

      /* if option is set, restrict keyspace to alpha-numeric */

      if( opt.is_alnum )
      {
            for( i = 1; i < 32; i++ )
                  wep.poll[B][i].val = -1;

            for( i = 127; i < 256; i++ )
                  wep.poll[B][i].val = -1;
      }

      if( opt.is_fritz )
      {
            for( i = 0; i < 48; i++ )
                  wep.poll[B][i].val = -1;

            for( i = 58; i < 256; i++ )
                  wep.poll[B][i].val = -1;
      }

      /* if option is set, restrict keyspace to BCD hex digits */

      if( opt.is_bcdonly )
      {
            for( i = 1; i < 256; i++ )
                  if( i > 0x99 || ( i & 0x0F ) > 0x09 )
                        wep.poll[B][i].val = -1;
      }

      /* sort the votes, highest ones first */

      qsort( wep.poll[B], 256, sizeof( vote ), cmp_votes );

      return( SUCCESS );
}

int update_ivbuf( void )
{
      int n;
      struct AP_info *ap_cur;

      /* 1st pass: compute the total number of available IVs */

      wep.nb_ivs_now = 0;
      wep.nb_aps = 0;
      ap_cur = ap_1st;

      while( ap_cur != NULL )
      {
            if( ap_cur->crypt == 2 && ap_cur->target )
            {
                  wep.nb_ivs_now += ap_cur->nb_ivs;
                  wep.nb_aps++;
            }

            ap_cur = ap_cur->next;
      }

      /* 2nd pass: create the main IVs buffer if necessary */

      if( wep.nb_ivs == 0 ||
            ( opt.keylen ==  5 && wep.nb_ivs_now - wep.nb_ivs > 20000 ) ||
            ( opt.keylen >= 13 && wep.nb_ivs_now - wep.nb_ivs > 40000 ) )
      {
            /* one buffer to rule them all */

            pthread_mutex_lock( &mx_ivb );

            if( wep.ivbuf != NULL )
            {
                  free( wep.ivbuf );
                  wep.ivbuf = NULL;
            }

            wep.nb_ivs = 0;

            ap_cur = ap_1st;

            while( ap_cur != NULL )
            {
                  if( ap_cur->crypt == 2 && ap_cur->target )
                  {
                        n = ap_cur->nb_ivs;

                        if( ( wep.ivbuf = realloc( wep.ivbuf,
                              ( wep.nb_ivs + n ) * 5 ) ) == NULL )
                        {
                              pthread_mutex_unlock( &mx_ivb );
                              perror( "realloc failed" );
                              kill( 0, SIGTERM );
                              _exit( FAILURE );
                        }

                        memcpy( wep.ivbuf + wep.nb_ivs * 5, ap_cur->ivbuf, 5 * n );

                        wep.nb_ivs += n;
                  }

                  ap_cur = ap_cur->next;
            }

            pthread_mutex_unlock( &mx_ivb );

            return( RESTART );
      }

      return( SUCCESS );
}

/*
 * It will remove votes for a specific keybyte (and remove from the requested current value)
 * Return 0 on success, another value on failure
 */
int remove_votes(int keybyte, unsigned char value)
{
      int i;
      int found = 0;
      for (i=0; i < 256; i++)
      {
            if (wep.poll[keybyte][i].idx == (int)value)
            {
                  found = 1;
                  //wep.poll[keybyte][i].val = 0;
                  // Update wep.key
            }
            if (found)
            {
                  // Put the value at the end with NO votes
                  if (i== 255)
                  {
                        wep.poll[keybyte][i].idx = (int)value;
                        wep.poll[keybyte][i].val = 0;
                  }
                  else
                  {
                        wep.poll[keybyte][i].idx = wep.poll[keybyte][i + 1].idx;
                        wep.poll[keybyte][i].val = wep.poll[keybyte][i + 1].val;
                        if (i == 0)
                        {
                              // Also update wep key if it's the first value to remove
                              wep.key[keybyte] = wep.poll[keybyte][i].idx;
                        }
                  }
            }
      }
      return 0;
}

/* standard attack mode: */
/* this routine gathers and sorts the votes, then recurses until it *
 * reaches B == keylen. It also stops when the current keybyte vote *
 * is lower than the highest vote divided by the fudge factor.      */

int do_wep_crack1( int B )
{
      int i, j, l, m, tsel, charread, askchange;
      int remove_keybyte_nr, remove_keybyte_value;
      //int a,b;
      static int k = 0;
      char user_guess[4];

      askchange = 1;

      get_ivs:

      switch( update_ivbuf() )
      {
            case FAILURE: return( FAILURE );
            case RESTART: return( RESTART );
            default: break;
      }

      if( ( wep.nb_ivs_now < 256 && opt.debug[0] == 0 ) ||
            ( wep.nb_ivs_now <  32 && opt.debug[0] != 0 ) )
      {
            if( ! opt.no_stdin )
            {
                  printf(
                        "Not enough IVs available. You need about 250.000 IVs to crack\n"
                        "40-bit WEP, and more than 800.000 IVs to crack a 104-bit key.\n" );
                  kill( 0, SIGTERM );
                  _exit( FAILURE );
            }
            else
            {
                  printf( "Read %ld packets, got %ld IVs...\r",
                        nb_pkt, wep.nb_ivs_now );
                  fflush( stdout );

                  sleep( 1 );
                  goto get_ivs;
            }
      }

      /* if last keybyte reached, check if the key is valid */

      if( B == opt.keylen )
      {
            if( ! opt.is_quiet )
                  show_wep_stats( B - 1, 0, NULL, NULL, NULL, 0 );

            return( check_wep_key( wep.key, B, 0 ) );
      }

      /* now compute the poll resultst for keybyte B */

      if( calc_poll( B ) != SUCCESS )
            return( FAILURE );

      /* fudge threshold = higest vote divided by fudge factor */

      for( wep.fudge[B] = 1; wep.fudge[B] < 256; wep.fudge[B]++ )
            if( (float) wep.poll[B][wep.fudge[B]].val <
            (float) wep.poll[B][0].val / opt.ffact )
                  break;

      /* try the most likely n votes, where n is the fudge threshold */

      for( wep.depth[B] = 0; wep.depth[B] < wep.fudge[B]; ( wep.depth[B] )++ )
      {
            switch( update_ivbuf() )
            {
                  case FAILURE: return( FAILURE );
                  case RESTART: return( RESTART );
                  default: break;
            }

            wep.key[B] = wep.poll[B][wep.depth[B]].idx;

            if( ! opt.is_quiet )
            {
                  show_wep_stats( B, 0, NULL, NULL, NULL, 0 );
            }

            if( B == 4 && opt.keylen == 13 )
            {
                  /* even when cracking 104-bit WEP, *
                   * check if the 40-bit key matches */

                  /* opt.keylen = 5; many functions use keylen. it is dangerous to do this in a multithreaded process */

                  if( check_wep_key( wep.key, B, 5 ) == SUCCESS )
                  {
                        opt.keylen = 5;
                        return( SUCCESS );
                  }

                  /* opt.keylen = 13; */
            }



            if( B + opt.do_brute + 1 == opt.keylen && opt.do_brute )
            {
                  /* as noted by Simon Marechal, it's more efficient
                   * to just bruteforce the last two keybytes. */

                  /*
                        Ask for removing votes here
                        1. Input keybyte. Use enter when it's done => Bruteforce will start
                        2. Input value to remove votes from: 00 -> FF or Enter to cancel remove
                        3. Remove votes
                        4. Redraw
                        5. Go back to 1
                  */
                  if (opt.visual_inspection == 1)
                  {
                        while(1)
                        {
                              // Show the current stat
                              show_wep_stats( B, 1, NULL, NULL, NULL, 0 );

                              // Inputting user value until it hits enter or give a valid value
                              printf("On which keybyte do you want to remove votes (Hit Enter when done)? ");
                              memset(user_guess, 0, 4);

                              charread = readLine(user_guess, 3);

                              // Break if 'Enter' key was hit
                              if (user_guess[0] == 0 || charread == 0)
                                    break;

                              // If it's not a number, reask
                              // Check if inputted value is correct (from 0 to and inferior to opt.keylen)
                              remove_keybyte_nr = atoi(user_guess);
                              if (isdigit((int)user_guess[0]) == 0 || remove_keybyte_nr < 0 || remove_keybyte_nr >= opt.keylen)
                                    continue;


                              // It's a number for sure and the number is correct
                              // Now ask which value should be removed
                              printf("From which keybyte value do you want to remove the votes (Hit Enter to cancel)? ");
                              memset(user_guess, 0, 4);
                              charread = readLine(user_guess, 3);

                              // Break if enter was hit
                              if (user_guess[0] == 0 || charread == 0)
                                    continue;

                              remove_keybyte_value = hexToInt(user_guess, charread);

                              // Check if inputted value is correct (hexa). Value range: 00 - FF
                              if (remove_keybyte_value < 0 || remove_keybyte_value > 255)
                                    continue;

                              // If correct, remove and redraw
                              remove_votes(remove_keybyte_nr, (unsigned char)remove_keybyte_value);
                        }
                  }
                  if (opt.nbcpu==1 || opt.do_mt_brute==0)
                  {

                        if (opt.do_brute==4)
                        {
                              for( l = 0; l < 256; l++)
                              {
                                    wep.key[opt.brutebytes[0]] = l;

                                    for( m = 0; m < 256; m++ )
                                    {
                                          wep.key[opt.brutebytes[1]] = m;

                                          for( i = 0; i < 256; i++ )
                                          {
                                                wep.key[opt.brutebytes[2]] = i;

                                                for( j = 0; j < 256; j++ )
                                                {
                                                      wep.key[opt.brutebytes[3]] = j;

                                                      if (check_wep_key( wep.key, B + 1, 0 ) == SUCCESS)
                                                            return SUCCESS;
                                                }
                                          }
                                    }
                              }
                        }
                        else if (opt.do_brute==3)
                        {
                              for( m = 0; m < 256; m++ )
                              {
                                    wep.key[opt.brutebytes[0]] = m;

                                    for( i = 0; i < 256; i++ )
                                    {
                                          wep.key[opt.brutebytes[1]] = i;

                                          for( j = 0; j < 256; j++ )
                                          {
                                                wep.key[opt.brutebytes[2]] = j;

                                                if (check_wep_key( wep.key, B + 1, 0 ) == SUCCESS)
                                                      return SUCCESS;
                                          }
                                    }
                              }
                        }
                        else if (opt.do_brute==2)
                        {
                              for( i = 0; i < 256; i++ )
                              {
                                    wep.key[opt.brutebytes[0]] = i;

                                    for( j = 0; j < 256; j++ )
                                    {
                                          wep.key[opt.brutebytes[1]] = j;

                                          if (check_wep_key( wep.key, B + 1, 0 ) == SUCCESS)
                                                return SUCCESS;
                                    }
                              }
                        }
                        else
                        {
                              for( i = 0; i < 256; i++ )
                              {
                                    wep.key[opt.brutebytes[0]] = i;

                                    if (check_wep_key( wep.key, B + 1, 0 ) == SUCCESS)
                                          return SUCCESS;
                              }
                        }
                  }
                  else
                  {
                        /* multithreaded bruteforcing of the last 2 keybytes */
                        k = (k+1) % opt.nbcpu;
                        do
                        {
                              for(tsel=0; tsel<opt.nbcpu && !wepkey_crack_success; ++tsel)
                              {
                                    if (bf_nkeys[(tsel+k) % opt.nbcpu]>16)
                                    {
                                          usleep(1);
                                          continue;
                                    }
                                    else
                                    {
                                          /* write our current key to the pipe so it'll have its last 2 bytes bruteforced */
                                          bf_nkeys[(tsel+k) % opt.nbcpu]++;

                                          if (safe_write(bf_pipe[(tsel+k) % opt.nbcpu][1], (void *) wep.key, 64) != 64)
                                          {
                                                perror( "write pmk failed" );
                                                kill( 0, SIGTERM );
                                                _exit( FAILURE );
                                          }
                                          break;
                                    }
                              }
                        } while (tsel>=opt.nbcpu && !wepkey_crack_success);

                        if (wepkey_crack_success)
                        {
                              memcpy(wep.key, bf_wepkey, opt.keylen);
                              return(SUCCESS);
                        }
                  }
            }
            else
            {
                  switch( do_wep_crack1( B + 1 ) )
                  {
                        case SUCCESS: return( SUCCESS );
                        case RESTART: return( RESTART );
                        default: break;
                  }
            }
      }

      //if we are going to fail on the root byte, check again if there are still threads bruting, if so wait and check again.
      if(B==0)
      {
            for(i=0; i<opt.nbcpu; i++)
            {
                  while(bf_nkeys[i]>0 && !wepkey_crack_success) usleep(1);
            }
            if (wepkey_crack_success)
            {
                  memcpy(wep.key, bf_wepkey, opt.keylen);
                  return(SUCCESS);
            }
      }
      return( FAILURE );
}

/* experimental single bruteforce attack */

int do_wep_crack2( int B )
{
      int i, j;

      switch( update_ivbuf() )
      {
            case FAILURE: return( FAILURE );
            case RESTART: return( RESTART );
            default: break;
      }

      if( wep.nb_ivs_now / opt.keylen < 60000 )
      {
            printf(
                  "Not enough IVs available. This option is only meant to be used\n"
                  "if the standard attack method fails with more than %d IVs.\n",
                  opt.keylen * 60000 );
            kill( 0, SIGTERM );
            _exit( FAILURE );
      }

      for( i = 0; i <= B; i++ )
      {
            if( calc_poll( i ) != SUCCESS )
                  return( FAILURE );

            wep.key[i] = wep.poll[i][0].idx;

            wep.fudge[i] = 1;
            wep.depth[i] = 0;

            if( ! opt.is_quiet )
                  show_wep_stats( i, 0, NULL, NULL, NULL, 0 );
      }

      for( wep.fudge[B] = 1; wep.fudge[B] < 256; wep.fudge[B]++ )
            if( (float) wep.poll[B][wep.fudge[B]].val <
            (float) wep.poll[B][0].val / opt.ffact )
                  break;

      for( wep.depth[B] = 0; wep.depth[B] < wep.fudge[B]; wep.depth[B]++ )
      {
            switch( update_ivbuf() )
            {
                  case FAILURE: return( FAILURE );
                  case RESTART: return( RESTART );
                  default: break;
            }

            wep.key[B] = wep.poll[B][wep.depth[B]].idx;

            if( ! opt.is_quiet )
                  show_wep_stats( B, 0, NULL, NULL, NULL, 0 );

            for( i = B + 1; i < opt.keylen - 2; i++ )
            {
                  if( calc_poll( i ) != SUCCESS )
                        return( FAILURE );

                  wep.key[i] = wep.poll[i][0].idx;

                  wep.fudge[i] = 1;
                  wep.depth[i] = 0;

                  if( ! opt.is_quiet )
                        show_wep_stats( i, 0, NULL, NULL, NULL, 0 );
            }

            for( i = 0; i < 256; i++ )
            {
                  wep.key[opt.keylen - 2] = i;

                  for( j = 0; j < 256; j++ )
                  {
                        wep.key[opt.keylen - 1] = j;

                        if( check_wep_key( wep.key, opt.keylen - 2, 0 ) == SUCCESS )
                              return( SUCCESS );
                  }
            }
      }

      return( FAILURE );
}

int inner_bruteforcer_thread(void *arg)
{
      int i, j, k, l, reduce=0;
      size_t nthread = (size_t)arg;
      uchar wepkey[64];
      int ret=0;

      inner_bruteforcer_thread_start:

      reduce=0;

      if( close_aircrack )
            return(ret);

      if (wepkey_crack_success)
            return(SUCCESS);

      /* we get the key for which we'll bruteforce the last 2 bytes from the pipe */
      if( safe_read( bf_pipe[nthread][0], (void *) wepkey, 64) != 64)
      {
            perror( "read failed" );
            kill( 0, SIGTERM );
            _exit( FAILURE );
      }
      else
            reduce=1;

      if( close_aircrack )
            return(ret);
      /* now we test the 256*256 keys... if we succeed we'll save it and exit the thread */
      if (opt.do_brute==4)
      {
            for( l = 0; l < 256; l++ )
            {
                  wepkey[opt.brutebytes[0]] = l;

                  for( k = 0; k < 256; k++ )
                  {
                        wepkey[opt.brutebytes[1]] = k;

                        for( i = 0; i < 256; i++ )
                        {
                              wepkey[opt.brutebytes[2]] = i;

                              for( j = 0; j < 256; j++ )
                              {
                                    wepkey[opt.brutebytes[3]] = j;

                                    if( check_wep_key( wepkey, opt.keylen - 2, 0 ) == SUCCESS )
                                          return(SUCCESS);
                              }
                        }
                  }
            }
      }
      else if (opt.do_brute==3)
      {
            for( k = 0; k < 256; k++ )
            {
                  wepkey[opt.brutebytes[0]] = k;

                  for( i = 0; i < 256; i++ )
                  {
                        wepkey[opt.brutebytes[1]] = i;

                        for( j = 0; j < 256; j++ )
                        {
                              wepkey[opt.brutebytes[2]] = j;

                              if( check_wep_key( wepkey, opt.keylen - 2, 0 ) == SUCCESS )
                                    return(SUCCESS);
                        }
                  }
            }
      }
      else if (opt.do_brute==2)
      {
            for( i = 0; i < 256; i++ )
            {
                  wepkey[opt.brutebytes[0]] = i;

                  for( j = 0; j < 256; j++ )
                  {
                        wepkey[opt.brutebytes[1]] = j;

                        if( check_wep_key( wepkey, opt.keylen - 2, 0 ) == SUCCESS )
                              return(SUCCESS);
                  }
            }
      }
      else
      {
            for( j = 0; j < 256; j++ )
            {
                  wepkey[opt.brutebytes[0]] = j;

                  if( check_wep_key( wepkey, opt.keylen - 2, 0 ) == SUCCESS )
                        return(SUCCESS);
            }
      }

      if(reduce)
            bf_nkeys[nthread]--;

      goto inner_bruteforcer_thread_start;

}


/* display the current wpa key info, matrix-like */

void show_wpa_stats( char *key, int keylen, uchar pmk[32], uchar ptk[64],
uchar mic[16], int force )
{
      float delta;
      int i, et_h, et_m, et_s;
      char tmpbuf[28];

      if (chrono( &t_stats, 0 ) < 0.15 && force == 0)
            return;

      if (force != 0)
            pthread_mutex_lock(&mx_wpastats);  // if forced, wait until we can lock
      else
            if (pthread_mutex_trylock(&mx_wpastats) != 0)  // if not forced, just try
                  return;

      chrono( &t_stats, 1 );

      delta = chrono( &t_begin, 0 );

      et_h =   delta / 3600;
      et_m = ( delta - et_h * 3600 ) / 60;
      et_s =   delta - et_h * 3600 - et_m * 60;

      if( ( delta = chrono( &t_kprev, 0 ) ) >= 6 )
      {
            int delta0;
            delta0 = delta;

            t_kprev.tv_sec += 3;
            delta = chrono( &t_kprev, 0 );
            nb_kprev *= delta / delta0;

      }

      if( opt.l33t ) printf( "\33[33;1m" );
      printf( "\33[5;20H[%02d:%02d:%02d] %lld keys tested "
            "(%2.2f k/s)", et_h, et_m, et_s,
            nb_tried, (float) nb_kprev / delta);

      memset( tmpbuf, ' ', sizeof( tmpbuf ) );
      memcpy( tmpbuf, key, keylen > 27 ? 27 : keylen );
      tmpbuf[27] = '\0';

      if( opt.l33t ) printf( "\33[37;1m" );
      printf( "\33[8;24HCurrent passphrase: %s\n", tmpbuf );

      if( opt.l33t ) printf( "\33[32;22m" );
      printf( "\33[11;7HMaster Key     : " );

      if( opt.l33t ) printf( "\33[32;1m" );
      for( i = 0; i < 32; i++ )
      {
            if( i == 16 ) printf( "\n\33[23C" );
            printf( "%02X ", pmk[i] );
      }

      if( opt.l33t ) printf( "\33[32;22m" );
      printf( "\33[14;7HTransient Key  : " );

      if( opt.l33t ) printf( "\33[32;1m" );
      for( i = 0; i < 64; i++ )
      {
            if( i > 0 && i % 16 == 0 ) printf( "\n\33[23C" );
            printf( "%02X ", ptk[i] );
      }

      if( opt.l33t ) printf( "\33[32;22m" );
      printf( "\33[19;7HEAPOL HMAC     : " );

      if( opt.l33t ) printf( "\33[32;1m" );
      for( i = 0; i < 16; i++ )
            printf( "%02X ", mic[i] );

      printf( "\n" );

      pthread_mutex_unlock(&mx_wpastats);
}


int crack_wpa_thread( void *arg )
{
      FILE * keyFile;
      char  essid[36];
      char  key[4][128];
      uchar pmk[4][128];

      uchar pke[100];
      uchar ptk[4][80];
      uchar mic[4][20];

      struct WPA_data* data;
      struct AP_info* ap;
      int thread;
      int ret=0;
      int i, j, len, slen;
      int nparallel = 1;

#if defined(__i386__) || defined(__x86_64__)
      // Check for SSE2, with SSE2 the algorithm works with 4 keys
      if (shasse2_cpuid()>=2)
            nparallel = 4;
#endif

      data = (struct WPA_data*)arg;
      ap = data->ap;
      thread = data->thread;
      strncpy(essid, ap->essid, 36);

      /* pre-compute the key expansion buffer */
      memcpy( pke, "Pairwise key expansion", 23 );
      if( memcmp( ap->wpa.stmac, ap->bssid, 6 ) < 0 ) {
            memcpy( pke + 23, ap->wpa.stmac, 6 );
            memcpy( pke + 29, ap->bssid, 6 );
      } else {
            memcpy( pke + 23, ap->bssid, 6 );
            memcpy( pke + 29, ap->wpa.stmac, 6 );
      }
      if( memcmp( ap->wpa.snonce, ap->wpa.anonce, 32 ) < 0 ) {
            memcpy( pke + 35, ap->wpa.snonce, 32 );
            memcpy( pke + 67, ap->wpa.anonce, 32 );
      } else {
            memcpy( pke + 35, ap->wpa.anonce, 32 );
            memcpy( pke + 67, ap->wpa.snonce, 32 );
      }

      /* receive the essid */

      slen = strlen(essid) + 4;

      while( 1 )
      {
            if (close_aircrack)
                  pthread_exit(&ret);

            /* receive passphrases */

            for(j=0; j<nparallel; ++j)
            {
                  key[j][0]=0;

                  while(wpa_receive_passphrase(key[j], data)==0)
                  {
                        if (wpa_wordlists_done==1) // if no more words will arrive and...
                        {
                              if (j==0) // ...this is the first key in this loop: there's nothing else to do
                                    return 0;
                              else    // ...we have some key pending in this loop: keep working
                                    break;
                        }

                        sched_yield(); // yield the processor until there are keys available
                        // this only happens when the queue is empty (when beginning and ending the wordlist)
                  }

                  key[j][127]=0;
            }


            // PMK calculation
            if (nparallel==4)
                  calc_4pmk(key[0], key[1], key[2], key[3], essid, pmk[0], pmk[1], pmk[2], pmk[3]);
            else
                  for(j=0; j<nparallel; ++j)
                        calc_pmk( key[j], essid, pmk[j] );

            for(j=0; j<nparallel; ++j)
            {
                  /* compute the pairwise transient key and the frame MIC */

                  for (i = 0; i < 4; i++)
                  {
                        pke[99] = i;
                        HMAC(EVP_sha1(), pmk[j], 32, pke, 100, ptk[j] + i * 20, NULL);
                  }

                  if (ap->wpa.keyver == 1)
                        HMAC(EVP_md5(), ptk[j], 16, ap->wpa.eapol, ap->wpa.eapol_size, mic[j], NULL);
                  else
                        HMAC(EVP_sha1(), ptk[j], 16, ap->wpa.eapol, ap->wpa.eapol_size, mic[j], NULL);

                  if (memcmp( mic[j], ap->wpa.keymic, 16 ) == 0)
                  {
                        // to stop do_wpa_crack, we close the dictionary
                        if(opt.dict != NULL)
                        {
                              if (!opt.stdin_dict) fclose(opt.dict);
                              opt.dict = NULL;
                        }

                        for( i = 0; i < opt.nbcpu; i++ )
                        {
                              // we make sure do_wpa_crack doesn't block before exiting,
                              // now that we're not consuming passphrases here any longer
                              pthread_mutex_lock(&wpa_data[i].mutex);
                              pthread_cond_signal(&wpa_data[i].cond);
                              pthread_mutex_unlock(&wpa_data[i].mutex);
                        }

                        memcpy(data->key, key[j], sizeof(data->key));

                        if (opt.is_quiet)
                              return SUCCESS;

                        pthread_mutex_lock(&mx_nb);
                        nb_tried += 4;
                        nb_kprev += 4;
                        pthread_mutex_unlock(&mx_nb);

                        len = strlen(key[j]);
                        if (len > 64 ) len = 64;
                        if (len < 8) len = 8;
                        show_wpa_stats( key[j], len, pmk[j], ptk[j], mic[j], 1 );

                        if (opt.l33t)
                              printf( "\33[31;1m" );

                        printf("\33[8;%dH\33[2KKEY FOUND! [ %s ]\33[11B\n",
                              ( 80 - 15 - (int) len ) / 2, key[j] );

                        if (opt.l33t)
                              printf( "\33[32;22m" );

                        // Write the key to a file
                        if (opt.logKeyToFile != NULL) {
                              keyFile = fopen(opt.logKeyToFile, "w");
                              if (keyFile != NULL)
                              {
                                    fprintf(keyFile, "%s", key[j]);
                                    fclose(keyFile);
                              }
                        }

                        return SUCCESS;
                  }
            }

            pthread_mutex_lock(&mx_nb);
            nb_tried += 4;
            nb_kprev += 4;
            pthread_mutex_unlock(&mx_nb);

            if (!opt.is_quiet)
            {
                  len = strlen(key[0]);
                  if (len > 64 ) len = 64;
                  if (len < 8) len = 8;

                  show_wpa_stats(key[0], len, pmk[0], ptk[0], mic[0], 0);
            }
      }
}

/**
 * Open a specific dictionnary
 * nb: index of the dictionnary
 * return 0 on success and FAILURE if it failed
 */
int next_dict(int nb)
{
      if(opt.dict != NULL)
      {
            if(!opt.stdin_dict) fclose(opt.dict);
            opt.dict = NULL;
      }
      opt.nbdict = nb;
      if(opt.dicts[opt.nbdict] == NULL)
            return( FAILURE );

      while(opt.nbdict < MAX_DICTS && opt.dicts[opt.nbdict] != NULL)
      {
            if( strcmp( opt.dicts[opt.nbdict], "-" ) == 0 )
            {
                  opt.stdin_dict = 1;

                  if( ( opt.dict = fdopen( fileno(stdin) , "r" ) ) == NULL )
                  {
                        perror( "fopen(dictionary) failed" );
                        opt.nbdict++;
                        continue;
                  }

                  opt.no_stdin = 1;
            }
            else
            {
                  opt.stdin_dict = 0;
                  if( ( opt.dict = fopen( opt.dicts[opt.nbdict], "r" ) ) == NULL )
                  {
                        perror( "fopen(dictionary) failed" );
                        opt.nbdict++;
                        continue;
                  }

                  fseek(opt.dict, 0L, SEEK_END);

                  if ( ftell( opt.dict ) <= 0L )
                  {
                        fclose( opt.dict );
                        opt.dict = NULL;
                        printf( "Empty dictionary\n" );
                        opt.nbdict++;
                        continue;
                  }

                  rewind( opt.dict );
            }
            break;
      }

      if(opt.nbdict >= MAX_DICTS || opt.dicts[opt.nbdict] == NULL)
          return( FAILURE );

      return( 0 );
}

#ifdef HAVE_SQLITE
int sql_wpacallback(void* arg, int ccount, char** values, char** columnnames ) {
      struct AP_info *ap = (struct AP_info*)arg;

      unsigned char ptk[80];
      unsigned char mic[20];
      FILE * keyFile;

      if(ccount) {} //XXX
      if(columnnames) {} //XXX

      calc_mic(ap, (unsigned char*) values[0], ptk, mic);

      if( memcmp( mic, ap->wpa.keymic, 16 ) == 0 )
      {
            // Write the key to a file
            if (opt.logKeyToFile != NULL) {
                  keyFile = fopen(opt.logKeyToFile, "w");
                  if (keyFile != NULL)
                  {
                        fprintf(keyFile, "%s", values[1]);
                        fclose(keyFile);
                  }
            }

            if( opt.is_quiet )
            {
                  printf( "KEY FOUND! [ %s ]\n", values[1] );
                  return 1;
            }

            show_wpa_stats( values[1], strlen(values[1]), (unsigned char*)(values[0]), ptk, mic, 1 );

            if( opt.l33t )
                  printf( "\33[31;1m" );

            printf( "\33[8;%dH\33[2KKEY FOUND! [ %s ]\33[11B\n",
                        ( 80 - 15 - (int) strlen(values[1])) / 2, values[1] );

            if( opt.l33t )
                  printf( "\33[32;22m" );

            // abort the query
            return 1;
      }

      nb_tried++;
      nb_kprev++;

      if( ! opt.is_quiet )
            show_wpa_stats( values[1], strlen(values[1]), (unsigned char*)(values[0]), ptk, mic, 0 );

      return 0;
}
#endif



int do_wpa_crack()
{
      int i, j, cid, num_cpus, res;
      char key1[128];

    i = 0;
      res = 0;
      opt.amode = 2;
      num_cpus = opt.nbcpu;


      if( ! opt.is_quiet )
      {
            if( opt.l33t )
                  printf( "\33[37;40m" );

            printf( "\33[2J" );

            if( opt.l33t )
                  printf( "\33[34;1m" );

            printf("\33[2;34H%s",progname);
      }

      cid = 0;
      while( num_cpus > 0 )
      {
            /* read a couple of keys (skip those < 8 chars) */

            if(opt.dict == NULL)
                  return( FAILURE );

            do
            {
                  memset(key1, 0, sizeof(key1));
                  if (fgets(key1, sizeof(key1), opt.dict) == NULL)
                  {
                        if( opt.l33t )
                              printf( "\33[32;22m" );

                        /* printf( "\nPassphrase not in dictionary %s \n", opt.dicts[opt.nbdict] );*/
                        if(next_dict(opt.nbdict+1) != 0)
                        {
                              /* no more words, but we still have to wait for the cracking threads */
                              num_cpus = cid;
                              //goto collect_and_test;
                              return( FAILURE );
                        }
                        else
                              continue;
                  }

                  i = strlen( key1 );
                  if( i < 8 ) continue;
                  if( i > 64 ) i = 64;

                  while(i>0 && (key1[i-1]=='\r' || key1[i-1]=='\n')) i--;
                  if (i==0) continue;
                  key1[i] = '\0';

                  for(j=0; j<i; j++)
                        if(!isascii(key1[j]) || key1[j] < 32) i=0;

            }
            while( i < 8 );

            /* send the keys */

            for(i=0; i<opt.nbcpu; ++i)
            {
                  res = wpa_send_passphrase(key1, &(wpa_data[cid]), 0/*don't block*/);
                  if (res != 0)
                        break;
                  cid = (cid+1) % opt.nbcpu;
            }

            if (res==0) // if all queues are full, we block until there's room
            {
                  wpa_send_passphrase(key1, &(wpa_data[cid]), 1/*block*/);
                  cid = (cid+1) % opt.nbcpu;
            }
      }

      //printf( "\nPassphrase not in dictionary \n" );
      return( FAILURE );
}

int next_key( char **key, int keysize )
{
      char *tmp, *tmp2;
      int i, rtn;
      unsigned int dec;
      char *hex;

      tmp2 = tmp = (char*) malloc(1024);

      while(1)
      {
            rtn = 0;
            tmp = tmp2;
            if(opt.dict == NULL)
            {
                  //printf( "\nPassphrase not in dictionary \n" );
                  free(tmp);
                  tmp = NULL;
                  return( FAILURE );
            }

            if( opt.hexdict[opt.nbdict] )
            {
                  if( fgets( tmp, ((keysize*2)+(keysize-1)), opt.dict ) == NULL )
                  {
                        if( opt.l33t )
                              printf( "\33[32;22m" );

//                      printf( "\nPassphrase not in dictionary \"%s\" \n", opt.dicts[opt.nbdict] );
                        if(next_dict(opt.nbdict+1) != 0)
                        {
                              free(tmp);
                              tmp = NULL;
                              return( FAILURE );
                        }
                        else
                        {
                              continue;
                        }
                  }

                  i=strlen(tmp);

                  if( i <= 2 ) continue;

                  if( tmp[i - 1] == '\n' ) tmp[--i] = '\0';
                  if( tmp[i - 1] == '\r' ) tmp[--i] = '\0';
                  if( i <= 0 ) continue;

                  i=0;

                  hex = strsep(&tmp, ":");

                  while( i<keysize && hex != NULL )
                  {
                        if(strlen(hex) > 2 || strlen(hex) == 0)
                        {
                              rtn = 1;
                              break;
                        }
                        if(sscanf(hex, "%x", &dec) == 0 )
                        {
                              rtn = 1;
                              break;
                        }

                        (*key)[i] = dec;
                        hex = strsep(&tmp, ":");
                        i++;
                  }
                  if(rtn)
                  {
                        continue;
                  }
            }
            else
            {
                  if( fgets( *key, keysize, opt.dict ) == NULL )
                  {
                        if( opt.l33t )
                              printf( "\33[32;22m" );

//                      printf( "\nPassphrase not in dictionary \"%s\" \n", opt.dicts[opt.nbdict] );
                        if(next_dict(opt.nbdict+1) != 0)
                        {
                              free(tmp);
                              tmp = NULL;
                              return( FAILURE );
                        }
                        else
                        {
                              continue;
                        }
                  }

                  i=strlen(*key);

                  if( i <= 2 ) continue;

                  if( (*key)[i - 1] == '\n' ) (*key)[--i] = '\0';
                  if( (*key)[i - 1] == '\r' ) (*key)[--i] = '\0';

                  if( i <= 0 ) continue;
            }

            break;
      }

      free(tmp);
      tmp = NULL;

      return( SUCCESS );
}

int set_dicts(char* optargs)
{
      int len;
      char *optarg;

      opt.nbdict = 0;
      optarg = strsep(&optargs, ",");

      for(len=0; len<MAX_DICTS; len++)
      {
            opt.dicts[len] = NULL;
      }

      while(optarg != NULL && opt.nbdict<MAX_DICTS)
      {
            len = strlen(optarg)+1;
            opt.dicts[opt.nbdict] = (char*)malloc(len * sizeof(char));
            if(opt.dicts[opt.nbdict] == NULL)
            {
                  perror("allocation failed!");
                  return( FAILURE );
            }
            if(strncasecmp(optarg, "h:", 2) == 0)
            {
                  strncpy(opt.dicts[opt.nbdict], optarg+2, len-2);
                  opt.hexdict[opt.nbdict] = 1;
            }
            else
            {
                  strncpy(opt.dicts[opt.nbdict], optarg, len);
                  opt.hexdict[opt.nbdict] = 0;
            }
            optarg = strsep(&optargs, ",");
            opt.nbdict++;
      }

      next_dict(0);

      while(next_dict(opt.nbdict+1) == 0) {}

      next_dict(0);

      return 0;
}

int crack_wep_dict()
{
      struct timeval t_last;
      struct timeval t_now;
      int i, origlen, keysize;
      char *key;

      key = (char*) malloc(sizeof(char) * (opt.keylen + 1));
      keysize = opt.keylen+1;

      update_ivbuf();

      if(wep.nb_ivs < TEST_MIN_IVS)
      {
            printf( "\n%ld IVs is below the minimum required for a dictionnary attack (%d IVs min.)!\n", wep.nb_ivs, TEST_MIN_IVS);
            return( FAILURE );
      }

      gettimeofday( &t_last, NULL );
      t_last.tv_sec--;

      while(1)
      {
            if( next_key( &key, keysize ) != SUCCESS) return( FAILURE );

            i = strlen( key );

            origlen = i;

            while(i<opt.keylen)
            {
                  key[i] = key[i - origlen];
                  i++;
            }

            key[i] = '\0';

            if( ! opt.is_quiet )
            {
                  gettimeofday( &t_now, NULL );
                  if( (t_now.tv_sec - t_last.tv_sec) > 0)
                  {
                        show_wep_stats(opt.keylen - 1, 1, NULL, NULL, NULL, 0);
                        gettimeofday( &t_last, NULL);
                  }
            }

            for(i=0; i<=opt.keylen; i++)
            {
                  wep.key[i] = (uchar)key[i];
            }

            if(check_wep_key(wep.key, opt.keylen, 0) == SUCCESS)
                  return( SUCCESS );
      }
}

static int crack_wep_ptw(struct AP_info *ap_cur)
{
    int (* all)[256];
    int i, j, len = 0;

    opt.ap = ap_cur;

    all = malloc(256*32*sizeof(int));
    if (all == NULL) {
      return FAILURE;
    }

    //initial setup (complete keyspace)
    for (i = 0; i < 32; i++) {
        for (j = 0; j < 256; j++) {
            all[i][j] = 1;
        }
    }

    //setting restricted keyspace
    for (i = 0; i < 32; i++) {
        for (j = 0; j < 256; j++) {
            if( (opt.is_alnum && (j<32 || j>=128) ) ||
                (opt.is_fritz && (j<48 || j>=58)) ||
                (opt.is_bcdonly && ( j > 0x99 || ( j & 0x0F ) > 0x09 )) )
                all[i][j] = 0;
        }
    }

    //if debug is specified, force a specific value.
    for (i=0; i<32; i++) {
        for (j = 0; j < 256; j++) {
            if(opt.debug_row[i] == 1 && opt.debug[i] != j)
                all[i][j] = 0;
            else if(opt.debug_row[i] == 1 && opt.debug[i] == j)
                all[i][j] = 1;
        }
    }

    if(ap_cur->nb_ivs_clean > 99)
    {
        ap_cur->nb_ivs = ap_cur->nb_ivs_clean;
        //first try without bruteforcing, using only "clean" keystreams
        if(opt.keylen != 13)
        {
            if(PTW_computeKey(ap_cur->ptw_clean, wep.key, opt.keylen, (KEYLIMIT*opt.ffact), PTW_DEFAULTBF, all, opt.ptw_attack) == 1)
                len = opt.keylen;
        }
        else
        {
            /* try 1000 40bit keys first, to find the key "instantly" and you don't need to wait for 104bit to fail */
            if(PTW_computeKey(ap_cur->ptw_clean, wep.key, 5, 1000, PTW_DEFAULTBF, all, opt.ptw_attack) == 1)
                len = 5;
            else if(PTW_computeKey(ap_cur->ptw_clean, wep.key, 13, (KEYLIMIT*opt.ffact), PTW_DEFAULTBF, all, opt.ptw_attack) == 1)
                len = 13;
            else if(PTW_computeKey(ap_cur->ptw_clean, wep.key, 5, (KEYLIMIT*opt.ffact)/3, PTW_DEFAULTBF, all, opt.ptw_attack) == 1)
                len = 5;
        }
    }
    if(!len)
    {
        ap_cur->nb_ivs = ap_cur->nb_ivs_vague;
        //in case its not found, try bruteforcing the id field and include "vague" keystreams
        PTW_DEFAULTBF[10]=1;
        PTW_DEFAULTBF[11]=1;
//        PTW_DEFAULTBF[12]=1;

        if(opt.keylen != 13)
        {
            if(PTW_computeKey(ap_cur->ptw_vague, wep.key, opt.keylen, (KEYLIMIT*opt.ffact), PTW_DEFAULTBF, all, opt.ptw_attack) == 1)
                len = opt.keylen;
        }
        else
        {
            /* try 1000 40bit keys first, to find the key "instantly" and you don't need to wait for 104bit to fail */
            if(PTW_computeKey(ap_cur->ptw_vague, wep.key, 5, 1000, PTW_DEFAULTBF, all, opt.ptw_attack) == 1)
                len = 5;
            else if(PTW_computeKey(ap_cur->ptw_vague, wep.key, 13, (KEYLIMIT*opt.ffact), PTW_DEFAULTBF, all, opt.ptw_attack) == 1)
                len = 13;
            else if(PTW_computeKey(ap_cur->ptw_vague, wep.key, 5, (KEYLIMIT*opt.ffact)/10, PTW_DEFAULTBF, all, opt.ptw_attack) == 1)
                len = 5;
        }
    }

    if (!len)
            return FAILURE;

    opt.probability = 100;
    key_found(wep.key, len, -1);

    return SUCCESS;
}

int main( int argc, char *argv[] )
{
      int i, n, ret, option, j, ret1, nbMergeBSSID, unused;
      int cpu_count, showhelp, z, zz, forceptw;
      char *s, buf[128];
      struct AP_info *ap_cur;
      int old=0;
      char essid[33];

#ifdef HAVE_SQLITE
      int rc;
      char *zErrMsg = 0;
      char looper[4] = {'|','/','-','\\'};
      int looperc = 0;
      int waited = 0;
      char *sqlformat = "SELECT pmk.PMK, passwd.passwd FROM pmk INNER JOIN passwd ON passwd.passwd_id = pmk.passwd_id INNER JOIN essid ON essid.essid_id = pmk.essid_id WHERE essid.essid = '%q'";
      char *sql;
#endif

      ret = FAILURE;
      showhelp = 0;

      // Start a new process group, we are perhaps going to call kill(0, ...) later
      setsid();

      progname = getVersion("Aircrack-ng", _MAJ, _MIN, _SUB_MIN, _REVISION, _BETA, _RC);

      memset( &opt, 0, sizeof( opt ) );

      srand( time( NULL ) );

      // Get number of CPU (return -1 if failed).
      cpu_count = get_nb_cpus();
      opt.nbcpu = 1;
      if (cpu_count > 1) {
            opt.nbcpu = cpu_count;
      }

      j=0;
      /* check the arguments */

      opt.nbdict        = 0;
      opt.amode         = 0;
      opt.do_brute    = 1;
      opt.do_mt_brute = 1;
      opt.showASCII   = 0;
      opt.probability = 51;
      opt.next_ptw_try= 0;
      opt.do_ptw        = 1;
      opt.max_ivs       = INT_MAX;
      opt.visual_inspection = 0;
      opt.firstbssid    = NULL;
      opt.bssid_list_1st = NULL;
      opt.bssidmerge    = NULL;
      opt.oneshot       = 0;
      opt.logKeyToFile = NULL;

      /*
      all_ivs = malloc( (256*256*256) * sizeof(used_iv));
      memset(all_ivs, 0, (256*256*256)*sizeof(used_iv));
      */

      forceptw = 0;

      while( 1 )
      {

        int option_index = 0;

        static struct option long_options[] = {
            {"bssid",             1, 0, 'b'},
            {"debug",             1, 0, 'd'},
            {"combine",           0, 0, 'C'},
            {"help",              0, 0, 'H'},
            {"wep-decloak",       0, 0, 'D'},
            {"ptw-debug",         0, 0, 'P'},
            {"visual-inspection", 0, 0, 'V'},
            {"oneshot",           0, 0, '1'},
            {"cpu-detect",        0, 0, 'u'},
            {0,                   0, 0,  0 }
        };

            option = getopt_long( argc, argv, "r:a:e:b:p:qcthd:l:m:n:i:f:k:x::Xysw:0HKC:M:DP:zV1",
                        long_options, &option_index );

            if( option < 0 ) break;

            switch( option )
            {

                  case ':' :

                        printf("\"%s --help\" for help.\n", argv[0]);
                        return( 1 );

                  case '?' :

                        printf("\"%s --help\" for help.\n", argv[0]);
                        return( 1 );

                  case 'u' :
                        printf("Nb CPU detected: %d ", cpu_count);
#if defined(__i386__) || defined(__x86_64__)
                        unused = shasse2_cpuid();

                        if (unused == 1) {
                              printf(" (MMX available)");
                        }
                        if (unused >= 2) {
                              printf(" (SSE2 available)");
                        }
#endif
                        printf("\n");
                        return( 0 );

                  case 'V' :
                        if (forceptw)
                        {
                              printf("Visual inspection can only be used with KoreK\n");
                              printf("Use \"%s --help\" for help.\n", argv[0]);
                              return FAILURE;
                        }

                        opt.visual_inspection = 1;
                        opt.do_ptw = 0;
                        break;

                  case 'a' :

                        ret1 = sscanf( optarg, "%d", &opt.amode );

                        if ( strcasecmp( optarg, "wep" ) == 0 )
                              opt.amode = 1;

                        else if ( strcasecmp( optarg, "wpa" ) == 0 )
                              opt.amode = 2;

                        if( opt.amode != 1 && opt.amode != 2 )
                        {
                              printf( "Invalid attack mode. [1,2] or [wep,wpa]\n" );
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        break;

                  case 'e' :

                        memset(  opt.essid, 0, sizeof( opt.essid ) );
                        strncpy( opt.essid, optarg, sizeof( opt.essid ) - 1 );
                        opt.essid_set = 1;
                        break;

                  case 'b' :

                        if (getmac(optarg, 1, opt.bssid) != 0)
                        {
                                    printf( "Invalid BSSID (not a MAC).\n" );
                                    printf("\"%s --help\" for help.\n", argv[0]);
                                    return( FAILURE );
                        }

                        opt.bssid_set = 1;
                        break;

                  case 'p' :
                        if( sscanf( optarg, "%d", &opt.nbcpu ) != 1 || opt.nbcpu < 1 || opt.nbcpu > MAX_THREADS)
                        {
                              printf( "Invalid number of processes (recommended: %d)\n", cpu_count );
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        break;

                  case 'q' :

                        opt.is_quiet = 1;

                        break;

                  case 'c' :

                        opt.is_alnum = 1;
                        break;

                  case 'D' :

                        opt.wep_decloak = 1;
                        break;

                  case 'h' :

                        opt.is_fritz = 1;
                        break;

                  case 't' :

                        opt.is_bcdonly = 1;
                        break;

                  case '1' :

                        opt.oneshot = 1;
                        break;

                  case 'd' :

                        i = 0 ;
                        n = 0;
                        s = optarg;
                        while( s[i] != '\0' )
                        {
                              if (s[i] == 'x')
                                    s[i] = 'X';
                              if (s[i] == 'y')
                                    s[i] = 'Y';
                              if ( s[i] == '-' ||  s[i] == ':' || s[i] == ' ')
                                    i++;
                              else
                                    s[n++] = s[i++];
                        }
                        s[n] = '\0' ;
                        buf[0] = s[0];
                        buf[1] = s[1];
                        buf[2] = '\0';
                        i = 0;
                        j = 0;
                        while( ( sscanf( buf, "%x", &n ) == 1 ) || ( buf[0] == 'X' && buf[1] == 'X' ) || ( buf[0] == 'Y' && buf[1] == 'Y' ))
                        {
                              if ( buf[0] == 'X' && buf[1] == 'X' ) {
                                    opt.debug_row[i++] = 0 ;
                              } else if ( buf[0] == 'Y' && buf[1] == 'Y' ) {
                                    opt.brutebytes[j++] = i++;
                              } else {
                                    if ( n < 0 || n > 255 )
                                    {
                                          printf( "Invalid debug key.\n" );
                                          printf("\"%s --help\" for help.\n", argv[0]);
                                          return( FAILURE );
                                    }
                                    opt.debug[i] = n ;
                                    opt.debug_row[i++] = 1;
                              }
                              if( i >= 64 ) break;
                              s += 2;
                              buf[0] = s[0];
                              buf[1] = s[1];
                        }
                        break;


                  case 'm' :

                        if ( getmac(optarg, 1, opt.maddr) != 0)
                        {
                              printf( "Invalid MAC address filter.\n" );
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        break;

                  case 'n' :

                        if( sscanf( optarg, "%d", &opt.keylen ) != 1 ||
                              ( opt.keylen !=  64 && opt.keylen != 128 &&
                              opt.keylen != 152 && opt.keylen != 256 &&
                              opt.keylen != 512 ) )
                        {
                              printf( "Invalid WEP key length. [64,128,152,256,512]\n" );
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        opt.keylen = ( opt.keylen / 8 ) - 3;

                        break;

                  case 'i' :

                        if( sscanf( optarg, "%d", &opt.index ) != 1 ||
                              opt.index < 1 || opt.index > 4 )
                        {
                              printf( "Invalid WEP key index. [1-4]\n" );
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        break;

                  case 'f' :

                        if( sscanf( optarg, "%f", &opt.ffact ) != 1 ||
                              opt.ffact < 1 )
                        {
                              printf( "Invalid fudge factor. [>=1]\n" );
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        break;

                  case 'k' :

                        if( sscanf( optarg, "%d", &opt.korek ) != 1 ||
                              opt.korek < 1 || opt.korek > N_ATTACKS )
                        {
                              printf( "Invalid KoreK attack strategy. [1-%d]\n", N_ATTACKS );
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        K_COEFF[(opt.korek) - 1] = 0;

                        break;

                  case 'l' :
                        opt.logKeyToFile = (char *)calloc(1, strlen(optarg) + 1);
                        if (opt.logKeyToFile == NULL)
                        {
                              printf("Error allocating memory\n");
                              return( FAILURE );
                        }

                        strncpy(opt.logKeyToFile, optarg, strlen(optarg));
                        break;

                  case 'M' :

                        if( sscanf( optarg, "%d", &opt.max_ivs) != 1 || opt.max_ivs < 1)
                        {
                              printf( "Invalid number of max. ivs [>1]\n");
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        K_COEFF[(opt.korek) - 1] = 0;

                        break;

                  case 'P' :

                        if( sscanf( optarg, "%d", &opt.ptw_attack) != 1 || opt.ptw_attack < 0 || opt.ptw_attack > 2)
                        {
                              printf( "Invalid number for ptw debug [0-2]\n");
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return( FAILURE );
                        }

                        break;

                  case 'x' :

                        opt.do_brute = 0;

                        if (optarg)
                        {
                              if (sscanf(optarg, "%d", &opt.do_brute)!=1
                                    || opt.do_brute<0 || opt.do_brute>4)
                              {
                                    printf("Invalid option -x%s. [0-4]\n", optarg);
                                    printf("\"%s --help\" for help.\n", argv[0]);
                                    return FAILURE;
                              }
                        }

                        break;

                  case 'X' :

                        opt.do_mt_brute = 0;
                        break;

                  case 'y' :

                        opt.do_testy = 1;
                        break;

                  case 'K' :
                        opt.do_ptw = 0;
                        break;

                  case 's' :
                        opt.showASCII = 1;
                        break;

                  case 'w' :
                        if(set_dicts(optarg) != 0)
                        {
                              printf("\"%s --help\" for help.\n", argv[0]);
                              return FAILURE;
                        }
                        break;

                  case 'r' :
#ifdef HAVE_SQLITE
                        if(sqlite3_open(optarg, &db)) {
                              fprintf(stderr, "Database error: %s\n", sqlite3_errmsg(db));
                              sqlite3_close(db);
                              return FAILURE;
                        }
#else
                        fprintf(stderr, "Error: Aircrack-ng wasn't compiled with sqlite support\n");
                        return FAILURE;
#endif
                        break;

                  case '0' :

                        opt.l33t = 1;
                        break;

                  case 'H' :

                        showhelp = 1;
                        goto usage;
                        break;

                  case 'C' :
                        nbMergeBSSID = checkbssids(optarg);

                        if(nbMergeBSSID < 1)
                        {
                              printf("Invalid bssids (-C).\n\"%s --help\" for help.\n", argv[0]);
                              return FAILURE;
                        }

                        // Useless to merge BSSID if only one element
                        if (nbMergeBSSID == 1)
                              printf("Merging BSSID disabled, only one BSSID specified\n");
                        else
                              opt.bssidmerge = optarg;

                        break;

                  case 'z' :
                        /* only for backwards compatibility - PTW used by default */
                        if (opt.visual_inspection)
                        {
                              printf("Visual inspection can only be used with KoreK\n");
                              printf("Use \"%s --help\" for help.\n", argv[0]);
                              return FAILURE;
                        }

                        forceptw = 1;

                        break;

                  default : goto usage;
            }
      }

      if( argc - optind < 1 )
      {
            if(argc == 1)
            {
usage:
                  printf (usage, progname,
                        ( cpu_count > 1 || cpu_count == -1) ? "\n      -X         : disable  bruteforce   multithreading\n" : "\n");

                  // If the user requested help, exit directly.
                  if (showhelp == 1)
                        exit(0);
            }

            // Missing parameters
            if( argc - optind == 0)
          {
            printf("No file to crack specified.\n");
          }
          if(argc > 1)
          {
            printf("\"%s --help\" for help.\n", argv[0]);
          }
            return( ret );
      }

      if( opt.amode == 2 && opt.dict == NULL )
      {
            nodict:
            printf( "Please specify a dictionary (option -w).\n" );
            goto exit_main;
      }

      if( (! opt.essid_set && ! opt.bssid_set) && ( opt.is_quiet || opt.no_stdin ) )
      {
            printf( "Please specify an ESSID or BSSID.\n" );
            goto exit_main;
      }

      /* start one thread per input file */

      signal( SIGINT,  sighandler );
      signal( SIGQUIT, sighandler );
      signal( SIGTERM, sighandler );
      signal( SIGALRM, SIG_IGN );

      pthread_mutex_init( &mx_apl, NULL );
      pthread_mutex_init( &mx_ivb, NULL );
      pthread_mutex_init( &mx_eof, NULL );
      pthread_cond_init(  &cv_eof, NULL );

      ap_1st = NULL;

      old = optind;
      n = argc - optind;
      id = 0;

      if( !opt.bssid_set )
      {
            do
            {
                  if( strcmp( argv[optind], "-" ) == 0 )
                        opt.no_stdin = 1;

                  if( pthread_create( &(tid[id]), NULL, (void *) check_thread,
                        (void *) argv[optind] ) != 0 )
                  {
                        perror( "pthread_create failed" );
                        goto exit_main;
                  }

                  usleep( 131071 );
                  id++;
                  if(id >= MAX_THREADS)
                  {
                        if(! opt.is_quiet)
                              printf("Only using the first %d files, ignoring the rest.\n", MAX_THREADS);
                        break;
                  }
            }
            while( ++optind < argc );

            /* wait until each thread reaches EOF */

            if( ! opt.is_quiet )
            {
                  printf( "Reading packets, please wait...\r" );
                  fflush( stdout );
            }

//          #ifndef DO_PGO_DUMP
//          signal( SIGINT, SIG_DFL );     /* we want sigint to stop and dump pgo data */
//          #endif
            intr_read=1;

            for(i=0; i<id; i++)
                  pthread_join( tid[i], NULL);

            id=0;

            if( ! opt.is_quiet && ! opt.no_stdin )
                  printf( "\33[KRead %ld packets.\n\n", nb_pkt );

            if( ap_1st == NULL )
            {
                  printf( "No networks found, exiting.\n" );
                  goto exit_main;
            }

            if( ! opt.essid_set && ! opt.bssid_set )
            {
                  /* ask the user which network is to be cracked */

                  printf( "   #  BSSID%14sESSID%21sEncryption\n\n", "", "" );

                  i = 1;

                  ap_cur = ap_1st;

                  while( ap_cur != NULL )
                  {
                        memset( essid, 0, sizeof(essid));
                        memcpy( essid, ap_cur->essid, 32);
                        for(zz=0;zz<32;zz++)
                        {
                              if( (essid[zz] > 0 && essid[zz] < 32) || (essid[zz] > 126) )
                                    essid[zz]='?';
                        }

                        printf( "%4d  %02X:%02X:%02X:%02X:%02X:%02X  %-24s  ",
                              i, ap_cur->bssid[0], ap_cur->bssid[1],
                              ap_cur->bssid[2], ap_cur->bssid[3],
                              ap_cur->bssid[4], ap_cur->bssid[5],
                              essid );

                        if( ap_cur->eapol )
                              printf( "EAPOL+" );

                        switch( ap_cur->crypt )
                        {
                              case  0: printf( "None (%d.%d.%d.%d)\n",
                                    ap_cur->lanip[0], ap_cur->lanip[1],
                                    ap_cur->lanip[2], ap_cur->lanip[3] );
                              break;

                              case  1: printf( "No data - WEP or WPA\n" );
                              break;

                              case  2: printf( "WEP (%ld IVs)\n",
                                    ap_cur->nb_ivs );
                              break;

                              case  3: printf( "WPA (%d handshake)\n",
                                    ap_cur->wpa.state == 7 );
                              break;

                              default: printf( "Unknown\n" );
                              break;
                        }

                        i++; ap_cur = ap_cur->next;
                  }

                  printf( "\n" );

                  if( ap_1st->next != NULL )
                  {
                        do
                        {
                              printf( "Index number of target network ? " );
                              fflush( stdout );
                              ret1 = 0;
                              while(!ret1) ret1 = scanf( "%127s", buf );

                              if( ( z = atoi( buf ) ) < 1 )
                                    continue;

                              i = 1; ap_cur = ap_1st;
                              while( ap_cur != NULL && i < z )
                                    { i++; ap_cur = ap_cur->next; }
                        }
                        while( z < 0 || ap_cur == NULL );
                  }
                  else
                  {
                        printf( "Choosing first network as target.\n" );
                        ap_cur = ap_1st;
                  }

                  printf( "\n" );

                  memcpy( opt.bssid, ap_cur->bssid,  6 );
                  opt.bssid_set = 1;

                  /* Disable PTW if dictionnary used in WEP */
                  if (ap_cur->crypt == 2 && opt.dict != NULL)
                  {
                        opt.do_ptw = 0;
                  }
            }

            ap_1st = NULL;
            optind = old;
            id=0;
      }

      nb_eof=0;
      signal( SIGINT, sighandler );

      do
      {
            if( strcmp( argv[optind], "-" ) == 0 )
                  opt.no_stdin = 1;

            if( pthread_create( &(tid[id]), NULL, (void *) read_thread,
                  (void *) argv[optind] ) != 0 )
            {
                  perror( "pthread_create failed" );
                  goto exit_main;
            }

            id++;
            usleep( 131071 );
            if(id >= MAX_THREADS)
                  break;
      }
      while( ++optind < argc );

      nb_pkt=0;

      /* wait until each thread reaches EOF */

      intr_read=0;
      pthread_mutex_lock( &mx_eof );

      if( ! opt.is_quiet )
      {
            printf( "Reading packets, please wait...\r" );
            fflush( stdout );
      }

      while( nb_eof < n && ! intr_read )
            pthread_cond_wait( &cv_eof, &mx_eof );

      pthread_mutex_unlock( &mx_eof );

      intr_read=1;
//    if( ! opt.is_quiet && ! opt.no_stdin )
//          printf( "\33[KRead %ld packets.\n\n", nb_pkt );

//    #ifndef DO_PGO_DUMP
//    signal( SIGINT, SIG_DFL );     /* we want sigint to stop and dump pgo data */
//    #endif

      /* mark the targeted access point(s) */

      ap_cur = ap_1st;

      while( ap_cur != NULL )
      {
            if( memcmp( opt.maddr, BROADCAST, 6 ) == 0 ||
                  ( opt.bssid_set && ! memcmp( opt.bssid, ap_cur->bssid, 6 ) ) ||
                  ( opt.essid_set && ! strcmp( opt.essid, ap_cur->essid    ) ) )
                  ap_cur->target = 1;

            ap_cur = ap_cur->next;
      }

      ap_cur = ap_1st;

      while( ap_cur != NULL )
      {
            if( ap_cur->target )
                  break;

            ap_cur = ap_cur->next;
      }

      if( ap_cur == NULL )
      {
            printf( "No matching network found - check your %s.\n",
                  ( opt.essid_set ) ? "essid" : "bssid" );

            goto exit_main;
      }

      if( ap_cur->crypt < 2 )
      {
            switch( ap_cur->crypt )
            {
                  case  0:
                        printf( "Target network doesn't seem encrypted.\n" );
                        break;

                  default:
                        printf( "Got no data packets from target network!\n" );
                        break;
            }

            goto exit_main;
      }

      /* create the cracker<->master communication pipes */

      for( i = 0; i < opt.nbcpu; i++ )
      {
            unused = pipe( mc_pipe[i] );
            unused = pipe( cm_pipe[i] );

            if (opt.amode<=1 && opt.nbcpu>1 && opt.do_brute && opt.do_mt_brute)
            {
                  unused = pipe(bf_pipe[i]);
                  bf_nkeys[i] = 0;
            }
      }

      /* launch the attack */

      nb_tried = 0;
      nb_kprev = 0;

      chrono( &t_begin, 1 );
      chrono( &t_stats, 1 );
      chrono( &t_kprev, 1 );

      signal( SIGWINCH, sighandler );

      if( opt.amode == 1 )
            goto crack_wep;

      if( opt.amode == 2 )
            goto crack_wpa;

      if( ap_cur->crypt == 2 )
      {
            crack_wep:

            /* Default key length: 128 bits */
            if( opt.keylen == 0 )
                  opt.keylen = 13;

            if(j + opt.do_brute > 4)
            {
                  printf( "Bruteforcing more then 4 bytes will take too long, aborting!" );
                  goto exit_main;
            }

            for( i=0; i<opt.do_brute; i++)
            {
                  opt.brutebytes[j+i] = opt.keylen -1 -i;
            }

            opt.do_brute += j;

            if( opt.ffact == 0 )
            {
                        if( opt.do_ptw ) opt.ffact = 2;
                        else
                        {
                            if( ! opt.do_testy )
                            {
                                if( opt.keylen == 5 )
                                    opt.ffact = 5;
                        else
                                    opt.ffact = 2;
                            }
                            else
                                opt.ffact = 30;
                        }
            }

            memset( &wep, 0, sizeof( wep ) );

            if (opt.do_ptw)
            {
                  if(!opt.is_quiet)
                        printf("Attack will be restarted every %d captured ivs.\n", PTW_TRY_STEP);
                  opt.next_ptw_try = ap_cur->nb_ivs_vague - (ap_cur->nb_ivs_vague % PTW_TRY_STEP);
                  do
                  {
                        if(ap_cur->nb_ivs_vague >= opt.next_ptw_try)
                        {
                              if(!opt.is_quiet)
                                    printf("Starting PTW attack with %ld ivs.\n", ap_cur->nb_ivs_vague);
                              ret = crack_wep_ptw(ap_cur);

                              if( opt.oneshot == 1 && ret == FAILURE )
                              {
                                    printf( "   Attack failed. Possible reasons:\n\n"
                                          "     * Out of luck: you must capture more IVs. Usually, 104-bit WEP\n"
                                          "       can be cracked with about 80.000 IVs, sometimes more.\n\n"
                                          "     * Try to raise the fudge factor (-f).\n");
                                    ret=0;
                              }

                              if(ret)
                              {
                                    opt.next_ptw_try += PTW_TRY_STEP;
                                    printf("Failed. Next try with %d IVs.\n", opt.next_ptw_try);
                              }
                        }
                        if(ret)
                              usleep(10000);
                  }while(ret != 0);
            }
            else if(opt.dict != NULL)
            {
                  ret = crack_wep_dict();
            }
            else
            {
                  for( i = 0; i < opt.nbcpu; i++ )
                  {
                        /* start one thread per cpu */

                        if (opt.amode<=1 && opt.nbcpu>1 && opt.do_brute && opt.do_mt_brute)
                        {
                              if (pthread_create( &(tid[id]), NULL, (void *) inner_bruteforcer_thread,
                                    (void *) (long) i ) != 0)
                              {
                                    perror( "pthread_create failed" );
                                    goto exit_main;
                              }
                              id++;
                        }

                        if( pthread_create( &(tid[id]), NULL, (void *) crack_wep_thread,
                              (void *) (long) i ) != 0 )
                        {
                              perror( "pthread_create failed" );
                              goto exit_main;
                        }
                        id++;
                  }

                  if( ! opt.do_testy )
                  {
                        do   { ret = do_wep_crack1( 0 ); }
                        while( ret == RESTART );

                        if( ret == FAILURE )
                        {
                              printf( "   Attack failed. Possible reasons:\n\n"
                                    "     * Out of luck: you must capture more IVs. Usually, 104-bit WEP\n"
                                    "       can be cracked with about one million IVs, sometimes more.\n\n"
                                    "     * If all votes seem equal, or if there are many negative votes,\n"
                                    "       then the capture file is corrupted, or the key is not static.\n\n"
                                    "     * A false positive prevented the key from being found.  Try to\n"
                                    "       disable each korek attack (-k 1 .. 17), raise the fudge factor\n"
                                    "       (-f)" );
                              if (opt.do_testy)
                                    printf( "and try the experimental bruteforce attacks (-y)." );
                              printf( "\n" );
                        }
                  }
                  else
                  {
                        for( i = opt.keylen - 3; i < opt.keylen - 2; i++ )
                        {
                              do   { ret = do_wep_crack2( i ); }
                              while( ret == RESTART );

                              if( ret == SUCCESS )
                                    break;
                        }

                        if( ret == FAILURE )
                        {
                              printf( "   Attack failed. Possible reasons:\n\n"
                                    "     * Out of luck: you must capture more IVs. Usually, 104-bit WEP\n"
                                    "       can be cracked with about one million IVs, sometimes more.\n\n"
                                    "     * If all votes seem equal, or if there are many negative votes,\n"
                                    "       then the capture file is corrupted, or the key is not static.\n\n"
                                    "     * A false positive prevented the key from being found.  Try to\n"
                                    "       disable each korek attack (-k 1 .. 17), raise the fudge factor\n"
                                    "       (-f)" );
                              if (opt.do_testy)
                                    printf( "or try the standard attack mode instead (no -y option)." );
                              printf( "\n" );
                        }
                  }
            }
      }

      if( ap_cur->crypt == 3 )
      {
            crack_wpa:

#ifdef HAVE_SQLITE
            if (opt.dict == NULL && db == NULL) goto nodict;
#else
            if ( opt.dict == NULL )
                  goto nodict;
#endif

            ap_cur = ap_1st;

            while( ap_cur != NULL )
            {
                  if( ap_cur->target && ap_cur->wpa.state == 7 )
                        break;

                  ap_cur = ap_cur->next;
            }

            if( ap_cur == NULL )
            {
                  printf( "No valid WPA handshakes found.\n" );
                  goto exit_main;
            }

            if( memcmp( ap_cur->essid, ZERO, 32 ) == 0 && ! opt.essid_set )
            {
                  printf( "An ESSID is required. Try option -e.\n" );
                  goto exit_main;
            }

            if( opt.essid_set && ap_cur->essid[0] == '\0' )
            {
                  memset(  ap_cur->essid, 0, sizeof( ap_cur->essid ) );
                  strncpy( ap_cur->essid, opt.essid, sizeof( ap_cur->essid ) - 1 );
            }
#ifdef HAVE_SQLITE
            if (db == NULL) {
#endif

                  for( i = 0; i < opt.nbcpu; i++ )
                  {
                        /* start one thread per cpu */
                        wpa_data[i].ap = ap_cur;
                        wpa_data[i].thread = i;
                        wpa_data[i].nkeys = 17;
                        wpa_data[i].key_buffer = (char*) malloc(wpa_data[i].nkeys * 128);
                        wpa_data[i].front = 0;
                        wpa_data[i].back = 0;
                        memset(wpa_data[i].key, 0, sizeof(wpa_data[i].key));
                        pthread_cond_init(&wpa_data[i].cond, NULL);
                        pthread_mutex_init(&wpa_data[i].mutex, NULL);

                        if( pthread_create( &(tid[id]), NULL, (void *) crack_wpa_thread,
                              (void *) &(wpa_data[i]) ) != 0 )
                        {
                              perror( "pthread_create failed" );
                              goto exit_main;
                        }

#ifdef pthread_setaffinity_np
                        // set affinity to one processor
                        cpu_set_t cpuset;
                        CPU_ZERO(&cpuset);
                        CPU_SET(i, &cpuset);
                        pthread_setaffinity_np(tid[id], sizeof(cpu_set_t), &cpuset);
#endif

                        id++;
                  }

                  ret = do_wpa_crack();   // we feed keys to the cracking threads
                  wpa_wordlists_done = 1; // we tell the threads that they shouldn't expect more words (don't wait for parallel crack)

                  for( i = 0; i < opt.nbcpu; i++ ) // we wait for the cracking threads to end
                        pthread_join(tid[--id], NULL);

                  for( i = 0; i < opt.nbcpu; i++ )
                  {
                        if (wpa_data[i].key[0] != 0)
                        {
                              ret = SUCCESS;
                              break;
                        }
                  }

                  if (ret==SUCCESS)
                  {
                        if( opt.is_quiet )
                        {
                              printf( "KEY FOUND! [ %s ]\n", wpa_data[i].key );
                              return( SUCCESS );
                        }

                        if( opt.l33t )
                              printf( "\33[31;1m" );

                        printf( "\33[8;%dH\33[2KKEY FOUND! [ %s ]\33[11B\n",
                              ( 80 - 15 - (int) strlen(wpa_data[i].key) ) / 2, wpa_data[i].key );

                        if( opt.l33t )
                              printf( "\33[32;22m" );

                        return( SUCCESS );
                  }
                  else
                        printf( "\nPassphrase not in dictionary \n" );

                  printf("\n");

#ifdef HAVE_SQLITE
            } else {
                  if( ! opt.is_quiet ) {
                        if( opt.l33t )
                              printf( "\33[37;40m" );
                              printf( "\33[2J" );
                        if( opt.l33t )
                              printf( "\33[34;1m" );
                  printf("\33[2;34H%s",progname);
                  }
                  sql = sqlite3_mprintf(sqlformat,ap_cur->essid);
                  while (1) {
                        rc = sqlite3_exec(db,sql,sql_wpacallback,ap_cur,&zErrMsg);
                        if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) {
                              fprintf(stdout,"Database is locked or busy. Waiting %is ... %1c    \r",++waited, looper[looperc]);
                              fflush(stdout);
                              looperc = (looperc+1) % sizeof(looper);
                              sleep(1);
                        } else {
                              if (rc != SQLITE_OK && rc != SQLITE_ABORT ) {
                                    fprintf(stderr, "SQL error: %s\n", zErrMsg);
                                    sqlite3_free(zErrMsg);
                              }
                              if (waited != 0) printf("\n\n");
                              break;
                        }
                  }
                  sqlite3_free(sql);

            }
      #endif
      }

      exit_main:

#ifdef HAVE_SQLITE
      if (db != NULL) {
            sqlite3_close(db);
      }
#endif

      #if ((defined(__INTEL_COMPILER) || defined(__ICC)) && defined(DO_PGO_DUMP))
      _PGOPTI_Prof_Dump();
      #endif
      if( ! opt.is_quiet )
            printf( "\n" );

      fflush( stdout );

//    if( ret == SUCCESS ) kill( 0, SIGQUIT );
//    if( ret == FAILURE ) kill( 0, SIGTERM );
      clean_exit(ret);

      _exit( ret );
}

Generated by  Doxygen 1.6.0   Back to index