diff --git a/feeds/wifi-ax/hostapd/files/hostapd.uc b/feeds/wifi-ax/hostapd/files/hostapd.uc index 9b356dcc3..ebf732bea 100644 --- a/feeds/wifi-ax/hostapd/files/hostapd.uc +++ b/feeds/wifi-ax/hostapd/files/hostapd.uc @@ -215,6 +215,7 @@ function bss_remove_file_fields(config) for (let key in config.hash) new_cfg.hash[key] = config.hash[key]; delete new_cfg.hash.wpa_psk_file; + delete new_cfg.hash.vlan_file; return new_cfg; } @@ -475,11 +476,12 @@ function iface_reload_config(phydev, config, old_config) bss_remove_file_fields(bss_list_cfg[i]))) { hostapd.printf(`Update config data files for bss ${ifname}`); if (bss.set_config(config_inline, i, true) < 0) { - hostapd.printf(`Failed to update config data files for bss ${ifname}`); + hostapd.printf(`Could not update config data files for bss ${ifname}`); return false; + } else { + bss.ctrl("RELOAD_WPA_PSK"); + continue; } - bss.ctrl("RELOAD_WPA_PSK"); - continue; } bss_reload_psk(bss, config.bss[i], bss_list_cfg[i]); @@ -487,8 +489,6 @@ function iface_reload_config(phydev, config, old_config) continue; hostapd.printf(`Reload config for bss '${config.bss[0].ifname}' on phy '${phy}'`); - hostapd.printf(`old: ${bss_remove_file_fields(bss_list_cfg[i])}`); - hostapd.printf(`new: ${bss_remove_file_fields(config.bss[i])}`); if (bss.set_config(config_inline, i) < 0) { hostapd.printf(`Failed to set config for bss ${ifname}`); return false; @@ -688,7 +688,6 @@ let main_obj = { freq_info.csa_count = req.args.csa_count ?? 10; ret = iface.switch_channel(freq_info); } else { - iface.stop(); ret = iface.start(freq_info); } if (!ret) diff --git a/feeds/wifi-ax/hostapd/src/src/ap/ucode.c b/feeds/wifi-ax/hostapd/src/src/ap/ucode.c index 6ce8a3395..9ffdbd96a 100644 --- a/feeds/wifi-ax/hostapd/src/src/ap/ucode.c +++ b/feeds/wifi-ax/hostapd/src/src/ap/ucode.c @@ -111,6 +111,94 @@ uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs) return NULL; } +static struct hostapd_vlan * +bss_conf_find_vlan(struct hostapd_bss_config *bss, int id) +{ + struct hostapd_vlan *vlan; + + for (vlan = bss->vlan; vlan; vlan = vlan->next) + if (vlan->vlan_id == id) + return vlan; + + return NULL; +} + +static int +bss_conf_rename_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan, + const char *ifname) +{ + if (!strcmp(ifname, vlan->ifname)) + return 0; + + hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, vlan->ifname, ifname); + os_strlcpy(vlan->ifname, ifname, sizeof(vlan->ifname)); + + return 0; +} + +static int +bss_reload_vlans(struct hostapd_data *hapd, struct hostapd_bss_config *bss) +{ + struct hostapd_bss_config *old_bss = hapd->conf; + struct hostapd_vlan *vlan, *vlan_new, *wildcard; + char ifname[IFNAMSIZ + 1], vlan_ifname[IFNAMSIZ + 1], *pos; + int ret; + + vlan = bss_conf_find_vlan(old_bss, VLAN_ID_WILDCARD); + wildcard = bss_conf_find_vlan(bss, VLAN_ID_WILDCARD); + if (!!vlan != !!wildcard) + return -1; + + if (vlan && wildcard && strcmp(vlan->ifname, wildcard->ifname) != 0) + strcpy(vlan->ifname, wildcard->ifname); + else + wildcard = NULL; + + for (vlan = bss->vlan; vlan; vlan = vlan->next) { + if (vlan->vlan_id == VLAN_ID_WILDCARD || + vlan->dynamic_vlan > 0) + continue; + + if (!bss_conf_find_vlan(old_bss, vlan->vlan_id)) + return -1; + } + + for (vlan = old_bss->vlan; vlan; vlan = vlan->next) { + if (vlan->vlan_id == VLAN_ID_WILDCARD) + continue; + + if (vlan->dynamic_vlan == 0) { + vlan_new = bss_conf_find_vlan(bss, vlan->vlan_id); + if (!vlan_new) + return -1; + + if (bss_conf_rename_vlan(hapd, vlan, vlan_new->ifname)) + return -1; + + continue; + } + + if (!wildcard) + continue; + + os_strlcpy(ifname, wildcard->ifname, sizeof(ifname)); + pos = os_strchr(ifname, '#'); + if (!pos) + return -1; + + *pos++ = '\0'; + ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s%d%s", + ifname, vlan->vlan_id, pos); + if (os_snprintf_error(sizeof(vlan_ifname), ret)) + return -1; + + if (bss_conf_rename_vlan(hapd, vlan, vlan_ifname)) + return -1; + } + + return 0; +} + static uc_value_t * uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) { @@ -150,6 +238,7 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) } while (0) swap_field(ssid.wpa_psk_file); + ret = bss_reload_vlans(hapd, bss); goto done; } @@ -382,13 +471,23 @@ uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs) struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); int i; + switch (iface->state) { + case HAPD_IFACE_ENABLED: + case HAPD_IFACE_DISABLED: + break; #ifdef CONFIG_ACS - if (iface->state == HAPD_IFACE_ACS) { + case HAPD_IFACE_ACS: acs_cleanup(iface); iface->scan_cb = NULL; - hostapd_disable_iface(iface); - } + /* fallthrough */ #endif + default: + hostapd_disable_iface(iface); + break; + } + + if (iface->state != HAPD_IFACE_ENABLED) + hostapd_disable_iface(iface); for (i = 0; i < iface->num_bss; i++) { struct hostapd_data *hapd = iface->bss[i]; @@ -396,6 +495,7 @@ uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs) hostapd_drv_stop_ap(hapd); hapd->beacon_set_done = 0; } + return NULL; } @@ -405,28 +505,37 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs) struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); uc_value_t *info = uc_fn_arg(0); struct hostapd_config *conf; + bool changed = false; uint64_t intval; int i; if (!iface) return NULL; - iface->freq = 0; - if (!info) + if (!info) { + iface->freq = 0; goto out; + } if (ucv_type(info) != UC_OBJECT) return NULL; +#define UPDATE_VAL(field, name) \ + if ((intval = ucv_int64_get(ucv_object_get(info, name, NULL))) && \ + !errno && intval != conf->field) do { \ + conf->field = intval; \ + changed = true; \ + } while(0) + conf = iface->conf; - if ((intval = ucv_int64_get(ucv_object_get(info, "op_class", NULL))) && !errno) - conf->op_class = intval; - if ((intval = ucv_int64_get(ucv_object_get(info, "hw_mode", NULL))) && !errno) - conf->hw_mode = intval; - if ((intval = ucv_int64_get(ucv_object_get(info, "channel", NULL))) && !errno) - conf->channel = intval; - if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno) - conf->secondary_channel = intval; + UPDATE_VAL(op_class, "op_class"); + UPDATE_VAL(hw_mode, "hw_mode"); + UPDATE_VAL(channel, "channel"); + UPDATE_VAL(secondary_channel, "sec_channel"); + if (!changed && + (iface->bss[0]->beacon_set_done || + iface->state == HAPD_IFACE_DFS)) + return ucv_boolean_new(true); intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL)); if (!errno) @@ -443,6 +552,8 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs) intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL)); if (!errno) iface->freq = intval; + else + iface->freq = 0; conf->acs = 0; out: