diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 285 |
1 files changed, 215 insertions, 70 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index a6cda52ed920..725af7a468d2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -317,7 +317,8 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | |||
317 | } | 317 | } |
318 | 318 | ||
319 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | 319 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, |
320 | enum queue_stop_reason reason) | 320 | enum queue_stop_reason reason, |
321 | bool refcounted) | ||
321 | { | 322 | { |
322 | struct ieee80211_local *local = hw_to_local(hw); | 323 | struct ieee80211_local *local = hw_to_local(hw); |
323 | 324 | ||
@@ -329,7 +330,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
329 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) | 330 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) |
330 | return; | 331 | return; |
331 | 332 | ||
332 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 333 | if (!refcounted) |
334 | local->q_stop_reasons[queue][reason] = 0; | ||
335 | else | ||
336 | local->q_stop_reasons[queue][reason]--; | ||
337 | |||
338 | if (local->q_stop_reasons[queue][reason] == 0) | ||
339 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
333 | 340 | ||
334 | if (local->queue_stop_reasons[queue] != 0) | 341 | if (local->queue_stop_reasons[queue] != 0) |
335 | /* someone still has this queue stopped */ | 342 | /* someone still has this queue stopped */ |
@@ -344,25 +351,28 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
344 | } | 351 | } |
345 | 352 | ||
346 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 353 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
347 | enum queue_stop_reason reason) | 354 | enum queue_stop_reason reason, |
355 | bool refcounted) | ||
348 | { | 356 | { |
349 | struct ieee80211_local *local = hw_to_local(hw); | 357 | struct ieee80211_local *local = hw_to_local(hw); |
350 | unsigned long flags; | 358 | unsigned long flags; |
351 | 359 | ||
352 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 360 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
353 | __ieee80211_wake_queue(hw, queue, reason); | 361 | __ieee80211_wake_queue(hw, queue, reason, refcounted); |
354 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 362 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
355 | } | 363 | } |
356 | 364 | ||
357 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | 365 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) |
358 | { | 366 | { |
359 | ieee80211_wake_queue_by_reason(hw, queue, | 367 | ieee80211_wake_queue_by_reason(hw, queue, |
360 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 368 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
369 | false); | ||
361 | } | 370 | } |
362 | EXPORT_SYMBOL(ieee80211_wake_queue); | 371 | EXPORT_SYMBOL(ieee80211_wake_queue); |
363 | 372 | ||
364 | static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | 373 | static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, |
365 | enum queue_stop_reason reason) | 374 | enum queue_stop_reason reason, |
375 | bool refcounted) | ||
366 | { | 376 | { |
367 | struct ieee80211_local *local = hw_to_local(hw); | 377 | struct ieee80211_local *local = hw_to_local(hw); |
368 | struct ieee80211_sub_if_data *sdata; | 378 | struct ieee80211_sub_if_data *sdata; |
@@ -373,10 +383,13 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
373 | if (WARN_ON(queue >= hw->queues)) | 383 | if (WARN_ON(queue >= hw->queues)) |
374 | return; | 384 | return; |
375 | 385 | ||
376 | if (test_bit(reason, &local->queue_stop_reasons[queue])) | 386 | if (!refcounted) |
377 | return; | 387 | local->q_stop_reasons[queue][reason] = 1; |
388 | else | ||
389 | local->q_stop_reasons[queue][reason]++; | ||
378 | 390 | ||
379 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 391 | if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue])) |
392 | return; | ||
380 | 393 | ||
381 | if (local->hw.queues < IEEE80211_NUM_ACS) | 394 | if (local->hw.queues < IEEE80211_NUM_ACS) |
382 | n_acs = 1; | 395 | n_acs = 1; |
@@ -398,20 +411,22 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
398 | } | 411 | } |
399 | 412 | ||
400 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 413 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
401 | enum queue_stop_reason reason) | 414 | enum queue_stop_reason reason, |
415 | bool refcounted) | ||
402 | { | 416 | { |
403 | struct ieee80211_local *local = hw_to_local(hw); | 417 | struct ieee80211_local *local = hw_to_local(hw); |
404 | unsigned long flags; | 418 | unsigned long flags; |
405 | 419 | ||
406 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 420 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
407 | __ieee80211_stop_queue(hw, queue, reason); | 421 | __ieee80211_stop_queue(hw, queue, reason, refcounted); |
408 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 422 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
409 | } | 423 | } |
410 | 424 | ||
411 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) | 425 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) |
412 | { | 426 | { |
413 | ieee80211_stop_queue_by_reason(hw, queue, | 427 | ieee80211_stop_queue_by_reason(hw, queue, |
414 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 428 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
429 | false); | ||
415 | } | 430 | } |
416 | EXPORT_SYMBOL(ieee80211_stop_queue); | 431 | EXPORT_SYMBOL(ieee80211_stop_queue); |
417 | 432 | ||
@@ -429,9 +444,11 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
429 | } | 444 | } |
430 | 445 | ||
431 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 446 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
432 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 447 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
448 | false); | ||
433 | __skb_queue_tail(&local->pending[queue], skb); | 449 | __skb_queue_tail(&local->pending[queue], skb); |
434 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 450 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
451 | false); | ||
435 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 452 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
436 | } | 453 | } |
437 | 454 | ||
@@ -455,20 +472,23 @@ void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
455 | queue = info->hw_queue; | 472 | queue = info->hw_queue; |
456 | 473 | ||
457 | __ieee80211_stop_queue(hw, queue, | 474 | __ieee80211_stop_queue(hw, queue, |
458 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 475 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
476 | false); | ||
459 | 477 | ||
460 | __skb_queue_tail(&local->pending[queue], skb); | 478 | __skb_queue_tail(&local->pending[queue], skb); |
461 | } | 479 | } |
462 | 480 | ||
463 | for (i = 0; i < hw->queues; i++) | 481 | for (i = 0; i < hw->queues; i++) |
464 | __ieee80211_wake_queue(hw, i, | 482 | __ieee80211_wake_queue(hw, i, |
465 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 483 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
484 | false); | ||
466 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 485 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
467 | } | 486 | } |
468 | 487 | ||
469 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 488 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
470 | unsigned long queues, | 489 | unsigned long queues, |
471 | enum queue_stop_reason reason) | 490 | enum queue_stop_reason reason, |
491 | bool refcounted) | ||
472 | { | 492 | { |
473 | struct ieee80211_local *local = hw_to_local(hw); | 493 | struct ieee80211_local *local = hw_to_local(hw); |
474 | unsigned long flags; | 494 | unsigned long flags; |
@@ -477,7 +497,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
477 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 497 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
478 | 498 | ||
479 | for_each_set_bit(i, &queues, hw->queues) | 499 | for_each_set_bit(i, &queues, hw->queues) |
480 | __ieee80211_stop_queue(hw, i, reason); | 500 | __ieee80211_stop_queue(hw, i, reason, refcounted); |
481 | 501 | ||
482 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 502 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
483 | } | 503 | } |
@@ -485,7 +505,8 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
485 | void ieee80211_stop_queues(struct ieee80211_hw *hw) | 505 | void ieee80211_stop_queues(struct ieee80211_hw *hw) |
486 | { | 506 | { |
487 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 507 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
488 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 508 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
509 | false); | ||
489 | } | 510 | } |
490 | EXPORT_SYMBOL(ieee80211_stop_queues); | 511 | EXPORT_SYMBOL(ieee80211_stop_queues); |
491 | 512 | ||
@@ -508,7 +529,8 @@ EXPORT_SYMBOL(ieee80211_queue_stopped); | |||
508 | 529 | ||
509 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 530 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
510 | unsigned long queues, | 531 | unsigned long queues, |
511 | enum queue_stop_reason reason) | 532 | enum queue_stop_reason reason, |
533 | bool refcounted) | ||
512 | { | 534 | { |
513 | struct ieee80211_local *local = hw_to_local(hw); | 535 | struct ieee80211_local *local = hw_to_local(hw); |
514 | unsigned long flags; | 536 | unsigned long flags; |
@@ -517,7 +539,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
517 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 539 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
518 | 540 | ||
519 | for_each_set_bit(i, &queues, hw->queues) | 541 | for_each_set_bit(i, &queues, hw->queues) |
520 | __ieee80211_wake_queue(hw, i, reason); | 542 | __ieee80211_wake_queue(hw, i, reason, refcounted); |
521 | 543 | ||
522 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 544 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
523 | } | 545 | } |
@@ -525,17 +547,16 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
525 | void ieee80211_wake_queues(struct ieee80211_hw *hw) | 547 | void ieee80211_wake_queues(struct ieee80211_hw *hw) |
526 | { | 548 | { |
527 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 549 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
528 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 550 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
551 | false); | ||
529 | } | 552 | } |
530 | EXPORT_SYMBOL(ieee80211_wake_queues); | 553 | EXPORT_SYMBOL(ieee80211_wake_queues); |
531 | 554 | ||
532 | void ieee80211_flush_queues(struct ieee80211_local *local, | 555 | static unsigned int |
533 | struct ieee80211_sub_if_data *sdata) | 556 | ieee80211_get_vif_queues(struct ieee80211_local *local, |
557 | struct ieee80211_sub_if_data *sdata) | ||
534 | { | 558 | { |
535 | u32 queues; | 559 | unsigned int queues; |
536 | |||
537 | if (!local->ops->flush) | ||
538 | return; | ||
539 | 560 | ||
540 | if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) { | 561 | if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) { |
541 | int ac; | 562 | int ac; |
@@ -551,13 +572,46 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
551 | queues = BIT(local->hw.queues) - 1; | 572 | queues = BIT(local->hw.queues) - 1; |
552 | } | 573 | } |
553 | 574 | ||
554 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 575 | return queues; |
555 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 576 | } |
577 | |||
578 | void ieee80211_flush_queues(struct ieee80211_local *local, | ||
579 | struct ieee80211_sub_if_data *sdata) | ||
580 | { | ||
581 | unsigned int queues; | ||
582 | |||
583 | if (!local->ops->flush) | ||
584 | return; | ||
585 | |||
586 | queues = ieee80211_get_vif_queues(local, sdata); | ||
587 | |||
588 | ieee80211_stop_queues_by_reason(&local->hw, queues, | ||
589 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | ||
590 | false); | ||
556 | 591 | ||
557 | drv_flush(local, sdata, queues, false); | 592 | drv_flush(local, sdata, queues, false); |
558 | 593 | ||
559 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 594 | ieee80211_wake_queues_by_reason(&local->hw, queues, |
560 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 595 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
596 | false); | ||
597 | } | ||
598 | |||
599 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | ||
600 | struct ieee80211_sub_if_data *sdata, | ||
601 | enum queue_stop_reason reason) | ||
602 | { | ||
603 | ieee80211_stop_queues_by_reason(&local->hw, | ||
604 | ieee80211_get_vif_queues(local, sdata), | ||
605 | reason, true); | ||
606 | } | ||
607 | |||
608 | void ieee80211_wake_vif_queues(struct ieee80211_local *local, | ||
609 | struct ieee80211_sub_if_data *sdata, | ||
610 | enum queue_stop_reason reason) | ||
611 | { | ||
612 | ieee80211_wake_queues_by_reason(&local->hw, | ||
613 | ieee80211_get_vif_queues(local, sdata), | ||
614 | reason, true); | ||
561 | } | 615 | } |
562 | 616 | ||
563 | static void __iterate_active_interfaces(struct ieee80211_local *local, | 617 | static void __iterate_active_interfaces(struct ieee80211_local *local, |
@@ -1166,14 +1220,17 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1166 | } | 1220 | } |
1167 | } | 1221 | } |
1168 | 1222 | ||
1169 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1223 | static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, |
1170 | size_t buffer_len, const u8 *ie, size_t ie_len, | 1224 | u8 *buffer, size_t buffer_len, |
1171 | enum ieee80211_band band, u32 rate_mask, | 1225 | const u8 *ie, size_t ie_len, |
1172 | struct cfg80211_chan_def *chandef) | 1226 | enum ieee80211_band band, |
1227 | u32 rate_mask, | ||
1228 | struct cfg80211_chan_def *chandef, | ||
1229 | size_t *offset) | ||
1173 | { | 1230 | { |
1174 | struct ieee80211_supported_band *sband; | 1231 | struct ieee80211_supported_band *sband; |
1175 | u8 *pos = buffer, *end = buffer + buffer_len; | 1232 | u8 *pos = buffer, *end = buffer + buffer_len; |
1176 | size_t offset = 0, noffset; | 1233 | size_t noffset; |
1177 | int supp_rates_len, i; | 1234 | int supp_rates_len, i; |
1178 | u8 rates[32]; | 1235 | u8 rates[32]; |
1179 | int num_rates; | 1236 | int num_rates; |
@@ -1181,6 +1238,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1181 | int shift; | 1238 | int shift; |
1182 | u32 rate_flags; | 1239 | u32 rate_flags; |
1183 | 1240 | ||
1241 | *offset = 0; | ||
1242 | |||
1184 | sband = local->hw.wiphy->bands[band]; | 1243 | sband = local->hw.wiphy->bands[band]; |
1185 | if (WARN_ON_ONCE(!sband)) | 1244 | if (WARN_ON_ONCE(!sband)) |
1186 | return 0; | 1245 | return 0; |
@@ -1219,12 +1278,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1219 | noffset = ieee80211_ie_split(ie, ie_len, | 1278 | noffset = ieee80211_ie_split(ie, ie_len, |
1220 | before_extrates, | 1279 | before_extrates, |
1221 | ARRAY_SIZE(before_extrates), | 1280 | ARRAY_SIZE(before_extrates), |
1222 | offset); | 1281 | *offset); |
1223 | if (end - pos < noffset - offset) | 1282 | if (end - pos < noffset - *offset) |
1224 | goto out_err; | 1283 | goto out_err; |
1225 | memcpy(pos, ie + offset, noffset - offset); | 1284 | memcpy(pos, ie + *offset, noffset - *offset); |
1226 | pos += noffset - offset; | 1285 | pos += noffset - *offset; |
1227 | offset = noffset; | 1286 | *offset = noffset; |
1228 | } | 1287 | } |
1229 | 1288 | ||
1230 | ext_rates_len = num_rates - supp_rates_len; | 1289 | ext_rates_len = num_rates - supp_rates_len; |
@@ -1258,12 +1317,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1258 | }; | 1317 | }; |
1259 | noffset = ieee80211_ie_split(ie, ie_len, | 1318 | noffset = ieee80211_ie_split(ie, ie_len, |
1260 | before_ht, ARRAY_SIZE(before_ht), | 1319 | before_ht, ARRAY_SIZE(before_ht), |
1261 | offset); | 1320 | *offset); |
1262 | if (end - pos < noffset - offset) | 1321 | if (end - pos < noffset - *offset) |
1263 | goto out_err; | 1322 | goto out_err; |
1264 | memcpy(pos, ie + offset, noffset - offset); | 1323 | memcpy(pos, ie + *offset, noffset - *offset); |
1265 | pos += noffset - offset; | 1324 | pos += noffset - *offset; |
1266 | offset = noffset; | 1325 | *offset = noffset; |
1267 | } | 1326 | } |
1268 | 1327 | ||
1269 | if (sband->ht_cap.ht_supported) { | 1328 | if (sband->ht_cap.ht_supported) { |
@@ -1298,12 +1357,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1298 | }; | 1357 | }; |
1299 | noffset = ieee80211_ie_split(ie, ie_len, | 1358 | noffset = ieee80211_ie_split(ie, ie_len, |
1300 | before_vht, ARRAY_SIZE(before_vht), | 1359 | before_vht, ARRAY_SIZE(before_vht), |
1301 | offset); | 1360 | *offset); |
1302 | if (end - pos < noffset - offset) | 1361 | if (end - pos < noffset - *offset) |
1303 | goto out_err; | 1362 | goto out_err; |
1304 | memcpy(pos, ie + offset, noffset - offset); | 1363 | memcpy(pos, ie + *offset, noffset - *offset); |
1305 | pos += noffset - offset; | 1364 | pos += noffset - *offset; |
1306 | offset = noffset; | 1365 | *offset = noffset; |
1307 | } | 1366 | } |
1308 | 1367 | ||
1309 | if (sband->vht_cap.vht_supported) { | 1368 | if (sband->vht_cap.vht_supported) { |
@@ -1313,21 +1372,54 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1313 | sband->vht_cap.cap); | 1372 | sband->vht_cap.cap); |
1314 | } | 1373 | } |
1315 | 1374 | ||
1316 | /* add any remaining custom IEs */ | ||
1317 | if (ie && ie_len) { | ||
1318 | noffset = ie_len; | ||
1319 | if (end - pos < noffset - offset) | ||
1320 | goto out_err; | ||
1321 | memcpy(pos, ie + offset, noffset - offset); | ||
1322 | pos += noffset - offset; | ||
1323 | } | ||
1324 | |||
1325 | return pos - buffer; | 1375 | return pos - buffer; |
1326 | out_err: | 1376 | out_err: |
1327 | WARN_ONCE(1, "not enough space for preq IEs\n"); | 1377 | WARN_ONCE(1, "not enough space for preq IEs\n"); |
1328 | return pos - buffer; | 1378 | return pos - buffer; |
1329 | } | 1379 | } |
1330 | 1380 | ||
1381 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||
1382 | size_t buffer_len, | ||
1383 | struct ieee80211_scan_ies *ie_desc, | ||
1384 | const u8 *ie, size_t ie_len, | ||
1385 | u8 bands_used, u32 *rate_masks, | ||
1386 | struct cfg80211_chan_def *chandef) | ||
1387 | { | ||
1388 | size_t pos = 0, old_pos = 0, custom_ie_offset = 0; | ||
1389 | int i; | ||
1390 | |||
1391 | memset(ie_desc, 0, sizeof(*ie_desc)); | ||
1392 | |||
1393 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
1394 | if (bands_used & BIT(i)) { | ||
1395 | pos += ieee80211_build_preq_ies_band(local, | ||
1396 | buffer + pos, | ||
1397 | buffer_len - pos, | ||
1398 | ie, ie_len, i, | ||
1399 | rate_masks[i], | ||
1400 | chandef, | ||
1401 | &custom_ie_offset); | ||
1402 | ie_desc->ies[i] = buffer + old_pos; | ||
1403 | ie_desc->len[i] = pos - old_pos; | ||
1404 | old_pos = pos; | ||
1405 | } | ||
1406 | } | ||
1407 | |||
1408 | /* add any remaining custom IEs */ | ||
1409 | if (ie && ie_len) { | ||
1410 | if (WARN_ONCE(buffer_len - pos < ie_len - custom_ie_offset, | ||
1411 | "not enough space for preq custom IEs\n")) | ||
1412 | return pos; | ||
1413 | memcpy(buffer + pos, ie + custom_ie_offset, | ||
1414 | ie_len - custom_ie_offset); | ||
1415 | ie_desc->common_ies = buffer + pos; | ||
1416 | ie_desc->common_ie_len = ie_len - custom_ie_offset; | ||
1417 | pos += ie_len - custom_ie_offset; | ||
1418 | } | ||
1419 | |||
1420 | return pos; | ||
1421 | }; | ||
1422 | |||
1331 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1423 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1332 | u8 *dst, u32 ratemask, | 1424 | u8 *dst, u32 ratemask, |
1333 | struct ieee80211_channel *chan, | 1425 | struct ieee80211_channel *chan, |
@@ -1340,6 +1432,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1340 | struct sk_buff *skb; | 1432 | struct sk_buff *skb; |
1341 | struct ieee80211_mgmt *mgmt; | 1433 | struct ieee80211_mgmt *mgmt; |
1342 | int ies_len; | 1434 | int ies_len; |
1435 | u32 rate_masks[IEEE80211_NUM_BANDS] = {}; | ||
1436 | struct ieee80211_scan_ies dummy_ie_desc; | ||
1343 | 1437 | ||
1344 | /* | 1438 | /* |
1345 | * Do not send DS Channel parameter for directed probe requests | 1439 | * Do not send DS Channel parameter for directed probe requests |
@@ -1357,10 +1451,11 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1357 | if (!skb) | 1451 | if (!skb) |
1358 | return NULL; | 1452 | return NULL; |
1359 | 1453 | ||
1454 | rate_masks[chan->band] = ratemask; | ||
1360 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), | 1455 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), |
1361 | skb_tailroom(skb), | 1456 | skb_tailroom(skb), &dummy_ie_desc, |
1362 | ie, ie_len, chan->band, | 1457 | ie, ie_len, BIT(chan->band), |
1363 | ratemask, &chandef); | 1458 | rate_masks, &chandef); |
1364 | skb_put(skb, ies_len); | 1459 | skb_put(skb, ies_len); |
1365 | 1460 | ||
1366 | if (dst) { | 1461 | if (dst) { |
@@ -1604,7 +1699,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1604 | if (local->use_chanctx) { | 1699 | if (local->use_chanctx) { |
1605 | mutex_lock(&local->chanctx_mtx); | 1700 | mutex_lock(&local->chanctx_mtx); |
1606 | list_for_each_entry(ctx, &local->chanctx_list, list) | 1701 | list_for_each_entry(ctx, &local->chanctx_list, list) |
1607 | WARN_ON(drv_add_chanctx(local, ctx)); | 1702 | if (ctx->replace_state != |
1703 | IEEE80211_CHANCTX_REPLACES_OTHER) | ||
1704 | WARN_ON(drv_add_chanctx(local, ctx)); | ||
1608 | mutex_unlock(&local->chanctx_mtx); | 1705 | mutex_unlock(&local->chanctx_mtx); |
1609 | 1706 | ||
1610 | list_for_each_entry(sdata, &local->interfaces, list) { | 1707 | list_for_each_entry(sdata, &local->interfaces, list) { |
@@ -1798,7 +1895,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1798 | } | 1895 | } |
1799 | 1896 | ||
1800 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 1897 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
1801 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1898 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
1899 | false); | ||
1802 | 1900 | ||
1803 | /* | 1901 | /* |
1804 | * Reconfigure sched scan if it was interrupted by FW restart or | 1902 | * Reconfigure sched scan if it was interrupted by FW restart or |
@@ -2836,6 +2934,35 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, | |||
2836 | ps->dtim_count = dtim_count; | 2934 | ps->dtim_count = dtim_count; |
2837 | } | 2935 | } |
2838 | 2936 | ||
2937 | static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, | ||
2938 | struct ieee80211_chanctx *ctx) | ||
2939 | { | ||
2940 | struct ieee80211_sub_if_data *sdata; | ||
2941 | u8 radar_detect = 0; | ||
2942 | |||
2943 | lockdep_assert_held(&local->chanctx_mtx); | ||
2944 | |||
2945 | if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)) | ||
2946 | return 0; | ||
2947 | |||
2948 | list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) | ||
2949 | if (sdata->reserved_radar_required) | ||
2950 | radar_detect |= BIT(sdata->reserved_chandef.width); | ||
2951 | |||
2952 | /* | ||
2953 | * An in-place reservation context should not have any assigned vifs | ||
2954 | * until it replaces the other context. | ||
2955 | */ | ||
2956 | WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER && | ||
2957 | !list_empty(&ctx->assigned_vifs)); | ||
2958 | |||
2959 | list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) | ||
2960 | if (sdata->radar_required) | ||
2961 | radar_detect |= BIT(sdata->vif.bss_conf.chandef.width); | ||
2962 | |||
2963 | return radar_detect; | ||
2964 | } | ||
2965 | |||
2839 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | 2966 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, |
2840 | const struct cfg80211_chan_def *chandef, | 2967 | const struct cfg80211_chan_def *chandef, |
2841 | enum ieee80211_chanctx_mode chanmode, | 2968 | enum ieee80211_chanctx_mode chanmode, |
@@ -2877,8 +3004,9 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | |||
2877 | num[iftype] = 1; | 3004 | num[iftype] = 1; |
2878 | 3005 | ||
2879 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 3006 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
2880 | if (ctx->conf.radar_enabled) | 3007 | if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) |
2881 | radar_detect |= BIT(ctx->conf.def.width); | 3008 | continue; |
3009 | radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); | ||
2882 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { | 3010 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { |
2883 | num_different_channels++; | 3011 | num_different_channels++; |
2884 | continue; | 3012 | continue; |
@@ -2935,10 +3063,12 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) | |||
2935 | lockdep_assert_held(&local->chanctx_mtx); | 3063 | lockdep_assert_held(&local->chanctx_mtx); |
2936 | 3064 | ||
2937 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 3065 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
3066 | if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
3067 | continue; | ||
3068 | |||
2938 | num_different_channels++; | 3069 | num_different_channels++; |
2939 | 3070 | ||
2940 | if (ctx->conf.radar_enabled) | 3071 | radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); |
2941 | radar_detect |= BIT(ctx->conf.def.width); | ||
2942 | } | 3072 | } |
2943 | 3073 | ||
2944 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 3074 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
@@ -2953,3 +3083,18 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) | |||
2953 | 3083 | ||
2954 | return max_num_different_channels; | 3084 | return max_num_different_channels; |
2955 | } | 3085 | } |
3086 | |||
3087 | u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo) | ||
3088 | { | ||
3089 | *buf++ = WLAN_EID_VENDOR_SPECIFIC; | ||
3090 | *buf++ = 7; /* len */ | ||
3091 | *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
3092 | *buf++ = 0x50; | ||
3093 | *buf++ = 0xf2; | ||
3094 | *buf++ = 2; /* WME */ | ||
3095 | *buf++ = 0; /* WME info */ | ||
3096 | *buf++ = 1; /* WME ver */ | ||
3097 | *buf++ = qosinfo; /* U-APSD no in use */ | ||
3098 | |||
3099 | return buf; | ||
3100 | } | ||