hostapd: Add Operating Mode Notification support
Handle Operating Mode Notification received in (Re)Association Request frames. Signed-hostap: Marek Kwaczynski <marek.kwaczynski@tieto.com>
This commit is contained in:
		
							parent
							
								
									d9dd86be1d
								
							
						
					
					
						commit
						8a45811638
					
				
					 11 changed files with 64 additions and 3 deletions
				
			
		|  | @ -346,7 +346,7 @@ int hostapd_sta_add(struct hostapd_data *hapd, | |||
| 		    u16 listen_interval, | ||||
| 		    const struct ieee80211_ht_capabilities *ht_capab, | ||||
| 		    const struct ieee80211_vht_capabilities *vht_capab, | ||||
| 		    u32 flags, u8 qosinfo) | ||||
| 		    u32 flags, u8 qosinfo, u8 vht_opmode) | ||||
| { | ||||
| 	struct hostapd_sta_add_params params; | ||||
| 
 | ||||
|  | @ -364,6 +364,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, | |||
| 	params.listen_interval = listen_interval; | ||||
| 	params.ht_capabilities = ht_capab; | ||||
| 	params.vht_capabilities = vht_capab; | ||||
| 	params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED); | ||||
| 	params.vht_opmode = vht_opmode; | ||||
| 	params.flags = hostapd_sta_flags_to_drv(flags); | ||||
| 	params.qosinfo = qosinfo; | ||||
| 	return hapd->driver->sta_add(hapd->drv_priv, ¶ms); | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ int hostapd_sta_add(struct hostapd_data *hapd, | |||
| 		    u16 listen_interval, | ||||
| 		    const struct ieee80211_ht_capabilities *ht_capab, | ||||
| 		    const struct ieee80211_vht_capabilities *vht_capab, | ||||
| 		    u32 flags, u8 qosinfo); | ||||
| 		    u32 flags, u8 qosinfo, u8 vht_opmode); | ||||
| int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); | ||||
| int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, | ||||
| 			     size_t elem_len); | ||||
|  |  | |||
|  | @ -895,6 +895,11 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, | |||
| 				  elems.vht_capabilities_len); | ||||
| 	if (resp != WLAN_STATUS_SUCCESS) | ||||
| 		return resp; | ||||
| 
 | ||||
| 	resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif); | ||||
| 	if (resp != WLAN_STATUS_SUCCESS) | ||||
| 		return resp; | ||||
| 
 | ||||
