nexmon – Rev 1

Subversion Repositories:
Rev:
  /*
   *  Copyright (c) 2007-2016 Thomas d'Otreppe <tdotreppe@aircrack-ng.org>
   *
   *  Airpcap stuff
   *
   *  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
   *
   * 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.
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
#ifdef HAVE_AIRPCAP

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <windows.h>
#include <airpcap.h>

#include "osdep.h"

//------------------ PPI ---------------------
#define PPH_PH_VERSION          ((u_int8_t)0x00)
#define PPI_FIELD_TYPE_802_11_COMMON            ((u_int16_t)0x02)

typedef struct _PPI_PACKET_HEADER
{
        u_int8_t        PphVersion;
        u_int8_t        PphFlags;
        u_int16_t       PphLength;
        u_int32_t       PphDlt;
}
PPI_PACKET_HEADER, *PPPI_PACKET_HEADER;

typedef struct _PPI_FIELD_HEADER
{
        u_int16_t PfhType;
        u_int16_t PfhLength;
}
PPI_FIELD_HEADER, *PPPI_FIELD_HEADER;

typedef struct _PPI_FIELD_802_11_COMMON
{
        u_int64_t       TsfTimer;
        u_int16_t       Flags;
        u_int16_t       Rate;
        u_int16_t       ChannelFrequency;
        u_int16_t       ChannelFlags;
        u_int8_t        FhssHopset;
        u_int8_t        FhssPattern;
        int8_t          DbmAntSignal;
        int8_t          DbmAntNoise;
}
PPI_FIELD_802_11_COMMON, *PPPI_FIELD_802_11_COMMON;


#define DEVICE_PREFIX "\\\\.\\"
#define DEVICE_COMMON_PART "airpcap"

PAirpcapHandle airpcap_handle;

/**
 * Check if the device is an Airpcap device
 * @param iface Interface name
 * @return 1 if it is an Airpcap device, 0 if not
 */
int isAirpcapDevice(const char * iface)
{
        char * pos;
        int len;

        pos = strstr(iface, DEVICE_COMMON_PART);

        // Check if it contains "airpcap"
        if (! pos)
                return 0;

        if (pos != iface)
        {
                // Check if it begins with '\\.\'
                if (strstr(iface, AIRPCAP_DEVICE_NAME_PREFIX) != iface)
                        return 0;
        }

        len = strlen(iface);

        // Checking that it contains 2 figures at the end.
        // No need to check for length, it was already done by the first check
        if (! (isdigit((int)iface[len - 1])) || !(isdigit((int)iface[len - 2])))
                return 0;

        return 1;
}

/**
 * Parse information from a PPI packet (will be used later).
 * @param p packet
 * @param caplen Length of the packet
 * @param hdrlen Length of the header
 * @param power pointer that will contains the power of the packet
 * @return 0 if successful decoding, 1 if it failed to decode
 */
int ppi_decode(const u_char *p, int caplen, int *hdrlen, int *power)
{
        PPPI_PACKET_HEADER pPpiPacketHeader;
        PPPI_FIELD_HEADER       pFieldHeader;
        ULONG position = 0;

        // Sanity checks
        if (caplen < (int)sizeof(*pPpiPacketHeader))
        {
                // Packet smaller than the PPI fixed header
                return( 1 );
        }

        pPpiPacketHeader = (PPPI_PACKET_HEADER)p;

        *hdrlen = pPpiPacketHeader->PphLength;

        if(caplen < *hdrlen)
        {
                // Packet smaller than the PPI fixed header
                return( 1 );
        }

        position = sizeof(*pPpiPacketHeader);

        if (pPpiPacketHeader->PphVersion != PPH_PH_VERSION)
        {
                fprintf( stderr, "Unknown PPI packet header version (%u)\n", pPpiPacketHeader->PphVersion);
                return( 1 );
        }

        do
        {
                // now we suppose to have an 802.11-Common header
                if (*hdrlen < (int)(sizeof(*pFieldHeader) + position))
                {
                        break;
                }

                pFieldHeader = (PPPI_FIELD_HEADER)(p + position);
                position += sizeof(*pFieldHeader);

                switch(pFieldHeader->PfhType)
                {
                        case PPI_FIELD_TYPE_802_11_COMMON:
                                if (pFieldHeader->PfhLength != sizeof(PPI_FIELD_802_11_COMMON) || caplen - position < sizeof(PPI_FIELD_802_11_COMMON))
                                {
                                        // the header is bogus, just skip it
                                        fprintf( stderr, "Bogus 802.11-Common Field. Skipping it.\n");
                                }
                                else
                                {
                                        PPPI_FIELD_802_11_COMMON pField = (PPPI_FIELD_802_11_COMMON)(p + position);

                                        if (pField->DbmAntSignal != -128)
                                        {
                                                *power = (int)pField->DbmAntSignal;
                                        }
                                        else
                                        {
                                                *power = 0;
                                        }
                                }
                                break;

                        default:
                                // we do not know this field. Just print type and length and skip
                                break;
                }

                position += pFieldHeader->PfhLength;
        }
        while(TRUE);

        return( 0 );
}

