uloop_timeout_set(&ln->req_timer, 1);
}
-static void
+static bool
usteer_add_rrm_data(struct usteer_local_node *ln, struct usteer_node *node)
{
if (node == &ln->node)
- return;
+ return false;
if (!node->rrm_nr)
- return;
+ return false;
+ /* Remote node only adds same SSID. Required for local-node. */
if (strcmp(ln->node.ssid, node->ssid) != 0)
- return;
+ return false;
blobmsg_add_field(&b, BLOBMSG_TYPE_ARRAY, "",
blobmsg_data(node->rrm_nr),
blobmsg_data_len(node->rrm_nr));
+
+ return true;
}
static void
usteer_local_node_prepare_rrm_set(struct usteer_local_node *ln)
{
- struct usteer_remote_node *rn;
- struct usteer_node *node;
+ struct usteer_node *node, *last_remote_neighbor = NULL;
+ int i = 0;
void *c;
c = blobmsg_open_array(&b, "list");
- for_each_local_node(node)
- usteer_add_rrm_data(ln, node);
- for_each_remote_node(rn)
- usteer_add_rrm_data(ln, &rn->node);
+ for_each_local_node(node) {
+ if (i >= config.max_neighbor_reports)
+ break;
+ if (usteer_add_rrm_data(ln, node))
+ i++;
+ }
+
+ while (i < config.max_neighbor_reports) {
+ node = usteer_node_get_next_neighbor(&ln->node, last_remote_neighbor);
+ if (!node) {
+ /* No more nodes available */
+ break;
+ }
+
+ last_remote_neighbor = node;
+ if (usteer_add_rrm_data(ln, node))
+ i++;
+ }
+
blobmsg_close_array(&b, c);
}
config.local_sta_timeout = 120 * 1000;
config.local_sta_update = 1 * 1000;
config.max_retry_band = 5;
+ config.max_neighbor_reports = 8;
config.seen_policy_timeout = 30 * 1000;
config.band_steering_threshold = 5;
config.load_balancing_threshold = 5;
* Copyright (C) 2020 John Crispin <john@phrozen.org>
*/
+#include "node.h"
#include "usteer.h"
void usteer_node_set_blob(struct blob_attr **dest, struct blob_attr *val)
*dest = realloc(*dest, new_len);
memcpy(*dest, val, new_len);
}
+
+static struct usteer_node *
+usteer_node_higher_bssid(struct usteer_node *node1, struct usteer_node *node2)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ if (node1->bssid[i] == node2->bssid[i])
+ continue;
+ if (node1->bssid[i] < node2->bssid[i])
+ return node2;
+
+ break;
+ }
+
+ return node1;
+}
+
+static struct usteer_node *
+usteer_node_more_roam_interactions(struct usteer_node *node, struct usteer_node *ref)
+{
+ int roam_actions_node, roam_actions_ref;
+
+ roam_actions_node = node->roam_source + node->roam_destination;
+ roam_actions_ref = ref->roam_source + ref->roam_destination;
+ if (roam_actions_node < roam_actions_ref)
+ return ref;
+
+ return node;
+}
+
+static struct usteer_node *
+usteer_node_better_neighbor(struct usteer_node *node, struct usteer_node *ref)
+{
+ struct usteer_node *n1, *n2;
+
+ /**
+ * 1. Return one node if the other one is NULL
+ * 2. Return the node with the higher roam events.
+ * 3. Return the node with the higher BSSID.
+ * 4. Return first method argument.
+ */
+
+ if (!ref)
+ return node;
+
+ if (!node)
+ return ref;
+
+ n1 = usteer_node_more_roam_interactions(node, ref);
+ n2 = usteer_node_more_roam_interactions(ref, node);
+ if (n1 == n2)
+ return n1;
+
+ /* Identical roam interactions. Check BSSID */
+ n1 = usteer_node_higher_bssid(node, ref);
+ n2 = usteer_node_higher_bssid(ref, node);
+ if (n1 == n2)
+ return n1;
+
+ return node;
+}
+
+struct usteer_node *
+usteer_node_get_next_neighbor(struct usteer_node *current_node, struct usteer_node *last)
+{
+ struct usteer_remote_node *rn;
+ struct usteer_node *next = NULL, *n1, *n2;
+
+ for_each_remote_node(rn) {
+ if (next == &rn->node)
+ continue;
+
+ if (strcmp(current_node->ssid, rn->node.ssid))
+ continue;
+
+ /* Check if this node is ranked lower than the last one */
+ n1 = usteer_node_better_neighbor(last, &rn->node);
+ n2 = usteer_node_better_neighbor(&rn->node, last);
+ if (n1 != n2) {
+ /* Identical rank. Skip. */
+ continue;
+ } else if (last && n1 == &rn->node) {
+ /* Candidate rank is higher than the last neighbor. Skip. */
+ continue;
+ }
+
+ /* Check with current next candidate */
+ n1 = usteer_node_better_neighbor(next, &rn->node);
+ n2 = usteer_node_better_neighbor(&rn->node, next);
+ if (n1 != n2) {
+ /* Identical rank. Skip. */
+ continue;
+ } else if (n1 != &rn->node) {
+ /* Next candidate ranked higher. */
+ continue;
+ }
+
+ next = n1;
+ }
+
+ return next;
+}
# 5 = all debug messages
option 'debug_level' '2'
+ # Maximum number of neighbor reports set for a node
+ #option max_neighbor_reports 8
+
# Maximum amount of time (ms) a station may be blocked due to policy decisions
#option sta_block_timeout 30000
for opt in \
debug_level \
sta_block_timeout local_sta_timeout local_sta_update \
- max_retry_band seen_policy_timeout \
+ max_neighbor_reports max_retry_band seen_policy_timeout \
load_balancing_threshold band_steering_threshold \
remote_update_interval \
min_connect_snr min_snr signal_diff_threshold \
_cfg(U32, sta_block_timeout), \
_cfg(U32, local_sta_timeout), \
_cfg(U32, local_sta_update), \
+ _cfg(U32, max_neighbor_reports), \
_cfg(U32, max_retry_band), \
_cfg(U32, seen_policy_timeout), \
_cfg(U32, load_balancing_threshold), \
bool assoc_steering;
+ uint32_t max_neighbor_reports;
+
uint32_t band_steering_threshold;
uint32_t load_balancing_threshold;
}
void usteer_node_set_blob(struct blob_attr **dest, struct blob_attr *val);
+struct usteer_node *usteer_node_get_next_neighbor(struct usteer_node *current_node, struct usteer_node *last);
bool usteer_check_request(struct sta_info *si, enum usteer_event_type type);
void config_set_interfaces(struct blob_attr *data);