Skip to content

Commit afe8ca1

Browse files
committed
Merge tag 'mac80211-for-net-2021-10-27' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211
Johannes Berg says: ==================== Two fixes: * bridge vs. 4-addr mode check was wrong * management frame registrations locking was wrong, causing list corruption/crashes ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 424a4f5 + 689a0a9 commit afe8ca1

File tree

5 files changed

+24
-22
lines changed

5 files changed

+24
-22
lines changed

include/net/cfg80211.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5376,7 +5376,6 @@ static inline void wiphy_unlock(struct wiphy *wiphy)
53765376
* netdev and may otherwise be used by driver read-only, will be update
53775377
* by cfg80211 on change_interface
53785378
* @mgmt_registrations: list of registrations for management frames
5379-
* @mgmt_registrations_lock: lock for the list
53805379
* @mgmt_registrations_need_update: mgmt registrations were updated,
53815380
* need to propagate the update to the driver
53825381
* @mtx: mutex used to lock data in this struct, may be used by drivers
@@ -5423,7 +5422,6 @@ struct wireless_dev {
54235422
u32 identifier;
54245423

54255424
struct list_head mgmt_registrations;
5426-
spinlock_t mgmt_registrations_lock;
54275425
u8 mgmt_registrations_need_update:1;
54285426

54295427
struct mutex mtx;

net/wireless/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
524524
INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk);
525525
INIT_WORK(&rdev->mgmt_registrations_update_wk,
526526
cfg80211_mgmt_registrations_update_wk);
527+
spin_lock_init(&rdev->mgmt_registrations_lock);
527528

528529
#ifdef CONFIG_CFG80211_DEFAULT_PS
529530
rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -1279,7 +1280,6 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
12791280
INIT_LIST_HEAD(&wdev->event_list);
12801281
spin_lock_init(&wdev->event_lock);
12811282
INIT_LIST_HEAD(&wdev->mgmt_registrations);
1282-
spin_lock_init(&wdev->mgmt_registrations_lock);
12831283
INIT_LIST_HEAD(&wdev->pmsr_list);
12841284
spin_lock_init(&wdev->pmsr_lock);
12851285
INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);

net/wireless/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ struct cfg80211_registered_device {
100100
struct work_struct propagate_cac_done_wk;
101101

102102
struct work_struct mgmt_registrations_update_wk;
103+
/* lock for all wdev lists */
104+
spinlock_t mgmt_registrations_lock;
103105

104106
/* must be last because of the way we do wiphy_priv(),
105107
* and it should at least be aligned to NETDEV_ALIGN */

net/wireless/mlme.c

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,9 @@ static void cfg80211_mgmt_registrations_update(struct wireless_dev *wdev)
452452

453453
lockdep_assert_held(&rdev->wiphy.mtx);
454454

455-
spin_lock_bh(&wdev->mgmt_registrations_lock);
455+
spin_lock_bh(&rdev->mgmt_registrations_lock);
456456
if (!wdev->mgmt_registrations_need_update) {
457-
spin_unlock_bh(&wdev->mgmt_registrations_lock);
457+
spin_unlock_bh(&rdev->mgmt_registrations_lock);
458458
return;
459459
}
460460

@@ -479,7 +479,7 @@ static void cfg80211_mgmt_registrations_update(struct wireless_dev *wdev)
479479
rcu_read_unlock();
480480

481481
wdev->mgmt_registrations_need_update = 0;
482-
spin_unlock_bh(&wdev->mgmt_registrations_lock);
482+
spin_unlock_bh(&rdev->mgmt_registrations_lock);
483483

484484
rdev_update_mgmt_frame_registrations(rdev, wdev, &upd);
485485
}
@@ -503,6 +503,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
503503
int match_len, bool multicast_rx,
504504
struct netlink_ext_ack *extack)
505505
{
506+
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
506507
struct cfg80211_mgmt_registration *reg, *nreg;
507508
int err = 0;
508509
u16 mgmt_type;
@@ -548,7 +549,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
548549
if (!nreg)
549550
return -ENOMEM;
550551

551-
spin_lock_bh(&wdev->mgmt_registrations_lock);
552+
spin_lock_bh(&rdev->mgmt_registrations_lock);
552553

553554
list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
554555
int mlen = min(match_len, reg->match_len);
@@ -583,15 +584,15 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
583584
list_add(&nreg->list, &wdev->mgmt_registrations);
584585
}
585586
wdev->mgmt_registrations_need_update = 1;
586-
spin_unlock_bh(&wdev->mgmt_registrations_lock);
587+
spin_unlock_bh(&rdev->mgmt_registrations_lock);
587588

