Allow add-BSS operation to re-use existing netdev
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>
This commit is contained in:
parent
5592065850
commit
2aec4f3c0c
7 changed files with 45 additions and 26 deletions
|
@ -286,7 +286,7 @@ int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
|
||||||
char force_ifname[IFNAMSIZ];
|
char force_ifname[IFNAMSIZ];
|
||||||
u8 if_addr[ETH_ALEN];
|
u8 if_addr[ETH_ALEN];
|
||||||
return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
|
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,
|
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, char *force_ifname, u8 *if_addr,
|
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)
|
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
|
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
|
||||||
bss_ctx, drv_priv, force_ifname, if_addr,
|
bss_ctx, drv_priv, force_ifname, if_addr,
|
||||||
bridge);
|
bridge, use_existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,
|
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, char *force_ifname, u8 *if_addr,
|
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,
|
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||||
const char *ifname);
|
const char *ifname);
|
||||||
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
|
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
|
||||||
|
|
|
@ -608,7 +608,8 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
|
||||||
/**
|
/**
|
||||||
* hostapd_setup_bss - Per-BSS setup (initialization)
|
* hostapd_setup_bss - Per-BSS setup (initialization)
|
||||||
* @hapd: Pointer to BSS data
|
* @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
|
* 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
|
* 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];
|
char force_ifname[IFNAMSIZ];
|
||||||
u8 if_addr[ETH_ALEN];
|
u8 if_addr[ETH_ALEN];
|
||||||
|
|
||||||
if (!first) {
|
if (!first || first == -1) {
|
||||||
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
|
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
|
||||||
/* Allocate the next available BSSID. */
|
/* Allocate the next available BSSID. */
|
||||||
do {
|
do {
|
||||||
|
@ -647,7 +648,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||||
hapd->conf->iface, hapd->own_addr, hapd,
|
hapd->conf->iface, hapd->own_addr, hapd,
|
||||||
&hapd->drv_priv, force_ifname, if_addr,
|
&hapd->drv_priv, force_ifname, if_addr,
|
||||||
hapd->conf->bridge[0] ? hapd->conf->bridge :
|
hapd->conf->bridge[0] ? hapd->conf->bridge :
|
||||||
NULL)) {
|
NULL, first == -1)) {
|
||||||
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
|
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
|
||||||
MACSTR ")", MAC2STR(hapd->own_addr));
|
MACSTR ")", MAC2STR(hapd->own_addr));
|
||||||
return -1;
|
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,
|
os_memcpy(hapd->own_addr, hapd_iface->bss[0]->own_addr,
|
||||||
ETH_ALEN);
|
ETH_ALEN);
|
||||||
|
|
||||||
if (hostapd_setup_bss(hapd, 0)) {
|
if (hostapd_setup_bss(hapd, -1)) {
|
||||||
hapd_iface->conf->num_bss--;
|
hapd_iface->conf->num_bss--;
|
||||||
hapd_iface->num_bss--;
|
hapd_iface->num_bss--;
|
||||||
os_free(hapd);
|
os_free(hapd);
|
||||||
|
|
|
@ -1955,12 +1955,13 @@ struct wpa_driver_ops {
|
||||||
* (this may differ from the requested addr if the driver cannot
|
* (this may differ from the requested addr if the driver cannot
|
||||||
* change interface address)
|
* change interface address)
|
||||||
* @bridge: Bridge interface to use or %NULL if no bridge configured
|
* @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
|
* Returns: 0 on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
int (*if_add)(void *priv, enum wpa_driver_if_type type,
|
int (*if_add)(void *priv, 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, char *force_ifname, u8 *if_addr,
|
void **drv_priv, char *force_ifname, u8 *if_addr,
|
||||||
const char *bridge);
|
const char *bridge, int use_existing);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if_remove - Remove a virtual interface
|
* if_remove - Remove a virtual interface
|
||||||
|
|
|
@ -7064,7 +7064,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
|
||||||
const char *ifname, enum nl80211_iftype iftype,
|
const char *ifname, enum nl80211_iftype iftype,
|
||||||
const u8 *addr, int wds,
|
const u8 *addr, int wds,
|
||||||
int (*handler)(struct nl_msg *, void *),
|
int (*handler)(struct nl_msg *, void *),
|
||||||
void *arg)
|
void *arg, int use_existing)
|
||||||
{
|
{
|
||||||
int ret;
|
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 error occurred and interface exists already */
|
||||||
if (ret == -ENFILE && if_nametoindex(ifname)) {
|
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);
|
wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
|
||||||
|
|
||||||
/* Try to remove the interface that was already there. */
|
/* 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 =
|
drv->monitor_ifidx =
|
||||||
nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
|
nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
|
||||||
0, NULL, NULL);
|
0, NULL, NULL, 0);
|
||||||
|
|
||||||
if (drv->monitor_ifidx == -EOPNOTSUPP) {
|
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 (!if_nametoindex(name)) {
|
||||||
if (nl80211_create_iface(drv, name,
|
if (nl80211_create_iface(drv, name,
|
||||||
NL80211_IFTYPE_AP_VLAN,
|
NL80211_IFTYPE_AP_VLAN,
|
||||||
bss->addr, 1, NULL, NULL) < 0)
|
bss->addr, 1, NULL, NULL, 0) <
|
||||||
|
0)
|
||||||
return -1;
|
return -1;
|
||||||
if (bridge_ifname &&
|
if (bridge_ifname &&
|
||||||
linux_br_add_if(drv->global->ioctl_sock,
|
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,
|
const char *ifname, const u8 *addr,
|
||||||
void *bss_ctx, void **drv_priv,
|
void *bss_ctx, void **drv_priv,
|
||||||
char *force_ifname, u8 *if_addr,
|
char *force_ifname, u8 *if_addr,
|
||||||
const char *bridge)
|
const char *bridge, int use_existing)
|
||||||
{
|
{
|
||||||
enum nl80211_iftype nlmode;
|
enum nl80211_iftype nlmode;
|
||||||
struct i802_bss *bss = priv;
|
struct i802_bss *bss = priv;
|
||||||
struct wpa_driver_nl80211_data *drv = bss->drv;
|
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||||
int ifidx;
|
int ifidx;
|
||||||
|
int added = 1;
|
||||||
|
|
||||||
if (addr)
|
if (addr)
|
||||||
os_memcpy(if_addr, addr, ETH_ALEN);
|
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));
|
os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
|
||||||
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
|
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
|
||||||
0, nl80211_wdev_handler,
|
0, nl80211_wdev_handler,
|
||||||
&p2pdev_info);
|
&p2pdev_info, use_existing);
|
||||||
if (!p2pdev_info.wdev_id_set || ifidx != 0) {
|
if (!p2pdev_info.wdev_id_set || ifidx != 0) {
|
||||||
wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
|
wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
|
||||||
ifname);
|
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);
|
(long long unsigned int) p2pdev_info.wdev_id);
|
||||||
} else {
|
} else {
|
||||||
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
|
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
|
||||||
0, NULL, NULL);
|
0, NULL, NULL, use_existing);
|
||||||
if (ifidx < 0) {
|
if (use_existing && ifidx == -ENFILE) {
|
||||||
|
added = 0;
|
||||||
|
ifidx = if_nametoindex(ifname);
|
||||||
|
} else if (ifidx < 0) {
|
||||||
return -1;
|
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);
|
os_memcpy(if_addr, bss->addr, ETH_ALEN);
|
||||||
else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
|
else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
|
||||||
bss->ifname, if_addr) < 0) {
|
bss->ifname, if_addr) < 0) {
|
||||||
nl80211_remove_iface(drv, ifidx);
|
if (added)
|
||||||
|
nl80211_remove_iface(drv, ifidx);
|
||||||
return -1;
|
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) {
|
if (type == WPA_IF_AP_BSS) {
|
||||||
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
|
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
|
||||||
if (new_bss == NULL) {
|
if (new_bss == NULL) {
|
||||||
nl80211_remove_iface(drv, ifidx);
|
if (added)
|
||||||
|
nl80211_remove_iface(drv, ifidx);
|
||||||
return -1;
|
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 "
|
wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
|
||||||
"interface %s to a bridge %s",
|
"interface %s to a bridge %s",
|
||||||
ifname, bridge);
|
ifname, bridge);
|
||||||
nl80211_remove_iface(drv, ifidx);
|
if (added)
|
||||||
|
nl80211_remove_iface(drv, ifidx);
|
||||||
os_free(new_bss);
|
os_free(new_bss);
|
||||||
return -1;
|
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->next = drv->first_bss->next;
|
||||||
new_bss->freq = drv->first_bss->freq;
|
new_bss->freq = drv->first_bss->freq;
|
||||||
new_bss->ctx = bss_ctx;
|
new_bss->ctx = bss_ctx;
|
||||||
new_bss->added_if = 1;
|
new_bss->added_if = added;
|
||||||
drv->first_bss->next = new_bss;
|
drv->first_bss->next = new_bss;
|
||||||
if (drv_priv)
|
if (drv_priv)
|
||||||
*drv_priv = new_bss;
|
*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;
|
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||||
int ifindex = if_nametoindex(ifname);
|
int ifindex = if_nametoindex(ifname);
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
|
wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
|
||||||
__func__, type, ifname, ifindex);
|
__func__, type, ifname, ifindex, bss->added_if);
|
||||||
if (ifindex > 0 && bss->added_if)
|
if (ifindex > 0 && bss->added_if)
|
||||||
nl80211_remove_iface(drv, ifindex);
|
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) {
|
if (bss != drv->first_bss) {
|
||||||
struct i802_bss *tbss;
|
struct i802_bss *tbss;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
|
||||||
for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
|
for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
|
||||||
if (tbss->next == bss) {
|
if (tbss->next == bss) {
|
||||||
tbss->next = bss->next;
|
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 "
|
wpa_printf(MSG_INFO, "nl80211: %s - could not find "
|
||||||
"BSS %p in the list", __func__, bss);
|
"BSS %p in the list", __func__, bss);
|
||||||
} else {
|
} else {
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
|
||||||
nl80211_teardown_ap(bss);
|
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);
|
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) {
|
if (drv->first_bss->next) {
|
||||||
drv->first_bss = drv->first_bss->next;
|
drv->first_bss = drv->first_bss->next;
|
||||||
drv->ctx = drv->first_bss->ctx;
|
drv->ctx = drv->first_bss->ctx;
|
||||||
|
|
|
@ -1059,7 +1059,7 @@ static int test_driver_if_add(void *priv, enum wpa_driver_if_type type,
|
||||||
const char *ifname, const u8 *addr,
|
const char *ifname, const u8 *addr,
|
||||||
void *bss_ctx, void **drv_priv,
|
void *bss_ctx, void **drv_priv,
|
||||||
char *force_ifname, u8 *if_addr,
|
char *force_ifname, u8 *if_addr,
|
||||||
const char *bridge)
|
const char *bridge, int use_existing)
|
||||||
{
|
{
|
||||||
struct test_driver_bss *dbss = priv;
|
struct test_driver_bss *dbss = priv;
|
||||||
struct wpa_driver_test_data *drv = dbss->drv;
|
struct wpa_driver_test_data *drv = dbss->drv;
|
||||||
|
|
|
@ -380,7 +380,7 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
|
||||||
if (wpa_s->driver->if_add)
|
if (wpa_s->driver->if_add)
|
||||||
return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
|
return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
|
||||||
addr, bss_ctx, NULL, force_ifname,
|
addr, bss_ctx, NULL, force_ifname,
|
||||||
if_addr, bridge);
|
if_addr, bridge, 0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue