mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	mac80211: support non-inheritance element
Subelement profile may specify element IDs it doesn't inherit from the management frame. Support it. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
		
							parent
							
								
									f7dacfb114
								
							
						
					
					
						commit
						671042a4fb
					
				
					 1 changed files with 77 additions and 57 deletions
				
			
		| 
						 | 
					@ -894,10 +894,10 @@ EXPORT_SYMBOL(ieee80211_queue_delayed_work);
 | 
				
			||||||
static u32
 | 
					static u32
 | 
				
			||||||
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 | 
					_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 | 
				
			||||||
			    struct ieee802_11_elems *elems,
 | 
								    struct ieee802_11_elems *elems,
 | 
				
			||||||
			    u64 filter, u32 crc, u8 *transmitter_bssid,
 | 
								    u64 filter, u32 crc,
 | 
				
			||||||
			    u8 *bss_bssid)
 | 
								    const struct element *check_inherit)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct element *elem, *sub;
 | 
						const struct element *elem;
 | 
				
			||||||
	bool calc_crc = filter != 0;
 | 
						bool calc_crc = filter != 0;
 | 
				
			||||||
	DECLARE_BITMAP(seen_elems, 256);
 | 
						DECLARE_BITMAP(seen_elems, 256);
 | 
				
			||||||
	const u8 *ie;
 | 
						const u8 *ie;
 | 
				
			||||||
