hostapd: sync upstream (#8078)

* hostapd: ubus: add notification for BSS transition response

To allow steering daemons to be aware of the STA-decided transition
target, publish WNM transition responses to ubus. This way, steerings
daemons can learn about STA-chosen targets and send a better selection
of transition candidates.

Signed-off-by: David Bauer <mail@david-bauer.net>

* hostapd: ubus: add BSS transtiton request method

The existing wnm_disassoc_imminent ubus method only supports issuing a
bss transition request with the disassoc imminent flag set.
For use-cases, where the client is requested to roam to another BSS
without a pending disassoc, this existing method is not suitable.

Add a new bss_transition_request ubus method, which provides a more
universal way to dispatch a transition request. It takes the following
arguments:

Required:
addr: String - MAC-address of the STA to send the request to (colon-seperated)

Optional:
abridged - Bool - Indicates if the abridged flag is set
disassociation_imminent: Bool - Whether or not the disassoc_imminent
                         flag is set
disassociation_timer: I32 - number of TBTTs after which the client will
                      be disassociated
validity_period: I32 - number of TBTTs after which the beacon
                 candidate list (if included) will be invalid
neighbors: blob-array - Array of strings containing neighbor reports as
           hex-string

Signed-off-by: David Bauer <mail@david-bauer.net>

* hostapd: fix goto loop for ubus assoc handler

When a ubus event handler denies a association with a non-zero return
value, the code jumps to preceeding code, creating an endless loop until
the event handler accepts the assc request.

Move the ubus handler further up the code to avoid creating such a loop.

Signed-off-by: David Bauer <mail@david-bauer.net>

Co-authored-by: David Bauer <mail@david-bauer.net>
This commit is contained in:
Beginner 2021-10-20 17:29:38 +08:00 committed by GitHub
parent 9a50fdefc9
commit 03ff629884
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 211 additions and 66 deletions

View File

@ -147,9 +147,9 @@
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
* is used */
@@ -5831,6 +5848,14 @@ static void handle_assoc(struct hostapd_
pos, left, rssi, omit_rsnxe);
os_free(tmp);
@@ -5765,6 +5782,13 @@ static void handle_assoc(struct hostapd_
}
#endif /* CONFIG_FILS */
+ ubus_resp = hostapd_ubus_handle_event(hapd, &req);
+ if (ubus_resp) {
@ -158,11 +158,10 @@
+ resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
fail:
/*
* Remove the station in case transmission of a success response fails
* (the STA was added associated to the driver) or if the station was
@@ -5858,6 +5883,7 @@ static void handle_disassoc(struct hosta
@@ -5858,6 +5882,7 @@ static void handle_disassoc(struct hosta
wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
MAC2STR(mgmt->sa),
le_to_host16(mgmt->u.disassoc.reason_code));
@ -170,7 +169,7 @@
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
@@ -5927,6 +5953,8 @@ static void handle_deauth(struct hostapd
@@ -5927,6 +5952,8 @@ static void handle_deauth(struct hostapd
/* Clear the PTKSA cache entries for PASN */
ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
@ -514,3 +513,33 @@
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -463,7 +463,7 @@ static void ieee802_11_rx_bss_trans_mgmt
size_t len)
{
u8 dialog_token, status_code, bss_termination_delay;
- const u8 *pos, *end;
+ const u8 *pos, *end, *target_bssid;
int enabled = hapd->conf->bss_transition;
struct sta_info *sta;
@@ -510,6 +510,7 @@ static void ieee802_11_rx_bss_trans_mgmt
wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
return;
}
+ target_bssid = pos;
sta->agreed_to_steer = 1;
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
@@ -529,6 +530,10 @@ static void ieee802_11_rx_bss_trans_mgmt
MAC2STR(addr), status_code, bss_termination_delay);
}
+ hostapd_ubus_notify_bss_transition_response(hapd, sta->addr, dialog_token,
+ status_code, bss_termination_delay,
+ target_bssid, pos, end - pos);
+
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
}

View File

