remote: close file on usteer_init_local_id fread fail
[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 struct usteer_remote_node *usteer_remote_node_by_bssid(uint8_t *bssid) {
24 struct usteer_remote_node *rn;
25
26 for_each_remote_node(rn) {
27 if (!memcmp(rn->node.bssid, bssid, 6))
28 return rn;
29 }
30
31 return NULL;
32 }
33
34 struct usteer_node *usteer_node_by_bssid(uint8_t *bssid) {
35 struct usteer_remote_node *rn;
36 struct usteer_local_node *ln;
37
38 rn = usteer_remote_node_by_bssid(bssid);
39 if (rn)
40 return &rn->node;
41
42 ln = usteer_local_node_by_bssid(bssid);
43 if (ln)
44 return &ln->node;
45
46 return NULL;
47 }
48
49 void usteer_node_set_blob(struct blob_attr **dest, struct blob_attr *val)
50 {
51 int new_len;
52 int len;
53
54 if (!val) {
55 free(*dest);
56 *dest = NULL;
57 return;
58 }
59
60 len = *dest ? blob_pad_len(*dest) : 0;
61 new_len = blob_pad_len(val);
62 if (new_len != len)
63 *dest = realloc(*dest, new_len);
64 memcpy(*dest, val, new_len);
65 }
66
67 static struct usteer_node *
68 usteer_node_higher_bssid(struct usteer_node *node1, struct usteer_node *node2)
69 {
70 int i;
71
72 for (i = 0; i < 6; i++) {
73 if (node1->bssid[i] == node2->bssid[i])
74 continue;
75 if (node1->bssid[i] < node2->bssid[i])
76 return node2;
77
78 break;
79 }
80
81 return node1;
82 }
83
84 static struct usteer_node *
85 usteer_node_higher_roamability(struct usteer_node *node, struct usteer_node *ref)
86 {
87 uint64_t roamability_node, roamability_ref;
88
89 roamability_node = ((uint64_t)(node->roam_events.source + node->roam_events.target)) * current_time / ((current_time - node->created) + 1);
90 roamability_ref = ((uint64_t)(ref->roam_events.source + ref->roam_events.target)) * current_time / ((current_time - ref->created) + 1);
91
92 if (roamability_node < roamability_ref)
93 return ref;
94
95 return node;
96 }
97
98 static struct usteer_node *
99 usteer_node_better_neighbor(struct usteer_node *node, struct usteer_node *ref)
100 {
101 struct usteer_node *n1, *n2;
102
103 /**
104 * 1. Return one node if the other one is NULL
105 * 2. Return the node with the higher roam events.
106 * 3. Return the node with the higher BSSID.
107 * 4. Return first method argument.
108 */
109
110 if (!ref)
111 return node;
112
113 if (!node)
114 return ref;
115
116 n1 = usteer_node_higher_roamability(node, ref);
117 n2 = usteer_node_higher_roamability(ref, node);
118 if (n1 == n2)
119 return n1;
120
121 /* Identical roam interactions. Check BSSID */
122 n1 = usteer_node_higher_bssid(node, ref);
123 n2 = usteer_node_higher_bssid(ref, node);
124 if (n1 == n2)
125 return n1;
126
127 return node;
128 }
129
130 struct usteer_node *
131 usteer_node_get_next_neighbor(struct usteer_node *current_node, struct usteer_node *last)
132 {
133 struct usteer_remote_node *rn;
134 struct usteer_node *next = NULL, *n1, *n2;
135
136 for_each_remote_node(rn) {
137 if (next == &rn->node)
138 continue;
139
140 if (strcmp(current_node->ssid, rn->node.ssid))
141 continue;
142
143 /* Skip nodes which can't handle additional STA */
144 if (rn->node.max_assoc && rn->node.n_assoc >= rn->node.max_assoc)
145 continue;
146
147 /* Check if this node is ranked lower than the last one */
148 n1 = usteer_node_better_neighbor(last, &rn->node);
149 n2 = usteer_node_better_neighbor(&rn->node, last);
150 if (n1 != n2) {
151 /* Identical rank. Skip. */
152 continue;
153 } else if (last && n1 == &rn->node) {
154 /* Candidate rank is higher than the last neighbor. Skip. */
155 continue;
156 }
157
158 /* Check with current next candidate */
159 n1 = usteer_node_better_neighbor(next, &rn->node);
160 n2 = usteer_node_better_neighbor(&rn->node, next);
161 if (n1 != n2) {
162 /* Identical rank. Skip. */
163 continue;
164 } else if (n1 != &rn->node) {
165 /* Next candidate ranked higher. */
166 continue;
167 }
168
169 next = n1;
170 }
171
172 return next;
173 }