nl80211: Preliminary code for usermode MLME support
authorJouni Malinen <jouni.malinen@atheros.com>
Fri, 15 Aug 2008 19:14:49 +0000 (22:14 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 15 Aug 2008 19:14:49 +0000 (22:14 +0300)
This adds some parts needed to use usermode MLME with the current mac80211
(plus a patch to add a new cfg80211 command; not yet submitted to
wireless-testing). This version creates a monitor interface for management
frames and is able to send Probe Request frames during scan. However, it
looks like management frame reception is not yet working properly. In
addition, mlme_{add,remove}_sta() handlers are still missing.

src/drivers/driver_nl80211.c
src/drivers/radiotap.c [new file with mode: 0644]
src/drivers/radiotap.h [new file with mode: 0644]
src/drivers/radiotap_iter.h [new file with mode: 0644]
wpa_supplicant/Makefile

index 2b8cde9..1085b7e 100644 (file)
 #include <netlink/genl/family.h>
 #include <netlink/genl/ctrl.h>
 #include <linux/nl80211.h>
+#ifdef CONFIG_CLIENT_MLME
+#include <netpacket/packet.h>
+#include <linux/if_ether.h>
+#include "radiotap.h"
+#include "radiotap_iter.h"
+#endif /* CONFIG_CLIENT_MLME */
 
 #include "wireless_copy.h"
 #include "common.h"
@@ -70,6 +76,11 @@ struct wpa_driver_nl80211_data {
        struct nl_cache *nl_cache;
        struct nl_cb *nl_cb;
        struct genl_family *nl80211;
+
+#ifdef CONFIG_CLIENT_MLME
+       int monitor_sock; /* socket for monitor */
+       int monitor_ifidx;
+#endif /* CONFIG_CLIENT_MLME */
 };
 
 
@@ -889,6 +900,276 @@ static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
 }
 
 
