diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 72f582d77..5e6b15ec9 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -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); } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 8a2b4dc7d..5defd8b38 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -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, diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 5d1e47f12..8ae753cbf 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -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); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 7eb71bac7..85f66ee41 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -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 diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index e8c140e48..a1c483730 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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; diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 541ebcced..5742b988b 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -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; diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index c39168012..6b5d49a83 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -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; }