hostapd: fix more AP+STA issues
authorFelix Fietkau <nbd@nbd.name>
Thu, 14 Sep 2023 17:08:34 +0000 (19:08 +0200)
committerFelix Fietkau <nbd@nbd.name>
Thu, 14 Sep 2023 17:13:36 +0000 (19:13 +0200)
When STA is disconnected, ensure that the interface is in a cleanly stopped
state:
 - if in regular enable/disable state, stop beacons if necessary
 - in any other state, disable the interface

When the STA is up, ignore repeated start commands for the same channel, in
order to avoid unnecessary AP restarts

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 9b356dcc309ebc7d9876db81b611ae5ab545ea2e..6b6e41b6f79dbbb5c29432ce8f8a232b0106bd42 100644 (file)
@@ -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)
index ba081d87c2dd19c7ec054bc6da94ccd6b7c388cd..7bc797acfc678a83dcd9b6cdcb4305191c17b761 100644 (file)
@@ -382,13 +382,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;
+               /* fallthrough */
+#endif
+       default:
                hostapd_disable_iface(iface);
+               break;
        }
-#endif
+
+       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];
@@ -406,28 +416,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)
@@ -444,6 +463,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: