node: move roam-events to dedicated struct
[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_higher_roamability(struct usteer_node *node, struct usteer_node *ref)
60 {
61 uint64_t roamability_node, roamability_ref;
62
63 roamability_node = ((uint64_t)(node->roam_events.source + node->roam_events.target)) * current_time / ((current_time - node->created) + 1);
64 roamability_ref = ((uint64_t)(ref->roam_events.source + ref->roam_events.target)) * current_time / ((current_time - ref->created) + 1);
65
66 if (roamability_node < roamability_ref)
67 return ref;
68
69 return node;
70 }
71
72 static struct usteer_node *
73 usteer_node_better_neighbor(struct usteer_node *node, struct usteer_node *ref)
74 {
75 struct usteer_node *n1, *n2;
76
77 /**
78 * 1. Return one node if the other one is NULL
79 * 2. Return the node with the higher roam events.
80 * 3. Return the node with the higher BSSID.
81 * 4. Return first method argument.
82 */
83
84 if (!ref)
85 return node;
86
87 if (!node)
88 return ref;
89
90 n1 = usteer_node_higher_roamability(node, ref);
91 n2 = usteer_node_higher_roamability(ref, node);
92 if (n1 == n2)
93 return n1;
94
95 /* Identical roam interactions. Check BSSID */
96 n1 = usteer_node_higher_bssid(node, ref);
97 n2 = usteer_node_higher_bssid(ref, node);
98 if (n1 == n2)
99 return n1;
100
101 return node;
102 }
103
104 struct usteer_node *
105 usteer_node_get_next_neighbor(struct usteer_node *current_node, struct usteer_node *last)
106 {
107 struct usteer_remote_node *rn;
108 struct usteer_node *next = NULL, *n1, *n2;
109
110 for_each_remote_node(rn) {
111 if (next == &rn->node)
112 continue;
113
114 if (strcmp(current_node->ssid, rn->node.ssid))
115 continue;
116
117 /* Skip nodes which can't handle additional STA */
118 if (rn->node.max_assoc && rn->node.n_assoc >= rn->node.max_assoc)
119 continue;
120
121 /* Check if this node is ranked lower than the last one */
122 n1 = usteer_node_better_neighbor(last, &rn->node);
123 n2 = usteer_node_better_neighbor(&rn->node, last);
124 if (n1 != n2) {
125 /* Identical rank. Skip. */
126 continue;
127 } else if (last && n1 == &rn->node) {
128 /* Candidate rank is higher than the last neighbor. Skip. */
129 continue;
130 }
131
132 /* Check with current next candidate */
133 n1 = usteer_node_better_neighbor(next, &rn->node);
134 n2 = usteer_node_better_neighbor(&rn->node, next);
135 if (n1 != n2) {
136 /* Identical rank. Skip. */
137 continue;
138 } else if (n1 != &rn->node) {
139 /* Next candidate ranked higher. */
140 continue;
141 }
142
143 next = n1;
144 }
145
146 return next;
147 }