/**
 * Set MAC Address of the device
 * @param mac MAC Address
 * @return 0 (successful)
 */
int airpcap_set_mac(void *mac)
{
        if (mac) {}
        return 0;
}

/**
 * Close device
 */
void airpcap_close(void)
{
        // By default, when plugged in, the adapter is set in monitor mode;
        // Application may assume it's already in monitor mode and forget to set it
        // So, do not remove monitor mode.
        if (airpcap_handle != NULL)
        {
                AirpcapClose(airpcap_handle);
                airpcap_handle = NULL;
        }
}

/**
 * Get MAC Address of the device (not yet implemented)
 * @param mac It will contain the mac address
 * @return 0 (successful)
 */
int airpcap_get_mac(void *mac)
{
   // Don't use the function from Airpcap
        if (mac) {}

        return 0;
}

/**
 * Capture one packet
 * @param buf Buffer for the packet
 * @param len Length of the buffer
 * @param ri Receive information
 * @return -1 if failure or the number of bytes received
 */
int airpcap_sniff(void *buf, int len, struct rx_info *ri)
{
        // Use PPI headers to obtain the different information for ri
        // Use AirpcapConvertFrequencyToChannel() to get channel
        // Add an option to give frequency instead of channel
        UINT BytesReceived = 0;

        if (ri) {}
        // Wait for the next packet
        // Maybe add an event packets to read
        // WaitForSingleObject(ReadEvent, INFINITE);

        // Read a packet
        if(AirpcapRead(airpcap_handle, buf, len, &BytesReceived))
                return (int)BytesReceived;

        return -1;
}

/**
 * Inject one packet
 * @param buf Buffer for the packet
 * @param len Length of the buffer
 * @param ti Transmit information
 * @return -1 if failure or the number of bytes sent
 */
int airpcap_inject(void *buf, int len, struct tx_info *ti)
{
        if (ti) {}
        if (AirpcapWrite (airpcap_handle, buf, len) != 1)
                return -1;

        return len;
}

/**
 * Print the error message
 * @param err Contains the error message and a %s in order to show the Airpcap error
 * @param retValue Value returned by the function
 * @return retValue
 */
int printErrorCloseAndReturn(const char * err, int retValue)
{
        if (err && airpcap_handle)
        {
                if (strlen(err))
                {
                        if (airpcap_handle)
                                fprintf( stderr, err, AirpcapGetLastError(airpcap_handle));
                        else
                                fprintf( stderr, err);
                }
        }

        airpcap_close();

    return retValue;
}

/**
 * Initialize the device
 * @param param Parameters for the initialization
 * @return 0 if successful, -1 in case of failure
 */
int airpcap_init(char *param)
{
        // Later: if several interfaces are given, aggregate them.

        char * iface;
    char errbuf[AIRPCAP_ERRBUF_SIZE ];

        iface = (char *)calloc(1, strlen(param) + 100);

        if (param)
        {
                // if it's empty, use the default adapter
                if (strlen(param) > 0)
                {
                        if (strstr(param, DEVICE_PREFIX) == NULL)
                        {
                                // Not found, add it

                                strcpy(iface, DEVICE_PREFIX);
                                strcat(iface, param);
                        }
                        else
                        {
                                // Already contains the adapter header
                                strcpy(iface, param);
                        }
                }
        }

    airpcap_handle = AirpcapOpen(iface, errbuf);

    if(airpcap_handle == NULL)
    {
        fprintf( stderr, "This adapter doesn't have wireless extensions. Quitting\n");
        //pcap_close( winpcap_adapter );
        return( -1 );
    }

    /* Tell the adapter that the packets we'll send and receive don't include the FCS */
    if(!AirpcapSetFcsPresence(airpcap_handle, FALSE))
                return printErrorCloseAndReturn("Error setting FCS presence: %s\n", -1);

    /* Set the link layer to bare 802.11 */
    if(!AirpcapSetLinkType(airpcap_handle, AIRPCAP_LT_802_11))
                return printErrorCloseAndReturn("Error setting the link type: %s\n", -1);

    /* Accept correct frames only */
        if( !AirpcapSetFcsValidation(airpcap_handle, AIRPCAP_VT_ACCEPT_CORRECT_FRAMES) )
                return printErrorCloseAndReturn("Error setting FCS validation: %s\n", -1);

    /* Set a low mintocopy for better responsiveness */
    if(!AirpcapSetMinToCopy(airpcap_handle, 1))
                return printErrorCloseAndReturn("Error setting MinToCopy: %s\n", -1);

        return 0;
}

/**
 * Set device channel
 * @param chan Channel
 * @return 0 if successful, -1 if it failed
 */
int airpcap_set_chan(int chan)
{
        // Make sure a valid channel is given
        if (chan <= 0)
                return -1;

        if(!AirpcapSetDeviceChannel(airpcap_handle, chan))
        {
                printf("Error setting the channel to %d: %s\n", chan, AirpcapGetLastError(airpcap_handle));
                return -1;
        }

        return 0;
}

#endif