remote: close file on usteer_init_local_id fread fail
[project/usteer.git] / policy.c
index 6399a7820f426efd8d0e7e00f13bb0e9c85f2ad2..8c5d244b35d8735f0918dfd8514d0abea9c5cd11 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
@@ -172,6 +176,9 @@ usteer_check_request(struct sta_info *si, enum usteer_event_type type)
        int min_signal;
        bool ret = true;
 
+       if (type == EVENT_TYPE_PROBE && !config.probe_steering)
+               goto out;
+
        if (type == EVENT_TYPE_AUTH)
                goto out;
 
@@ -219,21 +226,18 @@ usteer_check_request(struct sta_info *si, enum usteer_event_type type)
 out:
        switch (type) {
        case EVENT_TYPE_PROBE:
-               ev.type = UEV_PROBE_REQ_ACCEPT;
+               ev.type = ret ? UEV_PROBE_REQ_ACCEPT : UEV_PROBE_REQ_DENY;
                break;
        case EVENT_TYPE_ASSOC:
-               ev.type = UEV_ASSOC_REQ_ACCEPT;
+               ev.type = ret ? UEV_ASSOC_REQ_ACCEPT : UEV_ASSOC_REQ_DENY;
                break;
        case EVENT_TYPE_AUTH:
-               ev.type = UEV_AUTH_REQ_ACCEPT;
+               ev.type = ret ? UEV_AUTH_REQ_ACCEPT : UEV_AUTH_REQ_DENY;
                break;
        default:
                break;
        }
 
-       if (!ret)
-               ev.type++;
-
        if (!ret && si->stats[type].blocked_cur >= config.max_retry_band) {
                ev.reason = UEV_REASON_RETRY_EXCEEDED;
                ev.threshold.cur = si->stats[type].blocked_cur;
@@ -260,14 +264,15 @@ static void
 usteer_roam_set_state(struct sta_info *si, enum roam_trigger_state state,
                      struct uevent *ev)
 {
+       /* NOP in case we remain idle */
+       if (si->roam_state == state && si->roam_state == ROAM_TRIGGER_IDLE) {
+               si->roam_tries = 0;
+               return;
+       }
+
        si->roam_event = current_time;
 
        if (si->roam_state == state) {
-               if (si->roam_state == ROAM_TRIGGER_IDLE) {
-                       si->roam_tries = 0;
-                       return;
-               }
-
                si->roam_tries++;
        } else {
                si->roam_tries = 0;
@@ -297,25 +302,26 @@ 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 usteer_local_node *ln, struct sta_info *si)
 {
+       struct sta_info *candidate;
        struct uevent ev = {
                .si_cur = si,
        };
@@ -357,8 +363,15 @@ usteer_roam_trigger_sm(struct usteer_local_node *ln, struct sta_info *si)
                break;
 
        case ROAM_TRIGGER_SCAN_DONE:
-               usteer_ubus_bss_transition_request(si, 1, false, false, 100);
-               si->kick_time = current_time;
+               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_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);
                break;
        }
@@ -366,6 +379,44 @@ usteer_roam_trigger_sm(struct usteer_local_node *ln, struct sta_info *si)
        return false;
 }
 
+bool usteer_policy_can_perform_roam(struct sta_info *si)
+{
+       /* Only trigger for connected STAs */
+       if (si->connected != STA_CONNECTED)
+               return false;
+
+       /* Skip on pending kick */
+       if (si->kick_time)
+               return false;
+
+       /* Skip on rejected transition */
+       if (si->bss_transition_response.status_code && current_time - si->bss_transition_response.timestamp < config.steer_reject_timeout)
+               return false;
+
+       /* Skip on previous kick attempt */
+       if (current_time - si->roam_kick < config.roam_trigger_interval)
+               return false;
+
+       /* Skip if connection is established shorter than the trigger-interval */
+       if (current_time - si->connected_since < config.roam_trigger_interval)
+               return false;
+       
+       return true;
+}
+
+static bool
+usteer_local_node_roam_sm_active(struct sta_info *si, int min_signal)
+{
+       if (!usteer_policy_can_perform_roam(si))
+               return false;
+
+       /* Signal has to be below scan / roam threshold */
+       if (si->signal >= min_signal)
+               return false;
+
+       return true;
+}
+
 static void
 usteer_local_node_roam_check(struct usteer_local_node *ln, struct uevent *ev)
 {
@@ -383,10 +434,7 @@ usteer_local_node_roam_check(struct usteer_local_node *ln, struct uevent *ev)
        min_signal = usteer_snr_to_signal(&ln->node, min_signal);
 
        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) {
+               if (!usteer_local_node_roam_sm_active(si, min_signal)) {
                        usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, ev);
                        continue;
                }
@@ -430,8 +478,6 @@ usteer_local_node_snr_kick(struct usteer_local_node *ln)
                if (si->below_min_snr <= min_count)
                        continue;
 
-               si->kick_count++;
-
                ev.type = UEV_SIGNAL_KICK;
                ev.threshold.cur = si->signal;
                ev.count = si->kick_count;