text:  /*
    *  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;
  }
  