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 void usteer_node_set_blob(struct blob_attr
**dest
, struct blob_attr
*val
)
34 len
= *dest
? blob_pad_len(*dest
) : 0;
35 new_len
= blob_pad_len(val
);
37 *dest
= realloc(*dest
, new_len
);
38 memcpy(*dest
, val
, new_len
);
41 static struct usteer_node
*
42 usteer_node_higher_bssid(struct usteer_node
*node1
, struct usteer_node
*node2
)
46 for (i
= 0; i
< 6; i
++) {
47 if (node1
->bssid
[i
] == node2
->bssid
[i
])
49 if (node1
->bssid
[i
] < node2
->bssid
[i
])
58 static struct usteer_node
*
59 usteer_node_higher_roamability(struct usteer_node
*node
, struct usteer_node
*ref
)
61 uint64_t roamability_node
, roamability_ref
;
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);
66 if (roamability_node
< roamability_ref
)
72 static struct usteer_node
*
73 usteer_node_better_neighbor(struct usteer_node
*node
, struct usteer_node
*ref
)
75 struct usteer_node
*n1
, *n2
;
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.
90 n1
= usteer_node_higher_roamability(node
, ref
);
91 n2
= usteer_node_higher_roamability(ref
, node
);
95 /* Identical roam interactions. Check BSSID */
96 n1
= usteer_node_higher_bssid(node
, ref
);
97 n2
= usteer_node_higher_bssid(ref
, node
);
105 usteer_node_get_next_neighbor(struct usteer_node
*current_node
, struct usteer_node
*last
)
107 struct usteer_remote_node
*rn
;
108 struct usteer_node
*next
= NULL
, *n1
, *n2
;
110 for_each_remote_node(rn
) {
111 if (next
== &rn
->node
)
114 if (strcmp(current_node
->ssid
, rn
->node
.ssid
))
117 /* Skip nodes which can't handle additional STA */
118 if (rn
->node
.max_assoc
&& rn
->node
.n_assoc
>= rn
->node
.max_assoc
)
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
);
125 /* Identical rank. Skip. */
127 } else if (last
&& n1
== &rn
->node
) {
128 /* Candidate rank is higher than the last neighbor. Skip. */
132 /* Check with current next candidate */
133 n1
= usteer_node_better_neighbor(next
, &rn
->node
);
134 n2
= usteer_node_better_neighbor(&rn
->node
, next
);
136 /* Identical rank. Skip. */
138 } else if (n1
!= &rn
->node
) {
139 /* Next candidate ranked higher. */