Remove unnecessary ifname parameter from sta_add() driver op
[mech_eap.git] / src / drivers / driver_nl80211.c
index aff6b81..e566703 100644 (file)
 #endif
 
 struct i802_bss {
+       struct wpa_driver_nl80211_data *drv;
        struct i802_bss *next;
        int ifindex;
+       char ifname[IFNAMSIZ + 1];
        unsigned int beacon_set:1;
 };
 
@@ -67,7 +69,6 @@ struct wpa_driver_nl80211_data {
        void *ctx;
        struct netlink_data *netlink;
        int ioctl_sock; /* socket for ioctl() use */
-       char ifname[IFNAMSIZ + 1];
        char brname[IFNAMSIZ];
        int ifindex;
        int if_removed;
@@ -99,7 +100,6 @@ struct wpa_driver_nl80211_data {
        int probe_req_report;
        int disable_11b_rates;
 
-       unsigned int beacon_set:1;
        unsigned int pending_remain_on_chan:1;
        unsigned int pending_send_action:1;
        unsigned int added_bridge:1;
@@ -108,6 +108,11 @@ struct wpa_driver_nl80211_data {
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
 
+       struct wpa_driver_scan_filter *filter_ssids;
+       size_t num_filter_ssids;
+
+       struct i802_bss first_bss;
+
 #ifdef HOSTAPD
        int eapol_sock; /* socket for EAPOL frames */
 
@@ -115,8 +120,6 @@ struct wpa_driver_nl80211_data {
        int *if_indices;
        int num_if_indices;
 
-       struct i802_bss bss;
-
        int last_freq;
        int last_freq_ht;
 #endif /* HOSTAPD */
@@ -136,8 +139,6 @@ static void nl80211_remove_monitor_interface(
 #ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static struct i802_bss * get_bss(struct wpa_driver_nl80211_data *drv,
-                                int ifindex);
 static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
 static int wpa_driver_nl80211_if_remove(void *priv,
                                        enum wpa_driver_if_type type,
@@ -289,7 +290,8 @@ nla_put_failure:
 
 static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        if (!drv->associated)
                return -1;
        os_memcpy(bssid, drv->bssid, ETH_ALEN);
@@ -299,7 +301,8 @@ static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
 
 static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        if (!drv->associated)
                return -1;
        os_memcpy(ssid, drv->ssid, drv->ssid_len);
@@ -324,7 +327,7 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
                   event.interface_status.ifname,
                   del ? "removed" : "added");
 
-       if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
+       if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
                if (del)
                        drv->if_removed = 1;
                else
@@ -347,7 +350,7 @@ static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
        rta_len = RTA_ALIGN(sizeof(struct rtattr));
        while (RTA_OK(attr, attrlen)) {
                if (attr->rta_type == IFLA_IFNAME) {
-                       if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
+                       if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
                            == 0)
                                return 1;
                        else
@@ -367,7 +370,7 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
                return 1;
 
        if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
-               drv->ifindex = if_nametoindex(drv->ifname);
+               drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
                wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
                           "interface");
                wpa_driver_nl80211_finish_drv_init(drv);
@@ -868,7 +871,8 @@ static int process_event(struct nl_msg *msg, void *arg)
        if (drv->ap_scan_as_station &&
            (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
             gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
-               wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP);
+               wpa_driver_nl80211_set_mode(&drv->first_bss,
+                                           IEEE80211_MODE_AP);
                drv->ap_scan_as_station = 0;
        }
 
@@ -976,7 +980,8 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
  */
 static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        char alpha2[3];
        struct nl_msg *msg;
 
@@ -1065,7 +1070,7 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
        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);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
 
        if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
                return 0;
@@ -1239,12 +1244,15 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
 {
        struct wpa_driver_nl80211_data *drv;
        struct netlink_config *cfg;
+       struct i802_bss *bss;
 
        drv = os_zalloc(sizeof(*drv));
        if (drv == NULL)
                return NULL;
        drv->ctx = ctx;
-       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+       bss = &drv->first_bss;
+       bss->drv = drv;
+       os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
        drv->monitor_ifidx = -1;
        drv->monitor_sock = -1;
        drv->ioctl_sock = -1;
@@ -1274,7 +1282,7 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
        if (wpa_driver_nl80211_finish_drv_init(drv))
                goto failed;
 
-       return drv;
+       return bss;
 
 failed:
        netlink_deinit(drv->netlink);
@@ -1285,6 +1293,7 @@ failed:
        nl_cache_free(drv->nl_cache);
        nl_handle_destroy(drv->nl_handle);
        nl_cb_put(drv->nl_cb);
+       eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
 
        os_free(drv);
        return NULL;
@@ -1336,17 +1345,20 @@ static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 {
-       drv->ifindex = if_nametoindex(drv->ifname);
+       struct i802_bss *bss = &drv->first_bss;
+
+       drv->ifindex = if_nametoindex(bss->ifname);
+       drv->first_bss.ifindex = drv->ifindex;
 
 #ifndef HOSTAPD
-       if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA) < 0) {
+       if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
                           "use managed mode");
        }
 
-       if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) {
+       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
                wpa_printf(MSG_ERROR, "Could not set interface '%s' UP",
-                          drv->ifname);
+                          bss->ifname);
                return -1;
        }
 
