nexmon – Rev 1

Subversion Repositories:
Rev:
  /*
   *  Copyright (c) 2007, 2008, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
   *
   *  OS dependent API for cygwin. It relies on an external
   *  DLL to do the actual wifi 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
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */

#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <windows.h>

#include "osdep.h"
#include "network.h"
#include "cygwin.h"

#ifdef HAVE_AIRPCAP
        #include "airpcap.h"
#endif

#define xstr(s) str(s)
#define str(s) #s

#define DLL_EXTENSION ".dll"

struct priv_cygwin {
        pthread_t       pc_reader;
        volatile int    pc_running;
        int             pc_pipe[2]; /* reader -> parent */
        int             pc_channel;
        int             pc_frequency;
        struct wif      *pc_wi;
        int             pc_did_init;

        int             isAirpcap;
        int             useDll;

        int             (*pc_init)(char *param);
        int             (*pc_set_chan)(int chan);
        int             (*pc_set_freq)(int freq);
        int             (*pc_inject)(void *buf, int len, struct tx_info *ti);
        int             (*pc_sniff)(void *buf, int len, struct rx_info *ri);
        int             (*pc_get_mac)(void *mac);
        int             (*pc_set_mac)(void *mac);
        void            (*pc_close)(void);
};

/**
 * strstr() function case insensitive
 * @param String C string to be scanned
 * @param Pattern C string containing the sequence of characters to match
 * @return Pointer to the first occurrence of Pattern in String, or a null pointer if there Pattern is not part of String.
 */
char *stristr(const char *String, const char *Pattern)
{
      char *pptr, *sptr, *start;
      unsigned  slen, plen;

      for (start = (char *)String,
           pptr  = (char *)Pattern,
           slen  = strlen(String),
           plen  = strlen(Pattern);

           /* while string length not shorter than pattern length */

           slen >= plen;

           start++, slen--)
      {
            /* find start of pattern in string */
            while (toupper((int)*start) != toupper((int)*Pattern))
            {
                  start++;
                  slen--;

                  /* if pattern longer than string */

                  if (slen < plen)
                        return(NULL);
            }

            sptr = start;
            pptr = (char *)Pattern;

            while (toupper((int)*sptr) == toupper((int)*pptr))
            {
                  sptr++;
                  pptr++;

                  /* if end of pattern then pattern was found */

                  if ('\0' == *pptr)
                        return (start);
            }
      }
      return(NULL);
}

/**
 * Get the different functions for to interact with the device:
 * - setting monitor mode
 * - changing channel
 * - capturing data
 * - injecting packets
 * @param iface The interface name
 */
static int do_cygwin_open(struct wif *wi, char *iface)
{
        struct priv_cygwin *priv = wi_priv(wi);
        void *lib;
        char *file;
        char *parm;
        int rc = -1;
        int tempret = 0;

        if (!iface)
                return -1;
        if (strlen(iface) == 0)
                return -1;

        priv->useDll = 0;

        if (stristr(iface, DLL_EXTENSION))
                priv->useDll = 1;

        if (priv->useDll)
        {
                file = strdup(iface);
                if (!file)
                        return -1;

                parm = strchr(file, '|');
                if (parm)
                        *parm++ = 0;

                /* load lib */
                lib = dlopen(file, RTLD_LAZY);
                if (!lib)
                        goto errdll;

                priv->pc_init           = dlsym(lib, xstr(CYGWIN_DLL_INIT));
                priv->pc_set_chan       = dlsym(lib, xstr(CYGWIN_DLL_SET_CHAN));
                priv->pc_set_freq       = dlsym(lib, xstr(CYGWIN_DLL_SET_FREQ));
                priv->pc_get_mac        = dlsym(lib, xstr(CYGWIN_DLL_GET_MAC));
                priv->pc_set_mac        = dlsym(lib, xstr(CYGWIN_DLL_SET_MAC));
                priv->pc_close          = dlsym(lib, xstr(CYGWIN_DLL_CLOSE));
                priv->pc_inject         = dlsym(lib, xstr(CYGWIN_DLL_INJECT));
                priv->pc_sniff          = dlsym(lib, xstr(CYGWIN_DLL_SNIFF));

                if (!(priv->pc_init && priv->pc_set_chan && priv->pc_get_mac
                          && priv->pc_inject && priv->pc_sniff && priv->pc_close))
                        goto errdll;

                /* init lib */
                if ((rc = priv->pc_init(parm)))
                        goto errdll;
                priv->pc_did_init = 1;

                rc = 0;

errdll:
                free(file);
        }
        else
        {
                #ifdef HAVE_AIRPCAP
                        // Check if it's an Airpcap device
                        priv->isAirpcap = isAirpcapDevice(iface);


                        if (priv->isAirpcap)
                        {
                                // Get functions
                                priv->pc_init           = airpcap_init;
                                priv->pc_set_chan       = airpcap_set_chan;
                                priv->pc_get_mac        = airpcap_get_mac;
                                priv->pc_set_mac        = airpcap_set_mac;
                                priv->pc_close          = airpcap_close;
                                priv->pc_inject         = airpcap_inject;
                                priv->pc_sniff          = airpcap_sniff;

                                rc = 0;
                        }

                #endif

        }

        if (rc == 0)
        {
                // Don't forget to initialize
                if (! priv->useDll)
                {
                        rc = priv->pc_init(iface);

                        if (rc == 0)
                                priv->pc_did_init = 1;
                        else
                                fprintf(stderr,"Error initializing <%s>\n", iface);
                }

                if (priv->pc_did_init) {
                        /* set initial chan */
                        tempret = wi_set_channel(wi, 1);
                        if (tempret)
                                rc = tempret;
                }
        }
        else
        {
                // Show an error message if the adapter is not supported
                fprintf(stderr, "Adapter <%s> not supported\n", iface);
        }

        return rc;
}

