local-node: prioritize neighbor candidates
[project/usteer.git] / node.c
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
14 *
15 * Copyright (C) 2020 embedd.ch
16 * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
17 * Copyright (C) 2020 John Crispin <john@phrozen.org>
18 */
19
20 #include "node.h"
21 #include "usteer.h"
22
23 void usteer_node_set_blob(struct blob_attr **dest, struct blob_attr *val)
24 {
25 int new_len;
26 int len;
27
28 if (!val) {
29 free(*dest);
30 *dest = NULL;
31 return;
32 }
33
34 len = *dest ? blob_pad_len(*dest) : 0;
35 new_len = blob_pad_len(val);
36 if (new_len != len)
37 *dest = realloc(*dest, new_len);
38 memcpy(*dest, val, new_len);
39 }
40
41 static struct usteer_node *
42 usteer_node_higher_bssid(struct usteer_node *node1, struct usteer_node *node2)
43 {
44 int i;
45
46 for (i = 0; i < 6; i++) {
47 if (node1->bssid[i] == node2->bssid[i])
48 continue;
49 if (node1->bssid[i] < node2->bssid[i])
50 return node2;
51
52 break;
53 }
54
55 return node1;
56 }
57
58 static struct usteer_node *
59 usteer_node_more_roam_interactions(struct usteer_node *node, struct usteer_node *ref)
60 {
61 int roam_actions_node, roam_actions_ref;
62
63 roam_actions_node = node->roam_source + node->roam_destination;
64 roam_actions_ref = ref->roam_source + ref->roam_destination;
65 if (roam_actions_node < roam_actions_ref)
66 return ref;
67
68 return node;
69 }
70
71 static struct usteer_node *
72 usteer_node_better_neighbor(struct usteer_node *node, struct usteer_node *ref)
73 {
74 struct usteer_node *n1, *n2;
75
76 /**
77 * 1. Return one node if the other one is NULL
78 * 2. Return the node with the higher roam events.
79 * 3. Return the node with the higher BSSID.
80 * 4. Return first method argument.
81 */
82
83 if (!ref)
84 return node;
85
86 if (!node)
87 return ref;
88
89 n1 = usteer_node_more_roam_interactions(node, ref);
90 n2 = usteer_node_more_roam_interactions(ref, node);
91 if (n1 == n2)
92 return n1;
93
94 /* Identical roam interactions. Check BSSID */
95 n1 = usteer_node_higher_bssid(node, ref);
96 n2 = usteer_node_higher_bssid(ref, node);
97 if (n1 == n2)
98 return n1;
99
100 return node;
101 }
102
103 struct usteer_node *
104 usteer_node_get_next_neighbor(struct usteer_node *current_node, struct usteer_node *last)
105 {
106 struct usteer_remote_node *rn;
107 struct usteer_node *next = NULL, *n1, *n2;
108
109 for_each_remote_node(rn) {
110 if (next == &rn->node)
111 continue;
112
113 if (strcmp(current_node->ssid, rn->node.ssid))
114 continue;
115
116 /* Check if this node is ranked lower than the last one */
117 n1 = usteer_node_better_neighbor(last, &rn->node);
118 n2 = usteer_node_better_neighbor(&rn->node, last);
119 if (n1 != n2) {
120 /* Identical rank. Skip. */
121 continue;
122 } else if (last && n1 == &rn->node) {
123 /* Candidate rank is higher than the last neighbor. Skip. */
124 continue;
125 }
126
127 /* Check with current next candidate */
128 n1 = usteer_node_better_neighbor(next, &rn->node);
129 n2 = usteer_node_better_neighbor(&rn->node, next);
130 if (n1 != n2) {
131 /* Identical rank. Skip. */
132 continue;
133 } else if (n1 != &rn->node) {
134 /* Next candidate ranked higher. */
135 continue;
136 }
137
138 next = n1;
139 }
140
141 return next;
142 }