Logo Search packages:      
Sourcecode: aircrack-ng version File versions  Download package

netbsd.c

 /*
  *  Copyright (c) 2007, 2008, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
  *
  *  OS dependent API for NetBSD.
  *
  *  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/endian.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <net/bpf.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <sys/ioctl.h>
#include <net/if_dl.h>
#include <net80211/ieee80211.h>
#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_proto.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/uio.h>
#include <assert.h>
#include <ifaddrs.h>

#include "osdep.h"

#ifndef IEEE80211_RADIOTAP_F_FCS
#define IEEE80211_RADIOTAP_F_FCS    0x10  /* Frame includes FCS */
#endif

#ifndef IEEE80211_IOC_CHANNEL
#define IEEE80211_IOC_CHANNEL 0
#endif

#ifndef le32toh
#define le32toh(x)      htole32(x)
#endif

struct priv_nbsd {
      /* iface */
      int                     pn_fd;

      /* rx */
      int                     pn_nocrc;

      /* tx */
      unsigned char                 pn_buf[4096];
      unsigned char                 *pn_next;
      int                     pn_totlen;

      /* setchan */
      int                     pn_s;
      struct ifreq                  pn_ifr;
      struct ieee80211chanreq       pn_ireq;
        int                             pn_chan;
};

static void get_radiotap_info(struct priv_nbsd *pn,
                        struct ieee80211_radiotap_header *rth, int *plen,
                        struct rx_info *ri)
{
        uint32_t present;
      uint8_t rflags = 0;
      int i;
      unsigned char *body = (unsigned char*) (rth+1);
      int dbm_power = 0, db_power = 0;

      /* reset control info */
      if (ri)
            memset(ri, 0, sizeof(*ri));

            /* get info */
      present = le32toh(rth->it_present);
      for (i = IEEE80211_RADIOTAP_TSFT; i <= IEEE80211_RADIOTAP_EXT; i++) {
            if (!(present & (1 << i)))
                  continue;

            switch (i) {
            case IEEE80211_RADIOTAP_TSFT:
                  body += sizeof(uint64_t);
                  break;

            case IEEE80211_RADIOTAP_FLAGS:
                  rflags = *((uint8_t*)body);
                  /* fall through */
            case IEEE80211_RADIOTAP_RATE:
                  body += sizeof(uint8_t);
                  break;

            case IEEE80211_RADIOTAP_CHANNEL:
                  if (ri) {
                        ri->ri_channel = 1;
                  }
                  body += sizeof(uint16_t)*2;
                  break;

            case IEEE80211_RADIOTAP_FHSS:
                  body += sizeof(uint16_t);
                  break;

            case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
                  dbm_power = *body++;
                  break;

            case IEEE80211_RADIOTAP_DBM_ANTNOISE:
                  dbm_power -= *body++;
                  break;

            case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
                  db_power = *body++;
                  break;

            case IEEE80211_RADIOTAP_DB_ANTNOISE:
                  db_power -= *body++;
                  break;

            default:
                  i = IEEE80211_RADIOTAP_EXT+1;
                  break;
            }
      }

      /* set power */
      if (ri) {
            if (dbm_power)
                  ri->ri_power = dbm_power;
            else
                  ri->ri_power = db_power;
      }

        /* XXX cache; drivers won't change this per-packet */
        /* check if FCS/CRC is included in packet */
        if (pn->pn_nocrc || (rflags & IEEE80211_RADIOTAP_F_FCS)) {
                *plen -= IEEE80211_CRC_LEN;
                pn->pn_nocrc = 1;
        }
}

static unsigned char *get_80211(struct priv_nbsd *pn, int *plen,
                        struct rx_info *ri)
{
        struct bpf_hdr *bpfh;
        struct ieee80211_radiotap_header *rth;
        void *ptr;
        unsigned char **data;
      int *totlen;

      data = &pn->pn_next;
      totlen = &pn->pn_totlen;
      assert(*totlen);

        /* bpf hdr */
        bpfh = (struct bpf_hdr*) (*data);
        assert(bpfh->bh_caplen == bpfh->bh_datalen); /* XXX */
        *totlen -= bpfh->bh_hdrlen;

        /* check if more packets */
        if ((int)bpfh->bh_caplen < *totlen) {
            int tot = bpfh->bh_hdrlen + bpfh->bh_caplen;
            int offset = BPF_WORDALIGN(tot);

                *data = (unsigned char*)bpfh + offset;
            *totlen -= offset - tot; /* take into account align bytes */
      } else if ((int)bpfh->bh_caplen > *totlen)
            abort();

        *plen = bpfh->bh_caplen;
      *totlen -= bpfh->bh_caplen;
      assert(*totlen >= 0);

        /* radiotap */
        rth = (struct ieee80211_radiotap_header*)
              ((char*)bpfh + bpfh->bh_hdrlen);
      get_radiotap_info(pn, rth, plen, ri);
        *plen -= rth->it_len;
      assert(*plen > 0);

