| .. | .. |
|---|
| 4 | 4 | * |
|---|
| 5 | 5 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> |
|---|
| 6 | 6 | * Copyright (c) 2015 Intel Deutschland GmbH |
|---|
| 7 | + * Copyright (C) 2019 Intel Corporation |
|---|
| 7 | 8 | */ |
|---|
| 8 | 9 | |
|---|
| 9 | 10 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 21 | 22 | |
|---|
| 22 | 23 | |
|---|
| 23 | 24 | void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, |
|---|
| 24 | | - const u8 *buf, size_t len, int uapsd_queues) |
|---|
| 25 | + const u8 *buf, size_t len, int uapsd_queues, |
|---|
| 26 | + const u8 *req_ies, size_t req_ies_len) |
|---|
| 25 | 27 | { |
|---|
| 26 | 28 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
|---|
| 27 | 29 | struct wiphy *wiphy = wdev->wiphy; |
|---|
| 28 | 30 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
|---|
| 29 | 31 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
|---|
| 30 | 32 | struct cfg80211_connect_resp_params cr; |
|---|
| 33 | + const u8 *resp_ie = mgmt->u.assoc_resp.variable; |
|---|
| 34 | + size_t resp_ie_len = len - offsetof(struct ieee80211_mgmt, |
|---|
| 35 | + u.assoc_resp.variable); |
|---|
| 36 | + |
|---|
| 37 | + if (bss->channel->band == NL80211_BAND_S1GHZ) { |
|---|
| 38 | + resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable; |
|---|
| 39 | + resp_ie_len = len - offsetof(struct ieee80211_mgmt, |
|---|
| 40 | + u.s1g_assoc_resp.variable); |
|---|
| 41 | + } |
|---|
| 31 | 42 | |
|---|
| 32 | 43 | memset(&cr, 0, sizeof(cr)); |
|---|
| 33 | 44 | cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code); |
|---|
| 34 | 45 | cr.bssid = mgmt->bssid; |
|---|
| 35 | 46 | cr.bss = bss; |
|---|
| 36 | | - cr.resp_ie = mgmt->u.assoc_resp.variable; |
|---|
| 37 | | - cr.resp_ie_len = |
|---|
| 38 | | - len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
|---|
| 47 | + cr.req_ie = req_ies; |
|---|
| 48 | + cr.req_ie_len = req_ies_len; |
|---|
| 49 | + cr.resp_ie = resp_ie; |
|---|
| 50 | + cr.resp_ie_len = resp_ie_len; |
|---|
| 39 | 51 | cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED; |
|---|
| 40 | 52 | |
|---|
| 41 | 53 | trace_cfg80211_send_rx_assoc(dev, bss); |
|---|
| .. | .. |
|---|
| 52 | 64 | return; |
|---|
| 53 | 65 | } |
|---|
| 54 | 66 | |
|---|
| 55 | | - nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues); |
|---|
| 67 | + nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues, |
|---|
| 68 | + req_ies, req_ies_len); |
|---|
| 56 | 69 | /* update current_bss etc., consumes the bss reference */ |
|---|
| 57 | 70 | __cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS); |
|---|
| 58 | 71 | } |
|---|
| .. | .. |
|---|
| 272 | 285 | |
|---|
| 273 | 286 | p1 = (u8*)(ht_capa); |
|---|
| 274 | 287 | p2 = (u8*)(ht_capa_mask); |
|---|
| 275 | | - for (i = 0; i<sizeof(*ht_capa); i++) |
|---|
| 288 | + for (i = 0; i < sizeof(*ht_capa); i++) |
|---|
| 276 | 289 | p1[i] &= p2[i]; |
|---|
| 277 | 290 | } |
|---|
| 278 | 291 | |
|---|
| 279 | | -/* Do a logical ht_capa &= ht_capa_mask. */ |
|---|
| 292 | +/* Do a logical vht_capa &= vht_capa_mask. */ |
|---|
| 280 | 293 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, |
|---|
| 281 | 294 | const struct ieee80211_vht_cap *vht_capa_mask) |
|---|
| 282 | 295 | { |
|---|
| .. | .. |
|---|
| 421 | 434 | |
|---|
| 422 | 435 | __le16 frame_type; |
|---|
| 423 | 436 | |
|---|
| 437 | + bool multicast_rx; |
|---|
| 438 | + |
|---|
| 424 | 439 | u8 match[]; |
|---|
| 425 | 440 | }; |
|---|
| 426 | 441 | |
|---|
| 427 | | -static void |
|---|
| 428 | | -cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev) |
|---|
| 442 | +static void cfg80211_mgmt_registrations_update(struct wireless_dev *wdev) |
|---|
| 429 | 443 | { |
|---|
| 444 | + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
|---|
| 445 | + struct wireless_dev *tmp; |
|---|
| 430 | 446 | struct cfg80211_mgmt_registration *reg; |
|---|
| 447 | + struct mgmt_frame_regs upd = {}; |
|---|
| 431 | 448 | |
|---|
| 432 | 449 | ASSERT_RTNL(); |
|---|
| 433 | 450 | |
|---|
| 434 | | - spin_lock_bh(&rdev->mlme_unreg_lock); |
|---|
| 435 | | - while ((reg = list_first_entry_or_null(&rdev->mlme_unreg, |
|---|
| 436 | | - struct cfg80211_mgmt_registration, |
|---|
| 437 | | - list))) { |
|---|
| 438 | | - list_del(®->list); |
|---|
| 439 | | - spin_unlock_bh(&rdev->mlme_unreg_lock); |
|---|
| 440 | | - |
|---|
| 441 | | - if (rdev->ops->mgmt_frame_register) { |
|---|
| 442 | | - u16 frame_type = le16_to_cpu(reg->frame_type); |
|---|
| 443 | | - |
|---|
| 444 | | - rdev_mgmt_frame_register(rdev, reg->wdev, |
|---|
| 445 | | - frame_type, false); |
|---|
| 446 | | - } |
|---|
| 447 | | - |
|---|
| 448 | | - kfree(reg); |
|---|
| 449 | | - |
|---|
| 450 | | - spin_lock_bh(&rdev->mlme_unreg_lock); |
|---|
| 451 | + spin_lock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 452 | + if (!wdev->mgmt_registrations_need_update) { |
|---|
| 453 | + spin_unlock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 454 | + return; |
|---|
| 451 | 455 | } |
|---|
| 452 | | - spin_unlock_bh(&rdev->mlme_unreg_lock); |
|---|
| 456 | + |
|---|
| 457 | + rcu_read_lock(); |
|---|
| 458 | + list_for_each_entry_rcu(tmp, &rdev->wiphy.wdev_list, list) { |
|---|
| 459 | + list_for_each_entry(reg, &tmp->mgmt_registrations, list) { |
|---|
| 460 | + u32 mask = BIT(le16_to_cpu(reg->frame_type) >> 4); |
|---|
| 461 | + u32 mcast_mask = 0; |
|---|
| 462 | + |
|---|
| 463 | + if (reg->multicast_rx) |
|---|
| 464 | + mcast_mask = mask; |
|---|
| 465 | + |
|---|
| 466 | + upd.global_stypes |= mask; |
|---|
| 467 | + upd.global_mcast_stypes |= mcast_mask; |
|---|
| 468 | + |
|---|
| 469 | + if (tmp == wdev) { |
|---|
| 470 | + upd.interface_stypes |= mask; |
|---|
| 471 | + upd.interface_mcast_stypes |= mcast_mask; |
|---|
| 472 | + } |
|---|
| 473 | + } |
|---|
| 474 | + } |
|---|
| 475 | + rcu_read_unlock(); |
|---|
| 476 | + |
|---|
| 477 | + wdev->mgmt_registrations_need_update = 0; |
|---|
| 478 | + spin_unlock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 479 | + |
|---|
| 480 | + rdev_update_mgmt_frame_registrations(rdev, wdev, &upd); |
|---|
| 453 | 481 | } |
|---|
| 454 | 482 | |
|---|
| 455 | | -void cfg80211_mlme_unreg_wk(struct work_struct *wk) |
|---|
| 483 | +void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk) |
|---|
| 456 | 484 | { |
|---|
| 457 | 485 | struct cfg80211_registered_device *rdev; |
|---|
| 486 | + struct wireless_dev *wdev; |
|---|
| 458 | 487 | |
|---|
| 459 | 488 | rdev = container_of(wk, struct cfg80211_registered_device, |
|---|
| 460 | | - mlme_unreg_wk); |
|---|
| 489 | + mgmt_registrations_update_wk); |
|---|
| 461 | 490 | |
|---|
| 462 | 491 | rtnl_lock(); |
|---|
| 463 | | - cfg80211_process_mlme_unregistrations(rdev); |
|---|
| 492 | + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) |
|---|
| 493 | + cfg80211_mgmt_registrations_update(wdev); |
|---|
| 464 | 494 | rtnl_unlock(); |
|---|
| 465 | 495 | } |
|---|
| 466 | 496 | |
|---|
| 467 | 497 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, |
|---|
| 468 | 498 | u16 frame_type, const u8 *match_data, |
|---|
| 469 | | - int match_len) |
|---|
| 499 | + int match_len, bool multicast_rx, |
|---|
| 500 | + struct netlink_ext_ack *extack) |
|---|
| 470 | 501 | { |
|---|
| 471 | | - struct wiphy *wiphy = wdev->wiphy; |
|---|
| 472 | | - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
|---|
| 502 | + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
|---|
| 473 | 503 | struct cfg80211_mgmt_registration *reg, *nreg; |
|---|
| 474 | 504 | int err = 0; |
|---|
| 475 | 505 | u16 mgmt_type; |
|---|
| 506 | + bool update_multicast = false; |
|---|
| 476 | 507 | |
|---|
| 477 | 508 | if (!wdev->wiphy->mgmt_stypes) |
|---|
| 478 | 509 | return -EOPNOTSUPP; |
|---|
| 479 | 510 | |
|---|
| 480 | | - if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) |
|---|
| 511 | + if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) { |
|---|
| 512 | + NL_SET_ERR_MSG(extack, "frame type not management"); |
|---|
| 481 | 513 | return -EINVAL; |
|---|
| 514 | + } |
|---|
| 482 | 515 | |
|---|
| 483 | | - if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) |
|---|
| 516 | + if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) { |
|---|
| 517 | + NL_SET_ERR_MSG(extack, "Invalid frame type"); |
|---|
| 484 | 518 | return -EINVAL; |
|---|
| 519 | + } |
|---|
| 485 | 520 | |
|---|
| 486 | 521 | mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; |
|---|
| 487 | | - if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) |
|---|
| 522 | + if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) { |
|---|
| 523 | + NL_SET_ERR_MSG(extack, |
|---|
| 524 | + "Registration to specific type not supported"); |
|---|
| 488 | 525 | return -EINVAL; |
|---|
| 526 | + } |
|---|
| 527 | + |
|---|
| 528 | + /* |
|---|
| 529 | + * To support Pre Association Security Negotiation (PASN), registration |
|---|
| 530 | + * for authentication frames should be supported. However, as some |
|---|
| 531 | + * versions of the user space daemons wrongly register to all types of |
|---|
| 532 | + * authentication frames (which might result in unexpected behavior) |
|---|
| 533 | + * allow such registration if the request is for a specific |
|---|
| 534 | + * authentication algorithm number. |
|---|
| 535 | + */ |
|---|
| 536 | + if (wdev->iftype == NL80211_IFTYPE_STATION && |
|---|
| 537 | + (frame_type & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_AUTH && |
|---|
| 538 | + !(match_data && match_len >= 2)) { |
|---|
| 539 | + NL_SET_ERR_MSG(extack, |
|---|
| 540 | + "Authentication algorithm number required"); |
|---|
| 541 | + return -EINVAL; |
|---|
| 542 | + } |
|---|
| 489 | 543 | |
|---|
| 490 | 544 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); |
|---|
| 491 | 545 | if (!nreg) |
|---|
| 492 | 546 | return -ENOMEM; |
|---|
| 493 | 547 | |
|---|
| 494 | | - spin_lock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 548 | + spin_lock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 495 | 549 | |
|---|
| 496 | 550 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { |
|---|
| 497 | 551 | int mlen = min(match_len, reg->match_len); |
|---|
| .. | .. |
|---|
| 500 | 554 | continue; |
|---|
| 501 | 555 | |
|---|
| 502 | 556 | if (memcmp(reg->match, match_data, mlen) == 0) { |
|---|
| 557 | + if (reg->multicast_rx != multicast_rx) { |
|---|
| 558 | + update_multicast = true; |
|---|
| 559 | + reg->multicast_rx = multicast_rx; |
|---|
| 560 | + break; |
|---|
| 561 | + } |
|---|
| 562 | + NL_SET_ERR_MSG(extack, "Match already configured"); |
|---|
| 503 | 563 | err = -EALREADY; |
|---|
| 504 | 564 | break; |
|---|
| 505 | 565 | } |
|---|
| 506 | 566 | } |
|---|
| 507 | 567 | |
|---|
| 508 | | - if (err) { |
|---|
| 509 | | - kfree(nreg); |
|---|
| 568 | + if (err) |
|---|
| 510 | 569 | goto out; |
|---|
| 570 | + |
|---|
| 571 | + if (update_multicast) { |
|---|
| 572 | + kfree(nreg); |
|---|
| 573 | + } else { |
|---|
| 574 | + memcpy(nreg->match, match_data, match_len); |
|---|
| 575 | + nreg->match_len = match_len; |
|---|
| 576 | + nreg->nlportid = snd_portid; |
|---|
| 577 | + nreg->frame_type = cpu_to_le16(frame_type); |
|---|
| 578 | + nreg->wdev = wdev; |
|---|
| 579 | + nreg->multicast_rx = multicast_rx; |
|---|
| 580 | + list_add(&nreg->list, &wdev->mgmt_registrations); |
|---|
| 511 | 581 | } |
|---|
| 582 | + wdev->mgmt_registrations_need_update = 1; |
|---|
| 583 | + spin_unlock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 512 | 584 | |
|---|
| 513 | | - memcpy(nreg->match, match_data, match_len); |
|---|
| 514 | | - nreg->match_len = match_len; |
|---|
| 515 | | - nreg->nlportid = snd_portid; |
|---|
| 516 | | - nreg->frame_type = cpu_to_le16(frame_type); |
|---|
| 517 | | - nreg->wdev = wdev; |
|---|
| 518 | | - list_add(&nreg->list, &wdev->mgmt_registrations); |
|---|
| 519 | | - spin_unlock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 520 | | - |
|---|
| 521 | | - /* process all unregistrations to avoid driver confusion */ |
|---|
| 522 | | - cfg80211_process_mlme_unregistrations(rdev); |
|---|
| 523 | | - |
|---|
| 524 | | - if (rdev->ops->mgmt_frame_register) |
|---|
| 525 | | - rdev_mgmt_frame_register(rdev, wdev, frame_type, true); |
|---|
| 585 | + cfg80211_mgmt_registrations_update(wdev); |
|---|
| 526 | 586 | |
|---|
| 527 | 587 | return 0; |
|---|
| 528 | 588 | |
|---|
| 529 | 589 | out: |
|---|
| 530 | | - spin_unlock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 590 | + kfree(nreg); |
|---|
| 591 | + spin_unlock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 531 | 592 | |
|---|
| 532 | 593 | return err; |
|---|
| 533 | 594 | } |
|---|
| .. | .. |
|---|
| 538 | 599 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
|---|
| 539 | 600 | struct cfg80211_mgmt_registration *reg, *tmp; |
|---|
| 540 | 601 | |
|---|
| 541 | | - spin_lock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 602 | + spin_lock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 542 | 603 | |
|---|
| 543 | 604 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
|---|
| 544 | 605 | if (reg->nlportid != nlportid) |
|---|
| 545 | 606 | continue; |
|---|
| 546 | 607 | |
|---|
| 547 | 608 | list_del(®->list); |
|---|
| 548 | | - spin_lock(&rdev->mlme_unreg_lock); |
|---|
| 549 | | - list_add_tail(®->list, &rdev->mlme_unreg); |
|---|
| 550 | | - spin_unlock(&rdev->mlme_unreg_lock); |
|---|
| 609 | + kfree(reg); |
|---|
| 551 | 610 | |
|---|
| 552 | | - schedule_work(&rdev->mlme_unreg_wk); |
|---|
| 611 | + wdev->mgmt_registrations_need_update = 1; |
|---|
| 612 | + schedule_work(&rdev->mgmt_registrations_update_wk); |
|---|
| 553 | 613 | } |
|---|
| 554 | 614 | |
|---|
| 555 | | - spin_unlock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 615 | + spin_unlock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 556 | 616 | |
|---|
| 557 | 617 | if (nlportid && rdev->crit_proto_nlportid == nlportid) { |
|---|
| 558 | 618 | rdev->crit_proto_nlportid = 0; |
|---|
| .. | .. |
|---|
| 566 | 626 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) |
|---|
| 567 | 627 | { |
|---|
| 568 | 628 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
|---|
| 629 | + struct cfg80211_mgmt_registration *reg, *tmp; |
|---|
| 569 | 630 | |
|---|
| 570 | | - spin_lock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 571 | | - spin_lock(&rdev->mlme_unreg_lock); |
|---|
| 572 | | - list_splice_tail_init(&wdev->mgmt_registrations, &rdev->mlme_unreg); |
|---|
| 573 | | - spin_unlock(&rdev->mlme_unreg_lock); |
|---|
| 574 | | - spin_unlock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 631 | + spin_lock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 632 | + list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
|---|
| 633 | + list_del(®->list); |
|---|
| 634 | + kfree(reg); |
|---|
| 635 | + } |
|---|
| 636 | + wdev->mgmt_registrations_need_update = 1; |
|---|
| 637 | + spin_unlock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 575 | 638 | |
|---|
| 576 | | - cfg80211_process_mlme_unregistrations(rdev); |
|---|
| 639 | + cfg80211_mgmt_registrations_update(wdev); |
|---|
| 577 | 640 | } |
|---|
| 578 | 641 | |
|---|
| 579 | 642 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
|---|
| .. | .. |
|---|
| 692 | 755 | return rdev_mgmt_tx(rdev, wdev, params, cookie); |
|---|
| 693 | 756 | } |
|---|
| 694 | 757 | |
|---|
| 695 | | -bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, |
|---|
| 696 | | - const u8 *buf, size_t len, u32 flags) |
|---|
| 758 | +bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm, |
|---|
| 759 | + const u8 *buf, size_t len, u32 flags) |
|---|
| 697 | 760 | { |
|---|
| 698 | 761 | struct wiphy *wiphy = wdev->wiphy; |
|---|
| 699 | 762 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
|---|
| .. | .. |
|---|
| 719 | 782 | data = buf + ieee80211_hdrlen(mgmt->frame_control); |
|---|
| 720 | 783 | data_len = len - ieee80211_hdrlen(mgmt->frame_control); |
|---|
| 721 | 784 | |
|---|
| 722 | | - spin_lock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 785 | + spin_lock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 723 | 786 | |
|---|
| 724 | 787 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { |
|---|
| 725 | 788 | if (reg->frame_type != ftype) |
|---|
| .. | .. |
|---|
| 743 | 806 | break; |
|---|
| 744 | 807 | } |
|---|
| 745 | 808 | |
|---|
| 746 | | - spin_unlock_bh(&wdev->mgmt_registrations_lock); |
|---|
| 809 | + spin_unlock_bh(&rdev->mgmt_registrations_lock); |
|---|
| 747 | 810 | |
|---|
| 748 | 811 | trace_cfg80211_return_bool(result); |
|---|
| 749 | 812 | return result; |
|---|
| 750 | 813 | } |
|---|
| 751 | | -EXPORT_SYMBOL(cfg80211_rx_mgmt); |
|---|
| 814 | +EXPORT_SYMBOL(cfg80211_rx_mgmt_khz); |
|---|
| 752 | 815 | |
|---|
| 753 | 816 | void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev) |
|---|
| 754 | 817 | { |
|---|
| .. | .. |
|---|
| 888 | 951 | sizeof(struct cfg80211_chan_def)); |
|---|
| 889 | 952 | queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); |
|---|
| 890 | 953 | cfg80211_sched_dfs_chan_update(rdev); |
|---|
| 891 | | - /* fall through */ |
|---|
| 954 | + fallthrough; |
|---|
| 892 | 955 | case NL80211_RADAR_CAC_ABORTED: |
|---|
| 893 | 956 | wdev->cac_started = false; |
|---|
| 894 | 957 | break; |
|---|