@ -1275,6 +1275,129 @@ hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj,
#ifdef CONFIG_WNM_AP
static int
hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
u16 disassoc_timer, u8 validity_period, struct blob_attr *neighbors)
{
struct blob_attr *cur;
struct sta_info *sta;
int nr_len = 0;
int rem;
u8 *nr = NULL;
u8 req_mode = 0;
sta = ap_get_sta(hapd, addr);
if (!sta)
return UBUS_STATUS_NOT_FOUND;
if (neighbors) {
u8 *nr_cur;
if (blobmsg_check_array(neighbors,
BLOBMSG_TYPE_STRING) < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
blobmsg_for_each_attr(cur, neighbors, rem) {
int len = strlen(blobmsg_get_string(cur));
if (len % 2)
return UBUS_STATUS_INVALID_ARGUMENT;
nr_len += (len / 2) + 2;
}
if (nr_len) {
nr = os_zalloc(nr_len);
if (!nr)
return UBUS_STATUS_UNKNOWN_ERROR;
}
nr_cur = nr;
blobmsg_for_each_attr(cur, neighbors, rem) {
int len = strlen(blobmsg_get_string(cur)) / 2;
*nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
*nr_cur++ = (u8) len;
if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) {
free(nr);
return UBUS_STATUS_INVALID_ARGUMENT;
}
nr_cur += len;
}
}
if (nr)
req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
if (abridged)
req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
if (disassoc_imminent)
req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
NULL, nr, nr_len, NULL, 0))
return UBUS_STATUS_UNKNOWN_ERROR;
return 0;
}
enum {
BSS_TR_ADDR,
BSS_TR_DA_IMMINENT,
BSS_TR_DA_TIMER,
BSS_TR_VALID_PERIOD,
BSS_TR_NEIGHBORS,
BSS_TR_ABRIDGED,
__BSS_TR_DISASSOC_MAX
};
static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
[BSS_TR_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
[BSS_TR_DA_IMMINENT] = { "disassociation_imminent", BLOBMSG_TYPE_BOOL },
[BSS_TR_DA_TIMER] = { "disassociation_timer", BLOBMSG_TYPE_INT32 },
[BSS_TR_VALID_PERIOD] = { "validity_period", BLOBMSG_TYPE_INT32 },
[BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
[BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
};
static int
hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *ureq, const char *method,
struct blob_attr *msg)
{
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
struct blob_attr *tb[__BSS_TR_DISASSOC_MAX];
struct sta_info *sta;
u32 da_timer = 0;
u32 valid_period = 0;
u8 addr[ETH_ALEN];
bool abridged;
bool da_imminent;
blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
if (!tb[BSS_TR_ADDR])
return UBUS_STATUS_INVALID_ARGUMENT;
if (hwaddr_aton(blobmsg_data(tb[BSS_TR_ADDR]), addr))
return UBUS_STATUS_INVALID_ARGUMENT;
if (tb[BSS_TR_DA_TIMER])
da_timer = blobmsg_get_u32(tb[BSS_TR_DA_TIMER]);
if (tb[BSS_TR_VALID_PERIOD])
valid_period = blobmsg_get_u32(tb[BSS_TR_VALID_PERIOD]);
da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
tb[BSS_TR_NEIGHBORS]);
}
enum {
WNM_DISASSOC_ADDR,
WNM_DISASSOC_DURATION,
@ -1297,14 +1420,10 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
{
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
struct blob_attr *tb[__WNM_DISASSOC_MAX];
struct blob_attr *cur;
struct sta_info *sta;
int duration = 10;
int rem;
int nr_len = 0;
u8 *nr = NULL;
u8 req_mode = WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
u8 addr[ETH_ALEN];
bool abridged;
blobmsg_parse(wnm_disassoc_policy, __WNM_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
@ -1314,61 +1433,13 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
if (hwaddr_aton(blobmsg_data(tb[WNM_DISASSOC_ADDR]), addr))
return UBUS_STATUS_INVALID_ARGUMENT;
if ((cur = tb[WNM_DISASSOC_DURATION]) != NULL)
duration = blobmsg_get_u32(cur);
if (tb[WNM_DISASSOC_DURATION])
duration = blobmsg_get_u32(tb[WNM_DISASSOC_DURATION]);
sta = ap_get_sta(hapd, addr);
if (!sta)
return UBUS_STATUS_NOT_FOUND;
abridged = !!(tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED]));
if (tb[WNM_DISASSOC_NEIGHBORS]) {
u8 *nr_cur;
if (blobmsg_check_array(tb[WNM_DISASSOC_NEIGHBORS],
BLOBMSG_TYPE_STRING) < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) {
int len = strlen(blobmsg_get_string(cur));
if (len % 2)
return UBUS_STATUS_INVALID_ARGUMENT;
nr_len += (len / 2) + 2;
}
if (nr_len) {
nr = os_zalloc(nr_len);
if (!nr)
return UBUS_STATUS_UNKNOWN_ERROR;
}
nr_cur = nr;
blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) {
int len = strlen(blobmsg_get_string(cur)) / 2;
*nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
*nr_cur++ = (u8) len;
if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) {
free(nr);
return UBUS_STATUS_INVALID_ARGUMENT;
}
nr_cur += len;
}
}
if (nr)
req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
if (tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED]))
req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
if (wnm_send_bss_tm_req(hapd, sta, req_mode, duration, duration, NULL,
NULL, nr, nr_len, NULL, 0))
return UBUS_STATUS_UNKNOWN_ERROR;
return 0;
return hostapd_bss_tr_send(hapd, addr, true, abridged, duration, duration,
tb[WNM_DISASSOC_NEIGHBORS]);
}
#endif
@ -1454,6 +1525,7 @@ static const struct ubus_method bss_methods[] = {
UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
#ifdef CONFIG_WNM_AP
UBUS_METHOD("wnm_disassoc_imminent", hostapd_wnm_disassoc_imminent, wnm_disassoc_policy),
UBUS_METHOD("bss_transition_request", hostapd_bss_transition_request, bss_tr_policy),
#endif
};
@ -1757,3 +1829,36 @@ void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequen
ubus_notify(ctx, &hapd->ubus.obj, "radar-detected", b.head, -1);
}
}
void hostapd_ubus_notify_bss_transition_response(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
u8 bss_termination_delay, const u8 *target_bssid,
const u8 *candidate_list, u16 candidate_list_len)
{
#ifdef CONFIG_WNM_AP
char *cl_str;
u16 i;
if (!hapd->ubus.obj.has_subscribers)
return;
if (!addr)
return;
blob_buf_init(&b, 0);
blobmsg_add_macaddr(&b, "address", addr);
blobmsg_add_u8(&b, "dialog-token", dialog_token);
blobmsg_add_u8(&b, "status-code", status_code);
blobmsg_add_u8(&b, "bss-termination-delay", bss_termination_delay);
if (target_bssid)
blobmsg_add_macaddr(&b, "target-bssid", target_bssid);
if (candidate_list_len > 0) {
cl_str = blobmsg_alloc_string_buffer(&b, "candidate-list", candidate_list_len * 2 + 1);
for (i = 0; i < candidate_list_len; i++)
snprintf(&cl_str[i*2], 3, "%02X", candidate_list[i]);
blobmsg_add_string_buffer(&b);
}
ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1);
#endif
}

View File

@ -55,6 +55,10 @@ void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
int chan_width, int cf1, int cf2);
void hostapd_ubus_notify_bss_transition_response(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
u8 bss_termination_delay, const u8 *target_bssid,
const u8 *candidate_list, u16 candidate_list_len);
void hostapd_ubus_add(struct hapd_interfaces *interfaces);
void hostapd_ubus_free(struct hapd_interfaces *interfaces);
@ -107,6 +111,13 @@ static inline void hostapd_ubus_notify_radar_detected(struct hostapd_iface *ifac
{
}
static inline void hostapd_ubus_notify_bss_transition_response(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
u8 bss_termination_delay, const u8 *target_bssid,
const u8 *candidate_list, u16 candidate_list_len)
{
}
static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
{
}