hostapd: upgrade to latest git version, add patches to fix multi-bss support with...
authorFelix Fietkau <nbd@openwrt.org>
Wed, 20 Jan 2010 02:26:00 +0000 (02:26 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Wed, 20 Jan 2010 02:26:00 +0000 (02:26 +0000)
SVN-Revision: 19234

package/hostapd/Makefile
package/hostapd/patches/130-scan_wait.patch [new file with mode: 0644]
package/hostapd/patches/140-wds_sta_remove.patch [new file with mode: 0644]
package/hostapd/patches/150-mbss_driver_handling.patch [new file with mode: 0644]
package/hostapd/patches/160-sta_roam_between_bss.patch [new file with mode: 0644]

index 342c7519d5c55003f7783f4a14a28780b6728b76..682d6ab8524e4aab0e366708731176348993c7dd 100644 (file)
@@ -8,9 +8,9 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=hostapd
-PKG_VERSION:=20100108
+PKG_VERSION:=20100117
 PKG_RELEASE:=1
-PKG_REV:=d97572a40fd7ec77094e2e4ef83424a4c0f7e24d
+PKG_REV:=43a7fe2e0e614e52fa05ff4d78af91bd4e17d3b2
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=git://w1.fi/srv/git/hostap.git
diff --git a/package/hostapd/patches/130-scan_wait.patch b/package/hostapd/patches/130-scan_wait.patch
new file mode 100644 (file)
index 0000000..7fe9285
--- /dev/null
@@ -0,0 +1,148 @@
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -238,6 +238,7 @@ struct hostapd_iface {
+       int (*for_each_interface)(struct hapd_interfaces *interfaces,
+                                 int (*cb)(struct hostapd_iface *iface,
+                                           void *ctx), void *ctx);
++      int (*init_complete)(struct hostapd_iface *iface);
+ };
+ /* hostapd.c */
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -745,6 +745,9 @@ int hostapd_setup_interface_complete(str
+       wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
+                  iface->bss[0]->conf->iface);
++      if (iface->init_complete)
++              iface->init_complete(iface);
++
+       return 0;
+ }
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -35,6 +35,8 @@
+ extern int wpa_debug_level;
+ extern int wpa_debug_show_keys;
+ extern int wpa_debug_timestamp;
++static int daemonize = 0;
++static char *pid_file = NULL;
+ struct hapd_interfaces {
+@@ -162,6 +164,15 @@ static void hostapd_logger_cb(void *ctx,
+ }
+ #endif /* CONFIG_NO_HOSTAPD_LOGGER */
++static int hostapd_init_complete(struct hostapd_iface *iface)
++{
++      if (daemonize && os_daemonize(pid_file)) {
++              perror("daemon");
++              return -1;
++      }
++      daemonize = 0;
++}
++
+ /**
+  * hostapd_init - Allocate and initialize per-interface data
+@@ -183,6 +194,7 @@ static struct hostapd_iface * hostapd_in
+       if (hapd_iface == NULL)
+               goto fail;
++      hapd_iface->init_complete = hostapd_init_complete;
+       hapd_iface->reload_config = hostapd_reload_config;
+       hapd_iface->config_read_cb = hostapd_config_read;
+       hapd_iface->config_fname = os_strdup(config_file);
+@@ -390,7 +402,7 @@ static int hostapd_global_init(struct ha
+ }
+-static void hostapd_global_deinit(const char *pid_file)
++static void hostapd_global_deinit(void)
+ {
+ #ifdef EAP_SERVER_TNC
+       tncs_global_deinit();
+@@ -408,8 +420,7 @@ static void hostapd_global_deinit(const 
+ }
+-static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
+-                            const char *pid_file)
++static int hostapd_global_run(struct hapd_interfaces *iface)
+ {
+ #ifdef EAP_SERVER_TNC
+       int tnc = 0;
+@@ -430,11 +441,6 @@ static int hostapd_global_run(struct hap
+       }
+ #endif /* EAP_SERVER_TNC */
+-      if (daemonize && os_daemonize(pid_file)) {
+-              perror("daemon");
+-              return -1;
+-      }
+-
+       eloop_run();
+       return 0;
+@@ -478,8 +484,7 @@ int main(int argc, char *argv[])
+       struct hapd_interfaces interfaces;
+       int ret = 1;
+       size_t i;
+-      int c, debug = 0, daemonize = 0;
+-      char *pid_file = NULL;
++      int c, debug = 0;
+       if (os_program_init())
+               return -1;
+@@ -544,7 +549,7 @@ int main(int argc, char *argv[])
+                       goto out;
+       }
+-      if (hostapd_global_run(&interfaces, daemonize, pid_file))
++      if (hostapd_global_run(&interfaces))
+               goto out;
+       ret = 0;
+@@ -555,7 +560,7 @@ int main(int argc, char *argv[])
+               hostapd_interface_deinit_free(interfaces.iface[i]);
+       os_free(interfaces.iface);
+-      hostapd_global_deinit(pid_file);
++      hostapd_global_deinit();
+       os_free(pid_file);
+       os_program_deinit();
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -1854,6 +1854,8 @@ struct hostapd_config * hostapd_config_r
+                       }
+ #endif /* CONFIG_IEEE80211W */
+ #ifdef CONFIG_IEEE80211N
++              } else if (os_strcmp(buf, "noscan") == 0) {
++                      conf->noscan = atoi(pos);
+               } else if (os_strcmp(buf, "ieee80211n") == 0) {
+                       conf->ieee80211n = atoi(pos);
+               } else if (os_strcmp(buf, "ht_capab") == 0) {
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -366,6 +366,7 @@ struct hostapd_config {
+       int ht_op_mode_fixed;
+       u16 ht_capab;
++      int noscan;
+       int ieee80211n;
+       int secondary_channel;
+ };
+--- a/src/ap/hw_features.c
++++ b/src/ap/hw_features.c
+@@ -460,7 +460,7 @@ static int ieee80211n_check_40mhz(struct
+ {
+       struct wpa_driver_scan_params params;
+-      if (!iface->conf->secondary_channel)
++      if (!iface->conf->secondary_channel || iface->conf->noscan)
+               return 0; /* HT40 not used */
+       wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
diff --git a/package/hostapd/patches/140-wds_sta_remove.patch b/package/hostapd/patches/140-wds_sta_remove.patch
new file mode 100644 (file)
index 0000000..80e036e
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/src/ap/sta_info.c
++++ b/src/ap/sta_info.c
+@@ -121,7 +121,8 @@ void ap_free_sta(struct hostapd_data *ha
+       accounting_sta_stop(hapd, sta);
+-      hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 0);
++      if (sta->flags & WLAN_STA_WDS)
++              hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 0);
+       if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) &&
+           !(sta->flags & WLAN_STA_PREAUTH))
+               hapd->drv.sta_remove(hapd, sta->addr);
diff --git a/package/hostapd/patches/150-mbss_driver_handling.patch b/package/hostapd/patches/150-mbss_driver_handling.patch
new file mode 100644 (file)
index 0000000..ccae4e6
--- /dev/null
@@ -0,0 +1,1110 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -59,8 +59,10 @@
+ #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;
+ };
+@@ -68,7 +70,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;
+@@ -107,6 +108,8 @@ struct wpa_driver_nl80211_data {
+       u64 remain_on_chan_cookie;
++      struct i802_bss first_bss;
++
+ #ifdef HOSTAPD
+       int eapol_sock; /* socket for EAPOL frames */
+@@ -114,8 +117,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 */
+@@ -135,8 +136,6 @@ static void nl80211_remove_monitor_inter
+ #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,
+@@ -278,7 +277,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);
+@@ -288,7 +288,8 @@ static int wpa_driver_nl80211_get_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);
+@@ -313,7 +314,7 @@ static void wpa_driver_nl80211_event_lin
+                  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
+@@ -336,7 +337,7 @@ static int wpa_driver_nl80211_own_ifname
+       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
+@@ -356,7 +357,7 @@ static int wpa_driver_nl80211_own_ifinde
+               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);
+@@ -785,7 +786,7 @@ static int process_event(struct nl_msg *
+       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;
+       }
+@@ -889,7 +890,8 @@ static void wpa_driver_nl80211_event_rec
+  */
+ 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;
+@@ -978,7 +980,7 @@ static int wpa_driver_nl80211_get_info(s
+       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;
+@@ -1152,15 +1154,18 @@ static void * wpa_driver_nl80211_init(vo
+ {
+       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;
++      os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
+       drv->monitor_ifidx = -1;
+       drv->monitor_sock = -1;
+       drv->ioctl_sock = -1;
++      drv->first_bss.drv = drv;
+       if (wpa_driver_nl80211_init_nl(drv, ctx)) {
+               os_free(drv);
+@@ -1187,7 +1192,7 @@ static void * wpa_driver_nl80211_init(vo
+       if (wpa_driver_nl80211_finish_drv_init(drv))
+               goto failed;
+-      return drv;
++      return bss;
+ failed:
+       netlink_deinit(drv->netlink);
+@@ -1207,17 +1212,19 @@ failed:
+ 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(drv->first_bss.ifname);
+ #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;
+       }
+@@ -1232,20 +1239,6 @@ wpa_driver_nl80211_finish_drv_init(struc
+ }
+-#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;
+@@ -1273,14 +1266,15 @@ static int wpa_driver_nl80211_del_beacon
+  */
+ 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)
+@@ -1310,8 +1304,6 @@ static void wpa_driver_nl80211_deinit(vo
+       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)
+@@ -1322,8 +1314,8 @@ static void wpa_driver_nl80211_deinit(vo
+       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);
+@@ -1355,7 +1347,7 @@ static void wpa_driver_nl80211_scan_time
+ {
+       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");
+@@ -1372,7 +1364,8 @@ static void wpa_driver_nl80211_scan_time
+ 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;
+@@ -1421,12 +1414,12 @@ static int wpa_driver_nl80211_scan(void 
+                        * 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;
+                       }
+@@ -1662,7 +1655,8 @@ static void wpa_scan_results_free(struct
+ 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 nl_msg *msg;
+       struct wpa_scan_results *res;
+       int ret;
+@@ -1701,7 +1695,8 @@ static int wpa_driver_nl80211_set_key(co
+                                     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;
+@@ -1958,7 +1953,8 @@ static int wpa_driver_nl80211_disconnect
+ 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__);
+@@ -1971,7 +1967,8 @@ static int wpa_driver_nl80211_deauthenti
+ 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__);
+@@ -1984,7 +1981,8 @@ static int wpa_driver_nl80211_disassocia
+ 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;
+@@ -1996,7 +1994,7 @@ static int wpa_driver_nl80211_authentica
+       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:
+@@ -2013,7 +2011,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],
+@@ -2348,7 +2346,8 @@ wpa_driver_nl80211_add_11b(struct hostap
+ 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,
+@@ -2417,7 +2416,8 @@ static int wpa_driver_nl80211_send_frame
+ 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;
+@@ -2448,23 +2448,15 @@ static int wpa_driver_nl80211_set_beacon
+                                        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;
+-      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)
+               return -ENOMEM;
+@@ -2487,11 +2479,7 @@ static int wpa_driver_nl80211_set_beacon
+               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:
+@@ -2545,7 +2533,8 @@ nla_put_failure:
+ static int wpa_driver_nl80211_sta_add(const char *ifname, 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;
+@@ -2582,7 +2571,8 @@ static int wpa_driver_nl80211_sta_add(co
+ 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;
+@@ -2594,7 +2584,7 @@ static int wpa_driver_nl80211_sta_remove
+                   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);
+@@ -3032,7 +3022,7 @@ nl80211_create_monitor_interface(struct 
+       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 =
+@@ -3092,7 +3082,8 @@ static int wpa_driver_nl80211_hapd_send_
+       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;
+@@ -3177,7 +3168,8 @@ static int wpa_driver_nl80211_sta_set_fl
+                                           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;
+@@ -3195,7 +3187,7 @@ static int wpa_driver_nl80211_sta_set_fl
+                   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);
+       /*
+@@ -3234,7 +3226,7 @@ static int wpa_driver_nl80211_sta_set_fl
+ 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;
+@@ -3285,7 +3277,7 @@ static int wpa_driver_nl80211_ibss(struc
+       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;
+@@ -3499,7 +3491,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;
+@@ -3510,7 +3503,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);
+       }
+@@ -3611,7 +3604,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;
+@@ -3646,10 +3640,10 @@ static int wpa_driver_nl80211_set_mode(v
+        * 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;
+       }
+@@ -3684,7 +3678,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));
+@@ -3694,7 +3689,8 @@ static int wpa_driver_nl80211_get_capa(v
+ 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");
+@@ -3706,7 +3702,8 @@ static int wpa_driver_nl80211_set_operst
+ 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;
+@@ -3718,7 +3715,7 @@ static int wpa_driver_nl80211_set_supp_p
+                   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));
+@@ -3735,20 +3732,6 @@ static int wpa_driver_nl80211_set_supp_p
+ #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;
+@@ -3842,7 +3825,8 @@ static int get_key_handler(struct nl_msg
+ 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();
+@@ -3868,7 +3852,8 @@ static int i802_get_seqnum(const char *i
+ 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;
+@@ -3887,7 +3872,7 @@ static int i802_set_rate_sets(void *priv
+       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:
+@@ -3898,7 +3883,8 @@ static int i802_set_rate_sets(void *priv
+ /* 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);
+ }
+@@ -3906,7 +3892,8 @@ static int i802_set_freq(void *priv, str
+ 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;
+@@ -3937,7 +3924,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;
+@@ -3968,7 +3956,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();
+@@ -3982,7 +3971,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:
+@@ -4044,7 +4033,8 @@ static int get_sta_handler(struct nl_msg
+ 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));
+@@ -4056,7 +4046,7 @@ static int i802_read_sta_data(void *priv
+                   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:
+@@ -4067,7 +4057,8 @@ static int i802_read_sta_data(void *priv
+ 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;
+@@ -4078,7 +4069,7 @@ static int i802_set_tx_queue_params(void
+       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)
+@@ -4110,7 +4101,8 @@ static int i802_set_tx_queue_params(void
+ 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();
+@@ -4128,7 +4120,7 @@ static int i802_set_bss(void *priv, int 
+               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:
+@@ -4157,7 +4149,8 @@ static int i802_set_short_slot_time(void
+ 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();
+@@ -4168,7 +4161,7 @@ static int i802_set_sta_vlan(void *priv,
+                   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));
+@@ -4181,10 +4174,11 @@ static int i802_set_sta_vlan(void *priv,
+ 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[16];
+-      os_snprintf(name, sizeof(name), "%s.sta%d", drv->ifname, aid);
++      os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+       if (val) {
+               if (nl80211_create_iface(priv, name, NL80211_IFTYPE_AP_VLAN,
+                                        NULL, 1) < 0)
+@@ -4192,7 +4186,7 @@ static int i802_set_wds_sta(void *priv, 
+               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);
+       }
+@@ -4244,7 +4238,8 @@ static int i802_sta_clear_stats(void *pr
+ 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 wpa_driver_nl80211_data *drv = bss->drv;
+       struct ieee80211_mgmt mgmt;
+       memset(&mgmt, 0, sizeof(mgmt));
+@@ -4254,7 +4249,7 @@ static int i802_sta_deauth(void *priv, c
+       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));
+ }
+@@ -4263,7 +4258,8 @@ static int i802_sta_deauth(void *priv, c
+ 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 wpa_driver_nl80211_data *drv = bss->drv;
+       struct ieee80211_mgmt mgmt;
+       memset(&mgmt, 0, sizeof(mgmt));
+@@ -4273,7 +4269,7 @@ static int i802_sta_disassoc(void *priv,
+       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));
+ }
+@@ -4335,17 +4331,17 @@ static void *i802_init(struct hostapd_da
+                      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);
+@@ -4373,18 +4369,18 @@ static void *i802_init(struct hostapd_da
+       /* 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;
+       }
+@@ -4392,7 +4388,7 @@ static void *i802_init(struct hostapd_da
+           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));
+@@ -4407,10 +4403,10 @@ static void *i802_init(struct hostapd_da
+               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);
+@@ -4453,27 +4449,30 @@ static enum nl80211_iftype wpa_driver_nl
+ static int wpa_driver_nl80211_if_add(const char *iface, 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 */
++#endif
+       ifidx = nl80211_create_iface(drv, ifname,
+                                    wpa_driver_nl80211_if_type(type), addr,
+                                    0);
++
+       if (ifidx < 0) {
+ #ifdef HOSTAPD
+-              os_free(bss);
+-#endif /* HOSTAPD */
++              if (type == WPA_IF_AP_BSS)
++                      os_free(new_bss);
++#endif
+               return -1;
+       }
+@@ -4484,9 +4483,12 @@ static int wpa_driver_nl80211_if_add(con
+                       os_free(bss);
+                       return -1;
+               }
+-              bss->ifindex = ifidx;
+-              bss->next = drv->bss.next;
+-              drv->bss.next = bss;
++              strncpy(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;
++              *drv_priv = new_bss;
+       }
+ #endif /* HOSTAPD */
+@@ -4498,27 +4500,27 @@ static int wpa_driver_nl80211_if_remove(
+                                       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);
+       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 */
+       return 0;
+ }
+@@ -4540,7 +4542,8 @@ static int cookie_handler(struct nl_msg 
+ 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;
+@@ -4574,7 +4577,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;
+@@ -4629,7 +4633,8 @@ static void wpa_driver_nl80211_probe_req
+ 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 "
+@@ -4666,9 +4671,10 @@ static int wpa_driver_nl80211_probe_req_
+ static int wpa_driver_nl80211_alloc_interface_addr(void *priv, u8 *addr)
+ {
+-      struct wpa_driver_nl80211_data *drv = priv;
++      struct i802_bss *bss = priv;
++      struct wpa_driver_nl80211_data *drv = bss->drv;
+-      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) {
+@@ -4738,7 +4744,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);
+ }
+@@ -4746,11 +4753,12 @@ static int wpa_driver_nl80211_disable_11
+ 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);
+ }
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -1472,11 +1472,12 @@ struct wpa_driver_ops {
+        * @addr: Local address to use for the interface or %NULL to use the
+        *      parent interface address
+        * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
++       * @drv_priv: Pointer for overwriting the driver context
+        * Returns: 0 on success, -1 on failure
+        */
+       int (*if_add)(const char *iface, void *priv,
+                     enum wpa_driver_if_type type, const char *ifname,
+-                    const u8 *addr, void *bss_ctx);
++                    const u8 *addr, void *bss_ctx, void **drv_priv);
+       /**
+        * if_remove - Remove a virtual interface
+--- a/src/drivers/driver_test.c
++++ b/src/drivers/driver_test.c
+@@ -1030,7 +1030,7 @@ static int test_driver_bss_remove(void *
+ static int test_driver_if_add(const char *iface, void *priv,
+                             enum wpa_driver_if_type type, const char *ifname,
+-                            const u8 *addr, void *bss_ctx)
++                            const u8 *addr, void *bss_ctx, void **drv_priv)
+ {
+       wpa_printf(MSG_DEBUG, "%s(iface=%s type=%d ifname=%s bss_ctx=%p)",
+                  __func__, iface, type, ifname, bss_ctx);
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -242,7 +242,8 @@ static int hostapd_set_beacon(const char
+ static int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
+ {
+-      return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, NULL, NULL);
++      return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, NULL, NULL,
++                            &hapd->drv_priv);
+ }
+ static int hostapd_vlan_if_remove(struct hostapd_data *hapd,
+@@ -407,12 +408,13 @@ int hostapd_set_ssid(struct hostapd_data
+ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+-                 const char *ifname, const u8 *addr, void *bss_ctx)
++                 const char *ifname, const u8 *addr, void *bss_ctx,
++                 void **drv_priv)
+ {
+       if (hapd->driver == NULL || hapd->driver->if_add == NULL)
+               return -1;
+       return hapd->driver->if_add(hapd->conf->iface, hapd->drv_priv, type,
+-                                  ifname, addr, bss_ctx);
++                                  ifname, addr, bss_ctx, drv_priv);
+ }
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -26,7 +26,8 @@ int hostapd_set_generic_elem(struct host
+ int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
+ int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
+ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+-                 const char *ifname, const u8 *addr, void *bss_ctx);
++                 const char *ifname, const u8 *addr, void *bss_ctx,
++                 void **drv_priv);
+ int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+                     const char *ifname);
+ int hostapd_set_ieee8021x(struct hostapd_data *hapd,
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -484,7 +484,8 @@ static int hostapd_setup_bss(struct host
+               hapd->interface_added = 1;
+               if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
+-                                 hapd->conf->iface, hapd->own_addr, hapd)) {
++                                 hapd->conf->iface, hapd->own_addr, hapd,
++                                 &hapd->drv_priv)) {
+                       wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
+                                  MACSTR ")", MAC2STR(hapd->own_addr));
+                       return -1;
diff --git a/package/hostapd/patches/160-sta_roam_between_bss.patch b/package/hostapd/patches/160-sta_roam_between_bss.patch
new file mode 100644 (file)
index 0000000..dfd5fd8
--- /dev/null
@@ -0,0 +1,79 @@
+--- a/src/ap/sta_info.c
++++ b/src/ap/sta_info.c
+@@ -32,8 +32,8 @@
+ #include "vlan_init.h"
+ #include "sta_info.h"
+-static int ap_sta_in_other_bss(struct hostapd_data *hapd,
+-                             struct sta_info *sta, u32 flags);
++static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
++                                     struct sta_info *sta);
+ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+ #ifdef CONFIG_IEEE80211W
+ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
+@@ -123,8 +123,8 @@ void ap_free_sta(struct hostapd_data *ha
+       if (sta->flags & WLAN_STA_WDS)
+               hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 0);
+-      if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) &&
+-          !(sta->flags & WLAN_STA_PREAUTH))
++
++      if (!(sta->flags & WLAN_STA_PREAUTH))
+               hapd->drv.sta_remove(hapd, sta->addr);
+       ap_sta_hash_del(hapd, sta);
+@@ -451,6 +451,7 @@ struct sta_info * ap_sta_add(struct host
+       hapd->num_sta++;
+       ap_sta_hash_add(hapd, sta);
+       sta->ssid = &hapd->conf->ssid;
++      ap_sta_remove_in_other_bss(hapd, sta);
+       return sta;
+ }
+@@ -472,8 +473,8 @@ static int ap_sta_remove(struct hostapd_
+ }
+-static int ap_sta_in_other_bss(struct hostapd_data *hapd,
+-                             struct sta_info *sta, u32 flags)
++static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
++                                     struct sta_info *sta)
+ {
+       struct hostapd_iface *iface = hapd->iface;
+       size_t i;
+@@ -488,11 +489,11 @@ static int ap_sta_in_other_bss(struct ho
+               if (bss == hapd || bss == NULL)
+                       continue;
+               sta2 = ap_get_sta(bss, sta->addr);
+-              if (sta2 && ((sta2->flags & flags) == flags))
+-                      return 1;
+-      }
++              if (!sta2)
++                      continue;
+-      return 0;
++              ap_sta_disconnect(bss, sta2, sta2->addr, WLAN_REASON_DEAUTH_LEAVING);
++      }
+ }
+@@ -502,8 +503,7 @@ void ap_sta_disassociate(struct hostapd_
+       wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
+                  hapd->conf->iface, MAC2STR(sta->addr));
+       sta->flags &= ~WLAN_STA_ASSOC;
+-      if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
+-              ap_sta_remove(hapd, sta);
++      ap_sta_remove(hapd, sta);
+       sta->timeout_next = STA_DEAUTH;
+       eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+       eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
+@@ -521,8 +521,7 @@ void ap_sta_deauthenticate(struct hostap
+       wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
+                  hapd->conf->iface, MAC2STR(sta->addr));
+       sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+-      if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
+-              ap_sta_remove(hapd, sta);
++      ap_sta_remove(hapd, sta);
+       sta->timeout_next = STA_REMOVE;
+       eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+       eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,