hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/wireless/scan.c
....@@ -262,117 +262,152 @@
262262 }
263263 EXPORT_SYMBOL(cfg80211_is_element_inherited);
264264
265
-static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
266
- const u8 *subelement, size_t subie_len,
267
- u8 *new_ie, gfp_t gfp)
265
+static size_t cfg80211_copy_elem_with_frags(const struct element *elem,
266
+ const u8 *ie, size_t ie_len,
267
+ u8 **pos, u8 *buf, size_t buf_len)
268268 {
269
- u8 *pos, *tmp;
270
- const u8 *tmp_old, *tmp_new;
271
- const struct element *non_inherit_elem;
272
- u8 *sub_copy;
273
-
274
- /* copy subelement as we need to change its content to
275
- * mark an ie after it is processed.
276
- */
277
- sub_copy = kmemdup(subelement, subie_len, gfp);
278
- if (!sub_copy)
269
+ if (WARN_ON((u8 *)elem < ie || elem->data > ie + ie_len ||
270
+ elem->data + elem->datalen > ie + ie_len))
279271 return 0;
280272
281
- pos = &new_ie[0];
273
+ if (elem->datalen + 2 > buf + buf_len - *pos)
274
+ return 0;
282275
283
- /* set new ssid */
284
- tmp_new = cfg80211_find_ie(WLAN_EID_SSID, sub_copy, subie_len);
285
- if (tmp_new) {
286
- memcpy(pos, tmp_new, tmp_new[1] + 2);
287
- pos += (tmp_new[1] + 2);
276
+ memcpy(*pos, elem, elem->datalen + 2);
277
+ *pos += elem->datalen + 2;
278
+
279
+ /* Finish if it is not fragmented */
280
+ if (elem->datalen != 255)
281
+ return *pos - buf;
282
+
283
+ ie_len = ie + ie_len - elem->data - elem->datalen;
284
+ ie = (const u8 *)elem->data + elem->datalen;
285
+
286
+ for_each_element(elem, ie, ie_len) {
287
+ if (elem->id != WLAN_EID_FRAGMENT)
288
+ break;
289
+
290
+ if (elem->datalen + 2 > buf + buf_len - *pos)
291
+ return 0;
292
+
293
+ memcpy(*pos, elem, elem->datalen + 2);
294
+ *pos += elem->datalen + 2;
295
+
296
+ if (elem->datalen != 255)
297
+ break;
288298 }
289299
290
- /* get non inheritance list if exists */
291
- non_inherit_elem =
292
- cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
293
- sub_copy, subie_len);
300
+ return *pos - buf;
301
+}
294302
295
- /* go through IEs in ie (skip SSID) and subelement,
296
- * merge them into new_ie
303
+static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
304
+ const u8 *subie, size_t subie_len,
305
+ u8 *new_ie, size_t new_ie_len)
306
+{
307
+ const struct element *non_inherit_elem, *parent, *sub;
308
+ u8 *pos = new_ie;
309
+ u8 id, ext_id;
310
+ unsigned int match_len;
311
+
312
+ non_inherit_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
313
+ subie, subie_len);
314
+
315
+ /* We copy the elements one by one from the parent to the generated
316
+ * elements.
317
+ * If they are not inherited (included in subie or in the non
318
+ * inheritance element), then we copy all occurrences the first time
319
+ * we see this element type.
297320 */
298
- tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
299
- tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
321
+ for_each_element(parent, ie, ielen) {
322
+ if (parent->id == WLAN_EID_FRAGMENT)
323
+ continue;
300324
301
- while (tmp_old + 2 - ie <= ielen &&
302
- tmp_old + tmp_old[1] + 2 - ie <= ielen) {
303
- if (tmp_old[0] == 0) {
304
- tmp_old++;
325
+ if (parent->id == WLAN_EID_EXTENSION) {
326
+ if (parent->datalen < 1)
327
+ continue;
328
+
329
+ id = WLAN_EID_EXTENSION;
330
+ ext_id = parent->data[0];
331
+ match_len = 1;
332
+ } else {
333
+ id = parent->id;
334
+ match_len = 0;
335
+ }
336
+
337
+ /* Find first occurrence in subie */
338
+ sub = cfg80211_find_elem_match(id, subie, subie_len,
339
+ &ext_id, match_len, 0);
340
+
341
+ /* Copy from parent if not in subie and inherited */
342
+ if (!sub &&
343
+ cfg80211_is_element_inherited(parent, non_inherit_elem)) {
344
+ if (!cfg80211_copy_elem_with_frags(parent,
345
+ ie, ielen,
346
+ &pos, new_ie,
347
+ new_ie_len))
348
+ return 0;
349
+
305350 continue;
306351 }
307352
308
- if (tmp_old[0] == WLAN_EID_EXTENSION)
309
- tmp = (u8 *)cfg80211_find_ext_ie(tmp_old[2], sub_copy,
310
- subie_len);
311
- else
312
- tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy,
313
- subie_len);
353
+ /* Already copied if an earlier element had the same type */
354
+ if (cfg80211_find_elem_match(id, ie, (u8 *)parent - ie,
355
+ &ext_id, match_len, 0))
356
+ continue;
314357
315
- if (!tmp) {
316
- const struct element *old_elem = (void *)tmp_old;
358
+ /* Not inheriting, copy all similar elements from subie */
359
+ while (sub) {
360
+ if (!cfg80211_copy_elem_with_frags(sub,
361
+ subie, subie_len,
362
+ &pos, new_ie,
363
+ new_ie_len))
364
+ return 0;
317365
318
- /* ie in old ie but not in subelement */
319
- if (cfg80211_is_element_inherited(old_elem,
320
- non_inherit_elem)) {
321
- memcpy(pos, tmp_old, tmp_old[1] + 2);
322
- pos += tmp_old[1] + 2;
323
- }
324
- } else {
325
- /* ie in transmitting ie also in subelement,
326
- * copy from subelement and flag the ie in subelement
327
- * as copied (by setting eid field to WLAN_EID_SSID,
328
- * which is skipped anyway).
329
- * For vendor ie, compare OUI + type + subType to
330
- * determine if they are the same ie.
331
- */
332
- if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) {
333
- if (tmp_old[1] >= 5 && tmp[1] >= 5 &&
334
- !memcmp(tmp_old + 2, tmp + 2, 5)) {
335
- /* same vendor ie, copy from
336
- * subelement
337
- */
338
- memcpy(pos, tmp, tmp[1] + 2);
339
- pos += tmp[1] + 2;
340
- tmp[0] = WLAN_EID_SSID;
341
- } else {
342
- memcpy(pos, tmp_old, tmp_old[1] + 2);
343
- pos += tmp_old[1] + 2;
344
- }
345
- } else {
346
- /* copy ie from subelement into new ie */
347
- memcpy(pos, tmp, tmp[1] + 2);
348
- pos += tmp[1] + 2;
349
- tmp[0] = WLAN_EID_SSID;
350
- }
366
+ sub = cfg80211_find_elem_match(id,
367
+ sub->data + sub->datalen,
368
+ subie_len + subie -
369
+ (sub->data +
370
+ sub->datalen),
371
+ &ext_id, match_len, 0);
351372 }
352
-
353
- if (tmp_old + tmp_old[1] + 2 - ie == ielen)
354
- break;
355
-
356
- tmp_old += tmp_old[1] + 2;
357373 }
358374
359
- /* go through subelement again to check if there is any ie not
360
- * copied to new ie, skip ssid, capability, bssid-index ie
375
+ /* The above misses elements that are included in subie but not in the
376
+ * parent, so do a pass over subie and append those.
377
+ * Skip the non-tx BSSID caps and non-inheritance element.
361378 */
362
- tmp_new = sub_copy;
363
- while (tmp_new + 2 - sub_copy <= subie_len &&
364
- tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
365
- if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
366
- tmp_new[0] == WLAN_EID_SSID)) {
367
- memcpy(pos, tmp_new, tmp_new[1] + 2);
368
- pos += tmp_new[1] + 2;
379
+ for_each_element(sub, subie, subie_len) {
380
+ if (sub->id == WLAN_EID_NON_TX_BSSID_CAP)
381
+ continue;
382
+
383
+ if (sub->id == WLAN_EID_FRAGMENT)
384
+ continue;
385
+
386
+ if (sub->id == WLAN_EID_EXTENSION) {
387
+ if (sub->datalen < 1)
388
+ continue;
389
+
390
+ id = WLAN_EID_EXTENSION;
391
+ ext_id = sub->data[0];
392
+ match_len = 1;
393
+
394
+ if (ext_id == WLAN_EID_EXT_NON_INHERITANCE)
395
+ continue;
396
+ } else {
397
+ id = sub->id;
398
+ match_len = 0;
369399 }
370
- if (tmp_new + tmp_new[1] + 2 - sub_copy == subie_len)
371
- break;
372
- tmp_new += tmp_new[1] + 2;
400
+
401
+ /* Processed if one was included in the parent */
402
+ if (cfg80211_find_elem_match(id, ie, ielen,
403
+ &ext_id, match_len, 0))
404
+ continue;
405
+
406
+ if (!cfg80211_copy_elem_with_frags(sub, subie, subie_len,
407
+ &pos, new_ie, new_ie_len))
408
+ return 0;
373409 }
374410
375
- kfree(sub_copy);
376411 return pos - new_ie;
377412 }
378413
....@@ -606,7 +641,7 @@
606641
607642 ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp);
608643 if (ret)
609
- return ret;
644
+ return 0;
610645
611646 /* RNR IE may contain more than one NEIGHBOR_AP_INFO */
612647 while (pos + sizeof(*ap_info) <= end) {
....@@ -2170,7 +2205,7 @@
21702205 new_ie_len = cfg80211_gen_new_ie(ie, ielen,
21712206 profile,
21722207 profile_len, new_ie,
2173
- gfp);
2208
+ IEEE80211_MAX_DATA_LEN);
21742209 if (!new_ie_len)
21752210 continue;
21762211