mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-31 10:28:06 +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 { |  enum hostapd_chan_status { | ||||||
| @@ -154,6 +155,7 @@ struct hostapd_data { | @@ -171,6 +172,7 @@ struct hostapd_data { | ||||||
|  	struct hostapd_iface *iface; |  	struct hostapd_iface *iface; | ||||||
|  	struct hostapd_config *iconf; |  	struct hostapd_config *iconf; | ||||||
|  	struct hostapd_bss_config *conf; |  	struct hostapd_bss_config *conf; | ||||||
| @@ -39,7 +39,7 @@ | |||||||
|  	int interface_added; /* virtual interface added for this BSS */ |  	int interface_added; /* virtual interface added for this BSS */ | ||||||
|  	unsigned int started:1; |  	unsigned int started:1; | ||||||
|  	unsigned int disabled: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); |  		       struct hostapd_bss_config *bss); | ||||||
|  int hostapd_setup_interface(struct hostapd_iface *iface); |  int hostapd_setup_interface(struct hostapd_iface *iface); | ||||||
|  int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); |  int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); | ||||||
| @@ -126,7 +126,7 @@ | |||||||
|  	if (res == HOSTAPD_ACL_PENDING) |  	if (res == HOSTAPD_ACL_PENDING) | ||||||
|  		return; |  		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; |  	int resp = WLAN_STATUS_SUCCESS; | ||||||
|  	u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE; |  	u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||||
|  	const u8 *pos; |  	const u8 *pos; | ||||||
| @@ -135,7 +135,7 @@ | |||||||
|  	struct sta_info *sta; |  	struct sta_info *sta; | ||||||
|  	u8 *tmp = NULL; |  	u8 *tmp = NULL; | ||||||
|  #ifdef CONFIG_FILS |  #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; |  		left = res; | ||||||
|  	} |  	} | ||||||
|  #endif /* CONFIG_FILS */ |  #endif /* CONFIG_FILS */ | ||||||
| @@ -147,9 +147,9 @@ | |||||||
|   |   | ||||||
|  	/* followed by SSID and Supported rates; and HT capabilities if 802.11n |  	/* followed by SSID and Supported rates; and HT capabilities if 802.11n | ||||||
|  	 * is used */ |  	 * is used */ | ||||||
| @@ -5831,6 +5848,14 @@ static void handle_assoc(struct hostapd_ | @@ -5758,6 +5775,13 @@ static void handle_assoc(struct hostapd_ | ||||||
|  					    pos, left, rssi, omit_rsnxe); |  	} | ||||||
|  	os_free(tmp); |  #endif /* CONFIG_FILS */ | ||||||
|   |   | ||||||
| +	ubus_resp = hostapd_ubus_handle_event(hapd, &req); | +	ubus_resp = hostapd_ubus_handle_event(hapd, &req); | ||||||
| +	if (ubus_resp) { | +	if (ubus_resp) { | ||||||
| @@ -158,11 +158,10 @@ | |||||||
| +		resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE; | +		resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||||
| +		goto fail; | +		goto fail; | ||||||
| +	} | +	} | ||||||
| + |   fail: | ||||||
|  |   | ||||||
|  	/* |  	/* | ||||||
|  	 * Remove the station in case transmission of a success response fails | @@ -5851,6 +5875,7 @@ static void handle_disassoc(struct hosta | ||||||
|  	 * (the STA was added associated to the driver) or if the station was |  | ||||||
| @@ -5858,6 +5883,7 @@ static void handle_disassoc(struct hosta |  | ||||||
|  	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", |  	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", | ||||||
|  		   MAC2STR(mgmt->sa), |  		   MAC2STR(mgmt->sa), | ||||||
|  		   le_to_host16(mgmt->u.disassoc.reason_code)); |  		   le_to_host16(mgmt->u.disassoc.reason_code)); | ||||||
| @@ -170,7 +169,7 @@ | |||||||
|   |   | ||||||
|  	sta = ap_get_sta(hapd, mgmt->sa); |  	sta = ap_get_sta(hapd, mgmt->sa); | ||||||
|  	if (sta == NULL) { |  	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 */ |  	/* Clear the PTKSA cache entries for PASN */ | ||||||
|  	ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE); |  	ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE); | ||||||
|   |   | ||||||
| @@ -181,7 +180,7 @@ | |||||||
|  		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " |  		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " | ||||||
| --- a/src/ap/beacon.c | --- a/src/ap/beacon.c | ||||||
| +++ b/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]; |  	u16 csa_offs[2]; | ||||||
|  	size_t csa_offs_len; |  	size_t csa_offs_len; | ||||||
|  	struct radius_sta rad_info; |  	struct radius_sta rad_info; | ||||||
| @@ -194,7 +193,7 @@ | |||||||
|   |   | ||||||
|  	if (hapd->iconf->rssi_ignore_probe_request && ssi_signal && |  	if (hapd->iconf->rssi_ignore_probe_request && ssi_signal && | ||||||
|  	    ssi_signal < hapd->iconf->rssi_ignore_probe_request) |  	    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 */ |  #endif /* CONFIG_P2P */ | ||||||
|   |   | ||||||
| @@ -235,22 +234,22 @@ | |||||||
|  		wpabuf_free(sta->p2p_ie); |  		wpabuf_free(sta->p2p_ie); | ||||||
| --- a/src/ap/sta_info.c | --- a/src/ap/sta_info.c | ||||||
| +++ b/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 " |  			       HOSTAPD_LEVEL_INFO, "deauthenticated due to " | ||||||
|  			       "local deauth request"); |  			       "local deauth request"); | ||||||
|  		ap_free_sta(hapd, sta); |  | ||||||
| +		hostapd_ubus_notify(hapd, "local-deauth", sta->addr); | +		hostapd_ubus_notify(hapd, "local-deauth", sta->addr); | ||||||
|  |  		ap_free_sta(hapd, sta); | ||||||
|  		return; |  		return; | ||||||
|  	} |  	} | ||||||
|   | @@ -613,6 +614,7 @@ skip_poll: | ||||||
| @@ -614,6 +615,7 @@ skip_poll: |  		mlme_deauthenticate_indication( | ||||||
|  			hapd, sta, |  			hapd, sta, | ||||||
|  			WLAN_REASON_PREV_AUTH_NOT_VALID); |  			WLAN_REASON_PREV_AUTH_NOT_VALID); | ||||||
|  		ap_free_sta(hapd, sta); |  | ||||||
| +		hostapd_ubus_notify(hapd, "inactive-deauth", sta->addr); | +		hostapd_ubus_notify(hapd, "inactive-deauth", sta->addr); | ||||||
|  |  		ap_free_sta(hapd, sta); | ||||||
|  		break; |  		break; | ||||||
|  	} |  	} | ||||||
|  } |  | ||||||
| @@ -1329,6 +1331,7 @@ void ap_sta_set_authorized(struct hostap | @@ -1329,6 +1331,7 @@ void ap_sta_set_authorized(struct hostap | ||||||
|  					  buf, ip_addr, keyid_buf); |  					  buf, ip_addr, keyid_buf); | ||||||
|  	} else { |  	} else { | ||||||
| @@ -284,7 +283,7 @@ | |||||||
|  ifdef CONFIG_CODE_COVERAGE |  ifdef CONFIG_CODE_COVERAGE | ||||||
|  CFLAGS += -O0 -fprofile-arcs -ftest-coverage |  CFLAGS += -O0 -fprofile-arcs -ftest-coverage | ||||||
|  LIBS += -lgcov |  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 |  CFLAGS += -DCONFIG_CTRL_IFACE_MIB | ||||||
|  endif |  endif | ||||||
|  OBJS += ../src/ap/ctrl_iface_ap.o |  OBJS += ../src/ap/ctrl_iface_ap.o | ||||||
| @@ -296,7 +295,7 @@ | |||||||
|  CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY |  CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY | ||||||
| --- a/wpa_supplicant/wpa_supplicant.c | --- a/wpa_supplicant/wpa_supplicant.c | ||||||
| +++ b/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 */ |  #endif /* CONFIG_P2P */ | ||||||
|   |   | ||||||
| @@ -305,7 +304,7 @@ | |||||||
|  	return wpa_s; |  	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; |  	struct wpa_supplicant *parent = wpa_s->parent; | ||||||
|  #endif /* CONFIG_MESH */ |  #endif /* CONFIG_MESH */ | ||||||
|   |   | ||||||
| @@ -314,7 +313,7 @@ | |||||||
|  	/* Remove interface from the global list of interfaces */ |  	/* Remove interface from the global list of interfaces */ | ||||||
|  	prev = global->ifaces; |  	prev = global->ifaces; | ||||||
|  	if (prev == wpa_s) { |  	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_terminate(wpa_supplicant_terminate, global); | ||||||
|  	eloop_register_signal_reconfig(wpa_supplicant_reconfig, 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_version; | ||||||
|  extern const char *const wpa_supplicant_license; |  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 */ |  #endif /* CONFIG_WIFI_DISPLAY */ | ||||||
|   |   | ||||||
|  	struct psk_list_entry *add_psk; /* From group formation */ |  	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 own_addr[ETH_ALEN]; | ||||||
|  	unsigned char perm_addr[ETH_ALEN]; |  	unsigned char perm_addr[ETH_ALEN]; | ||||||
|  	char ifname[100]; |  	char ifname[100]; | ||||||
| @@ -364,7 +363,7 @@ | |||||||
|   |   | ||||||
|   |   | ||||||
|  #ifndef WPS_PIN_SCAN_IGNORE_SEL_REG |  #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", |  	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", | ||||||
|  			cred->cred_attr, cred->cred_attr_len); |  			cred->cred_attr, cred->cred_attr_len); | ||||||
|   |   | ||||||
| @@ -464,7 +463,7 @@ | |||||||
|   |   | ||||||
| --- a/src/ap/dfs.c | --- a/src/ap/dfs.c | ||||||
| +++ b/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=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", | ||||||
|  		freq, ht_enabled, chan_offset, chan_width, cf1, cf2); |  		freq, ht_enabled, chan_offset, chan_width, cf1, cf2); | ||||||
|   |   | ||||||
| @@ -514,3 +513,43 @@ | |||||||
|  	struct os_reltime backlogged_until; |  	struct os_reltime backlogged_until; | ||||||
|  #endif /* CONFIG_AIRTIME_POLICY */ |  #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 blob_attr *msg) | ||||||
| { | { | ||||||
| 	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); | 	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; | 	struct os_reltime now; | ||||||
| 	char ssid[SSID_MAX_LEN + 1]; | 	char ssid[SSID_MAX_LEN + 1]; | ||||||
| 	char phy_name[17]; | 	char phy_name[17]; | ||||||
| 	size_t ssid_len = SSID_MAX_LEN; | 	size_t ssid_len = SSID_MAX_LEN; | ||||||
|  | 	u8 channel = 0, op_class = 0; | ||||||
|  |  | ||||||
| 	if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN) | 	if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN) | ||||||
| 		ssid_len = hapd->conf->ssid.ssid_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); | 	blob_buf_init(&b, 0); | ||||||
| 	blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state)); | 	blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state)); | ||||||
| 	blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid)); | 	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_string(&b, "ssid", ssid); | ||||||
|  |  | ||||||
| 	blobmsg_add_u32(&b, "freq", hapd->iface->freq); | 	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); | 	snprintf(phy_name, 17, "%s", hapd->iface->phy); | ||||||
| 	blobmsg_add_string(&b, "phy", phy_name); | 	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 */ | ||||||
| 	airtime_table = blobmsg_open_table(&b, "airtime"); | 	airtime_table = blobmsg_open_table(&b, "airtime"); | ||||||
| 	blobmsg_add_u64(&b, "time", hapd->iface->last_channel_time); | 	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 | #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 { | enum { | ||||||
| 	WNM_DISASSOC_ADDR, | 	WNM_DISASSOC_ADDR, | ||||||
| 	WNM_DISASSOC_DURATION, | 	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 hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); | ||||||
| 	struct blob_attr *tb[__WNM_DISASSOC_MAX]; | 	struct blob_attr *tb[__WNM_DISASSOC_MAX]; | ||||||
| 	struct blob_attr *cur; |  | ||||||
| 	struct sta_info *sta; | 	struct sta_info *sta; | ||||||
| 	int duration = 10; | 	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]; | 	u8 addr[ETH_ALEN]; | ||||||
|  | 	bool abridged; | ||||||
|  |  | ||||||
| 	blobmsg_parse(wnm_disassoc_policy, __WNM_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg)); | 	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)) | 	if (hwaddr_aton(blobmsg_data(tb[WNM_DISASSOC_ADDR]), addr)) | ||||||
| 		return UBUS_STATUS_INVALID_ARGUMENT; | 		return UBUS_STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| 	if ((cur = tb[WNM_DISASSOC_DURATION]) != NULL) | 	if (tb[WNM_DISASSOC_DURATION]) | ||||||
| 		duration = blobmsg_get_u32(cur); | 		duration = blobmsg_get_u32(tb[WNM_DISASSOC_DURATION]); | ||||||
|  |  | ||||||
| 	sta = ap_get_sta(hapd, addr); | 	abridged = !!(tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED])); | ||||||
| 	if (!sta) |  | ||||||
| 		return UBUS_STATUS_NOT_FOUND; |  | ||||||
|  |  | ||||||
| 	if (tb[WNM_DISASSOC_NEIGHBORS]) { | 	return hostapd_bss_tr_send(hapd, addr, true, abridged, duration, duration, | ||||||
| 		u8 *nr_cur; | 				   1, tb[WNM_DISASSOC_NEIGHBORS]); | ||||||
|  |  | ||||||
| 		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; |  | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -1488,6 +1586,7 @@ static const struct ubus_method bss_methods[] = { | |||||||
| 	UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy), | 	UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy), | ||||||
| #ifdef CONFIG_WNM_AP | #ifdef CONFIG_WNM_AP | ||||||
| 	UBUS_METHOD("wnm_disassoc_imminent", hostapd_wnm_disassoc_imminent, wnm_disassoc_policy), | 	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 | #endif | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -1532,6 +1631,11 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd) | |||||||
| 	struct ubus_object *obj = &hapd->ubus.obj; | 	struct ubus_object *obj = &hapd->ubus.obj; | ||||||
| 	char *name = (char *) obj->name; | 	char *name = (char *) obj->name; | ||||||
|  |  | ||||||
|  | #ifdef CONFIG_MESH | ||||||
|  | 	if (hapd->conf->mesh & MESH_ENABLED) | ||||||
|  | 		return; | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	if (!ctx) | 	if (!ctx) | ||||||
| 		return; | 		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); | 		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, | void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency, | ||||||
| 					int chan_width, int cf1, int cf2); | 					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_add(struct hapd_interfaces *interfaces); | ||||||
| void hostapd_ubus_free(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 | #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) | 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 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 | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 John Crispin
					John Crispin