nl80211: Add Michael MIC failure event processing for wpa_supplicant
[wpasupplicant] / src / drivers / driver_nl80211.c
index 7abd50a..41819a6 100644 (file)
@@ -730,6 +730,41 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
+                                          struct nlattr *tb[])
+{
+       union wpa_event_data data;
+
+       wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
+       os_memset(&data, 0, sizeof(data));
+       if (tb[NL80211_ATTR_MAC]) {
+               wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
+                           nla_data(tb[NL80211_ATTR_MAC]),
+                           nla_len(tb[NL80211_ATTR_MAC]));
+       }
+       if (tb[NL80211_ATTR_KEY_SEQ]) {
+               wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
+                           nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+                           nla_len(tb[NL80211_ATTR_KEY_SEQ]));
+       }
+       if (tb[NL80211_ATTR_KEY_TYPE]) {
+               enum nl80211_key_type key_type =
+                       nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
+               wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
+               if (key_type == NL80211_KEYTYPE_PAIRWISE)
+                       data.michael_mic_failure.unicast = 1;
+       } else
+               data.michael_mic_failure.unicast = 1;
+
+       if (tb[NL80211_ATTR_KEY_IDX]) {
+               u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
+               wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
+       }
+
+       wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
 static int process_event(struct nl_msg *msg, void *arg)
 {
        struct wpa_driver_nl80211_data *drv = arg;
@@ -773,6 +808,9 @@ static int process_event(struct nl_msg *msg, void *arg)
        case NL80211_CMD_DISASSOCIATE:
                mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME]);
                break;
+       case NL80211_CMD_MICHAEL_MIC_FAILURE:
+               mlme_event_michael_mic_failure(drv, tb);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
                           "(cmd=%d)", gnlh->cmd);
@@ -1397,31 +1435,29 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
-                                     const u8 *addr, int key_idx,
-                                     int set_tx, const u8 *seq,
-                                     size_t seq_len,
-                                     const u8 *key, size_t key_len)
+static int nl_set_encr(int ifindex, struct wpa_driver_nl80211_data *drv,
+                      wpa_alg alg, const u8 *addr, int key_idx, int set_tx,
+                      const u8 *seq, size_t seq_len,
+                      const u8 *key, size_t key_len)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
-       int err;
        struct nl_msg *msg;
+       int ret;
 
-       wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
-                  "seq_len=%lu key_len=%lu",
-                  __func__, alg, addr, key_idx, set_tx,
+       wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+                  "set_tx=%d seq_len=%lu key_len=%lu",
+                  __func__, ifindex, alg, addr, key_idx, set_tx,
                   (unsigned long) seq_len, (unsigned long) key_len);
 
        msg = nlmsg_alloc();
-       if (msg == NULL)
-               return -1;
+       if (!msg)
+               return -ENOMEM;
 
        if (alg == WPA_ALG_NONE) {
-               genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-                           NL80211_CMD_DEL_KEY, 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);
+               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);
                switch (alg) {
                case WPA_ALG_WEP:
@@ -1438,57 +1474,84 @@ static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
                case WPA_ALG_CCMP:
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
                        break;
-#ifdef CONFIG_IEEE80211W
                case WPA_ALG_IGTK:
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
                        break;
-#endif /* CONFIG_IEEE80211W */
                default:
+                       wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
+                                  "algorithm %d", __func__, alg);
                        nlmsg_free(msg);
                        return -1;
                }
        }
 
+       if (seq)
+               NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
+
        if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
        {
                wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
                NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
        }
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
 
-       err = send_and_recv_msgs(drv, msg, NULL, NULL);
-       if (err) {
-               wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d", err);
-               return -1;
-       }
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret == -ENOENT && alg == WPA_ALG_NONE)
+               ret = 0;
+       if (ret)
+               wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
+                          ret, strerror(-ret));
 
-       if (set_tx && alg != WPA_ALG_NONE) {
-               msg = nlmsg_alloc();
-               if (msg == NULL)
-                       return -1;
+       /*
+        * If we failed or don't need to set the default TX key (below),
+        * we're done here.
+        */
+       if (ret || !set_tx || alg == WPA_ALG_NONE)
+               return ret;
+#ifdef HOSTAPD /* FIX: is this needed? */
+       if (addr)
+               return ret;
+#endif /* HOSTAPD */
 
-               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, key_idx);
-               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-               NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
 
-               err = send_and_recv_msgs(drv, msg, NULL, NULL);
-               if (err) {
-                       wpa_printf(MSG_DEBUG, "nl80211: set default key "
-                                  "failed; err=%d", err);
-                       return -1;
-               }
-       }
+       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, key_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+       if (alg == WPA_ALG_IGTK)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
+       else
+               NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
 
