policy: allow disabling load balancing
[project/usteer.git] / policy.c
index 329852ece6fd2c7050e16d7ecc513dc2031886b2..6738c99f2950f395314cefaa0a21ab918ac9d3c1 100644 (file)
--- a/policy.c
+++ b/policy.c
@@ -29,6 +29,9 @@ below_assoc_threshold(struct usteer_node *node_cur, struct usteer_node *node_new
        bool ref_5g = node_cur->freq > 4000;
        bool node_5g = node_new->freq > 4000;
 
+       if (!config.load_balancing_threshold)
+               return false;
+
        if (ref_5g && !node_5g)
                n_assoc_new += config.band_steering_threshold;
        else if (!ref_5g && node_5g)
@@ -114,7 +117,7 @@ is_better_candidate(struct sta_info *si_cur, struct sta_info *si_new)
 static struct sta_info *
 find_better_candidate(struct sta_info *si_ref, struct uevent *ev, uint32_t required_criteria, uint64_t max_age)
 {
-       struct sta_info *si;
+       struct sta_info *si, *candidate = NULL;
        struct sta *sta = si_ref->sta;
        uint32_t reasons;
 
@@ -143,10 +146,11 @@ find_better_candidate(struct sta_info *si_ref, struct uevent *ev, uint32_t requi
                        ev->select_reasons = reasons;
                }
 
-               return si;
+               if (!candidate || si->signal > candidate->signal)
+                       candidate = si;
        }
 
-       return NULL;
+       return candidate;
 }
 
 int
@@ -297,31 +301,29 @@ usteer_roam_sm_start_scan(struct sta_info *si, struct uevent *ev)
        usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, ev);
 }
 
-static bool
+static struct sta_info *
 usteer_roam_sm_found_better_node(struct sta_info *si, struct uevent *ev, enum roam_trigger_state next_state)
 {
        uint64_t max_age = 2 * config.roam_scan_interval;
+       struct sta_info *candidate;
 
        if (max_age > current_time - si->roam_scan_start)
                max_age = current_time - si->roam_scan_start;
 
-       if (find_better_candidate(si, ev, (1 << UEV_SELECT_REASON_SIGNAL), max_age)) {
+       candidate = find_better_candidate(si, ev, (1 << UEV_SELECT_REASON_SIGNAL), max_age);
+       if (candidate)
                usteer_roam_set_state(si, next_state, ev);
-               return true;
-       }
 
-       return false;
+       return candidate;
 }
 
 static bool
