diff options
| author | James Morris <james.l.morris@oracle.com> | 2014-11-19 05:32:12 -0500 |
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2014-11-19 05:32:12 -0500 |
| commit | b10778a00d40b3d9fdaaf5891e802794781ff71c (patch) | |
| tree | 6ba4cbac86eecedc3f30650e7f764ecf00c83898 /net/mac80211/util.c | |
| parent | 594081ee7145cc30a3977cb4e218f81213b63dc5 (diff) | |
| parent | bfe01a5ba2490f299e1d2d5508cbbbadd897bbe9 (diff) | |
Merge commit 'v3.17' into next
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 | } | ||
