hostapd: add internal API for renaming AP interfaces
Will be used for improving reload support Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
ddd012d5ff
commit
8566ddc8b3
|
@ -270,7 +270,33 @@
|
|||
|
||||
--- a/src/drivers/driver.h
|
||||
+++ b/src/drivers/driver.h
|
||||
@@ -6426,6 +6426,7 @@ union wpa_event_data {
|
||||
@@ -3787,6 +3787,25 @@ struct wpa_driver_ops {
|
||||
const char *ifname);
|
||||
|
||||
/**
|
||||
+ * if_rename - Rename a virtual interface
|
||||
+ * @priv: Private driver interface data
|
||||
+ * @type: Interface type
|
||||
+ * @ifname: Interface name of the virtual interface to be renamed
|
||||
+ * (NULL when renaming the AP BSS interface)
|
||||
+ * @new_name: New interface name of the virtual interface
|
||||
+ * Returns: 0 on success, -1 on failure
|
||||
+ */
|
||||
+ int (*if_rename)(void *priv, enum wpa_driver_if_type type,
|
||||
+ const char *ifname, const char *new_name);
|
||||
+
|
||||
+ /**
|
||||
+ * set_first_bss - Make a virtual interface the first (primary) bss
|
||||
+ * @priv: Private driver interface data
|
||||
+ * Returns: 0 on success, -1 on failure
|
||||
+ */
|
||||
+ int (*set_first_bss)(void *priv);
|
||||
+
|
||||
+ /**
|
||||
* set_sta_vlan - Bind a station into a specific interface (AP only)
|
||||
* @priv: Private driver interface data
|
||||
* @ifname: Interface (main or virtual BSS or VLAN)
|
||||
@@ -6426,6 +6445,7 @@ union wpa_event_data {
|
||||
|
||||
/**
|
||||
* struct ch_switch
|
||||
|
@ -278,7 +304,7 @@
|
|||
* @freq: Frequency of new channel in MHz
|
||||
* @ht_enabled: Whether this is an HT channel
|
||||
* @ch_offset: Secondary channel offset
|
||||
@@ -6436,6 +6437,7 @@ union wpa_event_data {
|
||||
@@ -6436,6 +6456,7 @@ union wpa_event_data {
|
||||
* @punct_bitmap: Puncturing bitmap
|
||||
*/
|
||||
struct ch_switch {
|
||||
|
@ -331,3 +357,187 @@
|
|||
switch (event) {
|
||||
case EVENT_AUTH:
|
||||
#ifdef CONFIG_FST
|
||||
--- a/src/ap/ap_drv_ops.h
|
||||
+++ b/src/ap/ap_drv_ops.h
|
||||
@@ -393,6 +393,23 @@ static inline int hostapd_drv_stop_ap(st
|
||||
return hapd->driver->stop_ap(hapd->drv_priv);
|
||||
}
|
||||
|
||||
+static inline int hostapd_drv_if_rename(struct hostapd_data *hapd,
|
||||
+ enum wpa_driver_if_type type,
|
||||
+ const char *ifname,
|
||||
+ const char *new_name)
|
||||
+{
|
||||
+ if (!hapd->driver || !hapd->driver->if_rename || !hapd->drv_priv)
|
||||
+ return -1;
|
||||
+ return hapd->driver->if_rename(hapd->drv_priv, type, ifname, new_name);
|
||||
+}
|
||||
+
|
||||
+static inline int hostapd_drv_set_first_bss(struct hostapd_data *hapd)
|
||||
+{
|
||||
+ if (!hapd->driver || !hapd->driver->set_first_bss || !hapd->drv_priv)
|
||||
+ return 0;
|
||||
+ return hapd->driver->set_first_bss(hapd->drv_priv);
|
||||
+}
|
||||
+
|
||||
static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
|
||||
struct wpa_channel_info *ci)
|
||||
{
|
||||
--- a/src/drivers/driver_nl80211.c
|
||||
+++ b/src/drivers/driver_nl80211.c
|
||||
@@ -1333,7 +1333,7 @@ static void wpa_driver_nl80211_event_rtm
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
|
||||
namebuf, ifname);
|
||||
- if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
|
||||
+ if (drv->first_bss->ifindex != ifi->ifi_index) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Not the main interface (%s) - do not indicate interface down",
|
||||
drv->first_bss->ifname);
|
||||
@@ -1369,7 +1369,7 @@ static void wpa_driver_nl80211_event_rtm
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
|
||||
namebuf, ifname);
|
||||
- if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
|
||||
+ if (drv->first_bss->ifindex != ifi->ifi_index) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Not the main interface (%s) - do not indicate interface up",
|
||||
drv->first_bss->ifname);
|
||||
@@ -8432,6 +8432,7 @@ static void *i802_init(struct hostapd_da
|
||||
char master_ifname[IFNAMSIZ];
|
||||
int ifindex, br_ifindex = 0;
|
||||
int br_added = 0;
|
||||
+ int err;
|
||||
|
||||
bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
|
||||
params->global_priv, 1,
|
||||
@@ -8491,21 +8492,17 @@ static void *i802_init(struct hostapd_da
|
||||
(params->num_bridge == 0 || !params->bridge[0]))
|
||||
add_ifidx(drv, br_ifindex, drv->ifindex);
|
||||
|
||||
- if (bss->added_if_into_bridge || bss->already_in_bridge) {
|
||||
- int err;
|
||||
-
|
||||
- drv->rtnl_sk = nl_socket_alloc();
|
||||
- if (drv->rtnl_sk == NULL) {
|
||||
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
|
||||
- goto failed;
|
||||
- }
|
||||
+ drv->rtnl_sk = nl_socket_alloc();
|
||||
+ if (drv->rtnl_sk == NULL) {
|
||||
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
|
||||
+ goto failed;
|
||||
+ }
|
||||
|
||||
- err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
|
||||
- if (err) {
|
||||
- wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
|
||||
- nl_geterror(err));
|
||||
- goto failed;
|
||||
- }
|
||||
+ err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
|
||||
+ if (err) {
|
||||
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
|
||||
+ nl_geterror(err));
|
||||
+ goto failed;
|
||||
}
|
||||
|
||||
if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
|
||||
@@ -8874,6 +8871,50 @@ static int wpa_driver_nl80211_if_remove(
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int wpa_driver_nl80211_if_rename(struct i802_bss *bss,
|
||||
+ enum wpa_driver_if_type type,
|
||||
+ const char *ifname, const char *new_name)
|
||||
+{
|
||||
+ struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||
+ struct ifinfomsg ifi = {
|
||||
+ .ifi_family = AF_UNSPEC,
|
||||
+ .ifi_index = bss->ifindex,
|
||||
+ };
|
||||
+ struct nl_msg *msg;
|
||||
+ int res = -ENOMEM;
|
||||
+
|
||||
+ if (ifname)
|
||||
+ ifi.ifi_index = if_nametoindex(ifname);
|
||||
+
|
||||
+ msg = nlmsg_alloc_simple(RTM_SETLINK, 0);
|
||||
+ if (!msg)
|
||||
+ return res;
|
||||
+
|
||||
+ if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (nla_put_string(msg, IFLA_IFNAME, new_name))
|
||||
+ goto out;
|
||||
+
|
||||
+ res = nl_send_auto_complete(drv->rtnl_sk, msg);
|
||||
+ if (res < 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ res = nl_wait_for_ack(drv->rtnl_sk);
|
||||
+ if (res) {
|
||||
+ wpa_printf(MSG_INFO,
|
||||
+ "nl80211: Renaming device %s to %s failed: %s",
|
||||
+ ifname ? ifname : bss->ifname, new_name, nl_geterror(res));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (type == WPA_IF_AP_BSS && !ifname)
|
||||
+ os_strlcpy(bss->ifname, new_name, sizeof(bss->ifname));
|
||||
+
|
||||
+out:
|
||||
+ nlmsg_free(msg);
|
||||
+ return res;
|
||||
+}
|
||||
|
||||
static int cookie_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
@@ -10472,6 +10513,37 @@ static int driver_nl80211_if_remove(void
|
||||
}
|
||||
|
||||
|
||||
+static int driver_nl80211_if_rename(void *priv, enum wpa_driver_if_type type,
|
||||
+ const char *ifname, const char *new_name)
|
||||
+{
|
||||
+ struct i802_bss *bss = priv;
|
||||
+ return wpa_driver_nl80211_if_rename(bss, type, ifname, new_name);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int driver_nl80211_set_first_bss(void *priv)
|
||||
+{
|
||||
+ struct i802_bss *bss = priv, *tbss;
|
||||
+ struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||
+
|
||||
+ if (drv->first_bss == bss)
|
||||
+ return 0;
|
||||
+
|
||||
+ for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
|
||||
+ if (tbss->next != bss)
|
||||
+ continue;
|
||||
+
|
||||
+ tbss->next = bss->next;
|
||||
+ bss->next = drv->first_bss;
|
||||
+ drv->first_bss = bss;
|
||||
+ drv->ctx = bss->ctx;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
|
||||
size_t data_len, int noack,
|
||||
unsigned int freq,
|
||||
@@ -13656,6 +13728,8 @@ const struct wpa_driver_ops wpa_driver_n
|
||||
.set_acl = wpa_driver_nl80211_set_acl,
|
||||
.if_add = wpa_driver_nl80211_if_add,
|
||||
.if_remove = driver_nl80211_if_remove,
|
||||
+ .if_rename = driver_nl80211_if_rename,
|
||||
+ .set_first_bss = driver_nl80211_set_first_bss,
|
||||
.send_mlme = driver_nl80211_send_mlme,
|
||||
.get_hw_feature_data = nl80211_get_hw_feature_data,
|
||||
.sta_add = wpa_driver_nl80211_sta_add,
|
||||
|
|
|
@ -120,6 +120,7 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
|
|||
struct hostapd_config *conf;
|
||||
uc_value_t *file = uc_fn_arg(0);
|
||||
uc_value_t *index = uc_fn_arg(1);
|
||||
uc_value_t *files_only = uc_fn_arg(2);
|
||||
unsigned int i, idx = 0;
|
||||
int ret = -1;
|
||||
|
||||
|
@ -131,9 +132,27 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
|
|||
|
||||
iface = hapd->iface;
|
||||
conf = interfaces->config_read_cb(ucv_string_get(file));
|
||||
if (!conf || idx > conf->num_bss || !conf->bss[idx])
|
||||
if (!conf)
|
||||
goto out;
|
||||
|
||||
if (idx > conf->num_bss || !conf->bss[idx])
|
||||
goto free;
|
||||
|
||||
if (ucv_boolean_get(files_only)) {
|
||||
struct hostapd_bss_config *bss = conf->bss[idx];
|
||||
struct hostapd_bss_config *old_bss = hapd->conf;
|
||||
|
||||
#define swap_field(name) \
|
||||
do { \
|
||||
void *ptr = old_bss->name; \
|
||||
old_bss->name = bss->name; \
|
||||
bss->name = ptr; \
|
||||
} while (0)
|
||||
|
||||
swap_field(ssid.wpa_psk_file);
|
||||
goto done;
|
||||
}
|
||||
|
||||
hostapd_bss_deinit_no_free(hapd);
|
||||
hostapd_drv_stop_ap(hapd);
|
||||
hostapd_free_hapd_data(hapd);
|
||||
|
@ -144,13 +163,14 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
|
|||
iface->conf->bss[i] = conf->bss[idx];
|
||||
hapd->conf = conf->bss[idx];
|
||||
conf->bss[idx] = old_bss;
|
||||
hostapd_config_free(conf);
|
||||
|
||||
hostapd_setup_bss(hapd, hapd == iface->bss[0], !iface->conf->mbssid);
|
||||
hostapd_setup_bss(hapd, hapd == iface->bss[0], true);
|
||||
hostapd_ucode_update_interfaces();
|
||||
|
||||
done:
|
||||
ret = 0;
|
||||
|
||||
free:
|
||||
hostapd_config_free(conf);
|
||||
out:
|
||||
return ucv_int64_new(ret);
|
||||
}
|
||||
|
@ -181,10 +201,15 @@ uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
|
|||
struct hostapd_iface *iface;
|
||||
int i, idx;
|
||||
|
||||
if (!hapd || hapd == hapd->iface->bss[0])
|
||||
if (!hapd)
|
||||
return NULL;
|
||||
|
||||
iface = hapd->iface;
|
||||
if (iface->num_bss == 1) {
|
||||
wpa_printf(MSG_ERROR, "trying to delete last bss of an iface: %s\n", hapd->conf->iface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < iface->num_bss; idx++)
|
||||
if (iface->bss[idx] == hapd)
|
||||
break;
|
||||
|
@ -194,8 +219,13 @@ uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
|
|||
|
||||
for (i = idx + 1; i < iface->num_bss; i++)
|
||||
iface->bss[i - 1] = iface->bss[i];
|
||||
|
||||
iface->num_bss--;
|
||||
|
||||
iface->bss[0]->interface_added = 0;
|
||||
hostapd_drv_set_first_bss(iface->bss[0]);
|
||||
hapd->interface_added = 1;
|
||||
|
||||
hostapd_drv_stop_ap(hapd);
|
||||
hostapd_bss_deinit(hapd);
|
||||
hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
|
||||
|
@ -269,6 +299,58 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_hostapd_iface_set_bss_order(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
|
||||
uc_value_t *bss_list = uc_fn_arg(0);
|
||||
struct hostapd_data **new_bss;
|
||||
struct hostapd_bss_config **new_conf;
|
||||
|
||||
if (!iface)
|
||||
return NULL;
|
||||
|
||||
if (ucv_type(bss_list) != UC_ARRAY ||
|
||||
ucv_array_length(bss_list) != iface->num_bss)
|
||||
return NULL;
|
||||
|
||||
new_bss = calloc(iface->num_bss, sizeof(*new_bss));
|
||||
new_conf = calloc(iface->num_bss, sizeof(*new_conf));
|
||||
for (size_t i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss;
|
||||
|
||||
bss = ucv_resource_data(ucv_array_get(bss_list, i), "hostapd.bss");
|
||||
if (bss->iface != iface)
|
||||
goto free;
|
||||
|
||||
for (size_t k = 0; k < i; k++)
|
||||
if (new_bss[k] == bss)
|
||||
goto free;
|
||||
|
||||
new_bss[i] = bss;
|
||||
new_conf[i] = bss->conf;
|
||||
}
|
||||
|
||||
new_bss[0]->interface_added = 0;
|
||||
for (size_t i = 1; i < iface->num_bss; i++)
|
||||
new_bss[i]->interface_added = 1;
|
||||
|
||||
free(iface->bss);
|
||||
iface->bss = new_bss;
|
||||
|
||||
free(iface->conf->bss);
|
||||
iface->conf->bss = new_conf;
|
||||
iface->conf->num_bss = iface->num_bss;
|
||||
hostapd_drv_set_first_bss(iface->bss[0]);
|
||||
|
||||
return ucv_boolean_new(true);
|
||||
|
||||
free:
|
||||
free(new_bss);
|
||||
free(new_conf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
|
@ -456,6 +538,55 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs)
|
|||
return ucv_boolean_new(!ret);
|
||||
}
|
||||
|
||||
static uc_value_t *
|
||||
uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs)
|
||||
{
|
||||
struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
|
||||
uc_value_t *ifname_arg = uc_fn_arg(0);
|
||||
char prev_ifname[IFNAMSIZ + 1];
|
||||
struct sta_info *sta;
|
||||
const char *ifname;
|
||||
int ret;
|
||||
|
||||
if (!hapd || ucv_type(ifname_arg) != UC_STRING)
|
||||
return NULL;
|
||||
|
||||
os_strlcpy(prev_ifname, hapd->conf->iface, sizeof(prev_ifname));
|
||||
ifname = ucv_string_get(ifname_arg);
|
||||
|
||||
hostapd_ubus_free_bss(hapd);
|
||||
if (interfaces->ctrl_iface_deinit)
|
||||
interfaces->ctrl_iface_deinit(hapd);
|
||||
|
||||
ret = hostapd_drv_if_rename(hapd, WPA_IF_AP_BSS, NULL, ifname);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
char cur_name[IFNAMSIZ + 1], new_name[IFNAMSIZ + 1];
|
||||
|
||||
if (!(sta->flags & WLAN_STA_WDS) || sta->pending_wds_enable)
|
||||
continue;
|
||||
|
||||
snprintf(cur_name, sizeof(cur_name), "%s.sta%d", prev_ifname, sta->aid);
|
||||
snprintf(new_name, sizeof(new_name), "%s.sta%d", ifname, sta->aid);
|
||||
hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, cur_name, new_name);
|
||||
}
|
||||
|
||||
if (!strncmp(hapd->conf->ssid.vlan, hapd->conf->iface, sizeof(hapd->conf->ssid.vlan)))
|
||||
os_strlcpy(hapd->conf->ssid.vlan, ifname, sizeof(hapd->conf->ssid.vlan));
|
||||
os_strlcpy(hapd->conf->iface, ifname, sizeof(hapd->conf->iface));
|
||||
hostapd_ubus_add_bss(hapd);
|
||||
|
||||
hostapd_ucode_update_interfaces();
|
||||
out:
|
||||
if (interfaces->ctrl_iface_init)
|
||||
interfaces->ctrl_iface_init(hapd);
|
||||
|
||||
return ret ? NULL : ucv_boolean_new(true);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ucode_init(struct hapd_interfaces *ifaces)
|
||||
{
|
||||
static const uc_function_list_t global_fns[] = {
|
||||
|
@ -469,9 +600,11 @@ int hostapd_ucode_init(struct hapd_interfaces *ifaces)
|
|||
static const uc_function_list_t bss_fns[] = {
|
||||
{ "ctrl", uc_hostapd_bss_ctrl },
|
||||
{ "set_config", uc_hostapd_bss_set_config },
|
||||
{ "rename", uc_hostapd_bss_rename },
|
||||
{ "delete", uc_hostapd_bss_delete },
|
||||
};
|
||||
static const uc_function_list_t iface_fns[] = {
|
||||
{ "set_bss_order", uc_hostapd_iface_set_bss_order },
|
||||
{ "add_bss", uc_hostapd_iface_add_bss },
|
||||
{ "stop", uc_hostapd_iface_stop },
|
||||
{ "start", uc_hostapd_iface_start },
|
||||
|
|
Loading…
Reference in New Issue