-usteer_roam_trigger_sm(struct sta_info *si)
+usteer_roam_trigger_sm(struct usteer_local_node *ln, struct sta_info *si)
 {
+       struct sta_info *candidate;
        struct uevent ev = {
                .si_cur = si,
        };
-       uint64_t min_signal;
-
-       min_signal = usteer_snr_to_signal(si->node, config.roam_trigger_snr);
 
        switch (si->roam_state) {
        case ROAM_TRIGGER_SCAN:
@@ -341,7 +343,7 @@ usteer_roam_trigger_sm(struct sta_info *si)
                if (config.roam_scan_tries && si->roam_tries >= config.roam_scan_tries) {
                        if (!config.roam_scan_timeout) {
                                /* Prepare to kick client */
-                               usteer_roam_set_state(si, ROAM_TRIGGER_WAIT_KICK, &ev);
+                               usteer_roam_set_state(si, ROAM_TRIGGER_SCAN_DONE, &ev);
                        } else {
                                /* Kick in scan timeout */
                                si->roam_scan_timeout_start = current_time;
@@ -360,30 +362,17 @@ usteer_roam_trigger_sm(struct sta_info *si)
                break;
 
        case ROAM_TRIGGER_SCAN_DONE:
-               if (usteer_roam_sm_found_better_node(si, &ev, ROAM_TRIGGER_WAIT_KICK))
-                       break;
-
-               /* Kick back to SCAN state if candidate expired */
-               usteer_roam_sm_start_scan(si, &ev);
-               break;
-
-       case ROAM_TRIGGER_WAIT_KICK:
-               if (si->signal > min_signal)
-                       break;
-
-               usteer_roam_set_state(si, ROAM_TRIGGER_NOTIFY_KICK, &ev);
-               usteer_ubus_notify_client_disassoc(si);
-               break;
-       case ROAM_TRIGGER_NOTIFY_KICK:
-               if (current_time - si->roam_event < config.roam_kick_delay * 100)
+               candidate = usteer_roam_sm_found_better_node(si, &ev, ROAM_TRIGGER_SCAN_DONE);
+               /* Kick back in case no better node is found */
+               if (!candidate) {
+                       usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, &ev);
                        break;
+               }
 
-               usteer_roam_set_state(si, ROAM_TRIGGER_KICK, &ev);
-               break;
-       case ROAM_TRIGGER_KICK:
-               usteer_ubus_kick_client(si);
+               usteer_ubus_bss_transition_request(si, 1, false, false, 100, candidate->node);
+               si->kick_time = current_time + config.roam_kick_delay;
                usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, &ev);
-               return true;
+               break;
        }
 
        return false;
@@ -407,6 +396,8 @@ usteer_local_node_roam_check(struct usteer_local_node *ln, struct uevent *ev)
 
        list_for_each_entry(si, &ln->node.sta_info, node_list) {
                if (si->connected != STA_CONNECTED || si->signal >= min_signal ||
+                       si->kick_time ||
+                       (si->bss_transition_response.status_code && current_time - si->bss_transition_response.timestamp < config.steer_reject_timeout) ||
                    current_time - si->roam_kick < config.roam_trigger_interval) {
                        usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, ev);
                        continue;
@@ -416,7 +407,7 @@ usteer_local_node_roam_check(struct usteer_local_node *ln, struct uevent *ev)
                 * If the state machine kicked a client, other clients should wait
                 * until the next turn
                 */
-               if (usteer_roam_trigger_sm(si))
+               if (usteer_roam_trigger_sm(ln, si))
                        return;
        }
 }
@@ -463,8 +454,8 @@ usteer_local_node_snr_kick(struct usteer_local_node *ln)
        }
 }
 
-void
-usteer_local_node_kick(struct usteer_local_node *ln)
+static void
+usteer_local_node_load_kick(struct usteer_local_node *ln)
 {
        struct usteer_node *node = &ln->node;
        struct sta_info *kick1 = NULL, *kick2 = NULL;
@@ -475,9 +466,6 @@ usteer_local_node_kick(struct usteer_local_node *ln)
        };
        unsigned int min_count = DIV_ROUND_UP(config.load_kick_delay, config.local_sta_update);
 
-       usteer_local_node_roam_check(ln, &ev);
-       usteer_local_node_snr_kick(ln);
-
        if (!config.load_kick_enabled || !config.load_kick_threshold ||
            !config.load_kick_delay)
                return;
@@ -550,3 +538,30 @@ usteer_local_node_kick(struct usteer_local_node *ln)
 out:
        usteer_event(&ev);
 }
+
+static void
+usteer_local_node_perform_kick(struct usteer_local_node *ln)
+{
+       struct sta_info *si;
+
+       list_for_each_entry(si, &ln->node.sta_info, node_list) {
+               if (!si->kick_time || si->kick_time > current_time)
+                       continue;
+
+               usteer_ubus_kick_client(si);
+       }
+}
+
+void
+usteer_local_node_kick(struct usteer_local_node *ln)
+{
+       struct uevent ev = {
+               .node_local = &ln->node,
+       };
+
+       usteer_local_node_perform_kick(ln);
+
+       usteer_local_node_snr_kick(ln);
+       usteer_local_node_load_kick(ln);
+       usteer_local_node_roam_check(ln, &ev);
+}