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 avl_macaddr_cmp(const void *k1
, const void *k2
, void *ptr
)
25 return memcmp(k1
, k2
, 6);
28 AVL_TREE(stations
, avl_macaddr_cmp
, false, NULL
);
29 static struct usteer_timeout_queue tq
;
32 usteer_sta_del(struct sta
*sta
)
34 MSG(DEBUG
, "Delete station " MAC_ADDR_FMT
"\n",
35 MAC_ADDR_DATA(sta
->addr
));
37 avl_delete(&stations
, &sta
->avl
);
38 usteer_measurement_report_sta_cleanup(sta
);
43 usteer_sta_info_del(struct sta_info
*si
)
45 struct sta
*sta
= si
->sta
;
47 MSG(DEBUG
, "Delete station " MAC_ADDR_FMT
" entry for node %s\n",
48 MAC_ADDR_DATA(sta
->addr
), usteer_node_name(si
->node
));
50 usteer_timeout_cancel(&tq
, &si
->timeout
);
52 list_del(&si
->node_list
);
55 if (list_empty(&sta
->nodes
))
60 usteer_sta_node_cleanup(struct usteer_node
*node
)
62 struct sta_info
*si
, *tmp
;
67 list_for_each_entry_safe(si
, tmp
, &node
->sta_info
, node_list
)
68 usteer_sta_info_del(si
);
72 usteer_sta_info_timeout(struct usteer_timeout_queue
*q
, struct usteer_timeout
*t
)
74 struct sta_info
*si
= container_of(t
, struct sta_info
, timeout
);
76 usteer_sta_info_del(si
);
80 usteer_sta_info_get(struct sta
*sta
, struct usteer_node
*node
, bool *create
)
84 list_for_each_entry(si
, &sta
->nodes
, list
) {
97 MSG(DEBUG
, "Create station " MAC_ADDR_FMT
" entry for node %s\n",
98 MAC_ADDR_DATA(sta
->addr
), usteer_node_name(node
));
100 si
= calloc(1, sizeof(*si
));
103 list_add(&si
->list
, &sta
->nodes
);
104 list_add(&si
->node_list
, &node
->sta_info
);
105 si
->created
= current_time
;
108 /* Node is by default not connected. */
109 usteer_sta_disconnected(si
);
116 usteer_sta_info_update_timeout(struct sta_info
*si
, int timeout
)
118 if (si
->connected
== STA_CONNECTED
)
119 usteer_timeout_cancel(&tq
, &si
->timeout
);
120 else if (timeout
> 0)
121 usteer_timeout_set(&tq
, &si
->timeout
, timeout
);
123 usteer_sta_info_del(si
);
127 usteer_sta_get(const uint8_t *addr
, bool create
)
131 sta
= avl_find_element(&stations
, addr
, sta
, avl
);
138 MSG(DEBUG
, "Create station entry " MAC_ADDR_FMT
"\n", MAC_ADDR_DATA(addr
));
139 sta
= calloc(1, sizeof(*sta
));
140 memcpy(sta
->addr
, addr
, sizeof(sta
->addr
));
141 sta
->avl
.key
= sta
->addr
;
142 avl_insert(&stations
, &sta
->avl
);
143 INIT_LIST_HEAD(&sta
->nodes
);
144 INIT_LIST_HEAD(&sta
->measurements
);
149 void usteer_sta_disconnected(struct sta_info
*si
)
151 si
->connected
= STA_NOT_CONNECTED
;
153 si
->connected_since
= 0;
154 usteer_sta_info_update_timeout(si
, config
.local_sta_timeout
);
158 usteer_sta_info_update(struct sta_info
*si
, int signal
, bool avg
)
160 /* ignore probe request signal when connected */
161 if (si
->connected
== STA_CONNECTED
&& si
->signal
!= NO_SIGNAL
&& !avg
)
164 if (signal
!= NO_SIGNAL
) {
166 usteer_band_steering_sta_update(si
);
169 si
->seen
= current_time
;
171 if (si
->node
->freq
< 4000)
172 si
->sta
->seen_2ghz
= 1;
174 si
->sta
->seen_5ghz
= 1;
176 usteer_sta_info_update_timeout(si
, config
.local_sta_timeout
);
180 usteer_handle_sta_event(struct usteer_node
*node
, const uint8_t *addr
,
181 enum usteer_event_type type
, int freq
, int signal
)
189 sta
= usteer_sta_get(addr
, true);
193 si
= usteer_sta_info_get(sta
, node
, &create
);
194 usteer_sta_info_update(si
, signal
, false);
195 si
->stats
[type
].requests
++;
197 diff
= si
->stats
[type
].blocked_last_time
- current_time
;
198 if (diff
> config
.sta_block_timeout
)
199 si
->stats
[type
].blocked_cur
= 0;
201 ret
= usteer_check_request(si
, type
);
203 si
->stats
[type
].blocked_cur
++;
204 si
->stats
[type
].blocked_total
++;
205 si
->stats
[type
].blocked_last_time
= current_time
;
207 si
->stats
[type
].blocked_cur
= 0;
211 usteer_send_sta_update(si
);
217 usteer_sta_supports_beacon_measurement_mode(struct sta_info
*si
, enum usteer_beacon_measurement_mode mode
)
220 case BEACON_MEASUREMENT_PASSIVE
:
221 return si
->rrm
& (1 << 4);
222 case BEACON_MEASUREMENT_ACTIVE
:
223 return si
->rrm
& (1 << 5);
224 case BEACON_MEASUREMENT_TABLE
:
225 return si
->rrm
& (1 << 6);
232 usteer_sta_supports_link_measurement(struct sta_info
*si
)
234 return si
->rrm
& (1 << 0);
237 static void __usteer_init
usteer_sta_init(void)
239 usteer_timeout_init(&tq
);
240 tq
.cb
= usteer_sta_info_timeout
;