            /* data */
      ptr = (char*)rth + rth->it_len;

        return ptr;
}

static int nbsd_get_channel(struct wif *wi)
{
      struct priv_nbsd *pn = wi_priv(wi);
      struct ieee80211chanreq channel;

      memset(&channel, 0, sizeof(channel));
      strlcpy(channel.i_name, wi_get_ifname(wi), sizeof(channel.i_name));

      if(ioctl(pn->pn_s, SIOCG80211CHANNEL, (caddr_t)&channel) < 0) return -1;

      return channel.i_channel;
}

static int nbsd_set_channel(struct wif *wi, int chan)
{
      struct priv_nbsd *pn = wi_priv(wi);
      struct ieee80211chanreq channel;

      memset(&channel, 0, sizeof(channel));
      strlcpy(channel.i_name, wi_get_ifname(wi), sizeof(channel.i_name));
      channel.i_channel = chan;
      if(ioctl(pn->pn_s, SIOCS80211CHANNEL, (caddr_t)&channel) < 0) return -1;
      pn->pn_chan = chan;

      return 0;
}

static int nbsd_read(struct wif *wi, unsigned char *h80211, int len,
                 struct rx_info *ri)
{
      struct priv_nbsd *pn = wi_priv(wi);
      unsigned char *wh;
      int plen;

      assert(len > 0);

      /* need to read more */
      if (pn->pn_totlen == 0) {
            pn->pn_totlen = read(pn->pn_fd, pn->pn_buf, sizeof(pn->pn_buf));
            if (pn->pn_totlen == -1) {
                  pn->pn_totlen = 0;
                  return -1;
            }
            pn->pn_next = pn->pn_buf;
      }

      /* read 802.11 packet */
      wh = get_80211(pn, &plen, ri);
      if (plen > len)
            plen = len;
      assert(plen > 0);
      memcpy(h80211, wh, plen);

        if(ri && !ri->ri_channel)
            ri->ri_channel = wi_get_channel(wi);

      return plen;
}

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

      /* XXX make use of ti */
      if (ti) {}

      rc = write(pn->pn_fd, h80211, len);
      if (rc == -1)
            return rc;

      return 0;
}

static void do_free(struct wif *wi)
{
      assert(wi->wi_priv);
      free(wi->wi_priv);
      wi->wi_priv = 0;
      free(wi);
}

static void nbsd_close(struct wif *wi)
{
      struct priv_nbsd *pn = wi_priv(wi);

      close(pn->pn_fd);
      close(pn->pn_s);
      do_free(wi);
}

static int do_nbsd_open(struct wif *wi, char *iface)
{
        int i;
        char buf[64];
        int fd = -1;
        struct ifreq ifr;
        unsigned int dlt = DLT_IEEE802_11_RADIO;
        int s;
        unsigned int flags;
        struct ifmediareq ifmr;
        int *mwords;
      struct priv_nbsd *pn = wi_priv(wi);
      unsigned int size=sizeof(pn->pn_buf);

      /* basic sanity check */
      if (strlen(iface) >= sizeof(ifr.ifr_name))
            return -1;

        /* open wifi */
        s = socket(PF_INET, SOCK_DGRAM, 0);
        if (s == -1)
            return -1;
      pn->pn_s = s;

        /* set iface up and promisc */
        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, iface, IFNAMSIZ);
        if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1)
            goto close_sock;

        flags = ifr.ifr_flags;
        flags |= IFF_UP | IFF_PROMISC;
        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, iface, IFNAMSIZ);
        ifr.ifr_flags = flags & 0xffff;
        if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1)
            goto close_sock;

      /* monitor mode */
        memset(&ifmr, 0, sizeof(ifmr));
        strncpy(ifmr.ifm_name, iface, IFNAMSIZ);
        if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1)
            goto close_sock;

        assert(ifmr.ifm_count != 0);

        mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
        if (!mwords)
            goto close_sock;
        ifmr.ifm_ulist = mwords;
        if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
            free(mwords);
            goto close_sock;
      }
        free(mwords);

        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, iface, IFNAMSIZ);
        ifr.ifr_media = ifmr.ifm_current | IFM_IEEE80211_MONITOR;
        if (ioctl(s, SIOCSIFMEDIA, &ifr) == -1)
            goto close_sock;

      /* setup ifreq for chan that may be used in future */
      strncpy(pn->pn_ireq.i_name, iface, IFNAMSIZ);

      /* same for ifreq [mac addr] */
      strncpy(pn->pn_ifr.ifr_name, iface, IFNAMSIZ);

        /* open bpf */
        for(i = 0; i < 256; i++) {
                snprintf(buf, sizeof(buf), "/dev/bpf%d", i);

                fd = open(buf, O_RDWR);
                if(fd < 0) {
                        if(errno != EBUSY)
                        return -1;
                        continue;
                }
                else
                        break;
        }

        if(fd < 0)
            goto close_sock;

      if (ioctl(fd, BIOCSBLEN, &size) < 0)
            goto close_bpf;

      strncpy(ifr.ifr_name, iface, IFNAMSIZ);

        if (ioctl(fd, BIOCSETIF, &ifr) < 0)
            goto close_bpf;

        if (ioctl(fd, BIOCSDLT, &dlt) < 0)
            goto close_bpf;

      if(ioctl(fd, BIOCPROMISC, NULL) < 0)
            goto close_bpf;

        dlt = 1;
        if (ioctl(fd, BIOCIMMEDIATE, &dlt) == -1)
            goto close_bpf;

      return fd;

