mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-29 17:42:41 +00:00
hostapd: backport rrm/wnm features
Fixes: WIFI-7049 Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
From 1b26807938815d0b0b266caf31d8ef0019607e64 Mon Sep 17 00:00:00 2001
|
||||
From: David Bauer <mail@david-bauer.net>
|
||||
Date: Mon, 27 Sep 2021 15:41:48 +0200
|
||||
Subject: [PATCH] WNM: allow specifying dialog-token
|
||||
|
||||
This commit adds the ability to specify the dialog token of a WNM BSS
|
||||
Transition request frame via the hostapd control socket.
|
||||
|
||||
FOr this, the new 'dialog_token' option can be used. It accepts values
|
||||
as a 8 bit unsigned integer. If not specified, the dialog token is set
|
||||
to 1 like before.
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
---
|
||||
hostapd/ctrl_iface.c | 10 ++++++++--
|
||||
src/ap/wnm_ap.c | 11 ++++++-----
|
||||
src/ap/wnm_ap.h | 4 ++--
|
||||
3 files changed, 16 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/hostapd/ctrl_iface.c
|
||||
+++ b/hostapd/ctrl_iface.c
|
||||
@@ -897,7 +897,7 @@ static int hostapd_ctrl_iface_bss_tm_req
|
||||
const char *pos, *end;
|
||||
int disassoc_timer = 0;
|
||||
struct sta_info *sta;
|
||||
- u8 req_mode = 0, valid_int = 0x01;
|
||||
+ u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
|
||||
u8 bss_term_dur[12];
|
||||
char *url = NULL;
|
||||
int ret;
|
||||
@@ -935,6 +935,12 @@ static int hostapd_ctrl_iface_bss_tm_req
|
||||
valid_int = atoi(pos);
|
||||
}
|
||||
|
||||
+ pos = os_strstr(cmd, " dialog_token=");
|
||||
+ if (pos) {
|
||||
+ pos += 14;
|
||||
+ dialog_token = atoi(pos);
|
||||
+ }
|
||||
+
|
||||
pos = os_strstr(cmd, " bss_term=");
|
||||
if (pos) {
|
||||
pos += 10;
|
||||
@@ -1041,7 +1047,7 @@ static int hostapd_ctrl_iface_bss_tm_req
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
|
||||
- valid_int, bss_term_dur, url,
|
||||
+ valid_int, bss_term_dur, dialog_token, url,
|
||||
nei_len ? nei_rep : NULL, nei_len,
|
||||
mbo_len ? mbo : NULL, mbo_len);
|
||||
#ifdef CONFIG_MBO
|
||||
--- a/src/ap/wnm_ap.c
|
||||
+++ b/src/ap/wnm_ap.c
|
||||
@@ -788,8 +788,8 @@ int wnm_send_ess_disassoc_imminent(struc
|
||||
|
||||
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 req_mode, int disassoc_timer, u8 valid_int,
|
||||
- const u8 *bss_term_dur, const char *url,
|
||||
- const u8 *nei_rep, size_t nei_rep_len,
|
||||
+ const u8 *bss_term_dur, u8 dialog_token,
|
||||
+ const char *url, const u8 *nei_rep, size_t nei_rep_len,
|
||||
const u8 *mbo_attrs, size_t mbo_len)
|
||||
{
|
||||
u8 *buf, *pos;
|
||||
@@ -797,8 +797,9 @@ int wnm_send_bss_tm_req(struct hostapd_d
|
||||
size_t url_len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
|
||||
- MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x",
|
||||
- MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int);
|
||||
+ MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x "
|
||||
+ "dialog_token=%x",
|
||||
+ MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int, dialog_token);
|
||||
buf = os_zalloc(1000 + nei_rep_len + mbo_len);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
@@ -810,7 +811,7 @@ int wnm_send_bss_tm_req(struct hostapd_d
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_ACTION_WNM;
|
||||
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
|
||||
- mgmt->u.action.u.bss_tm_req.dialog_token = 1;
|
||||
+ mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
|
||||
mgmt->u.action.u.bss_tm_req.req_mode = req_mode;
|
||||
mgmt->u.action.u.bss_tm_req.disassoc_timer =
|
||||
host_to_le16(disassoc_timer);
|
||||
--- a/src/ap/wnm_ap.h
|
||||
+++ b/src/ap/wnm_ap.h
|
||||
@@ -20,8 +20,8 @@ int wnm_send_ess_disassoc_imminent(struc
|
||||
int disassoc_timer);
|
||||
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 req_mode, int disassoc_timer, u8 valid_int,
|
||||
- const u8 *bss_term_dur, const char *url,
|
||||
- const u8 *nei_rep, size_t nei_rep_len,
|
||||
+ const u8 *bss_term_dur, u8 dialog_token,
|
||||
+ const char *url, const u8 *nei_rep, size_t nei_rep_len,
|
||||
const u8 *mbo_attrs, size_t mbo_len);
|
||||
void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx);
|
||||
int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
92
feeds/wifi-ax/hostapd/patches/590-rrm-wnm-statistics.patch
Normal file
92
feeds/wifi-ax/hostapd/patches/590-rrm-wnm-statistics.patch
Normal file
@@ -0,0 +1,92 @@
|
||||
--- a/src/ap/hostapd.h
|
||||
+++ b/src/ap/hostapd.h
|
||||
@@ -150,6 +150,21 @@ struct hostapd_sae_commit_queue {
|
||||
};
|
||||
|
||||
/**
|
||||
+ * struct hostapd_openwrt_stats - OpenWrt custom STA/AP statistics
|
||||
+ */
|
||||
+struct hostapd_openwrt_stats {
|
||||
+ struct {
|
||||
+ u64 neighbor_report_tx;
|
||||
+ } rrm;
|
||||
+
|
||||
+ struct {
|
||||
+ u64 bss_transition_query_rx;
|
||||
+ u64 bss_transition_request_tx;
|
||||
+ u64 bss_transition_response_rx;
|
||||
+ } wnm;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* struct hostapd_data - hostapd per-BSS data structure
|
||||
*/
|
||||
struct hostapd_data {
|
||||
@@ -163,6 +178,9 @@ struct hostapd_data {
|
||||
|
||||
u8 own_addr[ETH_ALEN];
|
||||
|
||||
+ /* OpenWrt specific statistics */
|
||||
+ struct hostapd_openwrt_stats openwrt_stats;
|
||||
+
|
||||
int num_sta; /* number of entries in sta_list */
|
||||
struct sta_info *sta_list; /* STA info list head */
|
||||
#define STA_HASH_SIZE 256
|
||||
--- a/src/ap/wnm_ap.c
|
||||
+++ b/src/ap/wnm_ap.c
|
||||
@@ -386,6 +386,7 @@ static int ieee802_11_send_bss_trans_mgm
|
||||
mgmt->u.action.u.bss_tm_req.validity_interval = 1;
|
||||
pos = mgmt->u.action.u.bss_tm_req.variable;
|
||||
|
||||
+ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
|
||||
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
|
||||
MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
|
||||
"validity_interval=%u",
|
||||
@@ -646,10 +647,12 @@ int ieee802_11_rx_wnm_action_ap(struct h
|
||||
|
||||
switch (action) {
|
||||
case WNM_BSS_TRANS_MGMT_QUERY:
|
||||
+ hapd->openwrt_stats.wnm.bss_transition_query_rx++;
|
||||
ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
|
||||
plen);
|
||||
return 0;
|
||||
case WNM_BSS_TRANS_MGMT_RESP:
|
||||
+ hapd->openwrt_stats.wnm.bss_transition_response_rx++;
|
||||
ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload,
|
||||
plen);
|
||||
return 0;
|
||||
@@ -696,6 +699,7 @@ int wnm_send_disassoc_imminent(struct ho
|
||||
|
||||
pos = mgmt->u.action.u.bss_tm_req.variable;
|
||||
|
||||
+ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
|
||||
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
|
||||
MACSTR, disassoc_timer, MAC2STR(sta->addr));
|
||||
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
|
||||
@@ -777,6 +781,7 @@ int wnm_send_ess_disassoc_imminent(struc
|
||||
return -1;
|
||||
}
|
||||
|
||||
+ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
|
||||
if (disassoc_timer) {
|
||||
/* send disassociation frame after time-out */
|
||||
set_disassoc_timer(hapd, sta, disassoc_timer);
|
||||
@@ -857,6 +862,7 @@ int wnm_send_bss_tm_req(struct hostapd_d
|
||||
}
|
||||
os_free(buf);
|
||||
|
||||
+ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
|
||||
if (disassoc_timer) {
|
||||
/* send disassociation frame after time-out */
|
||||
set_disassoc_timer(hapd, sta, disassoc_timer);
|
||||
--- a/src/ap/rrm.c
|
||||
+++ b/src/ap/rrm.c
|
||||
@@ -269,6 +269,8 @@ static void hostapd_send_nei_report_resp
|
||||
}
|
||||
}
|
||||
|
||||
+ hapd->openwrt_stats.rrm.neighbor_report_tx++;
|
||||
+
|
||||
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
@@ -31,7 +31,7 @@
|
||||
};
|
||||
|
||||
enum hostapd_chan_status {
|
||||
@@ -154,6 +155,7 @@ struct hostapd_data {
|
||||
@@ -171,6 +172,7 @@ struct hostapd_data {
|
||||
struct hostapd_iface *iface;
|
||||
struct hostapd_config *iconf;
|
||||
struct hostapd_bss_config *conf;
|
||||
@@ -39,7 +39,7 @@
|
||||
int interface_added; /* virtual interface added for this BSS */
|
||||
unsigned int started:1;
|
||||
unsigned int disabled:1;
|
||||
@@ -610,6 +612,7 @@ hostapd_alloc_bss_data(struct hostapd_if
|
||||
@@ -630,6 +632,7 @@ hostapd_alloc_bss_data(struct hostapd_if
|
||||
struct hostapd_bss_config *bss);
|
||||
int hostapd_setup_interface(struct hostapd_iface *iface);
|
||||
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
|
||||
@@ -126,7 +126,7 @@
|
||||
if (res == HOSTAPD_ACL_PENDING)
|
||||
return;
|
||||
|
||||
@@ -5454,7 +5466,7 @@ static void handle_assoc(struct hostapd_
|
||||
@@ -5447,7 +5459,7 @@ static void handle_assoc(struct hostapd_
|
||||
int resp = WLAN_STATUS_SUCCESS;
|
||||
u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
const u8 *pos;
|
||||
@@ -135,7 +135,7 @@
|
||||
struct sta_info *sta;
|
||||
u8 *tmp = NULL;
|
||||
#ifdef CONFIG_FILS
|
||||
@@ -5667,6 +5679,11 @@ static void handle_assoc(struct hostapd_
|
||||
@@ -5660,6 +5672,11 @@ static void handle_assoc(struct hostapd_
|
||||
left = res;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
@@ -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);
|
||||
@@ -5758,6 +5775,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
|
||||
@@ -5851,6 +5875,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
|
||||
@@ -5920,6 +5945,8 @@ static void handle_deauth(struct hostapd
|
||||
/* Clear the PTKSA cache entries for PASN */
|
||||
ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
|
||||
|
||||
@@ -181,7 +180,7 @@
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
|
||||
--- a/src/ap/beacon.c
|
||||
+++ b/src/ap/beacon.c
|
||||
@@ -823,6 +823,12 @@ void handle_probe_req(struct hostapd_dat
|
||||
@@ -852,6 +852,12 @@ void handle_probe_req(struct hostapd_dat
|
||||
u16 csa_offs[2];
|
||||
size_t csa_offs_len;
|
||||
struct radius_sta rad_info;
|
||||
@@ -194,7 +193,7 @@
|
||||
|
||||
if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
|
||||
ssi_signal < hapd->iconf->rssi_ignore_probe_request)
|
||||
@@ -1009,6 +1015,12 @@ void handle_probe_req(struct hostapd_dat
|
||||
@@ -1038,6 +1044,12 @@ void handle_probe_req(struct hostapd_dat
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
@@ -235,22 +234,22 @@
|
||||
wpabuf_free(sta->p2p_ie);
|
||||
--- a/src/ap/sta_info.c
|
||||
+++ b/src/ap/sta_info.c
|
||||
@@ -459,6 +459,7 @@ void ap_handle_timer(void *eloop_ctx, vo
|
||||
@@ -458,6 +458,7 @@ void ap_handle_timer(void *eloop_ctx, vo
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
||||
"local deauth request");
|
||||
ap_free_sta(hapd, sta);
|
||||
+ hostapd_ubus_notify(hapd, "local-deauth", sta->addr);
|
||||
ap_free_sta(hapd, sta);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -614,6 +615,7 @@ skip_poll:
|
||||
@@ -613,6 +614,7 @@ skip_poll:
|
||||
mlme_deauthenticate_indication(
|
||||
hapd, sta,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
ap_free_sta(hapd, sta);
|
||||
+ hostapd_ubus_notify(hapd, "inactive-deauth", sta->addr);
|
||||
ap_free_sta(hapd, sta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1329,6 +1331,7 @@ void ap_sta_set_authorized(struct hostap
|
||||
buf, ip_addr, keyid_buf);
|
||||
} else {
|
||||
@@ -284,7 +283,7 @@
|
||||
ifdef CONFIG_CODE_COVERAGE
|
||||
CFLAGS += -O0 -fprofile-arcs -ftest-coverage
|
||||
LIBS += -lgcov
|
||||
@@ -959,6 +965,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
|
||||
@@ -962,6 +968,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_MIB
|
||||
endif
|
||||
OBJS += ../src/ap/ctrl_iface_ap.o
|
||||
@@ -296,7 +295,7 @@
|
||||
CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
|
||||
--- a/wpa_supplicant/wpa_supplicant.c
|
||||
+++ b/wpa_supplicant/wpa_supplicant.c
|
||||
@@ -7017,6 +7017,8 @@ struct wpa_supplicant * wpa_supplicant_a
|
||||
@@ -7241,6 +7241,8 @@ struct wpa_supplicant * wpa_supplicant_a
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
@@ -305,7 +304,7 @@
|
||||
return wpa_s;
|
||||
}
|
||||
|
||||
@@ -7043,6 +7045,8 @@ int wpa_supplicant_remove_iface(struct w
|
||||
@@ -7267,6 +7269,8 @@ int wpa_supplicant_remove_iface(struct w
|
||||
struct wpa_supplicant *parent = wpa_s->parent;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
@@ -314,7 +313,7 @@
|
||||
/* Remove interface from the global list of interfaces */
|
||||
prev = global->ifaces;
|
||||
if (prev == wpa_s) {
|
||||
@@ -7346,8 +7350,12 @@ int wpa_supplicant_run(struct wpa_global
|
||||
@@ -7570,8 +7574,12 @@ int wpa_supplicant_run(struct wpa_global
|
||||
eloop_register_signal_terminate(wpa_supplicant_terminate, global);
|
||||
eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
|
||||
|
||||
@@ -337,7 +336,7 @@
|
||||
|
||||
extern const char *const wpa_supplicant_version;
|
||||
extern const char *const wpa_supplicant_license;
|
||||
@@ -321,6 +322,8 @@ struct wpa_global {
|
||||
@@ -322,6 +323,8 @@ struct wpa_global {
|
||||
#endif /* CONFIG_WIFI_DISPLAY */
|
||||
|
||||
struct psk_list_entry *add_psk; /* From group formation */
|
||||
@@ -346,7 +345,7 @@
|
||||
};
|
||||
|
||||
|
||||
@@ -605,6 +608,7 @@ struct wpa_supplicant {
|
||||
@@ -708,6 +711,7 @@ struct wpa_supplicant {
|
||||
unsigned char own_addr[ETH_ALEN];
|
||||
unsigned char perm_addr[ETH_ALEN];
|
||||
char ifname[100];
|
||||
@@ -364,7 +363,7 @@
|
||||
|
||||
|
||||
#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
|
||||
@@ -392,6 +393,8 @@ static int wpa_supplicant_wps_cred(void
|
||||
@@ -393,6 +394,8 @@ static int wpa_supplicant_wps_cred(void
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
|
||||
cred->cred_attr, cred->cred_attr_len);
|
||||
|
||||
@@ -464,7 +463,7 @@
|
||||
|
||||
--- a/src/ap/dfs.c
|
||||
+++ b/src/ap/dfs.c
|
||||
@@ -1193,6 +1193,8 @@ int hostapd_dfs_radar_detected(struct ho
|
||||
@@ -1196,6 +1196,8 @@ int hostapd_dfs_radar_detected(struct ho
|
||||
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
|
||||
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
|
||||
|
||||
@@ -514,3 +513,43 @@
|
||||
struct os_reltime backlogged_until;
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
--- a/src/ap/wnm_ap.c
|
||||
+++ b/src/ap/wnm_ap.c
|
||||
@@ -442,7 +442,8 @@ static void ieee802_11_rx_bss_trans_mgmt
|
||||
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
|
||||
pos, end - pos);
|
||||
|
||||
- ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
|
||||
+ if (!hostapd_ubus_notify_bss_transition_query(hapd, addr, dialog_token, reason, pos, end - pos))
|
||||
+ ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
|
||||
}
|
||||
|
||||
|
||||
@@ -464,7 +465,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 = NULL;
|
||||
int enabled = hapd->conf->bss_transition;
|
||||
struct sta_info *sta;
|
||||
|
||||
@@ -511,6 +512,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,
|
||||
@@ -530,6 +532,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);
|
||||
}
|
||||
|
||||
@@ -408,15 +408,21 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
|
||||
void *airtime_table, *dfs_table;
|
||||
void *airtime_table, *dfs_table, *rrm_table, *wnm_table;
|
||||
struct os_reltime now;
|
||||
char ssid[SSID_MAX_LEN + 1];
|
||||
char phy_name[17];
|
||||
size_t ssid_len = SSID_MAX_LEN;
|
||||
u8 channel = 0, op_class = 0;
|
||||
|
||||
if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN)
|
||||
ssid_len = hapd->conf->ssid.ssid_len;
|
||||
|
||||
ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hostapd_get_oper_chwidth(hapd->iconf),
|
||||
&op_class, &channel);
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state));
|
||||
blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid));
|
||||
@@ -426,11 +432,25 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
blobmsg_add_string(&b, "ssid", ssid);
|
||||
|
||||
blobmsg_add_u32(&b, "freq", hapd->iface->freq);
|
||||
blobmsg_add_u32(&b, "channel", ieee80211_frequency_to_channel(hapd->iface->freq));
|
||||
blobmsg_add_u32(&b, "channel", channel);
|
||||
blobmsg_add_u32(&b, "op_class", op_class);
|
||||
blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
|
||||
|
||||
snprintf(phy_name, 17, "%s", hapd->iface->phy);
|
||||
blobmsg_add_string(&b, "phy", phy_name);
|
||||
|
||||
/* RRM */
|
||||
rrm_table = blobmsg_open_table(&b, "rrm");
|
||||
blobmsg_add_u64(&b, "neighbor_report_tx", hapd->openwrt_stats.rrm.neighbor_report_tx);
|
||||
blobmsg_close_table(&b, rrm_table);
|
||||
|
||||
/* WNM */
|
||||
wnm_table = blobmsg_open_table(&b, "wnm");
|
||||
blobmsg_add_u64(&b, "bss_transition_query_rx", hapd->openwrt_stats.wnm.bss_transition_query_rx);
|
||||
blobmsg_add_u64(&b, "bss_transition_request_tx", hapd->openwrt_stats.wnm.bss_transition_request_tx);
|
||||
blobmsg_add_u64(&b, "bss_transition_response_rx", hapd->openwrt_stats.wnm.bss_transition_response_rx);
|
||||
blobmsg_close_table(&b, wnm_table);
|
||||
|
||||
/* Airtime */
|
||||
airtime_table = blobmsg_open_table(&b, "airtime");
|
||||
blobmsg_add_u64(&b, "time", hapd->iface->last_channel_time);
|
||||
@@ -1309,6 +1329,136 @@ 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, u8 dialog_token,
|
||||
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,
|
||||
dialog_token, 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_DIALOG_TOKEN,
|
||||
__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 },
|
||||
[BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
|
||||
};
|
||||
|
||||
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];
|
||||
u32 dialog_token = 1;
|
||||
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]);
|
||||
|
||||
if (tb[BSS_TR_DIALOG_TOKEN])
|
||||
dialog_token = blobmsg_get_u32(tb[BSS_TR_DIALOG_TOKEN]);
|
||||
|
||||
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,
|
||||
dialog_token, tb[BSS_TR_NEIGHBORS]);
|
||||
}
|
||||
|
||||
enum {
|
||||
WNM_DISASSOC_ADDR,
|
||||
WNM_DISASSOC_DURATION,
|
||||
@@ -1331,14 +1481,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));
|
||||
|
||||
@@ -1348,61 +1494,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,
|
||||
1, tb[WNM_DISASSOC_NEIGHBORS]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1488,6 +1586,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
|
||||
};
|
||||
|
||||
@@ -1532,6 +1631,11 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd)
|
||||
struct ubus_object *obj = &hapd->ubus.obj;
|
||||
char *name = (char *) obj->name;
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (hapd->conf->mesh & MESH_ENABLED)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
@@ -1786,3 +1890,85 @@ void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequen
|
||||
ubus_notify(ctx, &hapd->ubus.obj, "radar-detected", b.head, -1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WNM_AP
|
||||
static void hostapd_ubus_notify_bss_transition_add_candidate_list(
|
||||
const u8 *candidate_list, u16 candidate_list_len)
|
||||
{
|
||||
char *cl_str;
|
||||
int i;
|
||||
|
||||
if (candidate_list_len == 0)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
|
||||
|
||||
ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int hostapd_ubus_notify_bss_transition_query(
|
||||
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
|
||||
const u8 *candidate_list, u16 candidate_list_len)
|
||||
{
|
||||
#ifdef CONFIG_WNM_AP
|
||||
struct ubus_event_req ureq = {};
|
||||
char *cl_str;
|
||||
u16 i;
|
||||
|
||||
if (!hapd->ubus.obj.has_subscribers)
|
||||
return 0;
|
||||
|
||||
if (!addr)
|
||||
return 0;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_macaddr(&b, "address", addr);
|
||||
blobmsg_add_u8(&b, "dialog-token", dialog_token);
|
||||
blobmsg_add_u8(&b, "reason", reason);
|
||||
hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
|
||||
|
||||
if (!hapd->ubus.notify_response) {
|
||||
ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ubus_notify_async(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, &ureq.nreq))
|
||||
return 0;
|
||||
|
||||
ureq.nreq.status_cb = ubus_event_cb;
|
||||
ubus_complete_request(ctx, &ureq.nreq.req, 100);
|
||||
|
||||
return ureq.resp;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -55,8 +55,15 @@ 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);
|
||||
int hostapd_ubus_notify_bss_transition_query(
|
||||
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
|
||||
const u8 *candidate_list, u16 candidate_list_len);
|
||||
|
||||
#else
|
||||
|
||||
@@ -107,6 +114,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)
|
||||
{
|
||||
}
|
||||
@@ -114,6 +128,13 @@ static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
|
||||
static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int hostapd_ubus_notify_bss_transition_query(
|
||||
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
|
||||
const u8 *candidate_list, u16 candidate_list_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user