@@ -1364,20 +1376,6 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 }
 
 
-#ifdef HOSTAPD
-static void wpa_driver_nl80211_free_bss(struct wpa_driver_nl80211_data *drv)
-{
-       struct i802_bss *bss, *prev;
-       bss = drv->bss.next;
-       while (bss) {
-               prev = bss;
-               bss = bss->next;
-               os_free(bss);
-       }
-}
-#endif /* HOSTAPD */
-
-
 static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
 {
        struct nl_msg *msg;
@@ -1405,14 +1403,15 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
  */
 static void wpa_driver_nl80211_deinit(void *priv)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
 
        if (drv->added_if_into_bridge) {
-               if (linux_br_del_if(drv->ioctl_sock, drv->brname, drv->ifname)
+               if (linux_br_del_if(drv->ioctl_sock, drv->brname, bss->ifname)
                    < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "interface %s from bridge %s: %s",
-                                  drv->ifname, drv->brname, strerror(errno));
+                                  bss->ifname, drv->brname, strerror(errno));
        }
        if (drv->added_bridge) {
                if (linux_br_del(drv->ioctl_sock, drv->brname) < 0)
@@ -1442,8 +1441,6 @@ static void wpa_driver_nl80211_deinit(void *priv)
 
        if (drv->if_indices != drv->default_if_indices)
                os_free(drv->if_indices);
-
-       wpa_driver_nl80211_free_bss(drv);
 #endif /* HOSTAPD */
 
        if (drv->disable_11b_rates)
@@ -1454,8 +1451,8 @@ static void wpa_driver_nl80211_deinit(void *priv)
 
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-       (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
-       wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA);
+       (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
+       wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
 
        if (drv->ioctl_sock >= 0)
                close(drv->ioctl_sock);
@@ -1471,6 +1468,8 @@ static void wpa_driver_nl80211_deinit(void *priv)
        eloop_cancel_timeout(wpa_driver_nl80211_probe_req_report_timeout,
                             drv, NULL);
 
+       os_free(drv->filter_ssids);
+
        os_free(drv);
 }
 
@@ -1487,7 +1486,8 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_driver_nl80211_data *drv = eloop_ctx;
        if (drv->ap_scan_as_station) {
-               wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP);
+               wpa_driver_nl80211_set_mode(&drv->first_bss,
+                                           IEEE80211_MODE_AP);
                drv->ap_scan_as_station = 0;
        }
        wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
@@ -1504,7 +1504,8 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 static int wpa_driver_nl80211_scan(void *priv,
                                   struct wpa_driver_scan_params *params)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = 0, timeout;
        struct nl_msg *msg, *ssids, *freqs;
        size_t i;
@@ -1519,6 +1520,11 @@ static int wpa_driver_nl80211_scan(void *priv,
                return -1;
        }
 
+       os_free(drv->filter_ssids);
+       drv->filter_ssids = params->filter_ssids;
+       params->filter_ssids = NULL;
+       drv->num_filter_ssids = params->num_filter_ssids;
+
        genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
                    NL80211_CMD_TRIGGER_SCAN, 0);
 