/**
 * Change channel
 * @param chan Channel
 * @return 0 if successful, -1 if it failed
 */
static int cygwin_set_channel(struct wif *wi, int chan)
{
        struct priv_cygwin *priv = wi_priv(wi);

        if (priv->pc_set_chan(chan) == -1)
                return -1;

        priv->pc_channel = chan;
        return 0;
}

/**
 * Change frequency
 * @param freq Frequency
 * @return 0 if successful, -1 if it failed
 */
static int cygwin_set_freq(struct wif *wi, int freq)
{
        struct priv_cygwin *priv = wi_priv(wi);

        if (!priv->pc_set_freq || priv->pc_set_freq(freq) == -1)
                return -1;

        priv->pc_frequency = freq;
        return 0;
}


/**
 * Capture a packet
 * @param buf Buffer for the packet (has to be already allocated)
 * @param len Length of the buffer
 * @param ri Receive information structure
 * @return -1 in case of failure or the number of bytes received
 */
static int cygwin_read_packet(struct priv_cygwin *priv, void *buf, int len,
                              struct rx_info *ri)
{
        int rd;

        memset(ri, 0, sizeof(*ri));

        rd = priv->pc_sniff(buf, len, ri);
        if (rd == -1)
                return -1;

        if (!ri->ri_channel)
                ri->ri_channel = wi_get_channel(priv->pc_wi);

        return rd;
}

/**
 * Send a packet
 * @param h80211 The packet itself
 * @param len Length of the packet
 * @param ti Transmit information
 * @return -1 if failure or the number of bytes sent
 */
static int cygwin_write(struct wif *wi, unsigned char *h80211, int len,
                        struct tx_info *ti)
{
        struct priv_cygwin *priv = wi_priv(wi);
        int rc;

        if ((rc = priv->pc_inject(h80211, len, ti)) == -1)
                return -1;

        return rc;
}

/**
 * Get device channel
 * @return channel
 */
static int cygwin_get_channel(struct wif *wi)
{
        struct priv_cygwin *pc = wi_priv(wi);

        return pc->pc_channel;
}

static int cygwin_get_freq(struct wif *wi)
{
        struct priv_cygwin *pc = wi_priv(wi);

        return pc->pc_frequency;
}

int cygwin_read_reader(int fd, int plen, void *dst, int len)
{
        /* packet */
        if (len > plen)
                len = plen;
        if (net_read_exact(fd, dst, len) == -1)
                return -1;
        plen -= len;

        /* consume packet */
        while (plen) {
                char lame[1024];
                int rd = sizeof(lame);

                if (rd > plen)
                        rd = plen;

                if (net_read_exact(fd, lame, rd) == -1)
                        return -1;

                plen -= rd;

                assert(plen >= 0);
        }

        return len;
}

static int cygwin_read(struct wif *wi, unsigned char *h80211, int len,
                       struct rx_info *ri)
{
        struct priv_cygwin *pc = wi_priv(wi);
        struct rx_info tmp;
        int plen;

        if (pc->pc_running == -1)
                return -1;

        if (!ri)
                ri = &tmp;

        /* length */
        if (net_read_exact(pc->pc_pipe[0], &plen, sizeof(plen)) == -1)
                return -1;

        /* ri */
        if (net_read_exact(pc->pc_pipe[0], ri, sizeof(*ri)) == -1)
                return -1;
        plen -= sizeof(*ri);
        assert(plen > 0);

        return cygwin_read_reader(pc->pc_pipe[0], plen, h80211, len);
}

/**
 * Free allocated data
 */
