aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/Makefile2
-rw-r--r--hostapd/driver_nl80211.c557
-rw-r--r--hostapd/ieee802_11.c3
-rw-r--r--hostapd/radiotap.c287
-rw-r--r--hostapd/radiotap.h242
-rw-r--r--hostapd/radiotap_iter.h41
6 files changed, 814 insertions, 318 deletions
diff --git a/hostapd/Makefile b/hostapd/Makefile
index c2a5fa7..66f6fa4 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -118,7 +118,7 @@ endif
ifdef CONFIG_DRIVER_NL80211
CFLAGS += -DCONFIG_DRIVER_NL80211
-OBJS += driver_nl80211.o
+OBJS += driver_nl80211.o radiotap.o
LIBS += -lnl
endif
diff --git a/hostapd/driver_nl80211.c b/hostapd/driver_nl80211.c
index 34bf8d8..61b3132 100644
--- a/hostapd/driver_nl80211.c
+++ b/hostapd/driver_nl80211.c
@@ -38,6 +38,8 @@
#include "sta_info.h"
#include "hw_features.h"
#include "mlme.h"
+#include "radiotap.h"
+#include "radiotap_iter.h"
/*
* old definitions from the prism2/hostap driver interface that
@@ -49,7 +51,6 @@
#define PRISM2_PARAM_AP_BRIDGE_PACKETS 10
#define PRISM2_PARAM_IEEE_802_1X 23
-#define PRISM2_PARAM_MGMT_IF 1046
#define PRISM2_HOSTAPD_GET_HW_FEATURES 1002
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 2048
@@ -116,40 +117,10 @@ struct hostapd_ioctl_hw_modes_hdr {
int num_rates;
};
-/*
- * frame format for the management interface that is slated
- * to be replaced by "cooked monitor" with radiotap
- */
-#define IEEE80211_FI_VERSION 0x80211001
-struct ieee80211_frame_info {
- __be32 version;
- __be32 length;
- __be64 mactime;
- __be64 hosttime;
- __be32 phytype;
- __be32 channel;
- __be32 datarate;
- __be32 antenna;
- __be32 priority;
- __be32 ssi_type;
- __be32 ssi_signal;
- __be32 ssi_noise;
- __be32 preamble;
- __be32 encoding;
-
- /* Note: this structure is otherwise identical to capture format used
- * in linux-wlan-ng, but this additional field is used to provide meta
- * data about the frame to hostapd. This was the easiest method for
- * providing this information, but this might change in the future. */
- __be32 msg_type;
-} __attribute__ ((packed));
-
enum ieee80211_msg_type {
ieee80211_msg_normal = 0,
ieee80211_msg_tx_callback_ack = 1,
ieee80211_msg_tx_callback_fail = 2,
- ieee80211_msg_passive_scan = 3,
- ieee80211_msg_sta_not_assoc = 7,
};
/* old mode definitions */
@@ -167,12 +138,11 @@ struct i802_driver_data {
struct hostapd_data *hapd;
char iface[IFNAMSIZ + 1];
- char mgmt_iface[IFNAMSIZ + 1];
- int mgmt_ifindex;
- int sock; /* raw packet socket for driver access */
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;
@@ -270,7 +240,7 @@ static int hostapd_set_iface_flags(struct i802_driver_data *drv,
if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
perror("ioctl[SIOCGIFFLAGS]");
wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)",
- drv->mgmt_iface);
+ drv->iface);
return -1;
}
@@ -284,17 +254,6 @@ static int hostapd_set_iface_flags(struct i802_driver_data *drv,
return -1;
}
- if (dev_up) {
- memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->mgmt_iface, IFNAMSIZ);
- ifr.ifr_mtu = HOSTAPD_MTU;
- if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
- perror("ioctl[SIOCSIFMTU]");
- printf("Setting MTU failed - trying to survive with "
- "current value\n");
- }
- }
-
return 0;
}
@@ -579,37 +538,6 @@ static int hostap_ioctl_prism2param(struct i802_driver_data *drv, int param,
}
-static int hostap_ioctl_get_prism2param_iface(const char *iface,
- struct i802_driver_data *drv,
- int param)
-{
- struct iwreq iwr;
- int *i;
-
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, iface, IFNAMSIZ);
- i = (int *) iwr.u.name;
- *i = param;
-
- if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_GET_PRISM2_PARAM, &iwr) < 0) {
- char buf[128];
- snprintf(buf, sizeof(buf),
- "%s: ioctl[PRISM2_IOCTL_GET_PRISM2_PARAM]", iface);
- perror(buf);
- return -1;
- }
-
- return *i;
-}
-
-
-static int hostap_ioctl_get_prism2param(struct i802_driver_data *drv,
- int param)
-{
- return hostap_ioctl_get_prism2param_iface(drv->iface, drv, param);
-}
-
-
static int i802_set_ssid(const char *ifname, void *priv, const u8 *buf,
int len)
{
@@ -632,12 +560,46 @@ static int i802_set_ssid(const char *ifname, void *priv, const u8 *buf,
}
-static int i802_send_mgmt_frame(void *priv, const void *msg, size_t len,
+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,
+ };
- return send(drv->sock, msg, len, flags);
+ /*
+ * 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);
}
@@ -955,8 +917,6 @@ static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data,
hdr->frame_control =
IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
- /* Request TX callback */
- hdr->frame_control |= host_to_le16(BIT(1));
if (encrypt)
hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
#if 0 /* To be enabled if qos determination is added above */
@@ -1225,7 +1185,7 @@ static int nl80211_create_iface(struct i802_driver_data *drv,
enum nl80211_iftype iftype,
const u8 *addr)
{
- struct nl_msg *msg;
+ struct nl_msg *msg, *flags = NULL;
int ifidx;
struct ifreq ifreq;
struct iwreq iwr;
@@ -1241,6 +1201,23 @@ static int nl80211_create_iface(struct i802_driver_data *drv,
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:
@@ -1665,73 +1642,22 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
}
-static void handle_data(struct hostapd_data *hapd, u8 *buf, size_t len,
- u16 stype, struct ieee80211_frame_info *fi)
+static void handle_unknown_sta(struct hostapd_data *hapd, u8 *ta)
{
- struct ieee80211_hdr *hdr;
- u16 fc, ethertype;
- u8 *pos, *sa;
- size_t left;
struct sta_info *sta;
- if (len < sizeof(struct ieee80211_hdr))
- return;
-
- hdr = (struct ieee80211_hdr *) buf;
- fc = le_to_host16(hdr->frame_control);
-
- if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) {
- printf("Not ToDS data frame (fc=0x%04x)\n", fc);
- return;
- }
-
- sa = hdr->addr2;
- sta = ap_get_sta(hapd, sa);
+ sta = ap_get_sta(hapd, ta);
if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
- printf("Data frame from not associated STA " MACSTR "\n",
- MAC2STR(sa));
+ printf("Data/PS-poll frame from not associated STA "
+ MACSTR "\n", MAC2STR(ta));
if (sta && (sta->flags & WLAN_STA_AUTH))
hostapd_sta_disassoc(
- hapd, sa,
+ hapd, ta,
WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
else
hostapd_sta_deauth(
- hapd, sa,
+ hapd, ta,
WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
- return;
- }
-
- pos = (u8 *) (hdr + 1);
- left = len - sizeof(*hdr);
-
- if (left < sizeof(rfc1042_header)) {
- printf("Too short data frame\n");
- return;
- }
-
- if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) {
- printf("Data frame with no RFC1042 header\n");
- return;
- }
- pos += sizeof(rfc1042_header);
- left -= sizeof(rfc1042_header);
-
- if (left < 2) {
- printf("No ethertype in data frame\n");
- return;
- }
-
- ethertype = WPA_GET_BE16(pos);
- pos += 2;
- left -= 2;
- switch (ethertype) {
- case ETH_P_PAE:
- ieee802_1x_receive(hapd, sa, pos, left);
- break;
-
- default:
- printf("Unknown ethertype 0x%04x in data frame\n", ethertype);
- break;
}
}
@@ -1780,34 +1706,9 @@ static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len,
}
-static void dump_frame_info(struct ieee80211_frame_info *fi, size_t len)
-{
- u64 ts, tus;
-
- tus = ts = be_to_host64(fi->hosttime);
- ts /= 1000000;
- tus -= ts * 1000000;
- wpa_hexdump(MSG_DEBUG, "Frame info dump", (u8 *) fi, len);
- printf("version:\t0x%08x\n", ntohl(fi->version));
- printf("length:\t%d\n", ntohl(fi->length));
- printf("mactime:\t%lld\n", be_to_host64(fi->mactime));
- printf("hosttime:\t%lld.%06lld\n", ts, tus);
- printf("phytype:\t%d\n", ntohl(fi->phytype));
- printf("channel:\t%d\n", ntohl(fi->channel));
- printf("datarate:\t%d\n", ntohl(fi->datarate));
- printf("antenna:\t%d\n", ntohl(fi->antenna));
- printf("priority\t%d\n", ntohl(fi->priority));
- printf("ssi_type:\t%d\n", ntohl(fi->ssi_type));
- printf("ssi_signal:\t%d\n", ntohl(fi->ssi_signal));
- printf("ssi_noise:\t%d\n", ntohl(fi->ssi_noise));
- printf("preamble:\t%d\n", ntohl(fi->preamble));
- printf("encoding:\t%d\n", ntohl(fi->encoding));
- printf("msg_type:\t%d\n", ntohl(fi->msg_type));
-}
-
-
static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len,
- struct ieee80211_frame_info *fi)
+ struct hostapd_frame_info *hfi,
+ enum ieee80211_msg_type msg_type)
{
struct ieee80211_hdr *hdr;
u16 fc, type, stype;
@@ -1816,77 +1717,68 @@ static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len,
int broadcast_bssid = 0;
size_t i;
u8 *bssid;
- int msg_type = ntohl(fi->msg_type);
- struct hostapd_frame_info hfi;
-#if 0 /* TODO */
- /* special handling for message types without IEEE 802.11 header */
- if (msg_type == ieee80211_msg_set_aid_for_sta) {
- ieee802_11_set_aid_for_sta(iface->bss[0], buf, data_len);
- return;
- }
-#endif
-# if 0
-/* TODO
- * get key notification from kernel again... it doesn't give one now
- * because this code doesn't care
- */
- if (msg_type == ieee80211_msg_key_threshold_notification) {
- ieee802_11_key_threshold_notification(iface->bss[0], buf,
- data_len);
- return;
- }
-#endif
-
- /* PS-Poll frame from not associated is 16 bytes. All other frames
- * passed to hostapd are 24 bytes or longer.
- * Right now, the kernel doesn't send us any frames from not-associated
- * because the code here doesn't care. TODO: add support to kernel
- * and send DEAUTH/DISASSOC to them...
+ /*
+ * PS-Poll frames are 16 bytes. All other frames are
+ * 24 bytes or longer.
*/
- if (len < 24) {
- printf("handle_frame: too short (%lu), type %d\n",
- (unsigned long) len, msg_type);
+ if (len < 16)
return;
- }
hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control);
- bssid = hdr->addr3;
type = WLAN_FC_GET_TYPE(fc);
stype = WLAN_FC_GET_STYPE(fc);
- if (type == WLAN_FC_TYPE_DATA) {
+ 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;
- case WLAN_FC_FROMDS:
- bssid = hdr->addr2;
- 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)
+ /*
+ * 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 (msg_type != ieee80211_msg_passive_scan &&
- (type != WLAN_FC_TYPE_MGMT ||
+ if ((type != WLAN_FC_TYPE_MGMT ||
stype != WLAN_FC_STYPE_BEACON))
return;
} else
@@ -1895,7 +1787,6 @@ static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len,
switch (msg_type) {
case ieee80211_msg_normal:
- case ieee80211_msg_passive_scan:
/* continue processing */
break;
case ieee80211_msg_tx_callback_ack:
@@ -1904,27 +1795,6 @@ static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len,
case ieee80211_msg_tx_callback_fail:
handle_tx_callback(hapd, buf, data_len, 0);
return;
-/*
- * TODO
- * the kernel never sends this any more, add new nl80211
- * notification if you need this.
-
- case ieee80211_msg_wep_frame_unknown_key:
- ieee802_11_rx_unknown_key(hapd, buf, data_len);
- return;
- */
-/*
- * TODO
- * We should be telling them to go away. But we don't support that now.
- * See also below and above for other TODO items related to this.
-
- case ieee80211_msg_sta_not_assoc:
- ieee802_11_rx_sta_not_assoc(hapd, buf, data_len);
- return;
- */
- default:
- printf("handle_frame: unknown msg_type %d\n", msg_type);
- return;
}
switch (type) {
@@ -1932,88 +1802,176 @@ static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len,
if (stype != WLAN_FC_STYPE_BEACON &&
stype != WLAN_FC_STYPE_PROBE_REQ)
wpa_printf(MSG_MSGDUMP, "MGMT");
- memset(&hfi, 0, sizeof(hfi));
- hfi.phytype = ntohl(fi->phytype);
- hfi.channel = ntohl(fi->channel);
- hfi.datarate = ntohl(fi->datarate);
- hfi.ssi_signal = ntohl(fi->ssi_signal);
- hfi.passive_scan = ntohl(fi->msg_type) ==
- ieee80211_msg_passive_scan;
if (broadcast_bssid) {
for (i = 0; i < iface->num_bss; i++)
ieee802_11_mgmt(iface->bss[i], buf, data_len,
- stype, &hfi);
+ stype, hfi);
} else
- ieee802_11_mgmt(hapd, buf, data_len, stype, &hfi);
+ ieee802_11_mgmt(hapd, buf, data_len, stype, hfi);
break;
case WLAN_FC_TYPE_CTRL:
- /* TODO: send deauth/disassoc if not associated STA sends
- * PS-Poll */
+ /* 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_data(hapd, buf, data_len, stype, fi);
- break;
- default:
- printf("unknown frame type %d\n", type);
+ handle_unknown_sta(hapd, hdr->addr2);
break;
}
}
-static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+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 hostapd_iface *iface = eloop_ctx;
+ struct i802_driver_data *drv = eloop_ctx;
int len;
unsigned char buf[3000];
- struct ieee80211_frame_info *fi;
+ 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;
}
- wpa_hexdump(MSG_MSGDUMP, "Received management frame", buf, len);
- if (len < (int) sizeof(struct ieee80211_frame_info)) {
- printf("handle_read: too short (%d)\n", len);
+ if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
+ printf("received invalid radiotap frame\n");
return;
}
- fi = (struct ieee80211_frame_info *) buf;
+ memset(&hfi, 0, sizeof(hfi));
- if (ntohl(fi->version) != IEEE80211_FI_VERSION) {
- printf("Invalid frame info version!\n");
- dump_frame_info(fi, len);
- return;
+ 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;
+ }
}
- handle_frame(iface,
- buf + sizeof(struct ieee80211_frame_info),
- len - sizeof(struct ieee80211_frame_info),
- fi);
+ 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 void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+static int nl80211_create_monitor_interface(struct i802_driver_data *drv)
{
- 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);
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval;
+ socklen_t optlen;
- len = recvfrom(sock, buf, sizeof(buf), 0,
- (struct sockaddr *) &lladdr, &fromlen);
- if (len < 0) {
- perror("recv");
- return;
+ 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 (have_ifidx(drv, lladdr.sll_ifindex))
- ieee802_1x_receive(hapd, lladdr.sll_addr, buf, len);
+ 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;
}
@@ -2049,12 +2007,10 @@ static int nl80211_set_master_mode(struct i802_driver_data *drv,
static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid)
{
- struct hostapd_data *hapd = drv->hapd;
- struct hostapd_iface *iface = hapd->iface;
struct ifreq ifr;
struct sockaddr_ll addr;
- drv->sock = drv->ioctl_sock = -1;
+ drv->ioctl_sock = -1;
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
@@ -2105,26 +2061,9 @@ static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid)
return -1;
}
- /* Enable management interface */
- if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_MGMT_IF, 1) < 0) {
- printf("Failed to enable management interface.\n");
- return -1;
- }
- drv->mgmt_ifindex =
- hostap_ioctl_get_prism2param(drv, PRISM2_PARAM_MGMT_IF);
- if (drv->mgmt_ifindex < 0) {
- printf("Failed to get ifindex for the management "
- "interface.\n");
+ /* Initialise a monitor interface */
+ if (nl80211_create_monitor_interface(drv))
return -1;
- }
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = drv->mgmt_ifindex;
- if (ioctl(drv->ioctl_sock, SIOCGIFNAME, &ifr) != 0) {
- perror("ioctl(SIOCGIFNAME)");
- return -1;
- }
- os_strlcpy(drv->mgmt_iface, ifr.ifr_name, sizeof(drv->mgmt_iface));
if (nl80211_set_master_mode(drv, drv->iface))
return -1;
@@ -2138,22 +2077,6 @@ static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid)
wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
addr.sll_ifindex);
- drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (drv->sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
- return -1;
- }
-
- if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror(__FILE__ ":bind");
- return -1;
- }
-
- if (eloop_register_read_sock(drv->sock, handle_read, iface, NULL)) {
- printf("Could not register read socket\n");
- return -1;
- }
-
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)");
@@ -2168,7 +2091,7 @@ static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid)
memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) {
perror("ioctl(SIOCGIFHWADDR)");
return -1;
}
@@ -2530,14 +2453,14 @@ static void i802_deinit(void *priv)
i802_del_beacon(drv);
- /* Disable management interface */
- (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_MGMT_IF, 0);
+ /* remove monitor interface */
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
(void) hostapd_set_iface_flags(drv, drv->iface, 0);
- if (drv->sock >= 0) {
- eloop_unregister_read_sock(drv->sock);
- close(drv->sock);
+ 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);
diff --git a/hostapd/ieee802_11.c b/hostapd/ieee802_11.c
index 93ef723..a569138 100644
--- a/hostapd/ieee802_11.c
+++ b/hostapd/ieee802_11.c
@@ -1672,6 +1672,9 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
case WLAN_FC_STYPE_PROBE_RESP:
wpa_printf(MSG_DEBUG, "mgmt::proberesp cb");
break;
+ case WLAN_FC_STYPE_DEAUTH:
+ /* ignore */
+ break;
default:
printf("unknown mgmt cb frame subtype %d\n", stype);
break;
diff --git a/hostapd/radiotap.c b/hostapd/radiotap.c
new file mode 100644
index 0000000..804473f
--- /dev/null
+++ b/hostapd/radiotap.c
@@ -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 --git a/hostapd/radiotap.h b/hostapd/radiotap.h
new file mode 100644
index 0000000..508264c
--- /dev/null
+++ b/hostapd/radiotap.h
@@ -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 --git a/hostapd/radiotap_iter.h b/hostapd/radiotap_iter.h
new file mode 100644
index 0000000..92a798a
--- /dev/null
+++ b/hostapd/radiotap_iter.h
@@ -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 */