-       return 0;
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret == -ENOENT)
+               ret = 0;
+       if (ret)
+               wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
+                          "err=%d %s)", ret, strerror(-ret));
+       return ret;
 
 nla_put_failure:
        return -ENOBUFS;
 }
 
 
+static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
+                                     const u8 *addr, int key_idx,
+                                     int set_tx, const u8 *seq,
+                                     size_t seq_len,
+                                     const u8 *key, size_t key_len)
+{
+       struct wpa_driver_nl80211_data *drv = priv;
+       return nl_set_encr(drv->ifindex, drv, alg, addr, key_idx, set_tx, seq,
+                          seq_len, key, key_len);
+}
+
+
 static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
                                   const u8 *addr, int cmd, u16 reason_code)
 {
@@ -1622,7 +1685,7 @@ nla_put_failure:
 }
 
 
-#ifdef CONFIG_AP
+#if defined(CONFIG_AP) || defined(HOSTAPD)
 
 struct phy_info_arg {
        u16 *num_modes;
@@ -1720,7 +1783,7 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
 
                        /* crude heuristic */
                        if (mode->channels[idx].freq < 4000)
-                               if (mode->channels[idx].freq == 2848)
+                               if (mode->channels[idx].freq == 2484)
                                        mode->channels[idx].chan = 14;
                                else
                                        mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
@@ -1887,6 +1950,10 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
        return NULL;
 }
 
+#endif /* CONFIG_AP || HOSTAPD */
+
+
+#ifdef CONFIG_AP
 
 static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
                                         const void *data, size_t len,
@@ -2866,101 +2933,13 @@ static int hostapd_set_iface_flags(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static int nl_set_encr(int ifindex, struct wpa_driver_nl80211_data *drv,
-                      wpa_alg alg, const u8 *addr, int idx, const u8 *key,
-                      size_t key_len, int txkey)
-{
-       struct nl_msg *msg;
-       int ret;
-
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       if (alg == WPA_ALG_NONE) {
-               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);
-               switch (alg) {
-               case WPA_ALG_WEP:
-                       if (key_len == 5)
-                               NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-                                           0x000FAC01);
-                       else
-                               NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-                                           0x000FAC05);
-                       break;
-               case WPA_ALG_TKIP:
-                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
-                       break;
-               case WPA_ALG_CCMP:
-                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
-                       break;
-               case WPA_ALG_IGTK:
-                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
-                       break;
-               default:
-                       wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
-                                  "algorithm %d", __func__, alg);
-                       nlmsg_free(msg);
-                       return -1;
-               }
-       }
-
-       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, ifindex);
-
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-       if (ret == -ENOENT)
-               ret = 0;
-
-       /*
-        * If we failed or don't need to set the default TX key (below),
-        * we're done here.
-        */
-       if (ret || !txkey || addr)
-               return ret;
-
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -ENOMEM;
-
-       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, ifindex);
-       if (alg == WPA_ALG_IGTK)
-               NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
-       else
-               NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
-
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-       if (ret == -ENOENT)
-               ret = 0;
-       return ret;
- nla_put_failure:
-       return -ENOBUFS;
-}
-
-
 static int i802_set_key(const char *iface, void *priv, wpa_alg alg,
                        const u8 *addr, int key_idx, int set_tx, const u8 *seq,
                        size_t seq_len, const u8 *key, size_t key_len)
 {
        struct wpa_driver_nl80211_data *drv = priv;
-       int ret;
-
-       ret = nl_set_encr(if_nametoindex(iface), drv, alg, addr, key_idx, key,
-                         key_len, set_tx);
-       if (ret < 0)
-               return ret;
-
-       return ret;
+       return nl_set_encr(if_nametoindex(iface), drv, alg, addr, key_idx,
+                          set_tx, seq, seq_len, key, key_len);
 }
 
 
@@ -3869,270 +3848,6 @@ static int i802_if_remove(void *priv, enum hostapd_driver_if_type type,
 }
 
 