| 	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && | ||||
| 	    !(sta->flags & WLAN_STA_VHT)) { | ||||
| 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, | ||||
|  | @ -1937,7 +1942,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, | |||
| 			    sta->listen_interval, | ||||
| 			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL, | ||||
| 			    sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, | ||||
| 			    sta->flags, sta->qosinfo)) { | ||||
| 			    sta->flags, sta->qosinfo, sta->vht_opmode)) { | ||||
| 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, | ||||
| 			       HOSTAPD_LEVEL_NOTICE, | ||||
| 			       "Could not add STA to kernel driver"); | ||||
|  |  | |||
|  | @ -61,6 +61,8 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, | |||
| void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); | ||||
| u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, | ||||
| 		       const u8 *vht_capab, size_t vht_capab_len); | ||||
| u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta, | ||||
| 		       const u8 *vht_opmode); | ||||
| void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, | ||||
| 		       const u8 *buf, size_t len, int ack); | ||||
| void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, | ||||
|  |  | |||
|  | @ -108,6 +108,35 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, | |||
| 	return WLAN_STATUS_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta, | ||||
| 		       const u8 *vht_oper_notif) | ||||
| { | ||||
| 	u8 channel_width; | ||||
| 
 | ||||
| 	if (!vht_oper_notif) { | ||||
| 		sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED; | ||||
| 		return WLAN_STATUS_SUCCESS; | ||||
| 	} | ||||
| 
 | ||||
| 	channel_width = *vht_oper_notif & VHT_OPMODE_CHANNEL_WIDTH_MASK; | ||||
| 
 | ||||
| 	if (channel_width != VHT_CHANWIDTH_USE_HT && | ||||
| 	    channel_width != VHT_CHANWIDTH_80MHZ && | ||||
| 	    channel_width != VHT_CHANWIDTH_160MHZ && | ||||
| 	    channel_width != VHT_CHANWIDTH_80P80MHZ && | ||||
| 	    ((*vht_oper_notif & VHT_OPMODE_CHANNEL_RxNSS_MASK) >> | ||||
| 	     VHT_OPMODE_NOTIF_RX_NSS_SHIFT) > VHT_RX_NSS_MAX_STREAMS - 1) { | ||||
| 		sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED; | ||||
| 		return WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||
| 	} | ||||
| 
 | ||||
| 	sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED; | ||||
| 	sta->vht_opmode = *vht_oper_notif; | ||||
| 	return WLAN_STATUS_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void hostapd_get_vht_capab(struct hostapd_data *hapd, | ||||
| 			   struct ieee80211_vht_capabilities *vht_cap, | ||||
| 			   struct ieee80211_vht_capabilities *neg_vht_cap) | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ | |||
| #define WLAN_STA_GAS BIT(17) | ||||
| #define WLAN_STA_VHT BIT(18) | ||||
| #define WLAN_STA_WNM_SLEEP_MODE BIT(19) | ||||
| #define WLAN_STA_VHT_OPMODE_ENABLED BIT(20) | ||||
| #define WLAN_STA_PENDING_DISASSOC_CB BIT(29) | ||||
| #define WLAN_STA_PENDING_DEAUTH_CB BIT(30) | ||||
| #define WLAN_STA_NONERP BIT(31) | ||||
|  | @ -103,6 +104,7 @@ struct sta_info { | |||
| 
 | ||||
| 	struct ieee80211_ht_capabilities *ht_capabilities; | ||||
| 	struct ieee80211_vht_capabilities *vht_capabilities; | ||||
| 	u8 vht_opmode; | ||||
| 
 | ||||
| #ifdef CONFIG_IEEE80211W | ||||
| 	int sa_query_count; /* number of pending SA Query requests;
 | ||||
|  |  | |||
|  | @ -252,6 +252,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, | |||
| 			elems->vht_operation = pos; | ||||
| 			elems->vht_operation_len = elen; | ||||
| 			break; | ||||
| 		case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: | ||||
| 			if (elen != 1) | ||||
| 				break; | ||||
| 			elems->vht_opmode_notif = pos; | ||||
| 			break; | ||||
| 		case WLAN_EID_LINK_ID: | ||||
| 			if (elen < 18) | ||||
| 				break; | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ struct ieee802_11_elems { | |||
| 	const u8 *ht_operation; | ||||
| 	const u8 *vht_capabilities; | ||||
| 	const u8 *vht_operation; | ||||
| 	const u8 *vht_opmode_notif; | ||||
| 	const u8 *vendor_ht_cap; | ||||
| 	const u8 *p2p; | ||||
| 	const u8 *wfd; | ||||
|  |  | |||
|  | @ -764,6 +764,13 @@ struct ieee80211_vht_operation { | |||
| #define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28)) | ||||
| #define VHT_CAP_TX_ANTENNA_PATTERN                  ((u32) BIT(29)) | ||||
| 
 | ||||
| #define VHT_OPMODE_CHANNEL_WIDTH_MASK		    ((u8) BIT(0) | BIT(1)) | ||||
| #define VHT_OPMODE_CHANNEL_RxNSS_MASK		    ((u8) BIT(4) | BIT(5) | \ | ||||
| 						     BIT(6)) | ||||
| #define VHT_OPMODE_NOTIF_RX_NSS_SHIFT		    4 | ||||
| 
 | ||||
| #define VHT_RX_NSS_MAX_STREAMS			    8 | ||||
| 
 | ||||
| /* VHT channel widths */ | ||||
| #define VHT_CHANWIDTH_USE_HT	0 | ||||
| #define VHT_CHANWIDTH_80MHZ	1 | ||||
|  |  | |||
|  | @ -1028,6 +1028,8 @@ struct hostapd_sta_add_params { | |||
| 	u16 listen_interval; | ||||
| 	const struct ieee80211_ht_capabilities *ht_capabilities; | ||||
| 	const struct ieee80211_vht_capabilities *vht_capabilities; | ||||
| 	int vht_opmode_enabled; | ||||
| 	u8 vht_opmode; | ||||
| 	u32 flags; /* bitmask of WPA_STA_* flags */ | ||||
| 	int set; /* Set STA parameters instead of add */ | ||||
| 	u8 qosinfo; | ||||
|  |  | |||
|  | @ -7351,6 +7351,12 @@ static int wpa_driver_nl80211_sta_add(void *priv, | |||
| 			params->vht_capabilities); | ||||
| 	} | ||||
| 
 | ||||
| 	if (params->vht_opmode_enabled) { | ||||
| 		wpa_printf(MSG_DEBUG, "  * opmode=%u", params->vht_opmode); | ||||
| 		NLA_PUT_U8(msg, NL80211_ATTR_OPMODE_NOTIF, | ||||
| 			   params->vht_opmode); | ||||
| 	} | ||||
| 
 | ||||
| 	wpa_printf(MSG_DEBUG, "  * capability=0x%x", params->capability); | ||||
| 	NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Marek Kwaczynski
						Marek Kwaczynski