nexmon – Rev 1

Subversion Repositories:
Rev:
 /*
  *  Copyright (c) 2010 Andrea Bittau <bittau@cs.stanford.edu>
  *
  *  OS dependent API for using card via a pcap file.
  *
  *  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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/select.h>
#include <errno.h>
#include <fcntl.h>
#include <err.h>

#include "osdep.h"
#include "pcap.h"
#include "radiotap/radiotap_iter.h"

struct priv_file {
        int             pf_fd;
        int             pf_chan;
        int             pf_rate;
        int             pf_dtl;
        unsigned char   pf_mac[6];
};

static int file_read(struct wif *wi, unsigned char *h80211, int len,
                    struct rx_info *ri)
{
        struct priv_file *pf = wi_priv(wi);
        struct pcap_pkthdr pkh;
        int rc;
        unsigned char buf[4096];
        int off = 0;
        struct ieee80211_radiotap_header *rh;
        struct ieee80211_radiotap_iterator iter;

        rc = read(pf->pf_fd, &pkh, sizeof(pkh));
        if (rc != sizeof(pkh))
                return -1;

        if (pkh.caplen > sizeof(buf)) {
                printf("Bad caplen %d\n", pkh.caplen);
                return 0;
        }

        assert(pkh.caplen <= sizeof(buf));

        rc = read(pf->pf_fd, buf, pkh.caplen);
        if (rc != (int) pkh.caplen)
                return -1;

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

        switch (pf->pf_dtl) {
        case LINKTYPE_IEEE802_11:
                off = 0;
                break;

        case LINKTYPE_RADIOTAP_HDR:
                rh  = (struct ieee80211_radiotap_header*) buf;
                off = le16_to_cpu(rh->it_len);

                if (ieee80211_radiotap_iterator_init(&iter, rh, rc, NULL) < 0)
                        return -1;

                while (ieee80211_radiotap_iterator_next(&iter) >= 0) {
                        switch (iter.this_arg_index) {
                        case IEEE80211_RADIOTAP_FLAGS:
                                if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
                                        rc -= 4;
                                break;
                        }
                }
                break;

        case LINKTYPE_PRISM_HEADER:
                if (buf[7] == 0x40)
                        off = 0x40;
                else
                        off = *((int *)(buf + 4));

                rc -= 4;
                break;

        case LINKTYPE_PPI_HDR:
                off = le16_to_cpu(*(unsigned short *)(buf + 2));

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

        case LINKTYPE_ETHERNET:
                printf("Ethernet packets\n");
                return 0;

        default:
                errx(1, "Unknown DTL %d", pf->pf_dtl);
                break;
        }

        rc -= off;
        assert(rc >= 0);

        if (rc > len)
                rc = len;

        memcpy(h80211, &buf[off], rc);

        return rc;
}

static int file_get_mac(struct wif *wi, unsigned char *mac)
{
        struct priv_file *pn = wi_priv(wi);

        memcpy(mac, pn->pf_mac, sizeof(pn->pf_mac));

        return 0;
}

static int file_write(struct wif *wi, unsigned char *h80211, int len,
                     struct tx_info *ti)
{
        struct priv_file *pn = wi_priv(wi);

        if (h80211 && ti && pn) {}

        return len;
}

static int file_set_channel(struct wif *wi, int chan)
{
        struct priv_file *pf = wi_priv(wi);

        pf->pf_chan = chan;

        return 0;
}

static int file_get_channel(struct wif *wi)
{
        struct priv_file *pf = wi_priv(wi);

        return pf->pf_chan;
}

static int file_set_rate(struct wif *wi, int rate)
{
        struct priv_file *pf = wi_priv(wi);

        pf->pf_rate = rate;

        return 0;
}

static int file_get_rate(struct wif *wi)
{
        struct priv_file *pf = wi_priv(wi);

        return pf->pf_rate;
}

static int file_get_monitor(struct wif *wi)
{
        if (wi) {}

        return 1;
}

static void file_close(struct wif *wi)
{
        struct priv_file *pn = wi_priv(wi);

        if (pn->pf_fd)
                close(pn->pf_fd);

        free(wi);
}

static int file_fd(struct wif *wi)
{
        struct priv_file *pf = wi_priv(wi);

        return pf->pf_fd;
}

struct wif *file_open(char *iface)
{
        struct wif *wi;
        struct priv_file *pf;
        int fd;
        struct pcap_file_header pfh;
        int rc;

        if (strncmp(iface, "file://", 7) != 0)
                return NULL;

        /* setup wi struct */
        wi = wi_alloc(sizeof(*pf));
        if (!wi)
                return NULL;

        wi->wi_read             = file_read;
        wi->wi_write            = file_write;
        wi->wi_set_channel      = file_set_channel;
        wi->wi_get_channel      = file_get_channel;
        wi->wi_set_rate         = file_set_rate;
        wi->wi_get_rate         = file_get_rate;
        wi->wi_close            = file_close;
        wi->wi_fd               = file_fd;
        wi->wi_get_mac          = file_get_mac;
        wi->wi_get_monitor      = file_get_monitor;

        pf = wi_priv(wi);

        fd = open(iface + 7, O_RDONLY);
        if (fd == -1)
                err(1, "open()");

        pf->pf_fd = fd;

        if ((rc = read(fd, &pfh, sizeof(pfh))) != sizeof(pfh))
                goto __err;

        if (pfh.magic != TCPDUMP_MAGIC)
                goto __err;

        if (pfh.version_major != PCAP_VERSION_MAJOR
            || pfh.version_minor != PCAP_VERSION_MINOR)
                goto __err;

        pf->pf_dtl = pfh.linktype;

        return wi;

__err:
        wi_close(wi);
        return (struct wif*) -1;
}