close_sock:
      close(s);
      return -1;
close_bpf:
      close(fd);
      goto close_sock;
}

static int nbsd_fd(struct wif *wi)
{
      struct priv_nbsd *pn = wi_priv(wi);

      return pn->pn_fd;
}

static int nbsd_get_mac(struct wif *wi, unsigned char *mac)
{
      struct ifaddrs *ifa, *p;
      char *name = wi_get_ifname(wi);
      int rc = -1;
      struct sockaddr_dl* sdp;

      if (getifaddrs(&ifa) == -1)
            return -1;

      p = ifa;
      while (p) {
            if (p->ifa_addr->sa_family == AF_LINK &&
                strcmp(name, p->ifa_name) == 0) {

                  sdp = (struct sockaddr_dl*) p->ifa_addr;
                  memcpy(mac, sdp->sdl_data + sdp->sdl_nlen, 6);
                  rc = 0;
                  break;
            }

            p = p->ifa_next;
      }
      freeifaddrs(ifa);

      return rc;
}

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

      /* XXX */
      return 0;
}

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

      /* XXX */
      return 1000000;
}

static int nbsd_set_rate(struct wif *wi, int rate)
{
      if (wi || rate) {} /* XXX unused */

      /* XXX */
      return 0;
}

static int nbsd_set_mac(struct wif *wi, unsigned char *mac)
{
      struct priv_nbsd *pn = wi_priv(wi);
      struct ifreq *ifr = &pn->pn_ifr;

      ifr->ifr_addr.sa_family = AF_LINK;
      ifr->ifr_addr.sa_len = 6;
      memcpy(ifr->ifr_addr.sa_data, mac, 6);

      return ioctl(pn->pn_s, SIOCSIFADDR, ifr);
}

static struct wif *nbsd_open(char *iface)
{
      struct wif *wi;
      struct priv_nbsd *pn;
      int fd;

      /* setup wi struct */
      wi = wi_alloc(sizeof(*pn));
      if (!wi)
            return NULL;
      wi->wi_read       = nbsd_read;
      wi->wi_write            = nbsd_write;
      wi->wi_set_channel      = nbsd_set_channel;
      wi->wi_get_channel      = nbsd_get_channel;
      wi->wi_close            = nbsd_close;
      wi->wi_fd         = nbsd_fd;
      wi->wi_get_mac          = nbsd_get_mac;
      wi->wi_set_mac          = nbsd_set_mac;
      wi->wi_get_rate         = nbsd_get_rate;
      wi->wi_set_rate         = nbsd_set_rate;
        wi->wi_get_monitor      = nbsd_get_monitor;

      /* setup iface */
      fd = do_nbsd_open(wi, iface);
      if (fd == -1) {
            do_free(wi);
            return NULL;
      }

      /* setup private state */
      pn = wi_priv(wi);
      pn->pn_fd = fd;

      return wi;
}

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

int get_battery_state(void)
{
#if defined(__FreeBSD__)
    int value;
    size_t len;

    len = 1;
    value = 0;
    sysctlbyname("hw.acpi.acline", &value, &len, NULL, 0);
    if (value == 0)
    {
            sysctlbyname("hw.acpi.battery.time", &value, &len, NULL, 0);
            value = value * 60;
    }
    else
    {
            value = 0;
    }

    return( value );
#elif defined(_BSD_SOURCE)
    struct apm_power_info api;
    int apmfd;
    if ((apmfd = open("/dev/apm", O_RDONLY)) < 0)
        return 0;
    if (ioctl(apmfd, APM_IOC_GETPOWER, &api) < 0) {
        close(apmfd);
        return 0;
    }
    close(apmfd);
    if (api.battery_state == APM_BATT_UNKNOWN ||
        api.battery_state == APM_BATTERY_ABSENT ||
        api.battery_state == APM_BATT_CHARGING ||
    api.ac_state == APM_AC_ON) {
        return 0;
    }
    return ((int)(api.minutes_left))*60;
#else
    return 0;
#endif
}

Generated by  Doxygen 1.6.0   Back to index