@@ -1553,12 +1559,12 @@ static int wpa_driver_nl80211_scan(void *priv,
                         * mac80211 does not allow scan requests in AP mode, so
                         * try to do this in station mode.
                         */
-                       if (wpa_driver_nl80211_set_mode(drv,
+                       if (wpa_driver_nl80211_set_mode(bss,
                                                        IEEE80211_MODE_INFRA))
                                goto nla_put_failure;
 
                        if (wpa_driver_nl80211_scan(drv, params)) {
-                               wpa_driver_nl80211_set_mode(drv,
+                               wpa_driver_nl80211_set_mode(bss,
                                                            IEEE80211_MODE_AP);
                                goto nla_put_failure;
                        }
@@ -1598,6 +1604,57 @@ nla_put_failure:
 }
 
 
+static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+{
+       const u8 *end, *pos;
+
+       if (ies == NULL)
+               return NULL;
+
+       pos = ies;
+       end = ies + ies_len;
+
+       while (pos + 1 < end) {
+               if (pos + 2 + pos[1] > end)
+                       break;
+               if (pos[0] == ie)
+                       return pos;
+               pos += 2 + pos[1];
+       }
+
+       return NULL;
+}
+
+
+static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
+                                const u8 *ie, size_t ie_len)
+{
+       const u8 *ssid;
+       size_t i;
+
+       if (drv->filter_ssids == NULL)
+               return 0;
+
+       ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+       if (ssid == NULL)
+               return 1;
+
+       for (i = 0; i < drv->num_filter_ssids; i++) {
+               if (ssid[1] == drv->filter_ssids[i].ssid_len &&
+                   os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
+                   0)
+                       return 0;
+       }
+
+       return 1;
+}
+
+
+struct nl80211_bss_info_arg {
+       struct wpa_driver_nl80211_data *drv;
+       struct wpa_scan_results *res;
+};
+
 static int bss_info_handler(struct nl_msg *msg, void *arg)
 {
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1616,7 +1673,8 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
                [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
                [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
        };
-       struct wpa_scan_results *res = arg;
+       struct nl80211_bss_info_arg *_arg = arg;
+       struct wpa_scan_results *res = _arg->res;
        struct wpa_scan_res **tmp;
        struct wpa_scan_res *r;
        const u8 *ie, *beacon_ie;
@@ -1645,6 +1703,10 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
                beacon_ie_len = 0;
        }
 
+       if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+                                 ie ? ie_len : beacon_ie_len))
+               return NL_SKIP;
+
        r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
        if (r == NULL)
                return NL_SKIP;
@@ -1793,6 +1855,7 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
        struct nl_msg *msg;
        struct wpa_scan_results *res;
        int ret;
+       struct nl80211_bss_info_arg arg;
 
        res = os_zalloc(sizeof(*res));
        if (res == NULL)
@@ -1805,7 +1868,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
                    NL80211_CMD_GET_SCAN, 0);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
-       ret = send_and_recv_msgs(drv, msg, bss_info_handler, res);
+       arg.drv = drv;
+       arg.res = res;
+       ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
        msg = NULL;
        if (ret == 0) {
                wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
@@ -1829,7 +1894,8 @@ nla_put_failure:
 static struct wpa_scan_results *
 wpa_driver_nl80211_get_scan_results(void *priv)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct wpa_scan_results *res;
 
        res = nl80211_get_scan_results(drv);
@@ -1869,7 +1935,8 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
                                      const u8 *seq, size_t seq_len,
                                      const u8 *key, size_t key_len)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifindex = if_nametoindex(ifname);
        struct nl_msg *msg;
        int ret;
