0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "main.h"
0010
0011
0012
0013
0014
0015 static int
0016 mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx)
0017 {
0018 int i;
0019 struct mwifiex_adapter *adapter = priv->adapter;
0020 struct mwifiex_ie *ie;
0021
0022 for (i = 0; i < adapter->priv_num; i++) {
0023 if (adapter->priv[i] != priv) {
0024 ie = &adapter->priv[i]->mgmt_ie[idx];
0025 if (ie->mgmt_subtype_mask && ie->ie_length)
0026 return -1;
0027 }
0028 }
0029
0030 return 0;
0031 }
0032
0033
0034 static int
0035 mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask,
0036 struct mwifiex_ie *ie, u16 *index)
0037 {
0038 u16 mask, len, i;
0039
0040 for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) {
0041 mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask);
0042 len = le16_to_cpu(ie->ie_length);
0043
0044 if (mask == MWIFIEX_AUTO_IDX_MASK)
0045 continue;
0046
0047 if (mask == subtype_mask) {
0048 if (len > IEEE_MAX_IE_SIZE)
0049 continue;
0050
0051 *index = i;
0052 return 0;
0053 }
0054
0055 if (!priv->mgmt_ie[i].ie_length) {
0056 if (mwifiex_ie_index_used_by_other_intf(priv, i))
0057 continue;
0058
0059 *index = i;
0060 return 0;
0061 }
0062 }
0063
0064 return -1;
0065 }
0066
0067
0068 static int
0069 mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
0070 struct mwifiex_ie_list *ie_list)
0071 {
0072 u16 travel_len, index, mask;
0073 s16 input_len, tlv_len;
0074 struct mwifiex_ie *ie;
0075 u8 *tmp;
0076
0077 input_len = le16_to_cpu(ie_list->len);
0078 travel_len = sizeof(struct mwifiex_ie_types_header);
0079
0080 ie_list->len = 0;
0081
0082 while (input_len >= sizeof(struct mwifiex_ie_types_header)) {
0083 ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len);
0084 tlv_len = le16_to_cpu(ie->ie_length);
0085 travel_len += tlv_len + MWIFIEX_IE_HDR_SIZE;
0086
0087 if (input_len < tlv_len + MWIFIEX_IE_HDR_SIZE)
0088 return -1;
0089 index = le16_to_cpu(ie->ie_index);
0090 mask = le16_to_cpu(ie->mgmt_subtype_mask);
0091
0092 if (index == MWIFIEX_AUTO_IDX_MASK) {
0093
0094 if (mwifiex_ie_get_autoidx(priv, mask, ie, &index))
0095 return -1;
0096 if (index == MWIFIEX_AUTO_IDX_MASK)
0097 return -1;
0098
0099 tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer;
0100 memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length));
0101 priv->mgmt_ie[index].ie_length = ie->ie_length;
0102 priv->mgmt_ie[index].ie_index = cpu_to_le16(index);
0103 priv->mgmt_ie[index].mgmt_subtype_mask =
0104 cpu_to_le16(mask);
0105
0106 ie->ie_index = cpu_to_le16(index);
0107 } else {
0108 if (mask != MWIFIEX_DELETE_MASK)
0109 return -1;
0110
0111
0112
0113
0114 if (mwifiex_ie_index_used_by_other_intf(priv, index))
0115 return -1;
0116
0117 ie->ie_length = 0;
0118 memcpy(&priv->mgmt_ie[index], ie,
0119 sizeof(struct mwifiex_ie));
0120 }
0121
0122 le16_unaligned_add_cpu(&ie_list->len,
0123 le16_to_cpu(
0124 priv->mgmt_ie[index].ie_length) +
0125 MWIFIEX_IE_HDR_SIZE);
0126 input_len -= tlv_len + MWIFIEX_IE_HDR_SIZE;
0127 }
0128
0129 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
0130 return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
0131 HostCmd_ACT_GEN_SET,
0132 UAP_CUSTOM_IE_I, ie_list, true);
0133
0134 return 0;
0135 }
0136
0137
0138
0139
0140
0141 static int
0142 mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
0143 struct mwifiex_ie *beacon_ie, u16 *beacon_idx,
0144 struct mwifiex_ie *pr_ie, u16 *probe_idx,
0145 struct mwifiex_ie *ar_ie, u16 *assoc_idx)
0146 {
0147 struct mwifiex_ie_list *ap_custom_ie;
0148 u8 *pos;
0149 u16 len;
0150 int ret;
0151
0152 ap_custom_ie = kzalloc(sizeof(*ap_custom_ie), GFP_KERNEL);
0153 if (!ap_custom_ie)
0154 return -ENOMEM;
0155
0156 ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
0157 pos = (u8 *)ap_custom_ie->ie_list;
0158
0159 if (beacon_ie) {
0160 len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
0161 le16_to_cpu(beacon_ie->ie_length);
0162 memcpy(pos, beacon_ie, len);
0163 pos += len;
0164 le16_unaligned_add_cpu(&ap_custom_ie->len, len);
0165 }
0166 if (pr_ie) {
0167 len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
0168 le16_to_cpu(pr_ie->ie_length);
0169 memcpy(pos, pr_ie, len);
0170 pos += len;
0171 le16_unaligned_add_cpu(&ap_custom_ie->len, len);
0172 }
0173 if (ar_ie) {
0174 len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
0175 le16_to_cpu(ar_ie->ie_length);
0176 memcpy(pos, ar_ie, len);
0177 pos += len;
0178 le16_unaligned_add_cpu(&ap_custom_ie->len, len);
0179 }
0180
0181 ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie);
0182
0183 pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index);
0184 if (beacon_ie && *beacon_idx == MWIFIEX_AUTO_IDX_MASK) {
0185
0186 *beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index);
0187 len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE +
0188 le16_to_cpu(beacon_ie->ie_length);
0189 pos += len;
0190 }
0191 if (pr_ie && le16_to_cpu(pr_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) {
0192
0193 *probe_idx = *((u16 *)pos);
0194 len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE +
0195 le16_to_cpu(pr_ie->ie_length);
0196 pos += len;
0197 }
0198 if (ar_ie && le16_to_cpu(ar_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK)
0199
0200 *assoc_idx = *((u16 *)pos);
0201
0202 kfree(ap_custom_ie);
0203 return ret;
0204 }
0205
0206
0207
0208
0209
0210
0211
0212
0213 static int mwifiex_update_vs_ie(const u8 *ies, int ies_len,
0214 struct mwifiex_ie **ie_ptr, u16 mask,
0215 unsigned int oui, u8 oui_type)
0216 {
0217 struct ieee_types_header *vs_ie;
0218 struct mwifiex_ie *ie = *ie_ptr;
0219 const u8 *vendor_ie;
0220
0221 vendor_ie = cfg80211_find_vendor_ie(oui, oui_type, ies, ies_len);
0222 if (vendor_ie) {
0223 if (!*ie_ptr) {
0224 *ie_ptr = kzalloc(sizeof(struct mwifiex_ie),
0225 GFP_KERNEL);
0226 if (!*ie_ptr)
0227 return -ENOMEM;
0228 ie = *ie_ptr;
0229 }
0230
0231 vs_ie = (struct ieee_types_header *)vendor_ie;
0232 if (le16_to_cpu(ie->ie_length) + vs_ie->len + 2 >
0233 IEEE_MAX_IE_SIZE)
0234 return -EINVAL;
0235 memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length),
0236 vs_ie, vs_ie->len + 2);
0237 le16_unaligned_add_cpu(&ie->ie_length, vs_ie->len + 2);
0238 ie->mgmt_subtype_mask = cpu_to_le16(mask);
0239 ie->ie_index = cpu_to_le16(MWIFIEX_AUTO_IDX_MASK);
0240 }
0241
0242 *ie_ptr = ie;
0243 return 0;
0244 }
0245
0246
0247
0248
0249 static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private *priv,
0250 struct cfg80211_beacon_data *data)
0251 {
0252 struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL, *ar_ie = NULL;
0253 u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
0254 u16 ar_idx = MWIFIEX_AUTO_IDX_MASK;
0255 int ret = 0;
0256
0257 if (data->beacon_ies && data->beacon_ies_len) {
0258 mwifiex_update_vs_ie(data->beacon_ies, data->beacon_ies_len,
0259 &beacon_ie, MGMT_MASK_BEACON,
0260 WLAN_OUI_MICROSOFT,
0261 WLAN_OUI_TYPE_MICROSOFT_WPS);
0262 mwifiex_update_vs_ie(data->beacon_ies, data->beacon_ies_len,
0263 &beacon_ie, MGMT_MASK_BEACON,
0264 WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P);
0265 }
0266
0267 if (data->proberesp_ies && data->proberesp_ies_len) {
0268 mwifiex_update_vs_ie(data->proberesp_ies,
0269 data->proberesp_ies_len, &pr_ie,
0270 MGMT_MASK_PROBE_RESP, WLAN_OUI_MICROSOFT,
0271 WLAN_OUI_TYPE_MICROSOFT_WPS);
0272 mwifiex_update_vs_ie(data->proberesp_ies,
0273 data->proberesp_ies_len, &pr_ie,
0274 MGMT_MASK_PROBE_RESP,
0275 WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P);
0276 }
0277
0278 if (data->assocresp_ies && data->assocresp_ies_len) {
0279 mwifiex_update_vs_ie(data->assocresp_ies,
0280 data->assocresp_ies_len, &ar_ie,
0281 MGMT_MASK_ASSOC_RESP |
0282 MGMT_MASK_REASSOC_RESP,
0283 WLAN_OUI_MICROSOFT,
0284 WLAN_OUI_TYPE_MICROSOFT_WPS);
0285 mwifiex_update_vs_ie(data->assocresp_ies,
0286 data->assocresp_ies_len, &ar_ie,
0287 MGMT_MASK_ASSOC_RESP |
0288 MGMT_MASK_REASSOC_RESP, WLAN_OUI_WFA,
0289 WLAN_OUI_TYPE_WFA_P2P);
0290 }
0291
0292 if (beacon_ie || pr_ie || ar_ie) {
0293 ret = mwifiex_update_uap_custom_ie(priv, beacon_ie,
0294 &beacon_idx, pr_ie,
0295 &pr_idx, ar_ie, &ar_idx);
0296 if (ret)
0297 goto done;
0298 }
0299
0300 priv->beacon_idx = beacon_idx;
0301 priv->proberesp_idx = pr_idx;
0302 priv->assocresp_idx = ar_idx;
0303
0304 done:
0305 kfree(beacon_ie);
0306 kfree(pr_ie);
0307 kfree(ar_ie);
0308
0309 return ret;
0310 }
0311
0312
0313
0314
0315 static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
0316 struct cfg80211_beacon_data *info)
0317 {
0318 struct mwifiex_ie *gen_ie;
0319 struct ieee_types_header *hdr;
0320 struct ieee80211_vendor_ie *vendorhdr;
0321 u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
0322 int left_len, parsed_len = 0;
0323 unsigned int token_len;
0324 int err = 0;
0325
0326 if (!info->tail || !info->tail_len)
0327 return 0;
0328
0329 gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL);
0330 if (!gen_ie)
0331 return -ENOMEM;
0332
0333 left_len = info->tail_len;
0334
0335
0336
0337
0338 while (left_len > sizeof(struct ieee_types_header)) {
0339 hdr = (void *)(info->tail + parsed_len);
0340 token_len = hdr->len + sizeof(struct ieee_types_header);
0341 if (token_len > left_len) {
0342 err = -EINVAL;
0343 goto out;
0344 }
0345
0346 switch (hdr->element_id) {
0347 case WLAN_EID_SSID:
0348 case WLAN_EID_SUPP_RATES:
0349 case WLAN_EID_COUNTRY:
0350 case WLAN_EID_PWR_CONSTRAINT:
0351 case WLAN_EID_ERP_INFO:
0352 case WLAN_EID_EXT_SUPP_RATES:
0353 case WLAN_EID_HT_CAPABILITY:
0354 case WLAN_EID_HT_OPERATION:
0355 case WLAN_EID_VHT_CAPABILITY:
0356 case WLAN_EID_VHT_OPERATION:
0357 break;
0358 case WLAN_EID_VENDOR_SPECIFIC:
0359
0360 if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
0361 WLAN_OUI_TYPE_MICROSOFT_WMM,
0362 (const u8 *)hdr,
0363 token_len))
0364 break;
0365 fallthrough;
0366 default:
0367 if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
0368 err = -EINVAL;
0369 goto out;
0370 }
0371 memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len);
0372 ie_len += token_len;
0373 break;
0374 }
0375 left_len -= token_len;
0376 parsed_len += token_len;
0377 }
0378
0379
0380
0381
0382 vendorhdr = (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
0383 WLAN_OUI_TYPE_MICROSOFT_WPA,
0384 info->tail, info->tail_len);
0385 if (vendorhdr) {
0386 token_len = vendorhdr->len + sizeof(struct ieee_types_header);
0387 if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
0388 err = -EINVAL;
0389 goto out;
0390 }
0391 memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len);
0392 ie_len += token_len;
0393 }
0394
0395 if (!ie_len)
0396 goto out;
0397
0398 gen_ie->ie_index = cpu_to_le16(gen_idx);
0399 gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
0400 MGMT_MASK_PROBE_RESP |
0401 MGMT_MASK_ASSOC_RESP);
0402 gen_ie->ie_length = cpu_to_le16(ie_len);
0403
0404 if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL,
0405 NULL, NULL)) {
0406 err = -EINVAL;
0407 goto out;
0408 }
0409
0410 priv->gen_idx = gen_idx;
0411
0412 out:
0413 kfree(gen_ie);
0414 return err;
0415 }
0416
0417
0418
0419
0420
0421 int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
0422 struct cfg80211_beacon_data *info)
0423 {
0424 int ret;
0425
0426 ret = mwifiex_uap_parse_tail_ies(priv, info);
0427
0428 if (ret)
0429 return ret;
0430
0431 return mwifiex_set_mgmt_beacon_data_ies(priv, info);
0432 }
0433
0434
0435 int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)
0436 {
0437 struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
0438 struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL;
0439 int ret = 0;
0440
0441 if (priv->gen_idx != MWIFIEX_AUTO_IDX_MASK) {
0442 gen_ie = kmalloc(sizeof(*gen_ie), GFP_KERNEL);
0443 if (!gen_ie)
0444 return -ENOMEM;
0445
0446 gen_ie->ie_index = cpu_to_le16(priv->gen_idx);
0447 gen_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
0448 gen_ie->ie_length = 0;
0449 if (mwifiex_update_uap_custom_ie(priv, gen_ie, &priv->gen_idx,
0450 NULL, &priv->proberesp_idx,
0451 NULL, &priv->assocresp_idx)) {
0452 ret = -1;
0453 goto done;
0454 }
0455
0456 priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
0457 }
0458
0459 if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) {
0460 beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
0461 if (!beacon_ie) {
0462 ret = -ENOMEM;
0463 goto done;
0464 }
0465 beacon_ie->ie_index = cpu_to_le16(priv->beacon_idx);
0466 beacon_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
0467 beacon_ie->ie_length = 0;
0468 }
0469 if (priv->proberesp_idx != MWIFIEX_AUTO_IDX_MASK) {
0470 pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
0471 if (!pr_ie) {
0472 ret = -ENOMEM;
0473 goto done;
0474 }
0475 pr_ie->ie_index = cpu_to_le16(priv->proberesp_idx);
0476 pr_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
0477 pr_ie->ie_length = 0;
0478 }
0479 if (priv->assocresp_idx != MWIFIEX_AUTO_IDX_MASK) {
0480 ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
0481 if (!ar_ie) {
0482 ret = -ENOMEM;
0483 goto done;
0484 }
0485 ar_ie->ie_index = cpu_to_le16(priv->assocresp_idx);
0486 ar_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
0487 ar_ie->ie_length = 0;
0488 }
0489
0490 if (beacon_ie || pr_ie || ar_ie)
0491 ret = mwifiex_update_uap_custom_ie(priv,
0492 beacon_ie, &priv->beacon_idx,
0493 pr_ie, &priv->proberesp_idx,
0494 ar_ie, &priv->assocresp_idx);
0495
0496 done:
0497 kfree(gen_ie);
0498 kfree(beacon_ie);
0499 kfree(pr_ie);
0500 kfree(ar_ie);
0501
0502 return ret;
0503 }