static void do_free(struct wif *wi)
{
        struct priv_cygwin *pc = wi_priv(wi);
        int tries = 3;

        /* wait for reader */
        if (pc->pc_running == 1) {
                pc->pc_running = 0;

                while ((pc->pc_running != -1) && tries--)
                        sleep(1);
        }

        if (pc->pc_pipe[0]) {
                close(pc->pc_pipe[0]);
                close(pc->pc_pipe[1]);
        }

        if (pc->pc_did_init)
                pc->pc_close();

        assert(wi->wi_priv);
        free(wi->wi_priv);
        wi->wi_priv = 0;

        free(wi);
}

/**
 * Close the device and free data
 */
static void cygwin_close(struct wif *wi)
{
        do_free(wi);
}

/**
 * Get the file descriptor for the device
 */
static int cygwin_fd(struct wif *wi)
{
        struct priv_cygwin *pc = wi_priv(wi);

        if (pc->pc_running == -1)
                return -1;

        return pc->pc_pipe[0];
}

/**
 * Get MAC Address of the device
 * @param mac It will contain the mac address
 * @return 0 if successful
 */
static int cygwin_get_mac(struct wif *wi, unsigned char *mac)
{
        struct priv_cygwin *pc = wi_priv(wi);

        return pc->pc_get_mac(mac);
}
/**
 * Set MAC Address of the device
 * @param mac MAC Address
 * @return 0 if successful
 */
static int cygwin_set_mac(struct wif *wi, unsigned char *mac)
{
        struct priv_cygwin *pc = wi_priv(wi);

        return pc->pc_set_mac(mac);
}

static int cygwin_get_monitor(struct wif *wi)
{
        if (wi) {} /* XXX unused */

        return 0;
}

static int cygwin_get_rate(struct wif *wi)
{
        if (wi) {} /* XXX unused */

        return 1000000;
}

/**
 * Set (injection) rate of the device
 * @param rate Rate to be used
 * @return 0 (successful)
 */
static int cygwin_set_rate(struct wif *wi, int rate)
{
        if (wi || rate) {} /* XXX unused */

        return 0;
}

static void *cygwin_reader(void *arg)
{
        struct priv_cygwin *priv = arg;
        unsigned char buf[2048];
        int len;
        struct rx_info ri;

        while (priv->pc_running) {
                /* read one packet */

                /* a potential problem: the cygwin_read_packet will never return
                 * if there no packet sniffered, so the thread cannot be closed
                 * correctly.
                 */
                len = cygwin_read_packet(priv, buf, sizeof(buf), &ri);
                if (len == -1)
                        break;

                /* len */
                len += sizeof(ri);
                if (write(priv->pc_pipe[1], &len, sizeof(len)) != sizeof(len))
                        break;
                len -= sizeof(ri);

                /* ri */
                if (write(priv->pc_pipe[1], &ri, sizeof(ri)) != sizeof(ri))
                        break;

                /* packet */
                if (write(priv->pc_pipe[1], buf, len) != len)
                        break;
        }

        priv->pc_running = -1;
        return NULL;
}

static struct wif *cygwin_open(char *iface)
{
        struct wif *wi;
        struct priv_cygwin *priv;

        /* setup wi struct */
        wi = wi_alloc(sizeof(*priv));
        if (!wi)
                return NULL;
        wi->wi_read             = cygwin_read;
        wi->wi_write            = cygwin_write;
        wi->wi_set_channel      = cygwin_set_channel;
        wi->wi_get_channel      = cygwin_get_channel;
        wi->wi_set_freq         = cygwin_set_freq;
        wi->wi_get_freq         = cygwin_get_freq;
        wi->wi_close            = cygwin_close;
        wi->wi_fd               = cygwin_fd;
        wi->wi_get_mac          = cygwin_get_mac;
        wi->wi_set_mac          = cygwin_set_mac;
        wi->wi_get_rate         = cygwin_get_rate;
        wi->wi_set_rate         = cygwin_set_rate;
        wi->wi_get_monitor      = cygwin_get_monitor;

        /* setup iface */
        if (do_cygwin_open(wi, iface) == -1)
                goto err;

        /* setup private state */
        priv = wi_priv(wi);
        priv->pc_wi = wi;

        /* setup reader */
        if (pipe(priv->pc_pipe) == -1)
                goto err;
        priv->pc_running = 2;
        if (pthread_create(&priv->pc_reader, NULL, cygwin_reader, priv))
                goto err;
        priv->pc_running = 1;

        return wi;

err:
        do_free(wi);
        return NULL;
}

struct wif *wi_open_osdep(char *iface)
{
        return cygwin_open(iface);
}

/**
 * Return remaining battery time in seconds.
 * @return Battery time in seconds or 0 if no battery (or connected to power)
 */
int get_battery_state(void)
{
        SYSTEM_POWER_STATUS powerStatus;
        int batteryTime = 0;

        if (GetSystemPowerStatus(&powerStatus) == TRUE)
        {

                if (powerStatus.ACLineStatus == 0)
                        batteryTime = (int)powerStatus.BatteryLifeTime;

        }
        return batteryTime;
}