@@ -2126,7 +2193,8 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
 static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
                                             int reason_code)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
                return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
        wpa_printf(MSG_DEBUG, "%s", __func__);
@@ -2139,7 +2207,8 @@ static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
 static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
                                           int reason_code)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
                return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
        wpa_printf(MSG_DEBUG, "%s", __func__);
@@ -2152,7 +2221,8 @@ static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
 static int wpa_driver_nl80211_authenticate(
        void *priv, struct wpa_driver_auth_params *params)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1, i;
        struct nl_msg *msg;
        enum nl80211_auth_type type;
@@ -2164,7 +2234,7 @@ static int wpa_driver_nl80211_authenticate(
        if (drv->nlmode != NL80211_IFTYPE_STATION)
                wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
 
-       if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA) < 0)
+       if (wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
                return -1;
 
 retry:
@@ -2181,7 +2251,7 @@ retry:
        for (i = 0; i < 4; i++) {
                if (!params->wep_key[i])
                        continue;
-               wpa_driver_nl80211_set_key(drv->ifname, drv, WPA_ALG_WEP, NULL,
+               wpa_driver_nl80211_set_key(bss->ifname, drv, WPA_ALG_WEP, NULL,
                                           i,
                                           i == params->wep_tx_keyidx, NULL, 0,
                                           params->wep_key[i],
@@ -2516,7 +2586,8 @@ wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
 static struct hostapd_hw_modes *
 wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        struct phy_info_arg result = {
                .num_modes = num_modes,
@@ -2585,7 +2656,8 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
 static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
                                        size_t data_len)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct ieee80211_mgmt *mgmt;
        int encrypt = 1;
        u16 fc;
@@ -2611,27 +2683,20 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
 }
 
 
-static int wpa_driver_nl80211_set_beacon(const char *ifname, void *priv,
+static int wpa_driver_nl80211_set_beacon(void *priv,
                                         const u8 *head, size_t head_len,
                                         const u8 *tail, size_t tail_len,
                                         int dtim_period, int beacon_int)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        u8 cmd = NL80211_CMD_NEW_BEACON;
        int ret;
        int beacon_set;
-       int ifindex = if_nametoindex(ifname);
-#ifdef HOSTAPD
-       struct i802_bss *bss;
+       int ifindex = if_nametoindex(bss->ifname);
 
-       bss = get_bss(drv, ifindex);
-       if (bss == NULL)
-               return -ENOENT;
        beacon_set = bss->beacon_set;
-#else /* HOSTAPD */
-       beacon_set = drv->beacon_set;
-#endif /* HOSTAPD */
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -2655,11 +2720,7 @@ static int wpa_driver_nl80211_set_beacon(const char *ifname, void *priv,
                wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
                           ret, strerror(-ret));
        } else {
-#ifdef HOSTAPD
                bss->beacon_set = 1;
-#else /* HOSTAPD */
-               drv->beacon_set = 1;
-#endif /* HOSTAPD */
        }
        return ret;
  nla_put_failure:
@@ -2710,10 +2771,11 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_sta_add(const char *ifname, void *priv,
+static int wpa_driver_nl80211_sta_add(void *priv,
                                      struct hostapd_sta_add_params *params)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret = -ENOBUFS;
 
@@ -2724,7 +2786,7 @@ static int wpa_driver_nl80211_sta_add(const char *ifname, void *priv,
        genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
                    0, NL80211_CMD_NEW_STATION, 0);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
        NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
        NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
@@ -2750,7 +2812,8 @@ static int wpa_driver_nl80211_sta_add(const char *ifname, void *priv,
 
 static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
@@ -2762,7 +2825,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
                    0, NL80211_CMD_DEL_STATION, 0);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-                   if_nametoindex(drv->ifname));
+                   if_nametoindex(bss->ifname));
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -3199,7 +3262,7 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
        int optval;
        socklen_t optlen;
 
-       snprintf(buf, IFNAMSIZ, "mon.%s", drv->ifname);
+       snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
        buf[IFNAMSIZ - 1] = '\0';
 
        drv->monitor_ifidx =
@@ -3259,7 +3322,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        void *priv, const u8 *addr, const u8 *data,
        size_t data_len, int encrypt, const u8 *own_addr)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct ieee80211_hdr *hdr;
        size_t len;
        u8 *pos;
@@ -3340,11 +3404,12 @@ static u32 sta_flags_nl80211(int flags)
 }
 
 
