cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ie.c (14572B)


      1/*
      2 * NXP Wireless LAN device driver: management IE handling- setting and
      3 * deleting IE.
      4 *
      5 * Copyright 2011-2020 NXP
      6 *
      7 * This software file (the "File") is distributed by NXP
      8 * under the terms of the GNU General Public License Version 2, June 1991
      9 * (the "License").  You may use, redistribute and/or modify this File in
     10 * accordance with the terms and conditions of the License, a copy of which
     11 * is available by writing to the Free Software Foundation, Inc.,
     12 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
     13 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
     14 *
     15 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
     16 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
     17 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
     18 * this warranty disclaimer.
     19 */
     20
     21#include "main.h"
     22
     23/* This function checks if current IE index is used by any on other interface.
     24 * Return: -1: yes, current IE index is used by someone else.
     25 *          0: no, current IE index is NOT used by other interface.
     26 */
     27static int
     28mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx)
     29{
     30	int i;
     31	struct mwifiex_adapter *adapter = priv->adapter;
     32	struct mwifiex_ie *ie;
     33
     34	for (i = 0; i < adapter->priv_num; i++) {
     35		if (adapter->priv[i] != priv) {
     36			ie = &adapter->priv[i]->mgmt_ie[idx];
     37			if (ie->mgmt_subtype_mask && ie->ie_length)
     38				return -1;
     39		}
     40	}
     41
     42	return 0;
     43}
     44
     45/* Get unused IE index. This index will be used for setting new IE */
     46static int
     47mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask,
     48		       struct mwifiex_ie *ie, u16 *index)
     49{
     50	u16 mask, len, i;
     51
     52	for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) {
     53		mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask);
     54		len = le16_to_cpu(ie->ie_length);
     55
     56		if (mask == MWIFIEX_AUTO_IDX_MASK)
     57			continue;
     58
     59		if (mask == subtype_mask) {
     60			if (len > IEEE_MAX_IE_SIZE)
     61				continue;
     62
     63			*index = i;
     64			return 0;
     65		}
     66
     67		if (!priv->mgmt_ie[i].ie_length) {
     68			if (mwifiex_ie_index_used_by_other_intf(priv, i))
     69				continue;
     70
     71			*index = i;
     72			return 0;
     73		}
     74	}
     75
     76	return -1;
     77}
     78
     79/* This function prepares IE data buffer for command to be sent to FW */
     80static int
     81mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
     82			     struct mwifiex_ie_list *ie_list)
     83{
     84	u16 travel_len, index, mask;
     85	s16 input_len, tlv_len;
     86	struct mwifiex_ie *ie;
     87	u8 *tmp;
     88
     89	input_len = le16_to_cpu(ie_list->len);
     90	travel_len = sizeof(struct mwifiex_ie_types_header);
     91
     92	ie_list->len = 0;
     93
     94	while (input_len >= sizeof(struct mwifiex_ie_types_header)) {
     95		ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len);
     96		tlv_len = le16_to_cpu(ie->ie_length);
     97		travel_len += tlv_len + MWIFIEX_IE_HDR_SIZE;
     98
     99		if (input_len < tlv_len + MWIFIEX_IE_HDR_SIZE)
    100			return -1;
    101		index = le16_to_cpu(ie->ie_index);
    102		mask = le16_to_cpu(ie->mgmt_subtype_mask);
    103
    104		if (index == MWIFIEX_AUTO_IDX_MASK) {
    105			/* automatic addition */
    106			if (mwifiex_ie_get_autoidx(priv, mask, ie, &index))
    107				return -1;
    108			if (index == MWIFIEX_AUTO_IDX_MASK)
    109				return -1;
    110
    111			tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer;
    112			memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length));
    113			priv->mgmt_ie[index].ie_length = ie->ie_length;
    114			priv->mgmt_ie[index].ie_index = cpu_to_le16(index);
    115			priv->mgmt_ie[index].mgmt_subtype_mask =
    116							cpu_to_le16(mask);
    117
    118			ie->ie_index = cpu_to_le16(index);
    119		} else {
    120			if (mask != MWIFIEX_DELETE_MASK)
    121				return -1;
    122			/*
    123			 * Check if this index is being used on any
    124			 * other interface.
    125			 */
    126			if (mwifiex_ie_index_used_by_other_intf(priv, index))
    127				return -1;
    128
    129			ie->ie_length = 0;
    130			memcpy(&priv->mgmt_ie[index], ie,
    131			       sizeof(struct mwifiex_ie));
    132		}
    133
    134		le16_unaligned_add_cpu(&ie_list->len,
    135				       le16_to_cpu(
    136					    priv->mgmt_ie[index].ie_length) +
    137				       MWIFIEX_IE_HDR_SIZE);
    138		input_len -= tlv_len + MWIFIEX_IE_HDR_SIZE;
    139	}
    140
    141	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
    142		return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
    143					HostCmd_ACT_GEN_SET,
    144					UAP_CUSTOM_IE_I, ie_list, true);
    145
    146	return 0;
    147}
    148
    149/* Copy individual custom IEs for beacon, probe response and assoc response
    150 * and prepare single structure for IE setting.
    151 * This function also updates allocated IE indices from driver.
    152 */
    153static int
    154mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
    155			     struct mwifiex_ie *beacon_ie, u16 *beacon_idx,
    156			     struct mwifiex_ie *pr_ie, u16 *probe_idx,
    157			     struct mwifiex_ie *ar_ie, u16 *assoc_idx)
    158{
    159	struct mwifiex_ie_list *ap_custom_ie;
    160	u8 *pos;
    161	u16 len;
    162	int ret;
    163
    164	ap_custom_ie = kzalloc(sizeof(*ap_custom_ie), GFP_KERNEL);
    165	if (!ap_custom_ie)
    166		return -ENOMEM;
    167
    168	ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
    169	pos = (u8 *)ap_custom_ie->ie_list;
    170
    171	if (beacon_ie) {
    172		len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
    173		      le16_to_cpu(beacon_ie->ie_length);
    174		memcpy(pos, beacon_ie, len);
    175		pos += len;
    176		le16_unaligned_add_cpu(&ap_custom_ie->len, len);
    177	}
    178	if (pr_ie) {
    179		len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
    180		      le16_to_cpu(pr_ie->ie_length);
    181		memcpy(pos, pr_ie, len);
    182		pos += len;
    183		le16_unaligned_add_cpu(&ap_custom_ie->len, len);
    184	}
    185	if (ar_ie) {
    186		len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
    187		      le16_to_cpu(ar_ie->ie_length);
    188		memcpy(pos, ar_ie, len);
    189		pos += len;
    190		le16_unaligned_add_cpu(&ap_custom_ie->len, len);
    191	}
    192
    193	ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie);
    194
    195	pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index);
    196	if (beacon_ie && *beacon_idx == MWIFIEX_AUTO_IDX_MASK) {
    197		/* save beacon ie index after auto-indexing */
    198		*beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index);
    199		len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE +
    200		      le16_to_cpu(beacon_ie->ie_length);
    201		pos += len;
    202	}
    203	if (pr_ie && le16_to_cpu(pr_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) {
    204		/* save probe resp ie index after auto-indexing */
    205		*probe_idx = *((u16 *)pos);
    206		len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE +
    207		      le16_to_cpu(pr_ie->ie_length);
    208		pos += len;
    209	}
    210	if (ar_ie && le16_to_cpu(ar_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK)
    211		/* save assoc resp ie index after auto-indexing */
    212		*assoc_idx = *((u16 *)pos);
    213
    214	kfree(ap_custom_ie);
    215	return ret;
    216}
    217
    218/* This function checks if the vendor specified IE is present in passed buffer
    219 * and copies it to mwifiex_ie structure.
    220 * Function takes pointer to struct mwifiex_ie pointer as argument.
    221 * If the vendor specified IE is present then memory is allocated for
    222 * mwifiex_ie pointer and filled in with IE. Caller should take care of freeing
    223 * this memory.
    224 */
    225static int mwifiex_update_vs_ie(const u8 *ies, int ies_len,
    226				struct mwifiex_ie **ie_ptr, u16 mask,
    227				unsigned int oui, u8 oui_type)
    228{
    229	struct ieee_types_header *vs_ie;
    230	struct mwifiex_ie *ie = *ie_ptr;
    231	const u8 *vendor_ie;
    232
    233	vendor_ie = cfg80211_find_vendor_ie(oui, oui_type, ies, ies_len);
    234	if (vendor_ie) {
    235		if (!*ie_ptr) {
    236			*ie_ptr = kzalloc(sizeof(struct mwifiex_ie),
    237					  GFP_KERNEL);
    238			if (!*ie_ptr)
    239				return -ENOMEM;
    240			ie = *ie_ptr;
    241		}
    242
    243		vs_ie = (struct ieee_types_header *)vendor_ie;
    244		if (le16_to_cpu(ie->ie_length) + vs_ie->len + 2 >
    245			IEEE_MAX_IE_SIZE)
    246			return -EINVAL;
    247		memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length),
    248		       vs_ie, vs_ie->len + 2);
    249		le16_unaligned_add_cpu(&ie->ie_length, vs_ie->len + 2);
    250		ie->mgmt_subtype_mask = cpu_to_le16(mask);
    251		ie->ie_index = cpu_to_le16(MWIFIEX_AUTO_IDX_MASK);
    252	}
    253
    254	*ie_ptr = ie;
    255	return 0;
    256}
    257
    258/* This function parses beacon IEs, probe response IEs, association response IEs
    259 * from cfg80211_ap_settings->beacon and sets these IE to FW.
    260 */
    261static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private *priv,
    262					    struct cfg80211_beacon_data *data)
    263{
    264	struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL, *ar_ie = NULL;
    265	u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
    266	u16 ar_idx = MWIFIEX_AUTO_IDX_MASK;
    267	int ret = 0;
    268
    269	if (data->beacon_ies && data->beacon_ies_len) {
    270		mwifiex_update_vs_ie(data->beacon_ies, data->beacon_ies_len,
    271				     &beacon_ie, MGMT_MASK_BEACON,
    272				     WLAN_OUI_MICROSOFT,
    273				     WLAN_OUI_TYPE_MICROSOFT_WPS);
    274		mwifiex_update_vs_ie(data->beacon_ies, data->beacon_ies_len,
    275				     &beacon_ie, MGMT_MASK_BEACON,
    276				     WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P);
    277	}
    278
    279	if (data->proberesp_ies && data->proberesp_ies_len) {
    280		mwifiex_update_vs_ie(data->proberesp_ies,
    281				     data->proberesp_ies_len, &pr_ie,
    282				     MGMT_MASK_PROBE_RESP, WLAN_OUI_MICROSOFT,
    283				     WLAN_OUI_TYPE_MICROSOFT_WPS);
    284		mwifiex_update_vs_ie(data->proberesp_ies,
    285				     data->proberesp_ies_len, &pr_ie,
    286				     MGMT_MASK_PROBE_RESP,
    287				     WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P);
    288	}
    289
    290	if (data->assocresp_ies && data->assocresp_ies_len) {
    291		mwifiex_update_vs_ie(data->assocresp_ies,
    292				     data->assocresp_ies_len, &ar_ie,
    293				     MGMT_MASK_ASSOC_RESP |
    294				     MGMT_MASK_REASSOC_RESP,
    295				     WLAN_OUI_MICROSOFT,
    296				     WLAN_OUI_TYPE_MICROSOFT_WPS);
    297		mwifiex_update_vs_ie(data->assocresp_ies,
    298				     data->assocresp_ies_len, &ar_ie,
    299				     MGMT_MASK_ASSOC_RESP |
    300				     MGMT_MASK_REASSOC_RESP, WLAN_OUI_WFA,
    301				     WLAN_OUI_TYPE_WFA_P2P);
    302	}
    303
    304	if (beacon_ie || pr_ie || ar_ie) {
    305		ret = mwifiex_update_uap_custom_ie(priv, beacon_ie,
    306						   &beacon_idx, pr_ie,
    307						   &pr_idx, ar_ie, &ar_idx);
    308		if (ret)
    309			goto done;
    310	}
    311
    312	priv->beacon_idx = beacon_idx;
    313	priv->proberesp_idx = pr_idx;
    314	priv->assocresp_idx = ar_idx;
    315
    316done:
    317	kfree(beacon_ie);
    318	kfree(pr_ie);
    319	kfree(ar_ie);
    320
    321	return ret;
    322}
    323
    324/* This function parses  head and tail IEs, from cfg80211_beacon_data and sets
    325 * these IE to FW.
    326 */
    327static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
    328				      struct cfg80211_beacon_data *info)
    329{
    330	struct mwifiex_ie *gen_ie;
    331	struct ieee_types_header *hdr;
    332	struct ieee80211_vendor_ie *vendorhdr;
    333	u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
    334	int left_len, parsed_len = 0;
    335	unsigned int token_len;
    336	int err = 0;
    337
    338	if (!info->tail || !info->tail_len)
    339		return 0;
    340
    341	gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL);
    342	if (!gen_ie)
    343		return -ENOMEM;
    344
    345	left_len = info->tail_len;
    346
    347	/* Many IEs are generated in FW by parsing bss configuration.
    348	 * Let's not add them here; else we may end up duplicating these IEs
    349	 */
    350	while (left_len > sizeof(struct ieee_types_header)) {
    351		hdr = (void *)(info->tail + parsed_len);
    352		token_len = hdr->len + sizeof(struct ieee_types_header);
    353		if (token_len > left_len) {
    354			err = -EINVAL;
    355			goto out;
    356		}
    357
    358		switch (hdr->element_id) {
    359		case WLAN_EID_SSID:
    360		case WLAN_EID_SUPP_RATES:
    361		case WLAN_EID_COUNTRY:
    362		case WLAN_EID_PWR_CONSTRAINT:
    363		case WLAN_EID_ERP_INFO:
    364		case WLAN_EID_EXT_SUPP_RATES:
    365		case WLAN_EID_HT_CAPABILITY:
    366		case WLAN_EID_HT_OPERATION:
    367		case WLAN_EID_VHT_CAPABILITY:
    368		case WLAN_EID_VHT_OPERATION:
    369			break;
    370		case WLAN_EID_VENDOR_SPECIFIC:
    371			/* Skip only Microsoft WMM IE */
    372			if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
    373						    WLAN_OUI_TYPE_MICROSOFT_WMM,
    374						    (const u8 *)hdr,
    375						    token_len))
    376				break;
    377			fallthrough;
    378		default:
    379			if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
    380				err = -EINVAL;
    381				goto out;
    382			}
    383			memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len);
    384			ie_len += token_len;
    385			break;
    386		}
    387		left_len -= token_len;
    388		parsed_len += token_len;
    389	}
    390
    391	/* parse only WPA vendor IE from tail, WMM IE is configured by
    392	 * bss_config command
    393	 */
    394	vendorhdr = (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
    395						    WLAN_OUI_TYPE_MICROSOFT_WPA,
    396						    info->tail, info->tail_len);
    397	if (vendorhdr) {
    398		token_len = vendorhdr->len + sizeof(struct ieee_types_header);
    399		if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
    400			err = -EINVAL;
    401			goto out;
    402		}
    403		memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len);
    404		ie_len += token_len;
    405	}
    406
    407	if (!ie_len)
    408		goto out;
    409
    410	gen_ie->ie_index = cpu_to_le16(gen_idx);
    411	gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
    412						MGMT_MASK_PROBE_RESP |
    413						MGMT_MASK_ASSOC_RESP);
    414	gen_ie->ie_length = cpu_to_le16(ie_len);
    415
    416	if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL,
    417					 NULL, NULL)) {
    418		err = -EINVAL;
    419		goto out;
    420	}
    421
    422	priv->gen_idx = gen_idx;
    423
    424 out:
    425	kfree(gen_ie);
    426	return err;
    427}
    428
    429/* This function parses different IEs-head & tail IEs, beacon IEs,
    430 * probe response IEs, association response IEs from cfg80211_ap_settings
    431 * function and sets these IE to FW.
    432 */
    433int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
    434			 struct cfg80211_beacon_data *info)
    435{
    436	int ret;
    437
    438	ret = mwifiex_uap_parse_tail_ies(priv, info);
    439
    440	if (ret)
    441		return ret;
    442
    443	return mwifiex_set_mgmt_beacon_data_ies(priv, info);
    444}
    445
    446/* This function removes management IE set */
    447int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)
    448{
    449	struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
    450	struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL;
    451	int ret = 0;
    452
    453	if (priv->gen_idx != MWIFIEX_AUTO_IDX_MASK) {
    454		gen_ie = kmalloc(sizeof(*gen_ie), GFP_KERNEL);
    455		if (!gen_ie)
    456			return -ENOMEM;
    457
    458		gen_ie->ie_index = cpu_to_le16(priv->gen_idx);
    459		gen_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
    460		gen_ie->ie_length = 0;
    461		if (mwifiex_update_uap_custom_ie(priv, gen_ie, &priv->gen_idx,
    462						 NULL, &priv->proberesp_idx,
    463						 NULL, &priv->assocresp_idx)) {
    464			ret = -1;
    465			goto done;
    466		}
    467
    468		priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
    469	}
    470
    471	if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) {
    472		beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
    473		if (!beacon_ie) {
    474			ret = -ENOMEM;
    475			goto done;
    476		}
    477		beacon_ie->ie_index = cpu_to_le16(priv->beacon_idx);
    478		beacon_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
    479		beacon_ie->ie_length = 0;
    480	}
    481	if (priv->proberesp_idx != MWIFIEX_AUTO_IDX_MASK) {
    482		pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
    483		if (!pr_ie) {
    484			ret = -ENOMEM;
    485			goto done;
    486		}
    487		pr_ie->ie_index = cpu_to_le16(priv->proberesp_idx);
    488		pr_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
    489		pr_ie->ie_length = 0;
    490	}
    491	if (priv->assocresp_idx != MWIFIEX_AUTO_IDX_MASK) {
    492		ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
    493		if (!ar_ie) {
    494			ret = -ENOMEM;
    495			goto done;
    496		}
    497		ar_ie->ie_index = cpu_to_le16(priv->assocresp_idx);
    498		ar_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
    499		ar_ie->ie_length = 0;
    500	}
    501
    502	if (beacon_ie || pr_ie || ar_ie)
    503		ret = mwifiex_update_uap_custom_ie(priv,
    504						   beacon_ie, &priv->beacon_idx,
    505						   pr_ie, &priv->proberesp_idx,
    506						   ar_ie, &priv->assocresp_idx);
    507
    508done:
    509	kfree(gen_ie);
    510	kfree(beacon_ie);
    511	kfree(pr_ie);
    512	kfree(ar_ie);
    513
    514	return ret;
    515}