diff options
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 113 |
1 files changed, 65 insertions, 48 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4eaea0a9975b..6b6de43d9420 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <net/mac80211.h> @@ -148,7 +148,7 @@ static u32 ieee80211_calc_hw_conf_chan(struct ieee80211_local *local, offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; /* force it also for scanning, since drivers might config differently */ - if (offchannel_flag || local->scanning || + if (offchannel_flag || local->scanning || local->in_reconfig || !cfg80211_chandef_identical(&local->hw.conf.chandef, &chandef)) { local->hw.conf.chandef = chandef; changed |= IEEE80211_CONF_CHANGE_CHANNEL; @@ -167,6 +167,8 @@ static u32 ieee80211_calc_hw_conf_chan(struct ieee80211_local *local, } power = ieee80211_chandef_max_power(&chandef); + if (local->user_power_level != IEEE80211_UNSET_POWER_LEVEL) + power = min(local->user_power_level, power); rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { @@ -337,6 +339,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, might_sleep(); + WARN_ON_ONCE(ieee80211_vif_is_mld(&sdata->vif)); + if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) return; @@ -369,7 +373,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, if (changed & ~BSS_CHANGED_VIF_CFG_FLAGS) { u64 ch = changed & ~BSS_CHANGED_VIF_CFG_FLAGS; - /* FIXME: should be for each link */ trace_drv_link_info_changed(local, sdata, &sdata->vif.bss_conf, changed); if (local->ops->link_info_changed) @@ -423,9 +426,9 @@ u64 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) BSS_CHANGED_ERP_SLOT; } -static void ieee80211_tasklet_handler(struct tasklet_struct *t) +/* context: requires softirqs disabled */ +void ieee80211_handle_queued_frames(struct ieee80211_local *local) { - struct ieee80211_local *local = from_tasklet(local, t, tasklet); struct sk_buff *skb; while ((skb = skb_dequeue(&local->skb_queue)) || @@ -450,6 +453,13 @@ static void ieee80211_tasklet_handler(struct tasklet_struct *t) } } +static void ieee80211_tasklet_handler(struct tasklet_struct *t) +{ + struct ieee80211_local *local = from_tasklet(local, t, tasklet); + + ieee80211_handle_queued_frames(local); +} + static void ieee80211_restart_work(struct work_struct *work) { struct ieee80211_local *local = @@ -716,8 +726,13 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { }, [NL80211_IFTYPE_P2P_DEVICE] = { .tx = 0xffff, + /* + * To support P2P PASN pairing let user space register to rx + * also AUTH frames on P2P device interface. + */ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4), }, }; @@ -1043,9 +1058,9 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) return 0; /* Driver provides cipher suites, but we need to exclude WEP */ - suites = kmemdup(local->hw.wiphy->cipher_suites, - sizeof(u32) * local->hw.wiphy->n_cipher_suites, - GFP_KERNEL); + suites = kmemdup_array(local->hw.wiphy->cipher_suites, + local->hw.wiphy->n_cipher_suites, + sizeof(u32), GFP_KERNEL); if (!suites) return -ENOMEM; @@ -1083,6 +1098,27 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) return 0; } +static bool +ieee80211_ifcomb_check(const struct ieee80211_iface_combination *c, int n_comb) +{ + int i, j; + + for (i = 0; i < n_comb; i++, c++) { + /* DFS is not supported with multi-channel combinations yet */ + if (c->radar_detect_widths && + c->num_different_channels > 1) + return false; + + /* mac80211 doesn't support more than one IBSS interface */ + for (j = 0; j < c->n_limits; j++) + if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && + c->limits[j].max > 1) + return false; + } + + return true; +} + int ieee80211_register_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); @@ -1153,9 +1189,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (WARN_ON(!ieee80211_hw_check(hw, AP_LINK_PS))) return -EINVAL; - - if (WARN_ON(ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP))) - return -EINVAL; } #ifdef CONFIG_PM @@ -1172,17 +1205,20 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (comb->num_different_channels > 1) return -EINVAL; } - } else { - /* DFS is not supported with multi-channel combinations yet */ - for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { - const struct ieee80211_iface_combination *comb; + } - comb = &local->hw.wiphy->iface_combinations[i]; + if (hw->wiphy->n_radio) { + for (i = 0; i < hw->wiphy->n_radio; i++) { + const struct wiphy_radio *radio = &hw->wiphy->radio[i]; - if (comb->radar_detect_widths && - comb->num_different_channels > 1) + if (!ieee80211_ifcomb_check(radio->iface_combinations, + radio->n_iface_combinations)) return -EINVAL; } + } else { + if (!ieee80211_ifcomb_check(hw->wiphy->iface_combinations, + hw->wiphy->n_iface_combinations)) + return -EINVAL; } /* Only HW csum features are currently compatible with mac80211 */ @@ -1274,6 +1310,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && !(iftd->he_cap.he_cap_elem.phy_cap_info[0] & he_40_mhz_cap)) return -EINVAL; + + /* no support for per-band vendor elems with MLO */ + if (WARN_ON(iftd->vendor_elems.len && + hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) + return -EINVAL; } /* HT, VHT, HE require QoS, thus >= 4 queues */ @@ -1312,23 +1353,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); - /* mac80211 doesn't support more than one IBSS interface right now */ - for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { - const struct ieee80211_iface_combination *c; - int j; - c = &hw->wiphy->iface_combinations[i]; - - for (j = 0; j < c->n_limits; j++) - if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && - c->limits[j].max > 1) - return -EINVAL; - } - - local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + - sizeof(void *) * channels, GFP_KERNEL); + local->int_scan_req = kzalloc(struct_size(local->int_scan_req, + channels, channels), + GFP_KERNEL); if (!local->int_scan_req) return -ENOMEM; + local->int_scan_req->n_channels = channels; eth_broadcast_addr(local->int_scan_req->bssid); @@ -1715,18 +1746,7 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) wiphy_free(local->hw.wiphy); } EXPORT_SYMBOL(ieee80211_free_hw); - -static const char * const drop_reasons_monitor[] = { -#define V(x) #x, - [0] = "RX_DROP_MONITOR", - MAC80211_DROP_REASONS_MONITOR(V) -}; - -static struct drop_reason_list drop_reason_list_monitor = { - .reasons = drop_reasons_monitor, - .n_reasons = ARRAY_SIZE(drop_reasons_monitor), -}; - +#define V(x) #x, static const char * const drop_reasons_unusable[] = { [0] = "RX_DROP_UNUSABLE", MAC80211_DROP_REASONS_UNUSABLE(V) @@ -1755,8 +1775,6 @@ static int __init ieee80211_init(void) if (ret) goto err_netdev; - drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR, - &drop_reason_list_monitor); drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE, &drop_reason_list_unusable); @@ -1775,7 +1793,6 @@ static void __exit ieee80211_exit(void) ieee80211_iface_exit(); - drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR); drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE); rcu_barrier(); |