| 
						 | 
					@ -910,6 +910,11 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 | 
				
			||||||
		u8 elen = elem->datalen;
 | 
							u8 elen = elem->datalen;
 | 
				
			||||||
		const u8 *pos = elem->data;
 | 
							const u8 *pos = elem->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (check_inherit &&
 | 
				
			||||||
 | 
							    !cfg80211_is_element_inherited(elem,
 | 
				
			||||||
 | 
											   check_inherit))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (id) {
 | 
							switch (id) {
 | 
				
			||||||
		case WLAN_EID_SSID:
 | 
							case WLAN_EID_SSID:
 | 
				
			||||||
		case WLAN_EID_SUPP_RATES:
 | 
							case WLAN_EID_SUPP_RATES:
 | 
				
			||||||
| 
						 | 
					@ -1208,57 +1213,6 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 | 
				
			||||||
			if (elen >= sizeof(*elems->max_idle_period_ie))
 | 
								if (elen >= sizeof(*elems->max_idle_period_ie))
 | 
				
			||||||
				elems->max_idle_period_ie = (void *)pos;
 | 
									elems->max_idle_period_ie = (void *)pos;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case WLAN_EID_MULTIPLE_BSSID:
 | 
					 | 
				
			||||||
			if (!bss_bssid || !transmitter_bssid || elen < 4)
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			elems->max_bssid_indicator = pos[0];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for_each_element(sub, pos + 1, elen - 1) {
 | 
					 | 
				
			||||||
				u8 sub_len = sub->datalen;
 | 
					 | 
				
			||||||
				u8 new_bssid[ETH_ALEN];
 | 
					 | 
				
			||||||
				const u8 *index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/*
 | 
					 | 
				
			||||||
				 * we only expect the "non-transmitted BSSID
 | 
					 | 
				
			||||||
				 * profile" subelement (subelement id 0)
 | 
					 | 
				
			||||||
				 */
 | 
					 | 
				
			||||||
				if (sub->id != 0 || sub->datalen < 4) {
 | 
					 | 
				
			||||||
					/* not a valid BSS profile */
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
 | 
					 | 
				
			||||||
				    sub->data[1] != 2) {
 | 
					 | 
				
			||||||
					/* The first element of the
 | 
					 | 
				
			||||||
					 * Nontransmitted BSSID Profile is not
 | 
					 | 
				
			||||||
					 * the Nontransmitted BSSID Capability
 | 
					 | 
				
			||||||
					 * element.
 | 
					 | 
				
			||||||
					 */
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* found a Nontransmitted BSSID Profile */
 | 
					 | 
				
			||||||
				index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
 | 
					 | 
				
			||||||
							 sub->data, sub_len);
 | 
					 | 
				
			||||||
				if (!index || index[1] < 1 || index[2] == 0) {
 | 
					 | 
				
			||||||
					/* Invalid MBSSID Index element */
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				cfg80211_gen_new_bssid(transmitter_bssid,
 | 
					 | 
				
			||||||
						       pos[0],
 | 
					 | 
				
			||||||
						       index[2],
 | 
					 | 
				
			||||||
						       new_bssid);
 | 
					 | 
				
			||||||
				if (ether_addr_equal(new_bssid, bss_bssid)) {
 | 
					 | 
				
			||||||
					elems->nontransmitted_bssid_profile =
 | 
					 | 
				
			||||||
						(void *)sub;
 | 
					 | 
				
			||||||
					elems->bssid_index_len = index[1];
 | 
					 | 
				
			||||||
					elems->bssid_index = (void *)&index[2];
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case WLAN_EID_EXTENSION:
 | 
							case WLAN_EID_EXTENSION:
 | 
				
			||||||
			if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
 | 
								if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
 | 
				
			||||||
			    elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
 | 
								    elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
 | 
				
			||||||
| 
						 | 
					@ -1300,25 +1254,91 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 | 
				
			||||||
	return crc;
 | 
						return crc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ieee802_11_find_bssid_profile(const u8 *start, size_t len,
 | 
				
			||||||
 | 
										  struct ieee802_11_elems *elems,
 | 
				
			||||||
 | 
										  u8 *transmitter_bssid,
 | 
				
			||||||
 | 
										  u8 *bss_bssid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct element *elem, *sub;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!bss_bssid || !transmitter_bssid)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
 | 
				
			||||||
 | 
							if (elem->datalen < 2)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for_each_element(sub, elem->data + 1, elem->datalen - 1) {
 | 
				
			||||||
 | 
								u8 new_bssid[ETH_ALEN];
 | 
				
			||||||
 | 
								const u8 *index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (sub->id != 0 || sub->datalen < 4) {
 | 
				
			||||||
 | 
									/* not a valid BSS profile */
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
 | 
				
			||||||
 | 
								    sub->data[1] != 2) {
 | 
				
			||||||
 | 
									/* The first element of the
 | 
				
			||||||
 | 
									 * Nontransmitted BSSID Profile is not
 | 
				
			||||||
 | 
									 * the Nontransmitted BSSID Capability
 | 
				
			||||||
 | 
									 * element.
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* found a Nontransmitted BSSID Profile */
 | 
				
			||||||
 | 
								index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
 | 
				
			||||||
 | 
											 sub->data, sub->datalen);
 | 
				
			||||||
 | 
								if (!index || index[1] < 1 || index[2] == 0) {
 | 
				
			||||||
 | 
									/* Invalid MBSSID Index element */
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								cfg80211_gen_new_bssid(transmitter_bssid,
 | 
				
			||||||
 | 
										       elem->data[0],
 | 
				
			||||||
 | 
										       index[2],
 | 
				
			||||||
 | 
										       new_bssid);
 | 
				
			||||||
 | 
								if (ether_addr_equal(new_bssid, bss_bssid)) {
 | 
				
			||||||
 | 
									elems->nontransmitted_bssid_profile =
 | 
				
			||||||
 | 
										elem->data;
 | 
				
			||||||
 | 
									elems->bssid_index_len = index[1];
 | 
				
			||||||
 | 
									elems->bssid_index = (void *)&index[2];
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 | 
					u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 | 
				
			||||||
			       struct ieee802_11_elems *elems,
 | 
								       struct ieee802_11_elems *elems,
 | 
				
			||||||
			       u64 filter, u32 crc, u8 *transmitter_bssid,
 | 
								       u64 filter, u32 crc, u8 *transmitter_bssid,
 | 
				
			||||||
			       u8 *bss_bssid)
 | 
								       u8 *bss_bssid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						const struct element *non_inherit = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(elems, 0, sizeof(*elems));
 | 
						memset(elems, 0, sizeof(*elems));
 | 
				
			||||||
	elems->ie_start = start;
 | 
						elems->ie_start = start;
 | 
				
			||||||
	elems->total_len = len;
 | 
						elems->total_len = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ieee802_11_find_bssid_profile(start, len, elems, transmitter_bssid,
 | 
				
			||||||
 | 
									      bss_bssid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (elems->nontransmitted_bssid_profile)
 | 
				
			||||||
 | 
							non_inherit =
 | 
				
			||||||
 | 
								cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
 | 
				
			||||||
 | 
										       &elems->nontransmitted_bssid_profile[2],
 | 
				
			||||||
 | 
										       elems->nontransmitted_bssid_profile[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
 | 
						crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
 | 
				
			||||||
					  crc, transmitter_bssid, bss_bssid);
 | 
										  crc, non_inherit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Override with nontransmitted profile, if found */
 | 
						/* Override with nontransmitted profile, if found */
 | 
				
			||||||
	if (transmitter_bssid && elems->nontransmitted_bssid_profile) {
 | 
						if (transmitter_bssid && elems->nontransmitted_bssid_profile) {
 | 
				
			||||||
		const u8 *profile = elems->nontransmitted_bssid_profile;
 | 
							const u8 *profile = elems->nontransmitted_bssid_profile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_ieee802_11_parse_elems_crc(&profile[2], profile[1],
 | 
							_ieee802_11_parse_elems_crc(&profile[2], profile[1],
 | 
				
			||||||
					    action, elems, 0, 0,
 | 
										    action, elems, 0, 0, NULL);
 | 
				
			||||||
					    transmitter_bssid, bss_bssid);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (elems->tim && !elems->parse_error) {
 | 
						if (elems->tim && !elems->parse_error) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue