#include <string.h>
#include <stdio.h>
#include <time.h>

#include "pcap.h"

unsigned char buffer[65536];

int main( int argc, char *argv[] )
{
    time_t tt;
    int n, z;
    FILE *f_in, *f_out;
    unsigned long nbr;
    unsigned char *h80211;
    unsigned char bssid_cur[6];
    unsigned char bssid_prv[6];
    struct pcap_file_header pfh;
    struct pcap_pkthdr pkh;    

    if( argc != 3 )
    {
        printf( "usage: cap2ivs <pcap file> <ivs output file>\n" );
        return( 1 );
    }

    memset( bssid_cur, 0, 6 );
    memset( bssid_prv, 0, 6 );

    /* check the input pcap file */

    printf( "Opening %s\n", argv[1] );

    if( ( f_in = fopen( argv[1], "rb" ) ) == NULL )
    {
        perror( "fopen failed" );
        return( 1 );
    }

    n = sizeof( pfh );

    if( fread( &pfh, 1, n, f_in ) != (size_t) n )
    {
        perror( "fread(pcap file header) failed" );
        return( 1 );
    }

    if( pfh.magic != TCPDUMP_MAGIC &&
        pfh.magic != TCPDUMP_CIGAM )
    {
        printf( "\"%s\" isn't a pcap file (expected "
                "TCPDUMP_MAGIC).\n", argv[1] );
        return( 1 );
    }

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

    if( pfh.linktype != LINKTYPE_IEEE802_11 &&
        pfh.linktype != LINKTYPE_PRISM_HEADER &&
        pfh.linktype != LINKTYPE_RADIOTAP_HDR )
    {
        printf( "\"%s\" isn't a regular 802.11 "
                "(wireless) capture.\n", argv[1] );
        return( 1 );
    }

    /* create the output ivs file */

    printf( "Creating %s\n", argv[2] );

    if( ( f_out = fopen( argv[2], "wb+" ) ) == NULL )
    {
        perror( "fopen failed" );
        return( 1 );
    }

    fwrite( IVSONLY_MAGIC, 1, 4, f_out );

    nbr = 0;
    tt = time( NULL ) - 1;

    while( 1 )
    {
        if( time( NULL ) - tt > 0 )
        {
            printf( "\33[KRead %ld packets...\r", nbr );
            fflush( stdout );
            tt = time( NULL );
        }

        /* read one packet */

        n = sizeof( pkh );

        if( fread( &pkh, 1, n, f_in ) != (size_t) n )
            break;

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

        n = pkh.caplen;

        if( n <= 0 || n > 65535 )
        {
            printf( "Corrupted file? Invalid packet length %d.\n", n );
            return( 1 );
        }

        if( fread( buffer, 1, n, f_in ) != (size_t) n )
            break;

        nbr++;

        h80211 = buffer;

        /* remove any prism/radiotap header */

        if( pfh.linktype == LINKTYPE_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 )
        {
            n = *(unsigned short *)( h80211 + 2 );

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

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

        /* check if WEP data, min. length & bssid */

        if( ( h80211[0] & 0x0C ) != 0x08 ||
            ( h80211[1] & 0x40 ) != 0x40 )
            continue;

        z = ( ( h80211[1] & 3 ) != 3 ) ? 24 : 30;

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

        switch( h80211[0] & 3 )
        {
            case  0: memcpy( bssid_cur, h80211 + 16, 6 ); break;
            case  1: memcpy( bssid_cur, h80211 +  4, 6 ); break;
            case  2: memcpy( bssid_cur, h80211 + 10, 6 ); break;
            default: memcpy( bssid_cur, h80211 +  4, 6 ); break;
        }

        if( memcmp( bssid_cur, bssid_prv, 6 ) != 0 )
        {
            fwrite( bssid_cur, 1, 6, f_out );
            memcpy( bssid_prv, bssid_cur, 6 );
        }
        else
            fwrite( "\xFF", 1, 1, f_out );

        fwrite( h80211 + z    , 1, 3, f_out );
        fwrite( h80211 + z + 4, 1, 2, f_out );
    }

    printf( "\33[2KRead %ld packets.\n", nbr );

    fclose( f_in );
    fclose( f_out );

    return( 0 );
}