-static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
-                                           int total_flags, int flags_or,
-                                           int flags_and)
+static int wpa_driver_nl80211_sta_set_flags(const char *ifname, void *priv,
+                                           const u8 *addr, int total_flags,
+                                           int flags_or, int flags_and)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg, *flags = NULL;
        struct nl80211_sta_flag_update upd;
 
@@ -3362,7 +3427,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
                    0, NL80211_CMD_SET_STATION, 0);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-                   if_nametoindex(drv->ifname));
+                   if_nametoindex(ifname));
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 
        /*
@@ -3401,7 +3466,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
                                 struct wpa_driver_associate_params *params)
 {
-       if (wpa_driver_nl80211_set_mode(drv, params->mode) ||
+       if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
            wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
                nl80211_remove_monitor_interface(drv);
                return -1;
@@ -3452,7 +3517,7 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
 
        wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
 
-       if (wpa_driver_nl80211_set_mode(drv, params->mode)) {
+       if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
                wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
                           "IBSS mode");
                return -1;
@@ -3666,7 +3731,8 @@ nla_put_failure:
 static int wpa_driver_nl80211_associate(
        void *priv, struct wpa_driver_associate_params *params)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1;
        struct nl_msg *msg;
 
@@ -3677,7 +3743,7 @@ static int wpa_driver_nl80211_associate(
                return wpa_driver_nl80211_ibss(drv, params);
 
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
-               if (wpa_driver_nl80211_set_mode(drv, params->mode) < 0)
+               if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0)
                        return -1;
                return wpa_driver_nl80211_connect(drv, params);
        }
@@ -3779,7 +3845,8 @@ nla_put_failure:
 
 static int wpa_driver_nl80211_set_mode(void *priv, int mode)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1;
        int nlmode;
 
@@ -3814,10 +3881,10 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode)
         * take the device down, try to set the mode again, and bring the
         * device back up.
         */
-       if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
+       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == 0) {
                /* Try to set the mode again while the interface is down */
                ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
-               if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1))
+               if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
                        ret = -1;
        }
 
@@ -3836,9 +3903,7 @@ done:
        } else if (!ret && nlmode != NL80211_IFTYPE_AP) {
                /* Remove additional AP mode functionality */
                nl80211_remove_monitor_interface(drv);
-#ifndef HOSTAPD
-               drv->beacon_set = 0;
-#endif /* HOSTAPD */
+               bss->beacon_set = 0;
        }
 
        if (ret)
@@ -3852,7 +3917,8 @@ done:
 static int wpa_driver_nl80211_get_capa(void *priv,
                                       struct wpa_driver_capa *capa)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        if (!drv->has_capability)
                return -1;
        os_memcpy(capa, &drv->capa, sizeof(*capa));
@@ -3862,7 +3928,8 @@ static int wpa_driver_nl80211_get_capa(void *priv,
 
 static int wpa_driver_nl80211_set_operstate(void *priv, int state)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
 
        wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
                   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
@@ -3874,7 +3941,8 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state)
 
 static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        struct nl80211_sta_flag_update upd;
 
@@ -3886,7 +3954,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
                    0, NL80211_CMD_SET_STATION, 0);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-                   if_nametoindex(drv->ifname));
+                   if_nametoindex(bss->ifname));
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
 
        os_memset(&upd, 0, sizeof(upd));
@@ -3903,20 +3971,6 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
 
 #ifdef HOSTAPD
 
-static struct i802_bss * get_bss(struct wpa_driver_nl80211_data *drv,
-                                int ifindex)
-{
-       struct i802_bss *bss = &drv->bss;
-       while (bss) {
-               if (ifindex == bss->ifindex)
-                       return bss;
-               bss = bss->next;
-       }
-       wpa_printf(MSG_DEBUG, "nl80211: get_bss(%d) failed", ifindex);
-       return NULL;
-}
-
-
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
        int i;
