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.
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.
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.
15 * Copyright (C) 2020 embedd.ch
16 * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
17 * Copyright (C) 2020 John Crispin <john@phrozen.org>
23 struct usteer_remote_node
*usteer_remote_node_by_bssid(uint8_t *bssid
) {
24 struct usteer_remote_node
*rn
;
26 for_each_remote_node(rn
) {
27 if (!memcmp(rn
->node
.bssid
, bssid
, 6))
34 struct usteer_node
*usteer_node_by_bssid(uint8_t *bssid
) {
35 struct usteer_remote_node
*rn
;
36 struct usteer_local_node
*ln
;
38 rn
= usteer_remote_node_by_bssid(bssid
);
42 ln
= usteer_local_node_by_bssid(bssid
);
49 void usteer_node_set_blob(struct blob_attr
**dest
, struct blob_attr
*val
)
60 len
= *dest
? blob_pad_len(*dest
) : 0;
61 new_len
= blob_pad_len(val
);
63 *dest
= realloc(*dest
, new_len
);
64 memcpy(*dest
, val
, new_len
);
67 static struct usteer_node
*
68 usteer_node_higher_bssid(struct usteer_node
*node1
, struct usteer_node
*node2
)
72 for (i
= 0; i
< 6; i
++) {
73 if (node1
->bssid
[i
] == node2
->bssid
[i
])
75 if (node1
->bssid
[i
] < node2
->bssid
[i
])
84 static struct usteer_node
*
85 usteer_node_higher_roamability(struct usteer_node
*node
, struct usteer_node
*ref
)
87 uint64_t roamability_node
, roamability_ref
;
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);
92 if (roamability_node
< roamability_ref
)
98 static struct usteer_node
*
99 usteer_node_better_neighbor(struct usteer_node
*node
, struct usteer_node
*ref
)
101 struct usteer_node
*n1
, *n2
;
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.
116 n1
= usteer_node_higher_roamability(node
, ref
);
117 n2
= usteer_node_higher_roamability(ref
, node
);
121 /* Identical roam interactions. Check BSSID */
122 n1
= usteer_node_higher_bssid(node
, ref
);
123 n2
= usteer_node_higher_bssid(ref
, node
);
131 usteer_node_get_next_neighbor(struct usteer_node
*current_node
, struct usteer_node
*last
)
133 struct usteer_remote_node
*rn
;
134 struct usteer_node
*next
= NULL
, *n1
, *n2
;
136 for_each_remote_node(rn
) {
137 if (next
== &rn
->node
)
140 if (strcmp(current_node
->ssid
, rn
->node
.ssid
))
143 /* Skip nodes which can't handle additional STA */
144 if (rn
->node
.max_assoc
&& rn
->node
.n_assoc
>= rn
->node
.max_assoc
)
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
);
151 /* Identical rank. Skip. */
153 } else if (last
&& n1
== &rn
->node
) {
154 /* Candidate rank is higher than the last neighbor. Skip. */
158 /* Check with current next candidate */
159 n1
= usteer_node_better_neighbor(next
, &rn
->node
);
160 n2
= usteer_node_better_neighbor(&rn
->node
, next
);
162 /* Identical rank. Skip. */
164 } else if (n1
!= &rn
->node
) {
165 /* Next candidate ranked higher. */