+#ifdef CONFIG_CLIENT_MLME
+
+static int nl80211_set_vif(struct wpa_driver_nl80211_data *drv,
+                          int drop_unencrypted, int userspace_mlme)
+{
+#ifdef NL80211_CMD_SET_VIF
+       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_VIF, 0);
+
+       if (drop_unencrypted >= 0)
+               NLA_PUT_U8(msg, NL80211_ATTR_VIF_DROP_UNENCRYPTED,
+                          drop_unencrypted);
+       if (userspace_mlme >= 0)
+               NLA_PUT_U8(msg, NL80211_ATTR_VIF_USERSPACE_MLME,
+                          userspace_mlme);
+
+       ret = 0;
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       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;
+#else /* NL80211_CMD_SET_VIF */
+       return -1;
+#endif /* NL80211_CMD_SET_VIF */
+}
+
+
+static int wpa_driver_nl80211_set_userspace_mlme(
+       struct wpa_driver_nl80211_data *drv, int enabled)
+{
+       return nl80211_set_vif(drv, -1, enabled);
+}
+
+
+static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
+                                int ifidx)
+{
+       struct nl_msg *msg;
+
+       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:
+               wpa_printf(MSG_ERROR, "nl80211: Failed to remove interface.");
+       }
+       nlmsg_free(msg);
+}
+
+
+static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+                               const char *ifname, enum nl80211_iftype iftype)
+{
+       struct nl_msg *msg, *flags = NULL;
+       int ifidx, err;
+
+       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->ifname));
+       NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+
+       if (iftype == NL80211_IFTYPE_MONITOR) {
+               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;
+       }
+
+       err = nl_send_auto_complete(drv->nl_handle, msg);
+       if (err < 0)
+               wpa_printf(MSG_ERROR, "nl80211: nl_send_auto_complete failed: "
+                          "%d (create_iface)", err);
+       else {
+               err = nl_wait_for_ack(drv->nl_handle);
+               if (err < 0)
+                       wpa_printf(MSG_ERROR, "nl80211: nl_wait_for_ack "
+                                  "failed: %d (create_iface)", err);
+       }
+       if (err < 0) {
+ nla_put_failure:
+               wpa_printf(MSG_ERROR, "nl80211: Failed to create interface "
+                          "%s.", ifname);
+               nlmsg_free(msg);
+               return -1;
+       }
+
+       nlmsg_free(msg);
+
+       ifidx = if_nametoindex(ifname);
+       if (ifidx <= 0)
+               return -1;
+
+       return ifidx;
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct wpa_driver_nl80211_data *drv = eloop_ctx;
+       int len;
+       unsigned char buf[3000];
+       struct ieee80211_radiotap_iterator iter;
+       int ret;
+       int injected = 0, failed = 0, rxflags = 0;
+       struct ieee80211_rx_status rx_status;
+
+       len = recv(sock, buf, sizeof(buf), 0);
+       if (len < 0) {
+               perror("recv");
+               return;
+       }
+
+       if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len)) {
+               wpa_printf(MSG_DEBUG, "nl80211: received invalid radiotap "
+                          "frame");
+               return;
+       }
+
+       os_memset(&rx_status, 0, sizeof(rx_status));
+
+       while (1) {
+               ret = ieee80211_radiotap_iterator_next(&iter);
+               if (ret == -ENOENT)
+                       break;
+               if (ret) {
+                       wpa_printf(MSG_DEBUG, "nl80211: received invalid "
+                                  "radiotap frame (%d)", 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((*(u16 *) 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
+                        * rx_status.channel = XXX;
+                       */
+                       break;
+               case IEEE80211_RADIOTAP_RATE:
+                       break;
+               case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+                       rx_status.ssi = *iter.this_arg;
+                       break;
+               }
+       }
+
+       if (rxflags && injected)
+               return;
+
+       if (!injected) {
+               wpa_supplicant_sta_rx(drv->ctx, buf + iter.max_length,
+                                     len - iter.max_length, &rx_status);
+       } else if (failed) {
+               /* TX failure callback */
+       } else {
+               /* TX success (ACK) callback */
+       }
+}
+
+
+static int wpa_driver_nl80211_create_monitor_interface(
+       struct wpa_driver_nl80211_data *drv)
+{
+       char buf[IFNAMSIZ];
+       struct sockaddr_ll ll;
+       int optval, flags;
+       socklen_t optlen;
+
+       os_snprintf(buf, IFNAMSIZ, "mon.%s", drv->ifname);
+       buf[IFNAMSIZ - 1] = '\0';
+
+       drv->monitor_ifidx =
+               nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR);
+
+       if (drv->monitor_ifidx < 0)
+               return -1;
+
+       if (wpa_driver_nl80211_get_ifflags_ifname(drv, buf, &flags) != 0 ||
+           wpa_driver_nl80211_set_ifflags_ifname(drv, buf, flags | IFF_UP) !=
+           0) {
+               wpa_printf(MSG_ERROR, "nl80211: Could not set interface '%s' "
+                          "UP", buf);
+               goto error;
+       }
+
+       os_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)) {
+               wpa_printf(MSG_ERROR, "nl80211: Could not register monitor "
+                          "read socket");
+               goto error;
+       }
+
+       return 0;
+
+ error:
+       nl80211_remove_iface(drv, drv->monitor_ifidx);
+       return -1;
+}
+
+#endif /* CONFIG_CLIENT_MLME */
+
+
 /**
  * wpa_driver_nl80211_init - Initialize WE driver interface
  * @ctx: context to be used when calling wpa_supplicant functions,
@@ -1041,6 +1322,17 @@ void wpa_driver_nl80211_deinit(void *priv)
        struct wpa_driver_nl80211_data *drv = priv;
        int flags;
 
+#ifdef CONFIG_CLIENT_MLME
+       if (drv->monitor_sock >= 0) {
+               eloop_unregister_read_sock(drv->monitor_sock);
+               close(drv->monitor_sock);
+       }
+       if (drv->monitor_ifidx > 0)
+               nl80211_remove_iface(drv, drv->monitor_ifidx);
+       if (drv->capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
+               wpa_driver_nl80211_set_userspace_mlme(drv, 0);
+#endif /* CONFIG_CLIENT_MLME */
+
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
        /*
@@ -2152,6 +2444,334 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state)
 }
 
 
+#ifdef CONFIG_CLIENT_MLME
+static int wpa_driver_nl80211_open_mlme(struct wpa_driver_nl80211_data *drv)
+{
+       if (wpa_driver_nl80211_set_userspace_mlme(drv, 1) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to enable userspace "
+                          "MLME");
+               return -1;
+       }
+       if (wpa_driver_nl80211_create_monitor_interface(drv)) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to create monitor "
+                          "interface");
+               return -1;
+       }
+       return 0;
+}
+#endif /* CONFIG_CLIENT_MLME */
+
+
+static int wpa_driver_nl80211_set_param(void *priv, const char *param)
+{
+#ifdef CONFIG_CLIENT_MLME
+       struct wpa_driver_nl80211_data *drv = priv;
+
+       if (param == NULL)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+
+       if (os_strstr(param, "use_mlme=1")) {
+               wpa_printf(MSG_DEBUG, "nl80211: Using user space MLME");
+               drv->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+
+               if (wpa_driver_nl80211_open_mlme(drv))
+                       return -1;
+       }
+#endif /* CONFIG_CLIENT_MLME */
+
+       return 0;
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+
+static int ack_wait_handler(struct nl_msg *msg, void *arg)
+{
+       int *finished = arg;
+
+       *finished = 1;
+       return NL_STOP;
+}
+
+
+struct phy_info_arg {
+       u16 *num_modes;
+       struct wpa_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 wpa_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 = os_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)];
+               os_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 = os_zalloc(mode->num_channels *
+                                          sizeof(struct wpa_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 |= WPA_CHAN_W_SCAN |
+                               WPA_CHAN_W_ACTIVE_SCAN |
+                               WPA_CHAN_W_IBSS;
+
+                       if (!mode_is_set) {
+                               /* crude heuristic */
+                               if (mode->channels[idx].freq < 4000)
+                                       mode->mode = WPA_MODE_IEEE80211B;
+                               else
+                                       mode->mode = WPA_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 &= ~WPA_CHAN_W_SCAN;
+                       if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+                               mode->channels[idx].flag &=
+                                       ~WPA_CHAN_W_ACTIVE_SCAN;
+                       if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+                               mode->channels[idx].flag &= ~WPA_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 = os_zalloc(mode->num_rates *
+                                       sizeof(struct wpa_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 == WPA_MODE_IEEE80211B &&
+                           mode->rates[idx].rate > 200)
+                               mode->mode = WPA_MODE_IEEE80211G;
+
+                       if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE])
+                               mode->rates[idx].flags |= WPA_RATE_PREAMBLE2;
+
+                       idx++;
+               }
+       }
+
+       phy_info->error = 0;
+
+       return NL_SKIP;
+}
+
+
+static struct wpa_hw_modes *
+wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+       struct wpa_driver_nl80211_data *drv = priv;
+       struct nl_msg *msg;
+       int err = -1;
+       struct nl_cb *cb = NULL;
+       int finished = 0;
+       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, drv->ifindex);
+
+       cb = nl_cb_clone(drv->nl_cb);
+       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) {
+               wpa_supplicant_sta_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 wpa_driver_nl80211_set_channel(void *priv, wpa_hw_mode phymode,
+                                         int chan, int freq)
+{
+       return wpa_driver_nl80211_set_freq(priv, freq);
+}
+
+
+static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
+                                       size_t data_len)
+{
+       struct wpa_driver_nl80211_data *drv = priv;
+       __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 iovec iov[2] = {
+               {
+                       .iov_base = &rtap_hdr,
+                       .iov_len = sizeof(rtap_hdr),
+               },
+               {
+                       .iov_base = (void *) data,
+                       .iov_len = data_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,
+       };
+
+       if (sendmsg(drv->monitor_sock, &msg, 0) < 0) {
+               perror("send[MLME]");
+               return -1;
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_CLIENT_MLME */
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -2169,9 +2789,17 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_auth_alg = wpa_driver_nl80211_set_auth_alg,
        .init = wpa_driver_nl80211_init,
        .deinit = wpa_driver_nl80211_deinit,
+       .set_param = wpa_driver_nl80211_set_param,
        .add_pmkid = wpa_driver_nl80211_add_pmkid,
        .remove_pmkid = wpa_driver_nl80211_remove_pmkid,
        .flush_pmkid = wpa_driver_nl80211_flush_pmkid,
        .get_capa = wpa_driver_nl80211_get_capa,
        .set_operstate = wpa_driver_nl80211_set_operstate,
+#ifdef CONFIG_CLIENT_MLME
+       .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+       .set_channel = wpa_driver_nl80211_set_channel,
+       .set_ssid = wpa_driver_nl80211_set_ssid,
+       .set_bssid = wpa_driver_nl80211_set_bssid,
+       .send_mlme = wpa_driver_nl80211_send_mlme,
+#endif /* CONFIG_CLIENT_MLME */
 };
diff --git a/src/drivers/radiotap.c b/src/drivers/radiotap.c
new file mode 100644 (file)
index 0000000..804473f
--- /dev/null
@@ -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/src/drivers/radiotap.h b/src/drivers/radiotap.h
new file mode 100644 (file)
index 0000000..508264c
--- /dev/null
@@ -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/src/drivers/radiotap_iter.h b/src/drivers/radiotap_iter.h
new file mode 100644 (file)
index 0000000..92a798a
--- /dev/null
@@ -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 */
index 1096583..7fd3fc5 100644 (file)
@@ -131,6 +131,9 @@ ifdef CONFIG_DRIVER_NL80211
 CFLAGS += -DCONFIG_DRIVER_NL80211
 OBJS_d += ../src/drivers/driver_nl80211.o
 LIBS += -lnl
+ifdef CONFIG_CLIENT_MLME
+OBJS_d += ../src/drivers/radiotap.o
+endif
 endif
 
 ifdef CONFIG_DRIVER_PRISM54