@@ -4010,7 +4064,8 @@ static int get_key_handler(struct nl_msg *msg, void *arg)
 static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
                           int idx, u8 *seq)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
        msg = nlmsg_alloc();
@@ -4036,7 +4091,8 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
 static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
                              int mode)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        u8 rates[NL80211_MAX_SUPP_RATES];
        u8 rates_len = 0;
@@ -4054,8 +4110,7 @@ static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
 
        NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
 
-       /* TODO: multi-BSS support */
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
@@ -4066,7 +4121,8 @@ static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
 /* Set kernel driver on given frequency (MHz) */
 static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
                                           freq->sec_channel_offset);
 }
@@ -4074,7 +4130,8 @@ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 
 static int i802_set_rts(void *priv, int rts)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret = -ENOBUFS;
        u32 val;
@@ -4105,7 +4162,8 @@ nla_put_failure:
 
 static int i802_set_frag(void *priv, int frag)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret = -ENOBUFS;
        u32 val;
@@ -4136,7 +4194,8 @@ nla_put_failure:
 
 static int i802_flush(void *priv)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
        msg = nlmsg_alloc();
@@ -4150,7 +4209,7 @@ static int i802_flush(void *priv)
         * XXX: FIX! this needs to flush all VLANs too
         */
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-                   if_nametoindex(drv->ifname));
+                   if_nametoindex(bss->ifname));
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
@@ -4212,7 +4271,8 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
 static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
                              const u8 *addr)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
        os_memset(data, 0, sizeof(*data));
@@ -4224,7 +4284,7 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
                    0, NL80211_CMD_GET_STATION, 0);
 
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
        return send_and_recv_msgs(drv, msg, get_sta_handler, data);
  nla_put_failure:
@@ -4235,7 +4295,8 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
 static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
                                    int cw_min, int cw_max, int burst_time)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        struct nlattr *txq, *params;
 
@@ -4246,7 +4307,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
        genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
                    0, NL80211_CMD_SET_WIPHY, 0);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
        txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
        if (!txq)
@@ -4278,7 +4339,8 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
 
 static int i802_set_bss(void *priv, int cts, int preamble, int slot)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
        msg = nlmsg_alloc();
@@ -4295,8 +4357,7 @@ static int i802_set_bss(void *priv, int cts, int preamble, int slot)
        if (slot >= 0)
                NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
 
-       /* TODO: multi-BSS support */
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
@@ -4325,7 +4386,8 @@ static int i802_set_short_slot_time(void *priv, int value)
 static int i802_set_sta_vlan(void *priv, const u8 *addr,
                             const char *ifname, int vlan_id)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
 
        msg = nlmsg_alloc();
@@ -4336,7 +4398,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
                    0, NL80211_CMD_SET_STATION, 0);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-                   if_nametoindex(drv->ifname));
+                   if_nametoindex(bss->ifname));
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
        NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
                    if_nametoindex(ifname));
@@ -4349,20 +4411,21 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
 
 static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        char name[IFNAMSIZ + 1];
 
-       os_snprintf(name, sizeof(name), "%s.sta%d", drv->ifname, aid);
+       os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
        wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
                   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
        if (val) {
-               if (nl80211_create_iface(priv, name, NL80211_IFTYPE_AP_VLAN,
+               if (nl80211_create_iface(drv, name, NL80211_IFTYPE_AP_VLAN,
                                         NULL, 1) < 0)
                        return -1;
                linux_set_iface_flags(drv->ioctl_sock, name, 1);
                return i802_set_sta_vlan(priv, addr, name, 0);
        } else {
-               i802_set_sta_vlan(priv, addr, drv->ifname, 0);
+               i802_set_sta_vlan(priv, addr, bss->ifname, 0);
                return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
                                                    name);
        }
@@ -4414,7 +4477,7 @@ static int i802_sta_clear_stats(void *priv, const u8 *addr)
 static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
                           int reason)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
        struct ieee80211_mgmt mgmt;
 
        memset(&mgmt, 0, sizeof(mgmt));