-struct phy_info_arg {
-       u16 *num_modes;
-       struct hostapd_hw_modes *modes;
-};
-
-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 },
-               [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
-       };
-
-       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);
-
-               if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
-                       mode->ht_capab = nla_get_u16(
-                               tb_band[NL80211_BAND_ATTR_HT_CAPA]);
-               }
-
-               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 = 0;
-
-                       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_DISABLED;
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
-                               mode->channels[idx].flag |=
-                                       HOSTAPD_CHAN_PASSIVE_SCAN;
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
-                               mode->channels[idx].flag |=
-                                       HOSTAPD_CHAN_NO_IBSS;
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
-                               mode->channels[idx].flag |=
-                                       HOSTAPD_CHAN_RADAR;
-
-                       if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
-                           !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
-                               mode->channels[idx].max_tx_power =
-                                       nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
-
-                       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++;
-               }
-       }
-
-       return NL_SKIP;
-}
-
-static struct hostapd_hw_modes *i802_add_11b(struct hostapd_hw_modes *modes,
-                                            u16 *num_modes)
-{
-       u16 m;
-       struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
-       int i, mode11g_idx = -1;
-
-       /* If only 802.11g mode is included, use it to construct matching
-        * 802.11b mode data. */
-
-       for (m = 0; m < *num_modes; m++) {
-               if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
-                       return modes; /* 802.11b already included */
-               if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
-                       mode11g_idx = m;
-       }
-
-       if (mode11g_idx < 0)
-               return modes; /* 2.4 GHz band not supported at all */
-
-       nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
-       if (nmodes == NULL)
-               return modes; /* Could not add 802.11b mode */
-
-       mode = &nmodes[*num_modes];
-       os_memset(mode, 0, sizeof(*mode));
-       (*num_modes)++;
-       modes = nmodes;
-
-       mode->mode = HOSTAPD_MODE_IEEE80211B;
-
-       mode11g = &modes[mode11g_idx];
-       mode->num_channels = mode11g->num_channels;
-       mode->channels = os_malloc(mode11g->num_channels *
-                                  sizeof(struct hostapd_channel_data));
-       if (mode->channels == NULL) {
-               (*num_modes)--;
-               return modes; /* Could not add 802.11b mode */
-       }
-       os_memcpy(mode->channels, mode11g->channels,
-                 mode11g->num_channels * sizeof(struct hostapd_channel_data));
-
-       mode->num_rates = 0;
-       mode->rates = os_malloc(4 * sizeof(struct hostapd_rate_data));
-       if (mode->rates == NULL) {
-               os_free(mode->channels);
-               (*num_modes)--;
-               return modes; /* Could not add 802.11b mode */
-       }
-
-       for (i = 0; i < mode11g->num_rates; i++) {
-               if (mode11g->rates[i].rate > 110 ||
-                   mode11g->rates[i].flags &
-                   (HOSTAPD_RATE_ERP | HOSTAPD_RATE_OFDM))
-                       continue;
-               mode->rates[mode->num_rates] = mode11g->rates[i];
-               mode->num_rates++;
-               if (mode->num_rates == 4)
-                       break;
-       }
-
-       if (mode->num_rates == 0) {
-               os_free(mode->channels);
-               os_free(mode->rates);
-               (*num_modes)--;
-               return modes; /* No 802.11b rates */
-       }
-
-       wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
-                  "information");
-
-       return modes;
-}
-
-static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv,
-                                                        u16 *num_modes,
-                                                        u16 *flags)
-{
-       struct wpa_driver_nl80211_data *drv = priv;
-       struct nl_msg *msg;
-       struct phy_info_arg result = {
-               .num_modes = num_modes,
-               .modes = NULL,
-       };
-
-       *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->ifname));
-
-       if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0)
-               return i802_add_11b(result.modes, num_modes);
- nla_put_failure:
-       return NULL;
-}
-
-
 static int i802_set_sta_vlan(void *priv, const u8 *addr,
                             const char *ifname, int vlan_id)
 {
@@ -5490,6 +5205,7 @@ static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
        drv->hapd = hapd;
        memcpy(drv->ifname, hapd->conf->iface, sizeof(drv->ifname));
        memcpy(drv->bss.ifname, hapd->conf->iface, sizeof(drv->bss.ifname));
+       drv->ifindex = if_nametoindex(drv->ifname);
 
        drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
        drv->if_indices = drv->default_if_indices;
@@ -5597,8 +5313,10 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_beacon = wpa_driver_nl80211_set_beacon,
        .set_beacon_int = wpa_driver_nl80211_set_beacon_int,
        .send_mlme = wpa_driver_nl80211_send_mlme,
-       .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
 #endif /* CONFIG_AP */
+#if defined(CONFIG_AP) || defined(HOSTAPD)
+       .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+#endif /* CONFIG_AP || HOSTAPD */
 #ifdef HOSTAPD
        .hapd_init = i802_init,
        .init_bssid = i802_init_bssid,
@@ -5632,7 +5350,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .if_add = i802_if_add,
        .if_update = i802_if_update,
        .if_remove = i802_if_remove,
-       .hapd_get_hw_feature_data = i802_get_hw_feature_data,
        .set_sta_vlan = i802_set_sta_vlan,
        .hapd_set_country = i802_set_country,
        .get_neighbor_bss = i802_get_neighbor_bss,