diff options
Diffstat (limited to 'package/hostapd/patches/002-add-nl80211-driver.patch')
-rw-r--r-- | package/hostapd/patches/002-add-nl80211-driver.patch | 2968 |
1 files changed, 2968 insertions, 0 deletions
diff --git a/package/hostapd/patches/002-add-nl80211-driver.patch b/package/hostapd/patches/002-add-nl80211-driver.patch new file mode 100644 index 0000000000..ba178a0541 --- /dev/null +++ b/package/hostapd/patches/002-add-nl80211-driver.patch @@ -0,0 +1,2968 @@ +diff -urN hostapd.orig/driver_nl80211.c hostapd/driver_nl80211.c +--- a/hostapd/driver_nl80211.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/hostapd/driver_nl80211.c 2008-02-16 19:46:38.000000000 +0100 +@@ -0,0 +1,2382 @@ ++/* ++ * hostapd / Kernel driver communication via nl80211 ++ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> ++ * Copyright (c) 2003-2004, Instant802 Networks, Inc. ++ * Copyright (c) 2005-2006, Devicescape Software, Inc. ++ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Alternatively, this software may be distributed under the terms of BSD ++ * license. ++ * ++ * See README and COPYING for more details. ++ */ ++ ++#include "includes.h" ++ ++#include <sys/ioctl.h> ++#include <netlink/genl/genl.h> ++#include <netlink/genl/family.h> ++#include <netlink/genl/ctrl.h> ++#include <netlink/msg.h> ++#include <netlink/attr.h> ++#include <linux/nl80211.h> ++#include <net/if.h> ++#include <linux/if_packet.h> ++#include <linux/if_ether.h> /* The L2 protocols */ ++#include <linux/wireless.h> ++#include <net/if_arp.h> ++ ++#include "hostapd.h" ++#include "driver.h" ++#include "ieee802_1x.h" ++#include "eloop.h" ++#include "ieee802_11.h" ++#include "sta_info.h" ++#include "hw_features.h" ++#include "mlme.h" ++#include "radiotap.h" ++#include "radiotap_iter.h" ++ ++enum ieee80211_msg_type { ++ ieee80211_msg_normal = 0, ++ ieee80211_msg_tx_callback_ack = 1, ++ ieee80211_msg_tx_callback_fail = 2, ++}; ++ ++struct i802_driver_data { ++ struct hostapd_data *hapd; ++ ++ char iface[IFNAMSIZ + 1]; ++ int ioctl_sock; /* socket for ioctl() use */ ++ int wext_sock; /* socket for wireless events */ ++ int eapol_sock; /* socket for EAPOL frames */ ++ int monitor_sock; /* socket for monitor */ ++ int monitor_ifidx; ++ ++ int default_if_indices[16]; ++ int *if_indices; ++ int num_if_indices; ++ ++ int we_version; ++ struct nl_handle *nl_handle; ++ struct nl_cache *nl_cache; ++ struct genl_family *nl80211; ++ int dtim_period; ++ unsigned int beacon_set:1; ++ unsigned int ieee802_1x_active:1; ++}; ++ ++ ++static void add_ifidx(struct i802_driver_data *drv, int ifidx) ++{ ++ int i; ++ int *old; ++ ++ for (i = 0; i < drv->num_if_indices; i++) { ++ if (drv->if_indices[i] == 0) { ++ drv->if_indices[i] = ifidx; ++ return; ++ } ++ } ++ ++ if (drv->if_indices != drv->default_if_indices) ++ old = drv->if_indices; ++ else ++ old = NULL; ++ ++ drv->if_indices = realloc(old, ++ sizeof(int) * (drv->num_if_indices + 1)); ++ if (!drv->if_indices) { ++ if (!old) ++ drv->if_indices = drv->default_if_indices; ++ else ++ drv->if_indices = old; ++ wpa_printf(MSG_ERROR, "Failed to reallocate memory for " ++ "interfaces"); ++ wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); ++ return; ++ } ++ drv->if_indices[drv->num_if_indices] = ifidx; ++ drv->num_if_indices++; ++} ++ ++ ++static void del_ifidx(struct i802_driver_data *drv, int ifidx) ++{ ++ int i; ++ ++ for (i = 0; i < drv->num_if_indices; i++) { ++ if (drv->if_indices[i] == ifidx) { ++ drv->if_indices[i] = 0; ++ break; ++ } ++ } ++} ++ ++ ++static int have_ifidx(struct i802_driver_data *drv, int ifidx) ++{ ++ int i; ++ ++ for (i = 0; i < drv->num_if_indices; i++) ++ if (drv->if_indices[i] == ifidx) ++ return 1; ++ ++ return 0; ++} ++ ++ ++/* helper for netlink get routines */ ++static int ack_wait_handler(struct nl_msg *msg, void *arg) ++{ ++ int *finished = arg; ++ ++ *finished = 1; ++ return NL_STOP; ++} ++ ++ ++static int hostapd_set_iface_flags(struct i802_driver_data *drv, ++ const char *ifname, int dev_up) ++{ ++ struct ifreq ifr; ++ ++ if (drv->ioctl_sock < 0) ++ return -1; ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { ++ perror("ioctl[SIOCGIFFLAGS]"); ++ wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)", ++ drv->iface); ++ return -1; ++ } ++ ++ if (dev_up) ++ ifr.ifr_flags |= IFF_UP; ++ else ++ ifr.ifr_flags &= ~IFF_UP; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { ++ perror("ioctl[SIOCSIFFLAGS]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_set_encryption(const char *iface, void *priv, const char *alg, ++ const u8 *addr, int idx, const u8 *key, ++ size_t key_len, int txkey) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ int err = 0; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ if (strcmp(alg, "none") == 0) { ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_DEL_KEY, 0); ++ } else { ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_NEW_KEY, 0); ++ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); ++ if (strcmp(alg, "WEP") == 0) { ++ if (key_len == 5) ++ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, ++ 0x000FAC01); ++ else ++ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, ++ 0x000FAC05); ++ } else if (strcmp(alg, "TKIP") == 0) ++ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02); ++ else if (strcmp(alg, "CCMP") == 0) ++ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); ++ else ++ goto out; ++ } ++ ++ if (addr) ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ (err = nl_wait_for_ack(drv->nl_handle)) < 0) { ++ if (err != -ENOENT) { ++ err = 0; ++ goto out; ++ } ++ } ++ ++ /* ++ * If we need to set the default TX key we do that below, ++ * otherwise we're done here. ++ */ ++ if (!txkey || addr) { ++ ret = 0; ++ goto out; ++ } ++ ++ nlmsg_free(msg); ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_KEY, 0); ++ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ (err = nl_wait_for_ack(drv->nl_handle)) < 0) { ++ if (err != -ENOENT) { ++ err = 0; ++ goto out; ++ } ++ } ++ ++ ret = 0; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static inline int min_int(int a, int b) ++{ ++ if (a < b) ++ return a; ++ return b; ++} ++ ++ ++static int get_key_handler(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *tb[NL80211_ATTR_MAX]; ++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); ++ ++ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), ++ genlmsg_attrlen(gnlh, 0), NULL); ++ ++ /* ++ * TODO: validate the key index and mac address! ++ * Otherwise, there's a race condition as soon as ++ * the kernel starts sending key notifications. ++ */ ++ ++ if (tb[NL80211_ATTR_KEY_SEQ]) ++ memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), ++ min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); ++ return NL_SKIP; ++} ++ ++ ++static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, ++ int idx, u8 *seq) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ struct nl_cb *cb = NULL; ++ int ret = -1; ++ int err = 0; ++ int finished = 0; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_GET_KEY, 0); ++ ++ if (addr) ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ ++ cb = nl_cb_alloc(NL_CB_CUSTOM); ++ if (!cb) ++ goto out; ++ ++ memset(seq, 0, 6); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0) ++ goto out; ++ ++ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_key_handler, seq); ++ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); ++ ++ err = nl_recvmsgs(drv->nl_handle, cb); ++ ++ if (!finished) ++ err = nl_wait_for_ack(drv->nl_handle); ++ ++ if (err < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nl_cb_put(cb); ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, ++ int mode) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_ssid(const char *ifname, void *priv, const u8 *buf, ++ int len) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); ++ iwr.u.essid.flags = 1; /* SSID active */ ++ iwr.u.essid.pointer = (caddr_t) buf; ++ iwr.u.essid.length = len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { ++ perror("ioctl[SIOCSIWESSID]"); ++ printf("len=%d\n", len); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_send_mgmt_frame(void *priv, const void *data, size_t len, ++ int flags) ++{ ++ struct ieee80211_hdr *hdr = (void*) data; ++ __u8 rtap_hdr[] = { ++ 0x00, 0x00, /* radiotap version */ ++ 0x0e, 0x00, /* radiotap length */ ++ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ ++ 0x0c, /* F_WEP | F_FRAG (encrypt/fragment if required) */ ++ 0x00, /* padding */ ++ 0x00, 0x00, /* RX and TX flags to indicate that */ ++ 0x00, 0x00, /* this is the injected frame directly */ ++ }; ++ struct i802_driver_data *drv = priv; ++ struct iovec iov[2] = { ++ { ++ .iov_base = &rtap_hdr, ++ .iov_len = sizeof(rtap_hdr), ++ }, ++ { ++ .iov_base = (void*)data, ++ .iov_len = len, ++ } ++ }; ++ struct msghdr msg = { ++ .msg_name = NULL, ++ .msg_namelen = 0, ++ .msg_iov = iov, ++ .msg_iovlen = 2, ++ .msg_control = NULL, ++ .msg_controllen = 0, ++ .msg_flags = 0, ++ }; ++ ++ /* ++ * ugh, guess what, the generic code sets one of the version ++ * bits to request tx callback ++ */ ++ hdr->frame_control &= ~host_to_le16(BIT(1)); ++ return sendmsg(drv->monitor_sock, &msg, flags); ++} ++ ++ ++/* Set kernel driver on given frequency (MHz) */ ++static int i802_set_freq(void *priv, int mode, int freq) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ iwr.u.freq.m = freq; ++ iwr.u.freq.e = 6; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { ++ perror("ioctl[SIOCSIWFREQ]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_set_rts(void *priv, int rts) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ iwr.u.rts.value = rts; ++ iwr.u.rts.fixed = 1; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &iwr) < 0) { ++ perror("ioctl[SIOCSIWRTS]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_get_rts(void *priv, int *rts) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &iwr) < 0) { ++ perror("ioctl[SIOCGIWRTS]"); ++ return -1; ++ } ++ ++ *rts = iwr.u.rts.value; ++ ++ return 0; ++} ++ ++ ++static int i802_set_frag(void *priv, int frag) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ iwr.u.frag.value = frag; ++ iwr.u.frag.fixed = 1; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { ++ perror("ioctl[SIOCSIWFRAG]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_get_frag(void *priv, int *frag) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWFRAG, &iwr) < 0) { ++ perror("ioctl[SIOCGIWFRAG]"); ++ return -1; ++ } ++ ++ *frag = iwr.u.frag.value; ++ ++ return 0; ++} ++ ++ ++static int i802_set_retry(void *priv, int short_retry, int long_retry) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ ++ iwr.u.retry.value = short_retry; ++ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; ++ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { ++ perror("ioctl[SIOCSIWRETRY(short)]"); ++ return -1; ++ } ++ ++ iwr.u.retry.value = long_retry; ++ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; ++ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { ++ perror("ioctl[SIOCSIWRETRY(long)]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_get_retry(void *priv, int *short_retry, int *long_retry) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ ++ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; ++ if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { ++ perror("ioctl[SIOCGIWFRAG(short)]"); ++ return -1; ++ } ++ *short_retry = iwr.u.retry.value; ++ ++ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; ++ if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { ++ perror("ioctl[SIOCGIWFRAG(long)]"); ++ return -1; ++ } ++ *long_retry = iwr.u.retry.value; ++ ++ return 0; ++} ++ ++ ++static int i802_flush(void *priv) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_NEW_STATION, 0); ++ ++ /* ++ * XXX: FIX! this needs to flush all VLANs too ++ */ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ ++ ret = 0; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ ret = -1; ++ } ++ ++ nla_put_failure: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static int get_sta_handler(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *tb[NL80211_ATTR_MAX + 1]; ++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); ++ struct hostap_sta_driver_data *data = arg; ++ struct nlattr *stats[NL80211_STA_STAT_MAX + 1]; ++ static struct nla_policy stats_policy[NL80211_STA_STAT_MAX + 1] = { ++ [NL80211_STA_STAT_INACTIVE_TIME] = { .type = NLA_U32 }, ++ [NL80211_STA_STAT_RX_BYTES] = { .type = NLA_U32 }, ++ [NL80211_STA_STAT_TX_BYTES] = { .type = NLA_U32 }, ++ }; ++ ++ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), ++ genlmsg_attrlen(gnlh, 0), NULL); ++ ++ /* ++ * TODO: validate the interface and mac address! ++ * Otherwise, there's a race condition as soon as ++ * the kernel starts sending station notifications. ++ */ ++ ++ if (!tb[NL80211_ATTR_STA_STATS]) { ++ wpa_printf(MSG_DEBUG, "sta stats missing!"); ++ return NL_SKIP; ++ } ++ if (nla_parse_nested(stats, NL80211_STA_STAT_MAX, ++ tb[NL80211_ATTR_STA_STATS], ++ stats_policy)) { ++ wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); ++ return NL_SKIP; ++ } ++ ++ if (stats[NL80211_STA_STAT_INACTIVE_TIME]) ++ data->inactive_msec = ++ nla_get_u32(stats[NL80211_STA_STAT_INACTIVE_TIME]); ++ if (stats[NL80211_STA_STAT_RX_BYTES]) ++ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_RX_BYTES]); ++ if (stats[NL80211_STA_STAT_TX_BYTES]) ++ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_TX_BYTES]); ++ ++ return NL_SKIP; ++} ++ ++static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, ++ const u8 *addr) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ struct nl_cb *cb = NULL; ++ int ret = -1; ++ int err = 0; ++ int finished = 0; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_GET_STATION, 0); ++ ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); ++ ++ cb = nl_cb_alloc(NL_CB_CUSTOM); ++ if (!cb) ++ goto out; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0) ++ goto out; ++ ++ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data); ++ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); ++ ++ err = nl_recvmsgs(drv->nl_handle, cb); ++ ++ if (!finished) ++ err = nl_wait_for_ack(drv->nl_handle); ++ ++ if (err < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nl_cb_put(cb); ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++ ++} ++ ++ ++static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data, ++ size_t data_len, int encrypt, const u8 *own_addr) ++{ ++ struct i802_driver_data *drv = priv; ++ struct ieee80211_hdr *hdr; ++ size_t len; ++ u8 *pos; ++ int res; ++#if 0 /* FIX */ ++ int qos = sta->flags & WLAN_STA_WME; ++#else ++ int qos = 0; ++#endif ++ ++ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + ++ data_len; ++ hdr = os_zalloc(len); ++ if (hdr == NULL) { ++ printf("malloc() failed for i802_send_data(len=%lu)\n", ++ (unsigned long) len); ++ return -1; ++ } ++ ++ hdr->frame_control = ++ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); ++ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); ++ if (encrypt) ++ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); ++#if 0 /* To be enabled if qos determination is added above */ ++ if (qos) { ++ hdr->frame_control |= ++ host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); ++ } ++#endif ++ ++ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); ++ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); ++ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); ++ pos = (u8 *) (hdr + 1); ++ ++#if 0 /* To be enabled if qos determination is added above */ ++ if (qos) { ++ /* add an empty QoS header if needed */ ++ pos[0] = 0; ++ pos[1] = 0; ++ pos += 2; ++ } ++#endif ++ ++ memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); ++ pos += sizeof(rfc1042_header); ++ WPA_PUT_BE16(pos, ETH_P_PAE); ++ pos += 2; ++ memcpy(pos, data, data_len); ++ ++ res = i802_send_mgmt_frame(drv, (u8 *) hdr, len, 0); ++ free(hdr); ++ ++ if (res < 0) { ++ perror("i802_send_eapol: send"); ++ printf("i802_send_eapol - packet len: %lu - failed\n", ++ (unsigned long) len); ++ } ++ ++ return res; ++} ++ ++ ++static int i802_sta_add(const char *ifname, void *priv, const u8 *addr, ++ u16 aid, u16 capability, u8 *supp_rates, ++ size_t supp_rates_len, int flags) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_NEW_STATION, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, aid); ++ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len, ++ supp_rates); ++ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 0); ++ ++ ret = nl_send_auto_complete(drv->nl_handle, msg); ++ if (ret < 0) ++ goto nla_put_failure; ++ ++ ret = nl_wait_for_ack(drv->nl_handle); ++ /* ignore EEXIST, this happens if a STA associates while associated */ ++ if (ret == -EEXIST || ret >= 0) ++ ret = 0; ++ ++ nla_put_failure: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static int i802_sta_remove(void *priv, const u8 *addr) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_DEL_STATION, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ ++ ret = 0; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ ret = -1; ++ } ++ ++ nla_put_failure: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static int i802_sta_set_flags(void *priv, const u8 *addr, ++ int total_flags, int flags_or, int flags_and) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg, *flags = NULL; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ flags = nlmsg_alloc(); ++ if (!flags) ++ goto free_msg; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_STATION, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ ++ if (total_flags & WLAN_STA_AUTHORIZED || !drv->ieee802_1x_active) ++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); ++ ++ if (total_flags & WLAN_STA_WME) ++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); ++ ++ if (total_flags & WLAN_STA_SHORT_PREAMBLE) ++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); ++ ++ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) ++ goto nla_put_failure; ++ ++ ret = 0; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ ret = -1; ++ } ++ ++ nla_put_failure: ++ nlmsg_free(flags); ++ ++ free_msg: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static int i802_set_channel_flag(void *priv, int mode, int chan, int flag, ++ unsigned char power_level, ++ unsigned char antenna_max) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_regulatory_domain(void *priv, unsigned int rd) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_tx_queue_params(void *priv, int queue, int aifs, ++ int cw_min, int cw_max, int burst_time) ++{ ++ return -1; ++} ++ ++ ++static void nl80211_remove_iface(struct i802_driver_data *drv, int ifidx) ++{ ++ struct nl_msg *msg; ++ ++ /* stop listening for EAPOL on this interface */ ++ del_ifidx(drv, ifidx); ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto nla_put_failure; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_DEL_INTERFACE, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ nla_put_failure: ++ printf("Failed to remove interface.\n"); ++ nlmsg_free(msg); ++} ++ ++ ++static int nl80211_create_iface(struct i802_driver_data *drv, ++ const char *ifname, ++ enum nl80211_iftype iftype, ++ const u8 *addr) ++{ ++ struct nl_msg *msg, *flags = NULL; ++ int ifidx; ++ struct ifreq ifreq; ++ struct iwreq iwr; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ return -1; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_NEW_INTERFACE, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->hapd->conf->iface)); ++ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); ++ ++ if (iftype == NL80211_IFTYPE_MONITOR) { ++ int err; ++ ++ flags = nlmsg_alloc(); ++ if (!flags) ++ goto nla_put_failure; ++ ++ NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); ++ ++ err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); ++ ++ nlmsg_free(flags); ++ ++ if (err) ++ goto nla_put_failure; ++ } ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ nla_put_failure: ++ printf("Failed to create interface %s.\n", ifname); ++ nlmsg_free(msg); ++ return -1; ++ } ++ ++ nlmsg_free(msg); ++ ++ ifidx = if_nametoindex(ifname); ++ ++ if (ifidx <= 0) ++ return -1; ++ ++ /* start listening for EAPOL on this interface */ ++ add_ifidx(drv, ifidx); ++ ++ if (addr) { ++ switch (iftype) { ++ case NL80211_IFTYPE_AP: ++ os_strlcpy(ifreq.ifr_name, ifname, IFNAMSIZ); ++ memcpy(ifreq.ifr_hwaddr.sa_data, addr, ETH_ALEN); ++ ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifreq)) { ++ nl80211_remove_iface(drv, ifidx); ++ return -1; ++ } ++ break; ++ case NL80211_IFTYPE_WDS: ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); ++ iwr.u.addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwr.u.addr.sa_data, addr, ETH_ALEN); ++ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr)) ++ return -1; ++ break; ++ default: ++ /* nothing */ ++ break; ++ } ++ } ++ ++ return ifidx; ++} ++ ++ ++static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid) ++{ ++ int ifidx; ++ ++ /* ++ * The kernel supports that when the low-level driver does, ++ * but we currently don't because we need per-BSS data that ++ * currently we can't handle easily. ++ */ ++ return -1; ++ ++ ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid); ++ if (ifidx < 0) ++ return -1; ++ if (hostapd_set_iface_flags(priv, ifname, 1)) { ++ nl80211_remove_iface(priv, ifidx); ++ return -1; ++ } ++ return 0; ++} ++ ++ ++static int i802_bss_remove(void *priv, const char *ifname) ++{ ++ nl80211_remove_iface(priv, if_nametoindex(ifname)); ++ return 0; ++} ++ ++ ++static int i802_set_beacon(const char *iface, void *priv, ++ u8 *head, size_t head_len, ++ u8 *tail, size_t tail_len) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ u8 cmd = NL80211_CMD_NEW_BEACON; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ if (drv->beacon_set) ++ cmd = NL80211_CMD_SET_BEACON; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, cmd, 0); ++ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); ++ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, 1000); ++ ++ if (!drv->dtim_period) ++ drv->dtim_period = 2; ++ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ goto out; ++ ++ ret = 0; ++ ++ drv->beacon_set = 1; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_del_beacon(struct i802_driver_data *drv) ++{ ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_DEL_BEACON, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_set_ieee8021x(const char *ifname, void *priv, int enabled) ++{ ++ struct i802_driver_data *drv = priv; ++ ++ /* ++ * FIXME: This needs to be per interface (BSS) ++ */ ++ drv->ieee802_1x_active = enabled; ++ return 0; ++} ++ ++ ++static int i802_set_privacy(const char *ifname, void *priv, int enabled) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ ++ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); ++ iwr.u.param.flags = IW_AUTH_PRIVACY_INVOKED; ++ iwr.u.param.value = enabled; ++ ++ ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr); ++ ++ /* ignore errors, the kernel/driver might not care */ ++ return 0; ++} ++ ++ ++static int i802_set_internal_bridge(void *priv, int value) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_beacon_int(void *priv, int value) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_BEACON, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_set_dtim_period(const char *iface, void *priv, int value) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_BEACON, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ ++ drv->dtim_period = value; ++ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_set_cts_protect(void *priv, int value) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_preamble(void *priv, int value) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_short_slot_time(void *priv, int value) ++{ ++ return -1; ++} ++ ++ ++static enum nl80211_iftype i802_if_type(enum hostapd_driver_if_type type) ++{ ++ switch (type) { ++ case HOSTAPD_IF_VLAN: ++ return NL80211_IFTYPE_AP_VLAN; ++ case HOSTAPD_IF_WDS: ++ return NL80211_IFTYPE_WDS; ++ } ++ return -1; ++} ++ ++ ++static int i802_if_add(const char *iface, void *priv, ++ enum hostapd_driver_if_type type, char *ifname, ++ const u8 *addr) ++{ ++ if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr) < 0) ++ return -1; ++ return 0; ++} ++ ++ ++static int i802_if_update(void *priv, enum hostapd_driver_if_type type, ++ char *ifname, const u8 *addr) ++{ ++ /* unused at the moment */ ++ return -1; ++} ++ ++ ++static int i802_if_remove(void *priv, enum hostapd_driver_if_type type, ++ const char *ifname, const u8 *addr) ++{ ++ nl80211_remove_iface(priv, if_nametoindex(ifname)); ++ return 0; ++} ++ ++ ++struct phy_info_arg { ++ u16 *num_modes; ++ struct hostapd_hw_modes *modes; ++ int error; ++}; ++ ++static int phy_info_handler(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; ++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); ++ struct phy_info_arg *phy_info = arg; ++ ++ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; ++ ++ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; ++ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { ++ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, ++ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, ++ [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, ++ [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, ++ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, ++ }; ++ ++ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; ++ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { ++ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, ++ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, ++ }; ++ ++ struct nlattr *nl_band; ++ struct nlattr *nl_freq; ++ struct nlattr *nl_rate; ++ int rem_band, rem_freq, rem_rate; ++ struct hostapd_hw_modes *mode; ++ int idx, mode_is_set; ++ ++ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), ++ genlmsg_attrlen(gnlh, 0), NULL); ++ ++ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) ++ return NL_SKIP; ++ ++ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { ++ mode = realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode)); ++ if (!mode) ++ return NL_SKIP; ++ phy_info->modes = mode; ++ ++ mode_is_set = 0; ++ ++ mode = &phy_info->modes[*(phy_info->num_modes)]; ++ memset(mode, 0, sizeof(*mode)); ++ *(phy_info->num_modes) += 1; ++ ++ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), ++ nla_len(nl_band), NULL); ++ ++ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { ++ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), ++ nla_len(nl_freq), freq_policy); ++ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) ++ continue; ++ mode->num_channels++; ++ } ++ ++ mode->channels = calloc(mode->num_channels, sizeof(struct hostapd_channel_data)); ++ if (!mode->channels) ++ return NL_SKIP; ++ ++ idx = 0; ++ ++ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { ++ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), ++ nla_len(nl_freq), freq_policy); ++ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) ++ continue; ++ ++ mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); ++ mode->channels[idx].flag |= HOSTAPD_CHAN_W_SCAN | ++ HOSTAPD_CHAN_W_ACTIVE_SCAN | ++ HOSTAPD_CHAN_W_IBSS; ++ ++ if (!mode_is_set) { ++ /* crude heuristic */ ++ if (mode->channels[idx].freq < 4000) ++ mode->mode = HOSTAPD_MODE_IEEE80211B; ++ else ++ mode->mode = HOSTAPD_MODE_IEEE80211A; ++ mode_is_set = 1; ++ } ++ ++ /* crude heuristic */ ++ if (mode->channels[idx].freq < 4000) ++ if (mode->channels[idx].freq == 2848) ++ mode->channels[idx].chan = 14; ++ else ++ mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5; ++ else ++ mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000; ++ ++ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) ++ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_SCAN; ++ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) ++ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_ACTIVE_SCAN; ++ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) ++ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_IBSS; ++ idx++; ++ } ++ ++ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { ++ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), ++ nla_len(nl_rate), rate_policy); ++ if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) ++ continue; ++ mode->num_rates++; ++ } ++ ++ mode->rates = calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); ++ if (!mode->rates) ++ return NL_SKIP; ++ ++ idx = 0; ++ ++ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { ++ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), ++ nla_len(nl_rate), rate_policy); ++ if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) ++ continue; ++ mode->rates[idx].rate = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); ++ ++ /* crude heuristic */ ++ if (mode->mode == HOSTAPD_MODE_IEEE80211B && ++ mode->rates[idx].rate > 200) ++ mode->mode = HOSTAPD_MODE_IEEE80211G; ++ ++ if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE]) ++ mode->rates[idx].flags |= HOSTAPD_RATE_PREAMBLE2; ++ ++ idx++; ++ } ++ } ++ ++ phy_info->error = 0; ++ ++ return NL_SKIP; ++} ++ ++static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv, ++ u16 *num_modes, ++ u16 *flags) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int err = -1; ++ struct nl_cb *cb = NULL; ++ int finished; ++ struct phy_info_arg result = { ++ .num_modes = num_modes, ++ .modes = NULL, ++ .error = 1, ++ }; ++ ++ *num_modes = 0; ++ *flags = 0; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ return NULL; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_GET_WIPHY, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); ++ ++ cb = nl_cb_alloc(NL_CB_CUSTOM); ++ if (!cb) ++ goto out; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0) ++ goto out; ++ ++ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, phy_info_handler, &result); ++ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); ++ ++ err = nl_recvmsgs(drv->nl_handle, cb); ++ ++ if (!finished) ++ err = nl_wait_for_ack(drv->nl_handle); ++ ++ if (err < 0 || result.error) { ++ hostapd_free_hw_features(result.modes, *num_modes); ++ result.modes = NULL; ++ } ++ ++ out: ++ nl_cb_put(cb); ++ nla_put_failure: ++ if (err) ++ fprintf(stderr, "failed to get information: %d\n", err); ++ nlmsg_free(msg); ++ return result.modes; ++} ++ ++ ++static int i802_set_sta_vlan(void *priv, const u8 *addr, ++ const char *ifname, int vlan_id) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_STATION, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(ifname)); ++ ++ ret = 0; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ (errno = nl_wait_for_ack(drv->nl_handle) < 0)) { ++ ret = -1; ++ } ++ ++ nla_put_failure: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static void handle_unknown_sta(struct hostapd_data *hapd, u8 *ta) ++{ ++ struct sta_info *sta; ++ ++ sta = ap_get_sta(hapd, ta); ++ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { ++ printf("Data/PS-poll frame from not associated STA " ++ MACSTR "\n", MAC2STR(ta)); ++ if (sta && (sta->flags & WLAN_STA_AUTH)) ++ hostapd_sta_disassoc( ++ hapd, ta, ++ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ else ++ hostapd_sta_deauth( ++ hapd, ta, ++ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ } ++} ++ ++ ++static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len, ++ int ok) ++{ ++ struct ieee80211_hdr *hdr; ++ u16 fc, type, stype; ++ struct sta_info *sta; ++ ++ hdr = (struct ieee80211_hdr *) buf; ++ fc = le_to_host16(hdr->frame_control); ++ ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ ++ switch (type) { ++ case WLAN_FC_TYPE_MGMT: ++ wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s", ++ ok ? "ACK" : "fail"); ++ ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); ++ break; ++ case WLAN_FC_TYPE_CTRL: ++ wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s", ++ ok ? "ACK" : "fail"); ++ break; ++ case WLAN_FC_TYPE_DATA: ++ wpa_printf(MSG_DEBUG, "DATA (TX callback) %s", ++ ok ? "ACK" : "fail"); ++ sta = ap_get_sta(hapd, hdr->addr1); ++ if (sta && sta->flags & WLAN_STA_PENDING_POLL) { ++ wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " ++ "activity poll", MAC2STR(sta->addr), ++ ok ? "ACKed" : "did not ACK"); ++ if (ok) ++ sta->flags &= ~WLAN_STA_PENDING_POLL; ++ } ++ if (sta) ++ ieee802_1x_tx_status(hapd, sta, buf, len, ok); ++ break; ++ default: ++ printf("unknown TX callback frame type %d\n", type); ++ break; ++ } ++} ++ ++ ++static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len, ++ struct hostapd_frame_info *hfi, ++ enum ieee80211_msg_type msg_type) ++{ ++ struct ieee80211_hdr *hdr; ++ u16 fc, type, stype; ++ size_t data_len = len; ++ struct hostapd_data *hapd = NULL; ++ int broadcast_bssid = 0; ++ size_t i; ++ u8 *bssid; ++ ++ /* ++ * PS-Poll frames are 16 bytes. All other frames are ++ * 24 bytes or longer. ++ */ ++ if (len < 16) ++ return; ++ ++ hdr = (struct ieee80211_hdr *) buf; ++ fc = le_to_host16(hdr->frame_control); ++ ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ ++ switch (type) { ++ case WLAN_FC_TYPE_DATA: ++ if (len < 24) ++ return; ++ switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { ++ case WLAN_FC_TODS: ++ bssid = hdr->addr1; ++ break; ++ default: ++ /* discard */ ++ return; ++ } ++ break; ++ case WLAN_FC_TYPE_CTRL: ++ /* discard non-ps-poll frames */ ++ if (stype != WLAN_FC_STYPE_PSPOLL) ++ return; ++ bssid = hdr->addr1; ++ break; ++ case WLAN_FC_TYPE_MGMT: ++ bssid = hdr->addr3; ++ break; ++ default: ++ /* discard */ ++ return; ++ } ++ ++ /* find interface frame belongs to */ ++ for (i = 0; i < iface->num_bss; i++) { ++ if (memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) { ++ hapd = iface->bss[i]; ++ break; ++ } ++ } ++ ++ if (hapd == NULL) { ++ hapd = iface->bss[0]; ++ ++ if (bssid[0] != 0xff || bssid[1] != 0xff || ++ bssid[2] != 0xff || bssid[3] != 0xff || ++ bssid[4] != 0xff || bssid[5] != 0xff) { ++ /* ++ * Unknown BSSID - drop frame if this is not from ++ * passive scanning or a beacon (at least ProbeReq ++ * frames to other APs may be allowed through RX ++ * filtering in the wlan hw/driver) ++ */ ++ if ((type != WLAN_FC_TYPE_MGMT || ++ stype != WLAN_FC_STYPE_BEACON)) ++ return; ++ } else ++ broadcast_bssid = 1; ++ } ++ ++ switch (msg_type) { ++ case ieee80211_msg_normal: ++ /* continue processing */ ++ break; ++ case ieee80211_msg_tx_callback_ack: ++ handle_tx_callback(hapd, buf, data_len, 1); ++ return; ++ case ieee80211_msg_tx_callback_fail: ++ handle_tx_callback(hapd, buf, data_len, 0); ++ return; ++ } ++ ++ switch (type) { ++ case WLAN_FC_TYPE_MGMT: ++ if (stype != WLAN_FC_STYPE_BEACON && ++ stype != WLAN_FC_STYPE_PROBE_REQ) ++ wpa_printf(MSG_MSGDUMP, "MGMT"); ++ if (broadcast_bssid) { ++ for (i = 0; i < iface->num_bss; i++) ++ ieee802_11_mgmt(iface->bss[i], buf, data_len, ++ stype, hfi); ++ } else ++ ieee802_11_mgmt(hapd, buf, data_len, stype, hfi); ++ break; ++ case WLAN_FC_TYPE_CTRL: ++ /* can only get here with PS-Poll frames */ ++ wpa_printf(MSG_DEBUG, "CTRL"); ++ handle_unknown_sta(hapd, hdr->addr2); ++ break; ++ case WLAN_FC_TYPE_DATA: ++ wpa_printf(MSG_DEBUG, "DATA"); ++ handle_unknown_sta(hapd, hdr->addr2); ++ break; ++ } ++} ++ ++ ++static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) ++{ ++ struct i802_driver_data *drv = eloop_ctx; ++ struct hostapd_data *hapd = drv->hapd; ++ struct sockaddr_ll lladdr; ++ unsigned char buf[3000]; ++ int len; ++ socklen_t fromlen = sizeof(lladdr); ++ ++ len = recvfrom(sock, buf, sizeof(buf), 0, ++ (struct sockaddr *)&lladdr, &fromlen); ++ if (len < 0) { ++ perror("recv"); ++ return; ++ } ++ ++ if (have_ifidx(drv, lladdr.sll_ifindex)) ++ ieee802_1x_receive(hapd, lladdr.sll_addr, buf, len); ++} ++ ++ ++static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) ++{ ++ struct i802_driver_data *drv = eloop_ctx; ++ int len; ++ unsigned char buf[3000]; ++ struct hostapd_data *hapd = drv->hapd; ++ struct ieee80211_radiotap_iterator iter; ++ int ret; ++ struct hostapd_frame_info hfi; ++ int injected = 0, failed = 0, msg_type, rxflags = 0; ++ ++ len = recv(sock, buf, sizeof(buf), 0); ++ if (len < 0) { ++ perror("recv"); ++ return; ++ } ++ ++ if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { ++ printf("received invalid radiotap frame\n"); ++ return; ++ } ++ ++ memset(&hfi, 0, sizeof(hfi)); ++ ++ while (1) { ++ ret = ieee80211_radiotap_iterator_next(&iter); ++ if (ret == -ENOENT) ++ break; ++ if (ret) { ++ printf("received invalid radiotap frame (%d)\n", ret); ++ return; ++ } ++ switch (iter.this_arg_index) { ++ case IEEE80211_RADIOTAP_FLAGS: ++ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) ++ len -= 4; ++ break; ++ case IEEE80211_RADIOTAP_RX_FLAGS: ++ rxflags = 1; ++ break; ++ case IEEE80211_RADIOTAP_TX_FLAGS: ++ injected = 1; ++ failed = le_to_host16((*(uint16_t *) iter.this_arg)) & ++ IEEE80211_RADIOTAP_F_TX_FAIL; ++ break; ++ case IEEE80211_RADIOTAP_DATA_RETRIES: ++ break; ++ case IEEE80211_RADIOTAP_CHANNEL: ++ /* TODO convert from freq/flags to channel number ++ hfi.channel = XXX; ++ hfi.phytype = XXX; ++ */ ++ break; ++ case IEEE80211_RADIOTAP_RATE: ++ hfi.datarate = *iter.this_arg * 5; ++ break; ++ case IEEE80211_RADIOTAP_DB_ANTSIGNAL: ++ hfi.ssi_signal = *iter.this_arg; ++ break; ++ } ++ } ++ ++ if (rxflags && injected) ++ return; ++ ++ if (!injected) ++ msg_type = ieee80211_msg_normal; ++ else if (failed) ++ msg_type = ieee80211_msg_tx_callback_fail; ++ else ++ msg_type = ieee80211_msg_tx_callback_ack; ++ ++ handle_frame(hapd->iface, buf + iter.max_length, ++ len - iter.max_length, &hfi, msg_type); ++} ++ ++ ++static int nl80211_create_monitor_interface(struct i802_driver_data *drv) ++{ ++ char buf[IFNAMSIZ]; ++ struct sockaddr_ll ll; ++ int optval; ++ socklen_t optlen; ++ ++ snprintf(buf, IFNAMSIZ, "mon.%s", drv->iface); ++ buf[IFNAMSIZ - 1] = '\0'; ++ ++ drv->monitor_ifidx = ++ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL); ++ ++ if (drv->monitor_ifidx < 0) ++ return -1; ++ ++ if (hostapd_set_iface_flags(drv, buf, 1)) ++ goto error; ++ ++ memset(&ll, 0, sizeof(ll)); ++ ll.sll_family = AF_PACKET; ++ ll.sll_ifindex = drv->monitor_ifidx; ++ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); ++ if (drv->monitor_sock < 0) { ++ perror("socket[PF_PACKET,SOCK_RAW]"); ++ goto error; ++ } ++ ++ if (bind(drv->monitor_sock, (struct sockaddr *) &ll, ++ sizeof(ll)) < 0) { ++ perror("monitor socket bind"); ++ goto error; ++ } ++ ++ optlen = sizeof(optval); ++ optval = 20; ++ if (setsockopt ++ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { ++ perror("Failed to set socket priority"); ++ goto error; ++ } ++ ++ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, ++ drv, NULL)) { ++ printf("Could not register monitor read socket\n"); ++ goto error; ++ } ++ ++ return 0; ++ error: ++ nl80211_remove_iface(drv, drv->monitor_ifidx); ++ return -1; ++} ++ ++ ++static int nl80211_set_master_mode(struct i802_driver_data *drv, ++ const char *ifname) ++{ ++ struct nl_msg *msg; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ return -1; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_INTERFACE, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(ifname)); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ nla_put_failure: ++ wpa_printf(MSG_ERROR, "Failed to set interface %s to master " ++ "mode.", ifname); ++ nlmsg_free(msg); ++ return -1; ++ } ++ ++ nlmsg_free(msg); ++ ++ return 0; ++} ++ ++ ++static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid) ++{ ++ struct ifreq ifr; ++ struct sockaddr_ll addr; ++ ++ drv->ioctl_sock = -1; ++ ++ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->ioctl_sock < 0) { ++ perror("socket[PF_INET,SOCK_DGRAM]"); ++ return -1; ++ } ++ ++ /* start listening for EAPOL on the default AP interface */ ++ add_ifidx(drv, if_nametoindex(drv->iface)); ++ ++ if (hostapd_set_iface_flags(drv, drv->iface, 0)) ++ return -1; ++ ++ if (bssid) { ++ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); ++ memcpy(ifr.ifr_hwaddr.sa_data, bssid, ETH_ALEN); ++ ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) { ++ perror("ioctl(SIOCSIFHWADDR)"); ++ return -1; ++ } ++ } ++ ++ /* ++ * initialise generic netlink and nl80211 ++ */ ++ drv->nl_handle = nl_handle_alloc(); ++ if (!drv->nl_handle) { ++ printf("Failed to allocate netlink handle.\n"); ++ return -1; ++ } ++ ++ if (genl_connect(drv->nl_handle)) { ++ printf("Failed to connect to generic netlink.\n"); ++ return -1; ++ } ++ ++ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle); ++ if (!drv->nl_cache) { ++ printf("Failed to allocate generic netlink cache.\n"); ++ return -1; ++ } ++ ++ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211"); ++ if (!drv->nl80211) { ++ printf("nl80211 not found.\n"); ++ return -1; ++ } ++ ++ /* Initialise a monitor interface */ ++ if (nl80211_create_monitor_interface(drv)) ++ return -1; ++ ++ if (nl80211_set_master_mode(drv, drv->iface)) ++ return -1; ++ ++ if (hostapd_set_iface_flags(drv, drv->iface, 1)) ++ return -1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sll_family = AF_PACKET; ++ addr.sll_ifindex = ifr.ifr_ifindex; ++ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", ++ addr.sll_ifindex); ++ ++ drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); ++ if (drv->eapol_sock < 0) { ++ perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); ++ return -1; ++ } ++ ++ if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) ++ { ++ printf("Could not register read socket for eapol\n"); ++ return -1; ++ } ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); ++ if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) { ++ perror("ioctl(SIOCGIFHWADDR)"); ++ return -1; ++ } ++ ++ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { ++ printf("Invalid HW-addr family 0x%04x\n", ++ ifr.ifr_hwaddr.sa_family); ++ return -1; ++ } ++ memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); ++ ++ return 0; ++} ++ ++ ++static int i802_get_inact_sec(void *priv, const u8 *addr) ++{ ++ struct hostap_sta_driver_data data; ++ int ret; ++ ++ data.inactive_msec = (unsigned long) -1; ++ ret = i802_read_sta_data(priv, &data, addr); ++ if (ret || data.inactive_msec == (unsigned long) -1) ++ return -1; ++ return data.inactive_msec / 1000; ++} ++ ++ ++static int i802_sta_clear_stats(void *priv, const u8 *addr) ++{ ++#if 0 ++ /* TODO */ ++#endif ++ return 0; ++} ++ ++ ++static void ++hostapd_wireless_event_wireless_custom(struct i802_driver_data *drv, ++ char *custom) ++{ ++ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); ++ ++ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { ++ char *pos; ++ u8 addr[ETH_ALEN]; ++ pos = strstr(custom, "addr="); ++ if (pos == NULL) { ++ wpa_printf(MSG_DEBUG, ++ "MLME-MICHAELMICFAILURE.indication " ++ "without sender address ignored"); ++ return; ++ } ++ pos += 5; ++ if (hwaddr_aton(pos, addr) == 0) { ++ ieee80211_michael_mic_failure(drv->hapd, addr, 1); ++ } else { ++ wpa_printf(MSG_DEBUG, ++ "MLME-MICHAELMICFAILURE.indication " ++ "with invalid MAC address"); ++ } ++ } ++} ++ ++ ++static void hostapd_wireless_event_wireless(struct i802_driver_data *drv, ++ char *data, int len) ++{ ++ struct iw_event iwe_buf, *iwe = &iwe_buf; ++ char *pos, *end, *custom, *buf; ++ ++ pos = data; ++ end = data + len; ++ ++ while (pos + IW_EV_LCP_LEN <= end) { ++ /* Event data may be unaligned, so make a local, aligned copy ++ * before processing. */ ++ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); ++ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", ++ iwe->cmd, iwe->len); ++ if (iwe->len <= IW_EV_LCP_LEN) ++ return; ++ ++ custom = pos + IW_EV_POINT_LEN; ++ if (drv->we_version > 18 && ++ (iwe->cmd == IWEVMICHAELMICFAILURE || ++ iwe->cmd == IWEVCUSTOM)) { ++ /* WE-19 removed the pointer from struct iw_point */ ++ char *dpos = (char *) &iwe_buf.u.data.length; ++ int dlen = dpos - (char *) &iwe_buf; ++ memcpy(dpos, pos + IW_EV_LCP_LEN, ++ sizeof(struct iw_event) - dlen); ++ } else { ++ memcpy(&iwe_buf, pos, sizeof(struct iw_event)); ++ custom += IW_EV_POINT_OFF; ++ } ++ ++ switch (iwe->cmd) { ++ case IWEVCUSTOM: ++ if (custom + iwe->u.data.length > end) ++ return; ++ buf = malloc(iwe->u.data.length + 1); ++ if (buf == NULL) ++ return; ++ memcpy(buf, custom, iwe->u.data.length); ++ buf[iwe->u.data.length] = '\0'; ++ hostapd_wireless_event_wireless_custom(drv, buf); ++ free(buf); ++ break; ++ } ++ ++ pos += iwe->len; ++ } ++} ++ ++ ++static void hostapd_wireless_event_rtm_newlink(struct i802_driver_data *drv, ++ struct nlmsghdr *h, int len) ++{ ++ struct ifinfomsg *ifi; ++ int attrlen, nlmsg_len, rta_len; ++ struct rtattr *attr; ++ ++ if (len < (int) sizeof(*ifi)) ++ return; ++ ++ ifi = NLMSG_DATA(h); ++ ++ /* TODO: use ifi->ifi_index to filter out wireless events from other ++ * interfaces */ ++ ++ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); ++ ++ attrlen = h->nlmsg_len - nlmsg_len; ++ if (attrlen < 0) ++ return; ++ ++ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_WIRELESS) { ++ hostapd_wireless_event_wireless( ++ drv, ((char *) attr) + rta_len, ++ attr->rta_len - rta_len); ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++} ++ ++ ++static void hostapd_wireless_event_receive(int sock, void *eloop_ctx, ++ void *sock_ctx) ++{ ++ char buf[256]; ++ int left; ++ struct sockaddr_nl from; ++ socklen_t fromlen; ++ struct nlmsghdr *h; ++ struct i802_driver_data *drv = eloop_ctx; ++ ++ fromlen = sizeof(from); ++ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, ++ (struct sockaddr *) &from, &fromlen); ++ if (left < 0) { ++ if (errno != EINTR && errno != EAGAIN) ++ perror("recvfrom(netlink)"); ++ return; ++ } ++ ++ h = (struct nlmsghdr *) buf; ++ while (left >= (int) sizeof(*h)) { ++ int len, plen; ++ ++ len = h->nlmsg_len; ++ plen = len - sizeof(*h); ++ if (len > left || plen < 0) { ++ printf("Malformed netlink message: " ++ "len=%d left=%d plen=%d\n", ++ len, left, plen); ++ break; ++ } ++ ++ switch (h->nlmsg_type) { ++ case RTM_NEWLINK: ++ hostapd_wireless_event_rtm_newlink(drv, h, plen); ++ break; ++ } ++ ++ len = NLMSG_ALIGN(len); ++ left -= len; ++ h = (struct nlmsghdr *) ((char *) h + len); ++ } ++ ++ if (left > 0) { ++ printf("%d extra bytes in the end of netlink message\n", left); ++ } ++} ++ ++ ++static int hostap_get_we_version(struct i802_driver_data *drv) ++{ ++ struct iw_range *range; ++ struct iwreq iwr; ++ int minlen; ++ size_t buflen; ++ ++ drv->we_version = 0; ++ ++ /* ++ * Use larger buffer than struct iw_range in order to allow the ++ * structure to grow in the future. ++ */ ++ buflen = sizeof(struct iw_range) + 500; ++ range = os_zalloc(buflen); ++ if (range == NULL) ++ return -1; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) range; ++ iwr.u.data.length = buflen; ++ ++ minlen = ((char *) &range->enc_capa) - (char *) range + ++ sizeof(range->enc_capa); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { ++ perror("ioctl[SIOCGIWRANGE]"); ++ free(range); ++ return -1; ++ } else if (iwr.u.data.length >= minlen && ++ range->we_version_compiled >= 18) { ++ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " ++ "WE(source)=%d enc_capa=0x%x", ++ range->we_version_compiled, ++ range->we_version_source, ++ range->enc_capa); ++ drv->we_version = range->we_version_compiled; ++ } ++ ++ free(range); ++ return 0; ++} ++ ++ ++static int i802_wireless_event_init(void *priv) ++{ ++ struct i802_driver_data *drv = priv; ++ int s; ++ struct sockaddr_nl local; ++ ++ hostap_get_we_version(drv); ++ ++ drv->wext_sock = -1; ++ ++ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); ++ if (s < 0) { ++ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); ++ return -1; ++ } ++ ++ memset(&local, 0, sizeof(local)); ++ local.nl_family = AF_NETLINK; ++ local.nl_groups = RTMGRP_LINK; ++ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { ++ perror("bind(netlink)"); ++ close(s); ++ return -1; ++ } ++ ++ eloop_register_read_sock(s, hostapd_wireless_event_receive, drv, ++ NULL); ++ drv->wext_sock = s; ++ ++ return 0; ++} ++ ++ ++static void i802_wireless_event_deinit(void *priv) ++{ ++ struct i802_driver_data *drv = priv; ++ if (drv->wext_sock < 0) ++ return; ++ eloop_unregister_read_sock(drv->wext_sock); ++ close(drv->wext_sock); ++} ++ ++ ++static int i802_sta_deauth(void *priv, const u8 *addr, int reason) ++{ ++ struct i802_driver_data *drv = priv; ++ struct ieee80211_mgmt mgmt; ++ ++ memset(&mgmt, 0, sizeof(mgmt)); ++ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_DEAUTH); ++ memcpy(mgmt.da, addr, ETH_ALEN); ++ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); ++ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); ++ mgmt.u.deauth.reason_code = host_to_le16(reason); ++ return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + ++ sizeof(mgmt.u.deauth), 0); ++} ++ ++ ++static int i802_sta_disassoc(void *priv, const u8 *addr, int reason) ++{ ++ struct i802_driver_data *drv = priv; ++ struct ieee80211_mgmt mgmt; ++ ++ memset(&mgmt, 0, sizeof(mgmt)); ++ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_DISASSOC); ++ memcpy(mgmt.da, addr, ETH_ALEN); ++ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); ++ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); ++ mgmt.u.disassoc.reason_code = host_to_le16(reason); ++ return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + ++ sizeof(mgmt.u.disassoc), 0); ++} ++ ++ ++static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid) ++{ ++ struct i802_driver_data *drv; ++ ++ drv = os_zalloc(sizeof(struct i802_driver_data)); ++ if (drv == NULL) { ++ printf("Could not allocate memory for i802 driver data\n"); ++ return NULL; ++ } ++ ++ drv->hapd = hapd; ++ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); ++ ++ drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); ++ drv->if_indices = drv->default_if_indices; ++ ++ if (i802_init_sockets(drv, bssid)) ++ goto failed; ++ ++ return drv; ++ ++failed: ++ free(drv); ++ return NULL; ++} ++ ++ ++static void *i802_init(struct hostapd_data *hapd) ++{ ++ return i802_init_bssid(hapd, NULL); ++} ++ ++ ++static void i802_deinit(void *priv) ++{ ++ struct i802_driver_data *drv = priv; ++ ++ i802_del_beacon(drv); ++ ++ /* remove monitor interface */ ++ nl80211_remove_iface(drv, drv->monitor_ifidx); ++ ++ (void) hostapd_set_iface_flags(drv, drv->iface, 0); ++ ++ if (drv->monitor_sock >= 0) { ++ eloop_unregister_read_sock(drv->monitor_sock); ++ close(drv->monitor_sock); ++ } ++ if (drv->ioctl_sock >= 0) ++ close(drv->ioctl_sock); ++ if (drv->eapol_sock >= 0) { ++ eloop_unregister_read_sock(drv->eapol_sock); ++ close(drv->eapol_sock); ++ } ++ ++ genl_family_put(drv->nl80211); ++ nl_cache_free(drv->nl_cache); ++ nl_handle_destroy(drv->nl_handle); ++ ++ if (drv->if_indices != drv->default_if_indices) ++ free(drv->if_indices); ++ ++ free(drv); ++} ++ ++ ++const struct wpa_driver_ops wpa_driver_nl80211_ops = { ++ .name = "nl80211", ++ .init = i802_init, ++// .init_bssid = i802_init_bssid, ++ .deinit = i802_deinit, ++ .wireless_event_init = i802_wireless_event_init, ++ .wireless_event_deinit = i802_wireless_event_deinit, ++ .set_ieee8021x = i802_set_ieee8021x, ++ .set_privacy = i802_set_privacy, ++ .set_encryption = i802_set_encryption, ++ .get_seqnum = i802_get_seqnum, ++ .flush = i802_flush, ++ .read_sta_data = i802_read_sta_data, ++ .send_eapol = i802_send_eapol, ++ .sta_set_flags = i802_sta_set_flags, ++ .sta_deauth = i802_sta_deauth, ++ .sta_disassoc = i802_sta_disassoc, ++ .sta_remove = i802_sta_remove, ++ .set_ssid = i802_set_ssid, ++ .send_mgmt_frame = i802_send_mgmt_frame, ++ .sta_add = i802_sta_add, ++ .get_inact_sec = i802_get_inact_sec, ++ .sta_clear_stats = i802_sta_clear_stats, ++ .set_freq = i802_set_freq, ++ .set_rts = i802_set_rts, ++ .get_rts = i802_get_rts, ++ .set_frag = i802_set_frag, ++ .get_frag = i802_get_frag, ++ .set_retry = i802_set_retry, ++ .get_retry = i802_get_retry, ++ .set_rate_sets = i802_set_rate_sets, ++ .set_channel_flag = i802_set_channel_flag, ++ .set_regulatory_domain = i802_set_regulatory_domain, ++ .set_beacon = i802_set_beacon, ++ .set_internal_bridge = i802_set_internal_bridge, ++ .set_beacon_int = i802_set_beacon_int, ++ .set_dtim_period = i802_set_dtim_period, ++ .set_cts_protect = i802_set_cts_protect, ++ .set_preamble = i802_set_preamble, ++ .set_short_slot_time = i802_set_short_slot_time, ++ .set_tx_queue_params = i802_set_tx_queue_params, ++ .bss_add = i802_bss_add, ++ .bss_remove = i802_bss_remove, ++ .if_add = i802_if_add, ++ .if_update = i802_if_update, ++ .if_remove = i802_if_remove, ++ .get_hw_feature_data = i802_get_hw_feature_data, ++ .set_sta_vlan = i802_set_sta_vlan, ++}; +diff -urN hostapd.orig/radiotap.c hostapd/radiotap.c +--- a/hostapd/radiotap.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/hostapd/radiotap.c 2008-02-15 23:05:17.000000000 +0100 +@@ -0,0 +1,287 @@ ++/* ++ * Radiotap parser ++ * ++ * Copyright 2007 Andy Green <andy@warmcat.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Alternatively, this software may be distributed under the terms of BSD ++ * license. ++ * ++ * See README and COPYING for more details. ++ * ++ * ++ * Modified for userspace by Johannes Berg <johannes@sipsolutions.net> ++ * I only modified some things on top to ease syncing should bugs be found. ++ */ ++ ++#include "includes.h" ++ ++#include "common.h" ++#include "radiotap_iter.h" ++ ++#define le16_to_cpu le_to_host16 ++#define le32_to_cpu le_to_host32 ++#define __le32 uint32_t ++#define ulong unsigned long ++#define unlikely(cond) (cond) ++#define get_unaligned(p) \ ++({ \ ++ struct packed_dummy_struct { \ ++ typeof(*(p)) __val; \ ++ } __attribute__((packed)) *__ptr = (void *) (p); \ ++ \ ++ __ptr->__val; \ ++}) ++ ++/* function prototypes and related defs are in radiotap_iter.h */ ++ ++/** ++ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization ++ * @iterator: radiotap_iterator to initialize ++ * @radiotap_header: radiotap header to parse ++ * @max_length: total length we can parse into (eg, whole packet length) ++ * ++ * Returns: 0 or a negative error code if there is a problem. ++ * ++ * This function initializes an opaque iterator struct which can then ++ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap ++ * argument which is present in the header. It knows about extended ++ * present headers and handles them. ++ * ++ * How to use: ++ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator ++ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) ++ * checking for a good 0 return code. Then loop calling ++ * __ieee80211_radiotap_iterator_next()... it returns either 0, ++ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. ++ * The iterator's @this_arg member points to the start of the argument ++ * associated with the current argument index that is present, which can be ++ * found in the iterator's @this_arg_index member. This arg index corresponds ++ * to the IEEE80211_RADIOTAP_... defines. ++ * ++ * Radiotap header length: ++ * You can find the CPU-endian total radiotap header length in ++ * iterator->max_length after executing ieee80211_radiotap_iterator_init() ++ * successfully. ++ * ++ * Alignment Gotcha: ++ * You must take care when dereferencing iterator.this_arg ++ * for multibyte types... the pointer is not aligned. Use ++ * get_unaligned((type *)iterator.this_arg) to dereference ++ * iterator.this_arg for type "type" safely on all arches. ++ * ++ * Example code: ++ * See Documentation/networking/radiotap-headers.txt ++ */ ++ ++int ieee80211_radiotap_iterator_init( ++ struct ieee80211_radiotap_iterator *iterator, ++ struct ieee80211_radiotap_header *radiotap_header, ++ int max_length) ++{ ++ /* Linux only supports version 0 radiotap format */ ++ if (radiotap_header->it_version) ++ return -EINVAL; ++ ++ /* sanity check for allowed length and radiotap length field */ ++ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) ++ return -EINVAL; ++ ++ iterator->rtheader = radiotap_header; ++ iterator->max_length = le16_to_cpu(get_unaligned( ++ &radiotap_header->it_len)); ++ iterator->arg_index = 0; ++ iterator->bitmap_shifter = le32_to_cpu(get_unaligned( ++ &radiotap_header->it_present)); ++ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); ++ iterator->this_arg = NULL; ++ ++ /* find payload start allowing for extended bitmap(s) */ ++ ++ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { ++ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) & ++ (1<<IEEE80211_RADIOTAP_EXT)) { ++ iterator->arg += sizeof(u32); ++ ++ /* ++ * check for insanity where the present bitmaps ++ * keep claiming to extend up to or even beyond the ++ * stated radiotap header length ++ */ ++ ++ if (((ulong)iterator->arg - (ulong)iterator->rtheader) ++ > (ulong)iterator->max_length) ++ return -EINVAL; ++ } ++ ++ iterator->arg += sizeof(u32); ++ ++ /* ++ * no need to check again for blowing past stated radiotap ++ * header length, because ieee80211_radiotap_iterator_next ++ * checks it before it is dereferenced ++ */ ++ } ++ ++ /* we are all initialized happily */ ++ ++ return 0; ++} ++ ++ ++/** ++ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg ++ * @iterator: radiotap_iterator to move to next arg (if any) ++ * ++ * Returns: 0 if there is an argument to handle, ++ * -ENOENT if there are no more args or -EINVAL ++ * if there is something else wrong. ++ * ++ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) ++ * in @this_arg_index and sets @this_arg to point to the ++ * payload for the field. It takes care of alignment handling and extended ++ * present fields. @this_arg can be changed by the caller (eg, ++ * incremented to move inside a compound argument like ++ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in ++ * little-endian format whatever the endianess of your CPU. ++ * ++ * Alignment Gotcha: ++ * You must take care when dereferencing iterator.this_arg ++ * for multibyte types... the pointer is not aligned. Use ++ * get_unaligned((type *)iterator.this_arg) to dereference ++ * iterator.this_arg for type "type" safely on all arches. ++ */ ++ ++int ieee80211_radiotap_iterator_next( ++ struct ieee80211_radiotap_iterator *iterator) ++{ ++ ++ /* ++ * small length lookup table for all radiotap types we heard of ++ * starting from b0 in the bitmap, so we can walk the payload ++ * area of the radiotap header ++ * ++ * There is a requirement to pad args, so that args ++ * of a given length must begin at a boundary of that length ++ * -- but note that compound args are allowed (eg, 2 x u16 ++ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not ++ * a reliable indicator of alignment requirement. ++ * ++ * upper nybble: content alignment for arg ++ * lower nybble: content length for arg ++ */ ++ ++ static const u8 rt_sizes[] = { ++ [IEEE80211_RADIOTAP_TSFT] = 0x88, ++ [IEEE80211_RADIOTAP_FLAGS] = 0x11, ++ [IEEE80211_RADIOTAP_RATE] = 0x11, ++ [IEEE80211_RADIOTAP_CHANNEL] = 0x24, ++ [IEEE80211_RADIOTAP_FHSS] = 0x22, ++ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, ++ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, ++ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, ++ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, ++ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, ++ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, ++ [IEEE80211_RADIOTAP_ANTENNA] = 0x11, ++ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, ++ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, ++ [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, ++ [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, ++ [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, ++ [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, ++ /* ++ * add more here as they are defined in ++ * include/net/ieee80211_radiotap.h ++ */ ++ }; ++ ++ /* ++ * for every radiotap entry we can at ++ * least skip (by knowing the length)... ++ */ ++ ++ while (iterator->arg_index < (int) sizeof(rt_sizes)) { ++ int hit = 0; ++ int pad; ++ ++ if (!(iterator->bitmap_shifter & 1)) ++ goto next_entry; /* arg not present */ ++ ++ /* ++ * arg is present, account for alignment padding ++ * 8-bit args can be at any alignment ++ * 16-bit args must start on 16-bit boundary ++ * 32-bit args must start on 32-bit boundary ++ * 64-bit args must start on 64-bit boundary ++ * ++ * note that total arg size can differ from alignment of ++ * elements inside arg, so we use upper nybble of length ++ * table to base alignment on ++ * ++ * also note: these alignments are ** relative to the ++ * start of the radiotap header **. There is no guarantee ++ * that the radiotap header itself is aligned on any ++ * kind of boundary. ++ * ++ * the above is why get_unaligned() is used to dereference ++ * multibyte elements from the radiotap area ++ */ ++ ++ pad = (((ulong)iterator->arg) - ++ ((ulong)iterator->rtheader)) & ++ ((rt_sizes[iterator->arg_index] >> 4) - 1); ++ ++ if (pad) ++ iterator->arg += ++ (rt_sizes[iterator->arg_index] >> 4) - pad; ++ ++ /* ++ * this is what we will return to user, but we need to ++ * move on first so next call has something fresh to test ++ */ ++ iterator->this_arg_index = iterator->arg_index; ++ iterator->this_arg = iterator->arg; ++ hit = 1; ++ ++ /* internally move on the size of this arg */ ++ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; ++ ++ /* ++ * check for insanity where we are given a bitmap that ++ * claims to have more arg content than the length of the ++ * radiotap section. We will normally end up equalling this ++ * max_length on the last arg, never exceeding it. ++ */ ++ ++ if (((ulong)iterator->arg - (ulong)iterator->rtheader) > ++ (ulong) iterator->max_length) ++ return -EINVAL; ++ ++ next_entry: ++ iterator->arg_index++; ++ if (unlikely((iterator->arg_index & 31) == 0)) { ++ /* completed current u32 bitmap */ ++ if (iterator->bitmap_shifter & 1) { ++ /* b31 was set, there is more */ ++ /* move to next u32 bitmap */ ++ iterator->bitmap_shifter = le32_to_cpu( ++ get_unaligned(iterator->next_bitmap)); ++ iterator->next_bitmap++; ++ } else ++ /* no more bitmaps: end */ ++ iterator->arg_index = sizeof(rt_sizes); ++ } else /* just try the next bit */ ++ iterator->bitmap_shifter >>= 1; ++ ++ /* if we found a valid arg earlier, return it now */ ++ if (hit) ++ return 0; ++ } ++ ++ /* we don't know how to handle any more args, we're done */ ++ return -ENOENT; ++} +diff -urN hostapd.orig/radiotap.h hostapd/radiotap.h +--- a/hostapd/radiotap.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/hostapd/radiotap.h 2008-02-15 23:05:17.000000000 +0100 +@@ -0,0 +1,242 @@ ++/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ ++/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ ++ ++/*- ++ * Copyright (c) 2003, 2004 David Young. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of David Young may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID ++ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ++ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY ++ * OF SUCH DAMAGE. ++ */ ++ ++/* ++ * Modifications to fit into the linux IEEE 802.11 stack, ++ * Mike Kershaw (dragorn@kismetwireless.net) ++ */ ++ ++#ifndef IEEE80211RADIOTAP_H ++#define IEEE80211RADIOTAP_H ++ ++#include <stdint.h> ++ ++/* Base version of the radiotap packet header data */ ++#define PKTHDR_RADIOTAP_VERSION 0 ++ ++/* A generic radio capture format is desirable. There is one for ++ * Linux, but it is neither rigidly defined (there were not even ++ * units given for some fields) nor easily extensible. ++ * ++ * I suggest the following extensible radio capture format. It is ++ * based on a bitmap indicating which fields are present. ++ * ++ * I am trying to describe precisely what the application programmer ++ * should expect in the following, and for that reason I tell the ++ * units and origin of each measurement (where it applies), or else I ++ * use sufficiently weaselly language ("is a monotonically nondecreasing ++ * function of...") that I cannot set false expectations for lawyerly ++ * readers. ++ */ ++ ++/* The radio capture header precedes the 802.11 header. ++ * All data in the header is little endian on all platforms. ++ */ ++struct ieee80211_radiotap_header { ++ uint8_t it_version; /* Version 0. Only increases ++ * for drastic changes, ++ * introduction of compatible ++ * new fields does not count. ++ */ ++ uint8_t it_pad; ++ uint16_t it_len; /* length of the whole ++ * header in bytes, including ++ * it_version, it_pad, ++ * it_len, and data fields. ++ */ ++ uint32_t it_present; /* A bitmap telling which ++ * fields are present. Set bit 31 ++ * (0x80000000) to extend the ++ * bitmap by another 32 bits. ++ * Additional extensions are made ++ * by setting bit 31. ++ */ ++}; ++ ++/* Name Data type Units ++ * ---- --------- ----- ++ * ++ * IEEE80211_RADIOTAP_TSFT __le64 microseconds ++ * ++ * Value in microseconds of the MAC's 64-bit 802.11 Time ++ * Synchronization Function timer when the first bit of the ++ * MPDU arrived at the MAC. For received frames, only. ++ * ++ * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap ++ * ++ * Tx/Rx frequency in MHz, followed by flags (see below). ++ * ++ * IEEE80211_RADIOTAP_FHSS uint16_t see below ++ * ++ * For frequency-hopping radios, the hop set (first byte) ++ * and pattern (second byte). ++ * ++ * IEEE80211_RADIOTAP_RATE u8 500kb/s ++ * ++ * Tx/Rx data rate ++ * ++ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from ++ * one milliwatt (dBm) ++ * ++ * RF signal power at the antenna, decibel difference from ++ * one milliwatt. ++ * ++ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from ++ * one milliwatt (dBm) ++ * ++ * RF noise power at the antenna, decibel difference from one ++ * milliwatt. ++ * ++ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) ++ * ++ * RF signal power at the antenna, decibel difference from an ++ * arbitrary, fixed reference. ++ * ++ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) ++ * ++ * RF noise power at the antenna, decibel difference from an ++ * arbitrary, fixed reference point. ++ * ++ * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless ++ * ++ * Quality of Barker code lock. Unitless. Monotonically ++ * nondecreasing with "better" lock strength. Called "Signal ++ * Quality" in datasheets. (Is there a standard way to measure ++ * this?) ++ * ++ * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless ++ * ++ * Transmit power expressed as unitless distance from max ++ * power set at factory calibration. 0 is max power. ++ * Monotonically nondecreasing with lower power levels. ++ * ++ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB) ++ * ++ * Transmit power expressed as decibel distance from max power ++ * set at factory calibration. 0 is max power. Monotonically ++ * nondecreasing with lower power levels. ++ * ++ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from ++ * one milliwatt (dBm) ++ * ++ * Transmit power expressed as dBm (decibels from a 1 milliwatt ++ * reference). This is the absolute power level measured at ++ * the antenna port. ++ * ++ * IEEE80211_RADIOTAP_FLAGS u8 bitmap ++ * ++ * Properties of transmitted and received frames. See flags ++ * defined below. ++ * ++ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index ++ * ++ * Unitless indication of the Rx/Tx antenna for this packet. ++ * The first antenna is antenna 0. ++ * ++ * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap ++ * ++ * Properties of received frames. See flags defined below. ++ * ++ * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap ++ * ++ * Properties of transmitted frames. See flags defined below. ++ * ++ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data ++ * ++ * Number of rts retries a transmitted frame used. ++ * ++ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data ++ * ++ * Number of unicast retries a transmitted frame used. ++ * ++ */ ++enum ieee80211_radiotap_type { ++ IEEE80211_RADIOTAP_TSFT = 0, ++ IEEE80211_RADIOTAP_FLAGS = 1, ++ IEEE80211_RADIOTAP_RATE = 2, ++ IEEE80211_RADIOTAP_CHANNEL = 3, ++ IEEE80211_RADIOTAP_FHSS = 4, ++ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, ++ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, ++ IEEE80211_RADIOTAP_LOCK_QUALITY = 7, ++ IEEE80211_RADIOTAP_TX_ATTENUATION = 8, ++ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, ++ IEEE80211_RADIOTAP_DBM_TX_POWER = 10, ++ IEEE80211_RADIOTAP_ANTENNA = 11, ++ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, ++ IEEE80211_RADIOTAP_DB_ANTNOISE = 13, ++ IEEE80211_RADIOTAP_RX_FLAGS = 14, ++ IEEE80211_RADIOTAP_TX_FLAGS = 15, ++ IEEE80211_RADIOTAP_RTS_RETRIES = 16, ++ IEEE80211_RADIOTAP_DATA_RETRIES = 17, ++ IEEE80211_RADIOTAP_EXT = 31 ++}; ++ ++/* Channel flags. */ ++#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ ++#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ ++#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ ++#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ ++#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ ++#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ ++#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ ++#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ ++ ++/* For IEEE80211_RADIOTAP_FLAGS */ ++#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received ++ * during CFP ++ */ ++#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received ++ * with short ++ * preamble ++ */ ++#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received ++ * with WEP encryption ++ */ ++#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received ++ * with fragmentation ++ */ ++#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ ++#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between ++ * 802.11 header and payload ++ * (to 32-bit boundary) ++ */ ++/* For IEEE80211_RADIOTAP_RX_FLAGS */ ++#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ ++ ++/* For IEEE80211_RADIOTAP_TX_FLAGS */ ++#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive ++ * retries */ ++#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ ++#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ ++ ++#endif /* IEEE80211_RADIOTAP_H */ +diff -urN hostapd.orig/radiotap_iter.h hostapd/radiotap_iter.h +--- a/hostapd/radiotap_iter.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/hostapd/radiotap_iter.h 2008-02-15 23:05:17.000000000 +0100 +@@ -0,0 +1,41 @@ ++#ifndef __RADIOTAP_ITER_H ++#define __RADIOTAP_ITER_H ++ ++#include "radiotap.h" ++ ++/* Radiotap header iteration ++ * implemented in radiotap.c ++ */ ++/** ++ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args ++ * @rtheader: pointer to the radiotap header we are walking through ++ * @max_length: length of radiotap header in cpu byte ordering ++ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg ++ * @this_arg: pointer to current radiotap arg ++ * @arg_index: internal next argument index ++ * @arg: internal next argument pointer ++ * @next_bitmap: internal pointer to next present u32 ++ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present ++ */ ++ ++struct ieee80211_radiotap_iterator { ++ struct ieee80211_radiotap_header *rtheader; ++ int max_length; ++ int this_arg_index; ++ unsigned char *this_arg; ++ ++ int arg_index; ++ unsigned char *arg; ++ uint32_t *next_bitmap; ++ uint32_t bitmap_shifter; ++}; ++ ++extern int ieee80211_radiotap_iterator_init( ++ struct ieee80211_radiotap_iterator *iterator, ++ struct ieee80211_radiotap_header *radiotap_header, ++ int max_length); ++ ++extern int ieee80211_radiotap_iterator_next( ++ struct ieee80211_radiotap_iterator *iterator); ++ ++#endif /* __RADIOTAP_ITER_H */ |