@@ -4424,7 +4487,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
        memcpy(mgmt.sa, own_addr, ETH_ALEN);
        memcpy(mgmt.bssid, own_addr, ETH_ALEN);
        mgmt.u.deauth.reason_code = host_to_le16(reason);
-       return wpa_driver_nl80211_send_mlme(drv, (u8 *) &mgmt,
+       return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
                                            sizeof(mgmt.u.deauth));
 }
@@ -4433,7 +4496,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
 static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
                             int reason)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
        struct ieee80211_mgmt mgmt;
 
        memset(&mgmt, 0, sizeof(mgmt));
@@ -4443,7 +4506,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
        memcpy(mgmt.sa, own_addr, ETH_ALEN);
        memcpy(mgmt.bssid, own_addr, ETH_ALEN);
        mgmt.u.disassoc.reason_code = host_to_le16(reason);
-       return wpa_driver_nl80211_send_mlme(drv, (u8 *) &mgmt,
+       return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
                                            sizeof(mgmt.u.disassoc));
 }
@@ -4505,17 +4568,17 @@ static void *i802_init(struct hostapd_data *hapd,
                       struct wpa_init_params *params)
 {
        struct wpa_driver_nl80211_data *drv;
+       struct i802_bss *bss;
        size_t i;
        char brname[IFNAMSIZ];
        int ifindex, br_ifindex;
        int br_added = 0;
 
-       drv = wpa_driver_nl80211_init(hapd, params->ifname);
-       if (drv == NULL)
+       bss = wpa_driver_nl80211_init(hapd, params->ifname);
+       if (bss == NULL)
                return NULL;
 
-       drv->bss.ifindex = drv->ifindex;
-
+       drv = bss->drv;
        if (linux_br_get(brname, params->ifname) == 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
                           params->ifname, brname);
@@ -4543,18 +4606,18 @@ static void *i802_init(struct hostapd_data *hapd,
        /* start listening for EAPOL on the default AP interface */
        add_ifidx(drv, drv->ifindex);
 
-       if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0))
+       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
                goto failed;
 
        if (params->bssid) {
-               if (linux_set_ifhwaddr(drv->ioctl_sock, drv->ifname,
+               if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
                                       params->bssid))
                        goto failed;
        }
 
-       if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP)) {
+       if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
                wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
-                          "into AP mode", drv->ifname);
+                          "into AP mode", bss->ifname);
                goto failed;
        }
 
@@ -4562,7 +4625,7 @@ static void *i802_init(struct hostapd_data *hapd,
            i802_check_bridge(drv, params->bridge[0], params->ifname) < 0)
                goto failed;
 
-       if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1))
+       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
                goto failed;
 
        drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
@@ -4577,10 +4640,10 @@ static void *i802_init(struct hostapd_data *hapd,
                goto failed;
        }
 
-       if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, params->own_addr))
+       if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
                goto failed;
 
-       return drv;
+       return bss;
 
 failed:
        nl80211_remove_monitor_interface(drv);
@@ -4620,19 +4683,19 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
 }
 
 
-static int wpa_driver_nl80211_if_add(const char *iface, void *priv,
-                                    enum wpa_driver_if_type type,
+static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                                     const char *ifname, const u8 *addr,
-                                    void *bss_ctx)
+                                    void *bss_ctx, void **drv_priv)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifidx;
 #ifdef HOSTAPD
-       struct i802_bss *bss = NULL;
+       struct i802_bss *new_bss = NULL;
 
        if (type == WPA_IF_AP_BSS) {
-               bss = os_zalloc(sizeof(*bss));
-               if (bss == NULL)
+               new_bss = os_zalloc(sizeof(*new_bss));
+               if (new_bss == NULL)
                        return -1;
        }
 #endif /* HOSTAPD */