588589
cfg80211_mgmt_registrations_update(wdev);
589590

590591
return 0;
591592

592593
out:
593594
kfree(nreg);
594-
spin_unlock_bh(&wdev->mgmt_registrations_lock);
595+
spin_unlock_bh(&rdev->mgmt_registrations_lock);
595596

596597
return err;
597598
}
@@ -602,7 +603,7 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
602603
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
603604
struct cfg80211_mgmt_registration *reg, *tmp;
604605

605-
spin_lock_bh(&wdev->mgmt_registrations_lock);
606+
spin_lock_bh(&rdev->mgmt_registrations_lock);
606607

607608
list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
608609
if (reg->nlportid != nlportid)
@@ -615,7 +616,7 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
615616
schedule_work(&rdev->mgmt_registrations_update_wk);
616617
}
617618

618-
spin_unlock_bh(&wdev->mgmt_registrations_lock);
619+
spin_unlock_bh(&rdev->mgmt_registrations_lock);
619620

620621
if (nlportid && rdev->crit_proto_nlportid == nlportid) {
621622
rdev->crit_proto_nlportid = 0;
@@ -628,15 +629,16 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
628629

629630
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
630631
{
632+
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
631633
struct cfg80211_mgmt_registration *reg, *tmp;
632634

633-
spin_lock_bh(&wdev->mgmt_registrations_lock);
635+
spin_lock_bh(&rdev->mgmt_registrations_lock);
634636
list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
635637
list_del(&reg->list);
636638
kfree(reg);
637639
}
638640
wdev->mgmt_registrations_need_update = 1;
639-
spin_unlock_bh(&wdev->mgmt_registrations_lock);
641+
spin_unlock_bh(&rdev->mgmt_registrations_lock);
640642

641643
cfg80211_mgmt_registrations_update(wdev);
642644
}
@@ -784,7 +786,7 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm,
784786
data = buf + ieee80211_hdrlen(mgmt->frame_control);
785787
data_len = len - ieee80211_hdrlen(mgmt->frame_control);
786788

787-
spin_lock_bh(&wdev->mgmt_registrations_lock);
789+
spin_lock_bh(&rdev->mgmt_registrations_lock);
788790

789791
list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
790792
if (reg->frame_type != ftype)
@@ -808,7 +810,7 @@ bool cfg80211_rx_mgmt_khz(struct wireless_dev *wdev, int freq, int sig_dbm,
808810
break;
809811
}
810812

811-
spin_unlock_bh(&wdev->mgmt_registrations_lock);
813+
spin_unlock_bh(&rdev->mgmt_registrations_lock);
812814

813815
trace_cfg80211_return_bool(result);
814816
return result;

net/wireless/util.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,14 +1028,14 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
10281028
!(rdev->wiphy.interface_modes & (1 << ntype)))
10291029
return -EOPNOTSUPP;
10301030

1031-
/* if it's part of a bridge, reject changing type to station/ibss */
1032-
if (netif_is_bridge_port(dev) &&
1033-
(ntype == NL80211_IFTYPE_ADHOC ||
1034-
ntype == NL80211_IFTYPE_STATION ||
1035-
ntype == NL80211_IFTYPE_P2P_CLIENT))
1036-
return -EBUSY;
1037-
10381031
if (ntype != otype) {
1032+
/* if it's part of a bridge, reject changing type to station/ibss */
1033+
if (netif_is_bridge_port(dev) &&
1034+
(ntype == NL80211_IFTYPE_ADHOC ||
1035+
ntype == NL80211_IFTYPE_STATION ||
1036+
ntype == NL80211_IFTYPE_P2P_CLIENT))
1037+
return -EBUSY;
1038+
10391039
dev->ieee80211_ptr->use_4addr = false;
10401040
dev->ieee80211_ptr->mesh_id_up_len = 0;
10411041
wdev_lock(dev->ieee80211_ptr);

0 commit comments

Comments
 (0)