hostapd: support dynamic reload of vlan files when renaming interfaces
authorFelix Fietkau <nbd@nbd.name>
Fri, 15 Sep 2023 12:25:23 +0000 (14:25 +0200)
committerFelix Fietkau <nbd@nbd.name>
Fri, 15 Sep 2023 12:25:27 +0000 (14:25 +0200)
Avoids unnecessary AP restart on ifname changes when wifi-vlan sections
are present.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
package/network/services/hostapd/files/hostapd.uc
package/network/services/hostapd/src/src/ap/ucode.c

index 6b6e41b6f79dbbb5c29432ce8f8a232b0106bd42..ebf732bea51e2c27a03aeb71cd4a09aa5510648e 100644 (file)
@@ -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;
index 7bc797acfc678a83dcd9b6cdcb4305191c17b761..e79f2420c07a0af702b3317aa160e28bce71c45f 100644 (file)
@@ -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;
        }