]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Allow add-BSS operation to re-use existing netdev
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 31 Oct 2013 17:41:42 +0000 (19:41 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 31 Oct 2013 20:34:25 +0000 (22:34 +0200)
When removing and re-adding the first wlan# netdev to hostapd
dynamically, the netdev is already present and should not be removed and
re-added to maintain its state as not-added-by-hostapd so that it does
not get removed automatically.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/hostapd.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_test.c
wpa_supplicant/driver_i.h

index 72f582d773a623aea5065090fd65da1c0030c3dc..5e6b15ec9a87ad9a4e2f1cdf2d8c4abdb04eacf1 100644 (file)
@@ -286,7 +286,7 @@ int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
        char force_ifname[IFNAMSIZ];
        u8 if_addr[ETH_ALEN];
        return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
-                             NULL, NULL, force_ifname, if_addr, NULL);
+                             NULL, NULL, force_ifname, if_addr, NULL, 0);
 }
 
 
@@ -417,13 +417,13 @@ 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,
                   void **drv_priv, char *force_ifname, u8 *if_addr,
-                  const char *bridge)
+                  const char *bridge, int use_existing)
 {
        if (hapd->driver == NULL || hapd->driver->if_add == NULL)
                return -1;
        return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
                                    bss_ctx, drv_priv, force_ifname, if_addr,
-                                   bridge);
+                                   bridge, use_existing);
 }
 
 
index 8a2b4dc7dd4ef3c15701fdeb2740c1b3717864bc..5defd8b384e0dade0637ce196d7e06dd1bb7903a 100644 (file)
@@ -48,7 +48,7 @@ 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,
                   void **drv_priv, char *force_ifname, u8 *if_addr,
-                  const char *bridge);
+                  const char *bridge, int use_existing);
 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,
index 5d1e47f12e62a87d9ca31768ab78799244ccb88e..8ae753cbf17c8520282db7f95b6cdbc3bc4abe67 100644 (file)
@@ -608,7 +608,8 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
 /**
  * hostapd_setup_bss - Per-BSS setup (initialization)
  * @hapd: Pointer to BSS data
- * @first: Whether this BSS is the first BSS of an interface
+ * @first: Whether this BSS is the first BSS of an interface; -1 = not first,
+ *     but interface may exist
  *
  * This function is used to initialize all per-BSS data structures and
  * resources. This gets called in a loop for each BSS when an interface is
@@ -623,7 +624,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
        char force_ifname[IFNAMSIZ];
        u8 if_addr[ETH_ALEN];
 
-       if (!first) {
+       if (!first || first == -1) {
                if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
                        /* Allocate the next available BSSID. */
                        do {
@@ -647,7 +648,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                                   hapd->conf->iface, hapd->own_addr, hapd,
                                   &hapd->drv_priv, force_ifname, if_addr,
                                   hapd->conf->bridge[0] ? hapd->conf->bridge :
-                                  NULL)) {
+                                  NULL, first == -1)) {
                        wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
                                   MACSTR ")", MAC2STR(hapd->own_addr));
                        return -1;
@@ -1578,7 +1579,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
                        os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
                                  ETH_ALEN);
 
-                       if (hostapd_setup_bss(hapd, 0)) {
+                       if (hostapd_setup_bss(hapd, -1)) {
                                hapd_iface->conf->num_bss--;
                                hapd_iface->num_bss--;
                                os_free(hapd);
index 7eb71bac78a50b9296e3236172a806887e56ce8d..85f66ee41c7731dc172e1a0b609b2a76e8fedd3a 100644 (file)
@@ -1955,12 +1955,13 @@ struct wpa_driver_ops {
         *      (this may differ from the requested addr if the driver cannot
         *      change interface address)
         * @bridge: Bridge interface to use or %NULL if no bridge configured
+        * @use_existing: Whether to allow existing interface to be used
         * Returns: 0 on success, -1 on failure
         */
        int (*if_add)(void *priv, enum wpa_driver_if_type type,
                      const char *ifname, const u8 *addr, void *bss_ctx,
                      void **drv_priv, char *force_ifname, u8 *if_addr,
-                     const char *bridge);
+                     const char *bridge, int use_existing);
 
        /**
         * if_remove - Remove a virtual interface
index e8c140e4816c229e075c608b03988ae158309be5..a1c48373001b8640b51ebb50e56a2b3fef528f90 100644 (file)
@@ -7064,7 +7064,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                const char *ifname, enum nl80211_iftype iftype,
                                const u8 *addr, int wds,
                                int (*handler)(struct nl_msg *, void *),
-                               void *arg)
+                               void *arg, int use_existing)
 {
        int ret;
 
@@ -7073,6 +7073,11 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 
        /* if error occurred and interface exists already */
        if (ret == -ENFILE && if_nametoindex(ifname)) {
+               if (use_existing) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
+                                  ifname);
+                       return -ENFILE;
+               }
                wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
 
                /* Try to remove the interface that was already there. */
@@ -7438,7 +7443,7 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 
        drv->monitor_ifidx =
                nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-                                    0, NULL, NULL);
+                                    0, NULL, NULL, 0);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
                /*
@@ -8979,7 +8984,8 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                if (!if_nametoindex(name)) {
                        if (nl80211_create_iface(drv, name,
                                                 NL80211_IFTYPE_AP_VLAN,
-                                                bss->addr, 1, NULL, NULL) < 0)
+                                                bss->addr, 1, NULL, NULL, 0) <
+                           0)
                                return -1;
                        if (bridge_ifname &&
                            linux_br_add_if(drv->global->ioctl_sock,
@@ -9276,12 +9282,13 @@ 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 **drv_priv,
                                     char *force_ifname, u8 *if_addr,
-                                    const char *bridge)
+                                    const char *bridge, int use_existing)
 {
        enum nl80211_iftype nlmode;
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifidx;
+       int added = 1;
 
        if (addr)
                os_memcpy(if_addr, addr, ETH_ALEN);
@@ -9292,7 +9299,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
                ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
                                             0, nl80211_wdev_handler,
-                                            &p2pdev_info);
+                                            &p2pdev_info, use_existing);
                if (!p2pdev_info.wdev_id_set || ifidx != 0) {
                        wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
                                   ifname);
@@ -9308,8 +9315,11 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                           (long long unsigned int) p2pdev_info.wdev_id);
        } else {
                ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
-                                            0, NULL, NULL);
-               if (ifidx < 0) {
+                                            0, NULL, NULL, use_existing);
+               if (use_existing && ifidx == -ENFILE) {
+                       added = 0;
+                       ifidx = if_nametoindex(ifname);
+               } else if (ifidx < 0) {
                        return -1;
                }
        }
@@ -9319,7 +9329,8 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                        os_memcpy(if_addr, bss->addr, ETH_ALEN);
                else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
                                            bss->ifname, if_addr) < 0) {
-                       nl80211_remove_iface(drv, ifidx);
+                       if (added)
+                               nl80211_remove_iface(drv, ifidx);
                        return -1;
                }
        }
@@ -9357,7 +9368,8 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
        if (type == WPA_IF_AP_BSS) {
                struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
                if (new_bss == NULL) {
-                       nl80211_remove_iface(drv, ifidx);
+                       if (added)
+                               nl80211_remove_iface(drv, ifidx);
                        return -1;
                }
 
@@ -9366,7 +9378,8 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                        wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
                                   "interface %s to a bridge %s",
                                   ifname, bridge);
-                       nl80211_remove_iface(drv, ifidx);
+                       if (added)
+                               nl80211_remove_iface(drv, ifidx);
                        os_free(new_bss);
                        return -1;
                }
@@ -9384,7 +9397,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                new_bss->next = drv->first_bss->next;
                new_bss->freq = drv->first_bss->freq;
                new_bss->ctx = bss_ctx;
-               new_bss->added_if = 1;
+               new_bss->added_if = added;
                drv->first_bss->next = new_bss;
                if (drv_priv)
                        *drv_priv = new_bss;
@@ -9410,8 +9423,8 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
        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",
-                  __func__, type, ifname, ifindex);
+       wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
+                  __func__, type, ifname, ifindex, bss->added_if);
        if (ifindex > 0 && bss->added_if)
                nl80211_remove_iface(drv, ifindex);
 
@@ -9436,6 +9449,7 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
        if (bss != drv->first_bss) {
                struct i802_bss *tbss;
 
+               wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
                for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
                        if (tbss->next == bss) {
                                tbss->next = bss->next;
@@ -9451,10 +9465,13 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                        wpa_printf(MSG_INFO, "nl80211: %s - could not find "
                                   "BSS %p in the list", __func__, bss);
        } else {
+               wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
                nl80211_teardown_ap(bss);
-               wpa_driver_nl80211_del_beacon(drv);
+               if (!bss->added_if && !drv->first_bss->next)
+                       wpa_driver_nl80211_del_beacon(drv);
                nl80211_destroy_bss(bss);
-               i802_set_iface_flags(bss, 0);
+               if (!bss->added_if)
+                       i802_set_iface_flags(bss, 0);
                if (drv->first_bss->next) {
                        drv->first_bss = drv->first_bss->next;
                        drv->ctx = drv->first_bss->ctx;
index 541ebcced8ae4f0391e4eb3ed498c84341aafe86..5742b988b28c1c060fcf3de3742b7bae50242fa6 100644 (file)
@@ -1059,7 +1059,7 @@ static int test_driver_if_add(void *priv, enum wpa_driver_if_type type,
                              const char *ifname, const u8 *addr,
                              void *bss_ctx, void **drv_priv,
                              char *force_ifname, u8 *if_addr,
-                             const char *bridge)
+                             const char *bridge, int use_existing)
 {
        struct test_driver_bss *dbss = priv;
        struct wpa_driver_test_data *drv = dbss->drv;
index c3916801273d1ad8b526432d83bdc26c41f0342f..6b5d49a831cb8b4caa7143fb11a202f7cdc039a1 100644 (file)
@@ -380,7 +380,7 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
        if (wpa_s->driver->if_add)
                return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
                                             addr, bss_ctx, NULL, force_ifname,
-                                            if_addr, bridge);
+                                            if_addr, bridge, 0);
        return -1;
 }