@@ -4642,7 +4705,7 @@ static int wpa_driver_nl80211_if_add(const char *iface, void *priv,
                                     0);
        if (ifidx < 0) {
 #ifdef HOSTAPD
-               os_free(bss);
+               os_free(new_bss);
 #endif /* HOSTAPD */
                return -1;
        }
@@ -4651,12 +4714,16 @@ static int wpa_driver_nl80211_if_add(const char *iface, void *priv,
        if (type == WPA_IF_AP_BSS) {
                if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
                        nl80211_remove_iface(drv, ifidx);
-                       os_free(bss);
+                       os_free(new_bss);
                        return -1;
                }
-               bss->ifindex = ifidx;
-               bss->next = drv->bss.next;
-               drv->bss.next = bss;
+               os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+               new_bss->ifindex = ifidx;
+               new_bss->drv = drv;
+               new_bss->next = drv->first_bss.next;
+               drv->first_bss.next = new_bss;
+               if (drv_priv)
+                       *drv_priv = new_bss;
        }
 #endif /* HOSTAPD */
 
@@ -4668,7 +4735,8 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                                        enum wpa_driver_if_type type,
                                        const char *ifname)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifindex = if_nametoindex(ifname);
 
        wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
@@ -4678,18 +4746,19 @@ static int wpa_driver_nl80211_if_remove(void *priv,
        nl80211_remove_iface(drv, ifindex);
 
 #ifdef HOSTAPD
-       if (type == WPA_IF_AP_BSS) {
-               struct i802_bss *bss, *prev;
-               prev = &drv->bss;
-               bss = drv->bss.next;
-               while (bss) {
-                       if (ifindex == bss->ifindex) {
-                               prev->next = bss->next;
-                               os_free(bss);
-                               break;
-                       }
-                       prev = bss;
-                       bss = bss->next;
+       if (type != WPA_IF_AP_BSS)
+               return 0;
+
+       if (bss != &drv->first_bss) {
+               struct i802_bss *tbss = &drv->first_bss;
+
+               while (tbss) {
+                       if (tbss->next != bss)
+                               continue;
+
+                       tbss->next = bss->next;
+                       os_free(bss);
+                       break;
                }
        }
 #endif /* HOSTAPD */
@@ -4716,7 +4785,8 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
                                          const u8 *bssid,
                                          const u8 *data, size_t data_len)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1;
        struct nl_msg *msg;
        u8 *buf;
@@ -4778,7 +4848,8 @@ nla_put_failure:
 static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
                                                unsigned int duration)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
        u64 cookie;
@@ -4812,7 +4883,8 @@ nla_put_failure:
 
 static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        int ret;
 
@@ -4867,7 +4939,8 @@ static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx,
 
 static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
 
        if (drv->nlmode != NL80211_IFTYPE_STATION) {
                wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
@@ -4905,12 +4978,13 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
 static int wpa_driver_nl80211_alloc_interface_addr(void *priv, u8 *addr,
                                                   char *ifname)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
 
        if (ifname)
                ifname[0] = '\0';
 
-       if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr) < 0)
+       if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, addr) < 0)
                return -1;
 
        if (addr[0] & 0x02) {
@@ -4980,7 +5054,8 @@ nla_put_failure:
 
 static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        drv->disable_11b_rates = disabled;
        return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
 }
@@ -4988,11 +5063,23 @@ static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
 
 static int wpa_driver_nl80211_deinit_ap(void *priv)
 {
-       struct wpa_driver_nl80211_data *drv = priv;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        if (drv->nlmode != NL80211_IFTYPE_AP)
                return -1;
        wpa_driver_nl80211_del_beacon(drv);
-       return wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA);
+       return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
+}
+
+
+static void wpa_driver_nl80211_resume(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
+                          "resume event");
+       }
 }
 
 
@@ -5053,4 +5140,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .release_interface_addr = wpa_driver_nl80211_release_interface_addr,
        .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
        .deinit_ap = wpa_driver_nl80211_deinit_ap,
+       .resume = wpa_driver_nl80211_resume,
 };