Unified · Split
| @@ -154,6 +154,10 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) · 153 unmodified lines | ||
| 154 | 154 | 802.11e clarifies the figure in section 7.1.2. The frame body is |
| 155 | 155 | up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */ |
| 156 | 156 | #define IEEE80211_MAX_DATA_LEN 2304 |
| 157 | +/* 802.11ad extends maximum MSDU size for DMG (freq > 40Ghz) networks | |
| 158 | + * to 7920 bytes, see 8.2.3 General frame format | |
| 159 | + */ | |
| 160 | +#define IEEE80211_MAX_DATA_LEN_DMG 7920 | |
| 157 | 161 | /* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ |
| 158 | 162 | #define IEEE80211_MAX_FRAME_LEN 2352 |
| 159 | 163 | |
| @@ -151,6 +151,7 @@ enum ieee80211_channel_flags { · 150 unmodified lines | ||
| 151 | 151 | * @dfs_state: current state of this channel. Only relevant if radar is required |
| 152 | 152 | * on this channel. |
| 153 | 153 | * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered. |
| 154 | + * @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels. | |
| 154 | 155 | */ |
| 155 | 156 | struct ieee80211_channel { |
| 156 | 157 | enum ieee80211_band band; |
| @@ -165,6 +166,7 @@ struct ieee80211_channel { · 8 unmodified lines | ||
| 165 | 166 | int orig_mag, orig_mpwr; |
| 166 | 167 | enum nl80211_dfs_state dfs_state; |
| 167 | 168 | unsigned long dfs_state_entered; |
| 169 | + unsigned int dfs_cac_ms; | |
| 168 | 170 | }; |
| 169 | 171 | |
| 170 | 172 | /** |
| @@ -2503,7 +2505,8 @@ struct cfg80211_ops { · 2332 unmodified lines | ||
| 2503 | 2505 | |
| 2504 | 2506 | int (*start_radar_detection)(struct wiphy *wiphy, |
| 2505 | 2507 | struct net_device *dev, |
| 2506 | − struct cfg80211_chan_def *chandef); | |
| 2508 | + struct cfg80211_chan_def *chandef, | |
| 2509 | + u32 cac_time_ms); | |
| 2507 | 2510 | int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, |
| 2508 | 2511 | struct cfg80211_update_ft_ies_params *ftie); |
| 2509 | 2512 | int (*crit_proto_start)(struct wiphy *wiphy, |
| @@ -3180,6 +3183,7 @@ struct cfg80211_cached_keys; · 670 unmodified lines | ||
| 3180 | 3183 | * @p2p_started: true if this is a P2P Device that has been started |
| 3181 | 3184 | * @cac_started: true if DFS channel availability check has been started |
| 3182 | 3185 | * @cac_start_time: timestamp (jiffies) when the dfs state was entered. |
| 3186 | + * @cac_time_ms: CAC time in ms | |
| 3183 | 3187 | * @ps: powersave mode is enabled |
| 3184 | 3188 | * @ps_timeout: dynamic powersave timeout |
| 3185 | 3189 | * @ap_unexpected_nlportid: (private) netlink port ID of application |
| @@ -3235,6 +3239,7 @@ struct wireless_dev { · 49 unmodified lines | ||
| 3235 | 3239 | |
| 3236 | 3240 | bool cac_started; |
| 3237 | 3241 | unsigned long cac_start_time; |
| 3242 | + unsigned int cac_time_ms; | |
| 3238 | 3243 | |
| 3239 | 3244 | #ifdef CONFIG_CFG80211_WEXT |
| 3240 | 3245 | /* wext data */ |
| @@ -3667,7 +3672,7 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); · 426 unmodified lines | ||
| 3667 | 3672 | * cfg80211_inform_bss_width_frame - inform cfg80211 of a received BSS frame |
| 3668 | 3673 | * |
| 3669 | 3674 | * @wiphy: the wiphy reporting the BSS |
| 3670 | − * @channel: The channel the frame was received on | |
| 3675 | + * @rx_channel: The channel the frame was received on | |
| 3671 | 3676 | * @scan_width: width of the control channel |
| 3672 | 3677 | * @mgmt: the management frame (probe response or beacon) |
| 3673 | 3678 | * @len: length of the management frame |
| @@ -3682,18 +3687,18 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); · 8 unmodified lines | ||
| 3682 | 3687 | */ |
| 3683 | 3688 | struct cfg80211_bss * __must_check |
| 3684 | 3689 | cfg80211_inform_bss_width_frame(struct wiphy *wiphy, |
| 3685 | − struct ieee80211_channel *channel, | |
| 3690 | + struct ieee80211_channel *rx_channel, | |
| 3686 | 3691 | enum nl80211_bss_scan_width scan_width, |
| 3687 | 3692 | struct ieee80211_mgmt *mgmt, size_t len, |
| 3688 | 3693 | s32 signal, gfp_t gfp); |
| 3689 | 3694 | |
| 3690 | 3695 | static inline struct cfg80211_bss * __must_check |
| 3691 | 3696 | cfg80211_inform_bss_frame(struct wiphy *wiphy, |
| 3692 | − struct ieee80211_channel *channel, | |
| 3697 | + struct ieee80211_channel *rx_channel, | |
| 3693 | 3698 | struct ieee80211_mgmt *mgmt, size_t len, |
| 3694 | 3699 | s32 signal, gfp_t gfp) |
| 3695 | 3700 | { |
| 3696 | − return cfg80211_inform_bss_width_frame(wiphy, channel, | |
| 3701 | + return cfg80211_inform_bss_width_frame(wiphy, rx_channel, | |
| 3697 | 3702 | NL80211_BSS_CHAN_WIDTH_20, |
| 3698 | 3703 | mgmt, len, signal, gfp); |
| 3699 | 3704 | } |
| @@ -3702,7 +3707,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, · 2 unmodified lines | ||
| 3702 | 3707 | * cfg80211_inform_bss - inform cfg80211 of a new BSS |
| 3703 | 3708 | * |
| 3704 | 3709 | * @wiphy: the wiphy reporting the BSS |
| 3705 | − * @channel: The channel the frame was received on | |
| 3710 | + * @rx_channel: The channel the frame was received on | |
| 3706 | 3711 | * @scan_width: width of the control channel |
| 3707 | 3712 | * @bssid: the BSSID of the BSS |
| 3708 | 3713 | * @tsf: the TSF sent by the peer in the beacon/probe response (or 0) |
| @@ -3721,7 +3726,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, · 12 unmodified lines | ||
| 3721 | 3726 | */ |
| 3722 | 3727 | struct cfg80211_bss * __must_check |
| 3723 | 3728 | cfg80211_inform_bss_width(struct wiphy *wiphy, |
| 3724 | − struct ieee80211_channel *channel, | |
| 3729 | + struct ieee80211_channel *rx_channel, | |
| 3725 | 3730 | enum nl80211_bss_scan_width scan_width, |
| 3726 | 3731 | const u8 *bssid, u64 tsf, u16 capability, |
| 3727 | 3732 | u16 beacon_interval, const u8 *ie, size_t ielen, |
| @@ -3729,12 +3734,12 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, · 1 unmodified line | ||
| 3729 | 3734 | |
| 3730 | 3735 | static inline struct cfg80211_bss * __must_check |
| 3731 | 3736 | cfg80211_inform_bss(struct wiphy *wiphy, |
| 3732 | − struct ieee80211_channel *channel, | |
| 3737 | + struct ieee80211_channel *rx_channel, | |
| 3733 | 3738 | const u8 *bssid, u64 tsf, u16 capability, |
| 3734 | 3739 | u16 beacon_interval, const u8 *ie, size_t ielen, |
| 3735 | 3740 | s32 signal, gfp_t gfp) |
| 3736 | 3741 | { |
| 3737 | − return cfg80211_inform_bss_width(wiphy, channel, | |
| 3742 | + return cfg80211_inform_bss_width(wiphy, rx_channel, | |
| 3738 | 3743 | NL80211_BSS_CHAN_WIDTH_20, |
| 3739 | 3744 | bssid, tsf, capability, |
| 3740 | 3745 | beacon_interval, ie, ielen, signal, |
| @@ -697,11 +697,11 @@ struct ieee80211_tx_info { · 696 unmodified lines | ||
| 697 | 697 | } control; |
| 698 | 698 | struct { |
| 699 | 699 | struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; |
| 700 | − int ack_signal; | |
| 700 | + s32 ack_signal; | |
| 701 | 701 | u8 ampdu_ack_len; |
| 702 | 702 | u8 ampdu_len; |
| 703 | 703 | u8 antenna; |
| 704 | − /* 21 bytes free */ | |
| 704 | + void *status_driver_data[21 / sizeof(void *)]; | |
| 705 | 705 | } status; |
| 706 | 706 | struct { |
| 707 | 707 | struct ieee80211_tx_rate driver_rates[ |
| @@ -877,11 +877,13 @@ enum mac80211_rx_flags { · 169 unmodified lines | ||
| 877 | 877 | * @RX_VHT_FLAG_80MHZ: 80 MHz was used |
| 878 | 878 | * @RX_VHT_FLAG_80P80MHZ: 80+80 MHz was used |
| 879 | 879 | * @RX_VHT_FLAG_160MHZ: 160 MHz was used |
| 880 | + * @RX_VHT_FLAG_BF: packet was beamformed | |
| 880 | 881 | */ |
| 881 | 882 | enum mac80211_rx_vht_flags { |
| 882 | 883 | RX_VHT_FLAG_80MHZ = BIT(0), |
| 883 | 884 | RX_VHT_FLAG_80P80MHZ = BIT(1), |
| 884 | 885 | RX_VHT_FLAG_160MHZ = BIT(2), |
| 886 | + RX_VHT_FLAG_BF = BIT(3), | |
| 885 | 887 | }; |
| 886 | 888 | |
| 887 | 889 | /** |
| @@ -155,6 +155,7 @@ struct ieee80211_reg_rule { · 154 unmodified lines | ||
| 155 | 155 | struct ieee80211_freq_range freq_range; |
| 156 | 156 | struct ieee80211_power_rule power_rule; |
| 157 | 157 | u32 flags; |
| 158 | + u32 dfs_cac_ms; | |
| 158 | 159 | }; |
| 159 | 160 | |
| 160 | 161 | struct ieee80211_regdomain { |
| @@ -172,14 +173,18 @@ struct ieee80211_regdomain { · 11 unmodified lines | ||
| 172 | 173 | #define DBM_TO_MBM(gain) ((gain) * 100) |
| 173 | 174 | #define MBM_TO_DBM(gain) ((gain) / 100) |
| 174 | 175 | |
| 175 | −#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ | |
| 176 | −{ \ | |
| 177 | − .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ | |
| 178 | − .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ | |
| 179 | − .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ | |
| 180 | − .power_rule.max_antenna_gain = DBI_TO_MBI(gain),\ | |
| 181 | − .power_rule.max_eirp = DBM_TO_MBM(eirp), \ | |
| 182 | − .flags = reg_flags, \ | |
| 176 | +#define REG_RULE_EXT(start, end, bw, gain, eirp, dfs_cac, reg_flags) \ | |
| 177 | +{ \ | |
| 178 | + .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ | |
| 179 | + .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ | |
| 180 | + .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ | |
| 181 | + .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \ | |
| 182 | + .power_rule.max_eirp = DBM_TO_MBM(eirp), \ | |
| 183 | + .flags = reg_flags, \ | |
| 184 | + .dfs_cac_ms = dfs_cac, \ | |
| 183 | 185 | } |
| 184 | 186 | |
| 187 | +#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ | |
| 188 | + REG_RULE_EXT(start, end, bw, gain, eirp, 0, reg_flags) | |
| 189 | + | |
| 185 | 190 | #endif |
| @@ -2335,6 +2335,7 @@ enum nl80211_band_attr { · 2334 unmodified lines | ||
| 2335 | 2335 | * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel |
| 2336 | 2336 | * using this channel as the primary or any of the secondary channels |
| 2337 | 2337 | * isn't possible |
| 2338 | + * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. | |
| 2338 | 2339 | * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number |
| 2339 | 2340 | * currently defined |
| 2340 | 2341 | * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use |
| @@ -2353,6 +2354,7 @@ enum nl80211_frequency_attr { · 12 unmodified lines | ||
| 2353 | 2354 | NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, |
| 2354 | 2355 | NL80211_FREQUENCY_ATTR_NO_80MHZ, |
| 2355 | 2356 | NL80211_FREQUENCY_ATTR_NO_160MHZ, |
| 2357 | + NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, | |
| 2356 | 2358 | |
| 2357 | 2359 | /* keep last */ |
| 2358 | 2360 | __NL80211_FREQUENCY_ATTR_AFTER_LAST, |
| @@ -2449,6 +2451,8 @@ enum nl80211_reg_type { · 90 unmodified lines | ||
| 2449 | 2451 | * If you don't have one then don't send this. |
| 2450 | 2452 | * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for |
| 2451 | 2453 | * a given frequency range. The value is in mBm (100 * dBm). |
| 2454 | + * @NL80211_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. | |
| 2455 | + * If not present or 0 default CAC time will be used. | |
| 2452 | 2456 | * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number |
| 2453 | 2457 | * currently defined |
| 2454 | 2458 | * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use |
| @@ -2464,6 +2468,8 @@ enum nl80211_reg_rule_attr { · 9 unmodified lines | ||
| 2464 | 2468 | NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, |
| 2465 | 2469 | NL80211_ATTR_POWER_RULE_MAX_EIRP, |
| 2466 | 2470 | |
| 2471 | + NL80211_ATTR_DFS_CAC_TIME, | |
| 2472 | + | |
| 2467 | 2473 | /* keep last */ |
| 2468 | 2474 | __NL80211_REG_RULE_ATTR_AFTER_LAST, |
| 2469 | 2475 | NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 |
| @@ -2914,11 +2914,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, · 2913 unmodified lines | ||
| 2914 | 2914 | |
| 2915 | 2915 | static int ieee80211_start_radar_detection(struct wiphy *wiphy, |
| 2916 | 2916 | struct net_device *dev, |
| 2917 | − struct cfg80211_chan_def *chandef) | |
| 2917 | + struct cfg80211_chan_def *chandef, | |
| 2918 | + u32 cac_time_ms) | |
| 2918 | 2919 | { |
| 2919 | 2920 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 2920 | 2921 | struct ieee80211_local *local = sdata->local; |
| 2921 | − unsigned long timeout; | |
| 2922 | 2922 | int err; |
| 2923 | 2923 | |
| 2924 | 2924 | mutex_lock(&local->mtx); |
| @@ -2937,9 +2937,9 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, · 12 unmodified lines | ||
| 2937 | 2937 | if (err) |
| 2938 | 2938 | goto out_unlock; |
| 2939 | 2939 | |
| 2940 | − timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | |
| 2941 | 2940 | ieee80211_queue_delayed_work(&sdata->local->hw, |
| 2942 | − &sdata->dfs_cac_timer_work, timeout); | |
| 2941 | + &sdata->dfs_cac_timer_work, | |
| 2942 | + msecs_to_jiffies(cac_time_ms)); | |
| 2943 | 2943 | |
| 2944 | 2944 | out_unlock: |
| 2945 | 2945 | mutex_unlock(&local->mtx); |
| @@ -3089,52 +3089,11 @@ unlock: · 143 unmodified lines | ||
| 3089 | 3089 | sdata_unlock(sdata); |
| 3090 | 3090 | } |
| 3091 | 3091 | |
| 3092 | −int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |
| 3093 | − struct cfg80211_csa_settings *params) | |
| 3092 | +static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |
| 3093 | + struct cfg80211_csa_settings *params, | |
| 3094 | + u32 *changed) | |
| 3094 | 3095 | { |
| 3095 | − struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | |
| 3096 | − struct ieee80211_local *local = sdata->local; | |
| 3097 | − struct ieee80211_chanctx_conf *chanctx_conf; | |
| 3098 | − struct ieee80211_chanctx *chanctx; | |
| 3099 | − struct ieee80211_if_mesh __maybe_unused *ifmsh; | |
| 3100 | − int err, num_chanctx, changed = 0; | |
| 3101 | − | |
| 3102 | − sdata_assert_lock(sdata); | |
| 3103 | − | |
| 3104 | − if (!list_empty(&local->roc_list) || local->scanning) | |
| 3105 | − return -EBUSY; | |
| 3106 | − | |
| 3107 | − if (sdata->wdev.cac_started) | |
| 3108 | − return -EBUSY; | |
| 3109 | − | |
| 3110 | − if (cfg80211_chandef_identical(¶ms->chandef, | |
| 3111 | − &sdata->vif.bss_conf.chandef)) | |
| 3112 | − return -EINVAL; | |
| 3113 | − | |
| 3114 | − rcu_read_lock(); | |
| 3115 | − chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | |
| 3116 | − if (!chanctx_conf) { | |
| 3117 | − rcu_read_unlock(); | |
| 3118 | − return -EBUSY; | |
| 3119 | − } | |
| 3120 | − | |
| 3121 | − /* don't handle for multi-VIF cases */ | |
| 3122 | − chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | |
| 3123 | − if (chanctx->refcount > 1) { | |
| 3124 | − rcu_read_unlock(); | |
| 3125 | − return -EBUSY; | |
| 3126 | − } | |
| 3127 | − num_chanctx = 0; | |
| 3128 | − list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) | |
| 3129 | − num_chanctx++; | |
| 3130 | − rcu_read_unlock(); | |
| 3131 | − | |
| 3132 | − if (num_chanctx > 1) | |
| 3133 | − return -EBUSY; | |
| 3134 | − | |
| 3135 | − /* don't allow another channel switch if one is already active. */ | |
| 3136 | − if (sdata->vif.csa_active) | |
| 3137 | − return -EBUSY; | |
| 3096 | + int err; | |
| 3138 | 3097 | |
| 3139 | 3098 | switch (sdata->vif.type) { |
| 3140 | 3099 | case NL80211_IFTYPE_AP: |
| @@ -3170,7 +3129,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, · 29 unmodified lines | ||
| 3170 | 3129 | kfree(sdata->u.ap.next_beacon); |
| 3171 | 3130 | return err; |
| 3172 | 3131 | } |
| 3173 | − changed |= err; | |
| 3132 | + *changed |= err; | |
| 3174 | 3133 | |
| 3175 | 3134 | break; |
| 3176 | 3135 | case NL80211_IFTYPE_ADHOC: |
| @@ -3204,15 +3163,15 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, · 27 unmodified lines | ||
| 3204 | 3163 | err = ieee80211_ibss_csa_beacon(sdata, params); |
| 3205 | 3164 | if (err < 0) |
| 3206 | 3165 | return err; |
| 3207 | − changed |= err; | |
| 3166 | + *changed |= err; | |
| 3208 | 3167 | } |
| 3209 | 3168 | |
| 3210 | 3169 | ieee80211_send_action_csa(sdata, params); |
| 3211 | 3170 | |
| 3212 | 3171 | break; |
| 3213 | 3172 | #ifdef CONFIG_MAC80211_MESH |
| 3214 | − case NL80211_IFTYPE_MESH_POINT: | |
| 3215 | − ifmsh = &sdata->u.mesh; | |
| 3173 | + case NL80211_IFTYPE_MESH_POINT: { | |
| 3174 | + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | |
| 3216 | 3175 | |
| 3217 | 3176 | if (params->chandef.width != sdata->vif.bss_conf.chandef.width) |
| 3218 | 3177 | return -EINVAL; |
| @@ -3237,18 +3196,72 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, · 18 unmodified lines | ||
| 3237 | 3196 | ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; |
| 3238 | 3197 | return err; |
| 3239 | 3198 | } |
| 3240 | − changed |= err; | |
| 3199 | + *changed |= err; | |
| 3241 | 3200 | } |
| 3242 | 3201 | |
| 3243 | 3202 | if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) |
| 3244 | 3203 | ieee80211_send_action_csa(sdata, params); |
| 3245 | 3204 | |
| 3246 | 3205 | break; |
| 3206 | + } | |
| 3247 | 3207 | #endif |
| 3248 | 3208 | default: |
| 3249 | 3209 | return -EOPNOTSUPP; |
| 3250 | 3210 | } |
| 3251 | 3211 | |
| 3212 | + return 0; | |
| 3213 | +} | |
| 3214 | + | |
| 3215 | +int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |
| 3216 | + struct cfg80211_csa_settings *params) | |
| 3217 | +{ | |
| 3218 | + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | |
| 3219 | + struct ieee80211_local *local = sdata->local; | |
| 3220 | + struct ieee80211_chanctx_conf *chanctx_conf; | |
| 3221 | + struct ieee80211_chanctx *chanctx; | |
| 3222 | + int err, num_chanctx, changed = 0; | |
| 3223 | + | |
| 3224 | + sdata_assert_lock(sdata); | |
| 3225 | + | |
| 3226 | + if (!list_empty(&local->roc_list) || local->scanning) | |
| 3227 | + return -EBUSY; | |
| 3228 | + | |
| 3229 | + if (sdata->wdev.cac_started) | |
| 3230 | + return -EBUSY; | |
| 3231 | + | |
| 3232 | + if (cfg80211_chandef_identical(¶ms->chandef, | |
| 3233 | + &sdata->vif.bss_conf.chandef)) | |
| 3234 | + return -EINVAL; | |
| 3235 | + | |
| 3236 | + rcu_read_lock(); | |
| 3237 | + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | |
| 3238 | + if (!chanctx_conf) { | |
| 3239 | + rcu_read_unlock(); | |
| 3240 | + return -EBUSY; | |
| 3241 | + } | |
| 3242 | + | |
| 3243 | + /* don't handle for multi-VIF cases */ | |
| 3244 | + chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | |
| 3245 | + if (chanctx->refcount > 1) { | |
| 3246 | + rcu_read_unlock(); | |
| 3247 | + return -EBUSY; | |
| 3248 | + } | |
| 3249 | + num_chanctx = 0; | |
| 3250 | + list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) | |
| 3251 | + num_chanctx++; | |
| 3252 | + rcu_read_unlock(); | |
| 3253 | + | |
| 3254 | + if (num_chanctx > 1) | |
| 3255 | + return -EBUSY; | |
| 3256 | + | |
| 3257 | + /* don't allow another channel switch if one is already active. */ | |
| 3258 | + if (sdata->vif.csa_active) | |
| 3259 | + return -EBUSY; | |
| 3260 | + | |
| 3261 | + err = ieee80211_set_csa_beacon(sdata, params, &changed); | |
| 3262 | + if (err) | |
| 3263 | + return err; | |
| 3264 | + | |
| 3252 | 3265 | sdata->csa_radar_required = params->radar_required; |
| 3253 | 3266 | |
| 3254 | 3267 | if (params->block_tx) |
| @@ -991,7 +991,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, · 990 unmodified lines | ||
| 991 | 991 | struct ieee802_11_elems *elems) |
| 992 | 992 | { |
| 993 | 993 | struct ieee80211_local *local = sdata->local; |
| 994 | − int freq; | |
| 995 | 994 | struct cfg80211_bss *cbss; |
| 996 | 995 | struct ieee80211_bss *bss; |
| 997 | 996 | struct sta_info *sta; |
| @@ -1003,15 +1002,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, · 5 unmodified lines | ||
| 1003 | 1002 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; |
| 1004 | 1003 | bool rates_updated = false; |
| 1005 | 1004 | |
| 1006 | − if (elems->ds_params) | |
| 1007 | − freq = ieee80211_channel_to_frequency(elems->ds_params[0], | |
| 1008 | − band); | |
| 1009 | − else | |
| 1010 | − freq = rx_status->freq; | |
| 1011 | − | |
| 1012 | − channel = ieee80211_get_channel(local->hw.wiphy, freq); | |
| 1013 | − | |
| 1014 | − if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | |
| 1005 | + channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); | |
| 1006 | + if (!channel) | |
| 1015 | 1007 | return; |
| 1016 | 1008 | |
| 1017 | 1009 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
| @@ -1391,6 +1391,7 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); · 1390 unmodified lines | ||
| 1391 | 1391 | void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata); |
| 1392 | 1392 | void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, |
| 1393 | 1393 | __le16 fc, bool acked); |
| 1394 | +void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); | |
| 1394 | 1395 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); |
| 1395 | 1396 | |
| 1396 | 1397 | /* IBSS code */ |
| @@ -2783,28 +2783,20 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, · 2782 unmodified lines | ||
| 2783 | 2783 | struct ieee802_11_elems *elems) |
| 2784 | 2784 | { |
| 2785 | 2785 | struct ieee80211_local *local = sdata->local; |
| 2786 | − int freq; | |
| 2787 | 2786 | struct ieee80211_bss *bss; |
| 2788 | 2787 | struct ieee80211_channel *channel; |
| 2789 | 2788 | |
| 2790 | 2789 | sdata_assert_lock(sdata); |
| 2791 | 2790 | |
| 2792 | − if (elems->ds_params) | |
| 2793 | − freq = ieee80211_channel_to_frequency(elems->ds_params[0], | |
| 2794 | − rx_status->band); | |
| 2795 | − else | |
| 2796 | − freq = rx_status->freq; | |
| 2797 | − | |
| 2798 | − channel = ieee80211_get_channel(local->hw.wiphy, freq); | |
| 2799 | − | |
| 2800 | − if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | |
| 2791 | + channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); | |
| 2792 | + if (!channel) | |
| 2801 | 2793 | return; |
| 2802 | 2794 | |
| 2803 | 2795 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
| 2804 | 2796 | channel); |
| 2805 | 2797 | if (bss) { |
| 2806 | − ieee80211_rx_bss_put(local, bss); | |
| 2807 | 2798 | sdata->vif.bss_conf.beacon_rate = bss->beacon_rate; |
| 2799 | + ieee80211_rx_bss_put(local, bss); | |
| 2808 | 2800 | } |
| 2809 | 2801 | } |
| 2810 | 2802 | |
| @@ -3599,6 +3591,32 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) · 788 unmodified lines | ||
| 3599 | 3591 | } |
| 3600 | 3592 | |
| 3601 | 3593 | #ifdef CONFIG_PM |
| 3594 | +void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) | |
| 3595 | +{ | |
| 3596 | + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | |
| 3597 | + u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | |
| 3598 | + | |
| 3599 | + sdata_lock(sdata); | |
| 3600 | + | |
| 3601 | + if (ifmgd->auth_data) { | |
| 3602 | + /* | |
| 3603 | + * If we are trying to authenticate while suspending, cfg80211 | |
| 3604 | + * won't know and won't actually abort those attempts, thus we | |
| 3605 | + * need to do that ourselves. | |
| 3606 | + */ | |
| 3607 | + ieee80211_send_deauth_disassoc(sdata, | |
| 3608 | + ifmgd->auth_data->bss->bssid, | |
| 3609 | + IEEE80211_STYPE_DEAUTH, | |
| 3610 | + WLAN_REASON_DEAUTH_LEAVING, | |
| 3611 | + false, frame_buf); | |
| 3612 | + ieee80211_destroy_auth_data(sdata, false); | |
| 3613 | + cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | |
| 3614 | + IEEE80211_DEAUTH_FRAME_LEN); | |
| 3615 | + } | |
| 3616 | + | |
| 3617 | + sdata_unlock(sdata); | |
| 3618 | +} | |
| 3619 | + | |
| 3602 | 3620 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) |
| 3603 | 3621 | { |
| 3604 | 3622 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| @@ -4417,37 +4435,41 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, · 812 unmodified lines | ||
| 4417 | 4435 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 4418 | 4436 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
| 4419 | 4437 | bool tx = !req->local_state_change; |
| 4420 | − bool report_frame = false; | |
| 4421 | 4438 | |
| 4422 | − sdata_info(sdata, | |
| 4423 | − "deauthenticating from %pM by local choice (Reason: %u=%s)\n", | |
| 4424 | − req->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code)); | |
| 4439 | + if (ifmgd->auth_data && | |
| 4440 | + ether_addr_equal(ifmgd->auth_data->bss->bssid, req->bssid)) { | |
| 4441 | + sdata_info(sdata, | |
| 4442 | + "aborting authentication with %pM by local choice (Reason: %u=%s)\n", | |
| 4443 | + req->bssid, req->reason_code, | |
| 4444 | + ieee80211_get_reason_code_string(req->reason_code)); | |
| 4425 | 4445 | |
| 4426 | − if (ifmgd->auth_data) { | |
| 4427 | 4446 | drv_mgd_prepare_tx(sdata->local, sdata); |
| 4428 | 4447 | ieee80211_send_deauth_disassoc(sdata, req->bssid, |
| 4429 | 4448 | IEEE80211_STYPE_DEAUTH, |
| 4430 | 4449 | req->reason_code, tx, |
| 4431 | 4450 | frame_buf); |
| 4432 | 4451 | ieee80211_destroy_auth_data(sdata, false); |
| 4452 | + cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | |
| 4453 | + IEEE80211_DEAUTH_FRAME_LEN); | |
| 4433 | 4454 | |
| 4434 | − report_frame = true; | |
| 4435 | − goto out; | |
| 4455 | + return 0; | |
| 4436 | 4456 | } |
| 4437 | 4457 | |
| 4438 | 4458 | if (ifmgd->associated && |
| 4439 | 4459 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { |
| 4460 | + sdata_info(sdata, | |
| 4461 | + "deauthenticating from %pM by local choice (Reason: %u=%s)\n", | |
| 4462 | + req->bssid, req->reason_code, | |
| 4463 | + ieee80211_get_reason_code_string(req->reason_code)); | |
| 4464 | + | |
| 4440 | 4465 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
| 4441 | 4466 | req->reason_code, tx, frame_buf); |
| 4442 | − report_frame = true; | |
| 4443 | − } | |
| 4444 | − | |
| 4445 | − out: | |
| 4446 | − if (report_frame) | |
| 4447 | 4467 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
| 4448 | 4468 | IEEE80211_DEAUTH_FRAME_LEN); |
| 4469 | + return 0; | |
| 4470 | + } | |
| 4449 | 4471 | |
| 4450 | − return 0; | |
| 4472 | + return -ENOTCONN; | |
| 4451 | 4473 | } |
| 4452 | 4474 | |
| 4453 | 4475 | int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, |
| @@ -100,10 +100,18 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) · 99 unmodified lines | ||
| 100 | 100 | |
| 101 | 101 | /* remove all interfaces that were created in the driver */ |
| 102 | 102 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 103 | − if (!ieee80211_sdata_running(sdata) || | |
| 104 | − sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | |
| 105 | − sdata->vif.type == NL80211_IFTYPE_MONITOR) | |
| 103 | + if (!ieee80211_sdata_running(sdata)) | |
| 106 | 104 | continue; |
| 105 | + switch (sdata->vif.type) { | |
| 106 | + case NL80211_IFTYPE_AP_VLAN: | |
| 107 | + case NL80211_IFTYPE_MONITOR: | |
| 108 | + continue; | |
| 109 | + case NL80211_IFTYPE_STATION: | |
| 110 | + ieee80211_mgd_quiesce(sdata); | |
| 111 | + break; | |
| 112 | + default: | |
| 113 | + break; | |
| 114 | + } | |
| 107 | 115 | |
| 108 | 116 | drv_remove_interface(local, sdata); |
| 109 | 117 | } |
| @@ -333,6 +333,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, · 332 unmodified lines | ||
| 333 | 333 | /* in VHT, STBC is binary */ |
| 334 | 334 | if (status->flag & RX_FLAG_STBC_MASK) |
| 335 | 335 | *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; |
| 336 | + if (status->vht_flag & RX_VHT_FLAG_BF) | |
| 337 | + *pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED; | |
| 336 | 338 | pos++; |
| 337 | 339 | /* bandwidth */ |
| 338 | 340 | if (status->vht_flag & RX_VHT_FLAG_80MHZ) |
| @@ -1245,6 +1247,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) · 906 unmodified lines | ||
| 1245 | 1247 | if (ieee80211_is_data(hdr->frame_control)) { |
| 1246 | 1248 | sta->last_rx_rate_idx = status->rate_idx; |
| 1247 | 1249 | sta->last_rx_rate_flag = status->flag; |
| 1250 | + sta->last_rx_rate_vht_flag = status->vht_flag; | |
| 1248 | 1251 | sta->last_rx_rate_vht_nss = status->vht_nss; |
| 1249 | 1252 | } |
| 1250 | 1253 | } |
| @@ -1055,9 +1055,11 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) · 1054 unmodified lines | ||
| 1055 | 1055 | /* We don't want to restart sched scan anymore. */ |
| 1056 | 1056 | local->sched_scan_req = NULL; |
| 1057 | 1057 | |
| 1058 | − if (rcu_access_pointer(local->sched_scan_sdata)) | |
| 1058 | + if (rcu_access_pointer(local->sched_scan_sdata)) { | |
| 1059 | 1059 | ret = drv_sched_scan_stop(local, sdata); |
| 1060 | − | |
| 1060 | + if (!ret) | |
| 1061 | + rcu_assign_pointer(local->sched_scan_sdata, NULL); | |
| 1062 | + } | |
| 1061 | 1063 | out: |
| 1062 | 1064 | mutex_unlock(&local->mtx); |
| 1063 | 1065 | |
| @@ -2900,7 +2900,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, · 2899 unmodified lines | ||
| 2900 | 2900 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
| 2901 | 2901 | } |
| 2902 | 2902 | |
| 2903 | − if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | |
| 2903 | + if (sdata->vif.type == NL80211_IFTYPE_AP) | |
| 2904 | 2904 | sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); |
| 2905 | 2905 | if (!ieee80211_tx_prepare(sdata, &tx, skb)) |
| 2906 | 2906 | break; |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | |
| 9 | 9 | static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, |
| 10 | − struct net_device *dev) | |
| 10 | + struct net_device *dev, bool notify) | |
| 11 | 11 | { |
| 12 | 12 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 13 | 13 | int err; |
| @@ -30,20 +30,21 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, · 16 unmodified lines | ||
| 30 | 30 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); |
| 31 | 31 | wdev->ssid_len = 0; |
| 32 | 32 | rdev_set_qos_map(rdev, dev, NULL); |
| 33 | − nl80211_send_ap_stopped(wdev); | |
| 33 | + if (notify) | |
| 34 | + nl80211_send_ap_stopped(wdev); | |
| 34 | 35 | } |
| 35 | 36 | |
| 36 | 37 | return err; |
| 37 | 38 | } |
| 38 | 39 | |
| 39 | 40 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, |
| 40 | − struct net_device *dev) | |
| 41 | + struct net_device *dev, bool notify) | |
| 41 | 42 | { |
| 42 | 43 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 43 | 44 | int err; |
| 44 | 45 | |
| 45 | 46 | wdev_lock(wdev); |
| 46 | − err = __cfg80211_stop_ap(rdev, dev); | |
| 47 | + err = __cfg80211_stop_ap(rdev, dev, notify); | |
| 47 | 48 | wdev_unlock(wdev); |
| 48 | 49 | |
| 49 | 50 | return err; |
| @@ -490,6 +490,62 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy, · 489 unmodified lines | ||
| 490 | 490 | return r; |
| 491 | 491 | } |
| 492 | 492 | |
| 493 | +static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy, | |
| 494 | + u32 center_freq, | |
| 495 | + u32 bandwidth) | |
| 496 | +{ | |
| 497 | + struct ieee80211_channel *c; | |
| 498 | + u32 start_freq, end_freq, freq; | |
| 499 | + unsigned int dfs_cac_ms = 0; | |
| 500 | + | |
| 501 | + start_freq = cfg80211_get_start_freq(center_freq, bandwidth); | |
| 502 | + end_freq = cfg80211_get_end_freq(center_freq, bandwidth); | |
| 503 | + | |
| 504 | + for (freq = start_freq; freq <= end_freq; freq += 20) { | |
| 505 | + c = ieee80211_get_channel(wiphy, freq); | |
| 506 | + if (!c) | |
| 507 | + return 0; | |
| 508 | + | |
| 509 | + if (c->flags & IEEE80211_CHAN_DISABLED) | |
| 510 | + return 0; | |
| 511 | + | |
| 512 | + if (!(c->flags & IEEE80211_CHAN_RADAR)) | |
| 513 | + continue; | |
| 514 | + | |
| 515 | + if (c->dfs_cac_ms > dfs_cac_ms) | |
| 516 | + dfs_cac_ms = c->dfs_cac_ms; | |
| 517 | + } | |
| 518 | + | |
| 519 | + return dfs_cac_ms; | |
| 520 | +} | |
| 521 | + | |
| 522 | +unsigned int | |
| 523 | +cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, | |
| 524 | + const struct cfg80211_chan_def *chandef) | |
| 525 | +{ | |
| 526 | + int width; | |
| 527 | + unsigned int t1 = 0, t2 = 0; | |
| 528 | + | |
| 529 | + if (WARN_ON(!cfg80211_chandef_valid(chandef))) | |
| 530 | + return 0; | |
| 531 | + | |
| 532 | + width = cfg80211_chandef_get_width(chandef); | |
| 533 | + if (width < 0) | |
| 534 | + return 0; | |
| 535 | + | |
| 536 | + t1 = cfg80211_get_chans_dfs_cac_time(wiphy, | |
| 537 | + chandef->center_freq1, | |
| 538 | + width); | |
| 539 | + | |
| 540 | + if (!chandef->center_freq2) | |
| 541 | + return t1; | |
| 542 | + | |
| 543 | + t2 = cfg80211_get_chans_dfs_cac_time(wiphy, | |
| 544 | + chandef->center_freq2, | |
| 545 | + width); | |
| 546 | + | |
| 547 | + return max(t1, t2); | |
| 548 | +} | |
| 493 | 549 | |
| 494 | 550 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, |
| 495 | 551 | u32 center_freq, u32 bandwidth, |
| @@ -783,7 +783,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, · 782 unmodified lines | ||
| 783 | 783 | break; |
| 784 | 784 | case NL80211_IFTYPE_AP: |
| 785 | 785 | case NL80211_IFTYPE_P2P_GO: |
| 786 | − cfg80211_stop_ap(rdev, dev); | |
| 786 | + cfg80211_stop_ap(rdev, dev, true); | |
| 787 | 787 | break; |
| 788 | 788 | default: |
| 789 | 789 | break; |
| @@ -166,7 +166,6 @@ static inline void wdev_unlock(struct wireless_dev *wdev) · 165 unmodified lines | ||
| 166 | 166 | mutex_unlock(&wdev->mtx); |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | −#define ASSERT_RDEV_LOCK(rdev) ASSERT_RTNL() | |
| 170 | 169 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
| 171 | 170 | |
| 172 | 171 | static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) |
| @@ -246,10 +245,6 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, · 73 unmodified lines | ||
| 246 | 245 | unsigned long age_secs); |
| 247 | 246 | |
| 248 | 247 | /* IBSS */ |
| 249 | −int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |
| 250 | − struct net_device *dev, | |
| 251 | − struct cfg80211_ibss_params *params, | |
| 252 | − struct cfg80211_cached_keys *connkeys); | |
| 253 | 248 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, |
| 254 | 249 | struct net_device *dev, |
| 255 | 250 | struct cfg80211_ibss_params *params, |
| @@ -283,7 +278,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, · 27 unmodified lines | ||
| 283 | 278 | |
| 284 | 279 | /* AP */ |
| 285 | 280 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, |
| 286 | − struct net_device *dev); | |
| 281 | + struct net_device *dev, bool notify); | |
| 287 | 282 | |
| 288 | 283 | /* MLME */ |
| 289 | 284 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
| @@ -402,6 +397,9 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy, · 112 unmodified lines | ||
| 402 | 397 | |
| 403 | 398 | void cfg80211_dfs_channels_update_work(struct work_struct *work); |
| 404 | 399 | |
| 400 | +unsigned int | |
| 401 | +cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, | |
| 402 | + const struct cfg80211_chan_def *chandef); | |
| 405 | 403 | |
| 406 | 404 | static inline int |
| 407 | 405 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, |
| @@ -66,6 +66,7 @@ function parse_reg_rule() · 65 unmodified lines | ||
| 66 | 66 | units = $8 |
| 67 | 67 | sub(/\)/, "", units) |
| 68 | 68 | sub(/,/, "", units) |
| 69 | + dfs_cac = $9 | |
| 69 | 70 | if (units == "mW") { |
| 70 | 71 | if (power == 100) { |
| 71 | 72 | power = 20 |
| @@ -78,7 +79,12 @@ function parse_reg_rule() · 6 unmodified lines | ||
| 78 | 79 | } else { |
| 79 | 80 | print "Unknown power value in database!" |
| 80 | 81 | } |
| 82 | + } else { | |
| 83 | + dfs_cac = $8 | |
| 81 | 84 | } |
| 85 | + sub(/,/, "", dfs_cac) | |
| 86 | + sub(/\(/, "", dfs_cac) | |
| 87 | + sub(/\)/, "", dfs_cac) | |
| 82 | 88 | flagstr = "" |
| 83 | 89 | for (i=8; i<=NF; i++) |
| 84 | 90 | flagstr = flagstr $i |
| @@ -111,7 +117,7 @@ function parse_reg_rule() · 26 unmodified lines | ||
| 111 | 117 | |
| 112 | 118 | } |
| 113 | 119 | flags = flags "0" |
| 114 | − printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags | |
| 120 | + printf "\t\tREG_RULE_EXT(%d, %d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, dfs_cac, flags | |
| 115 | 121 | rules++ |
| 116 | 122 | } |
| 117 | 123 | |
| @@ -82,10 +82,10 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, · 81 unmodified lines | ||
| 82 | 82 | } |
| 83 | 83 | EXPORT_SYMBOL(cfg80211_ibss_joined); |
| 84 | 84 | |
| 85 | −int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |
| 86 | − struct net_device *dev, | |
| 87 | − struct cfg80211_ibss_params *params, | |
| 88 | − struct cfg80211_cached_keys *connkeys) | |
| 85 | +static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |
| 86 | + struct net_device *dev, | |
| 87 | + struct cfg80211_ibss_params *params, | |
| 88 | + struct cfg80211_cached_keys *connkeys) | |
| 89 | 89 | { |
| 90 | 90 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 91 | 91 | struct ieee80211_channel *check_chan; |
| @@ -778,7 +778,7 @@ void cfg80211_cac_event(struct net_device *netdev, · 777 unmodified lines | ||
| 778 | 778 | switch (event) { |
| 779 | 779 | case NL80211_RADAR_CAC_FINISHED: |
| 780 | 780 | timeout = wdev->cac_start_time + |
| 781 | − msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | |
| 781 | + msecs_to_jiffies(wdev->cac_time_ms); | |
| 782 | 782 | WARN_ON(!time_after_eq(jiffies, timeout)); |
| 783 | 783 | cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); |
| 784 | 784 | break; |
| @@ -593,6 +593,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, · 592 unmodified lines | ||
| 593 | 593 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, |
| 594 | 594 | time)) |
| 595 | 595 | goto nla_put_failure; |
| 596 | + if (nla_put_u32(msg, | |
| 597 | + NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, | |
| 598 | + chan->dfs_cac_ms)) | |
| 599 | + goto nla_put_failure; | |
| 596 | 600 | } |
| 597 | 601 | } |
| 598 | 602 | |
| @@ -3328,7 +3332,7 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) · 2729 unmodified lines | ||
| 3328 | 3332 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 3329 | 3333 | struct net_device *dev = info->user_ptr[1]; |
| 3330 | 3334 | |
| 3331 | − return cfg80211_stop_ap(rdev, dev); | |
| 3335 | + return cfg80211_stop_ap(rdev, dev, false); | |
| 3332 | 3336 | } |
| 3333 | 3337 | |
| 3334 | 3338 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
| @@ -4614,6 +4618,7 @@ static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = · 1279 unmodified lines | ||
| 4614 | 4618 | [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, |
| 4615 | 4619 | [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, |
| 4616 | 4620 | [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, |
| 4621 | + [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 }, | |
| 4617 | 4622 | }; |
| 4618 | 4623 | |
| 4619 | 4624 | static int parse_reg_rule(struct nlattr *tb[], |
| @@ -4649,6 +4654,10 @@ static int parse_reg_rule(struct nlattr *tb[], · 29 unmodified lines | ||
| 4649 | 4654 | power_rule->max_antenna_gain = |
| 4650 | 4655 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); |
| 4651 | 4656 | |
| 4657 | + if (tb[NL80211_ATTR_DFS_CAC_TIME]) | |
| 4658 | + reg_rule->dfs_cac_ms = | |
| 4659 | + nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]); | |
| 4660 | + | |
| 4652 | 4661 | return 0; |
| 4653 | 4662 | } |
| 4654 | 4663 | |
| @@ -5136,7 +5145,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) · 481 unmodified lines | ||
| 5136 | 5145 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, |
| 5137 | 5146 | power_rule->max_antenna_gain) || |
| 5138 | 5147 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, |
| 5139 | − power_rule->max_eirp)) | |
| 5148 | + power_rule->max_eirp) || | |
| 5149 | + nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME, | |
| 5150 | + reg_rule->dfs_cac_ms)) | |
| 5140 | 5151 | goto nla_put_failure_rcu; |
| 5141 | 5152 | |
| 5142 | 5153 | nla_nest_end(msg, nl_reg_rule); |
| @@ -5768,6 +5779,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, · 625 unmodified lines | ||
| 5768 | 5779 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 5769 | 5780 | struct cfg80211_chan_def chandef; |
| 5770 | 5781 | enum nl80211_dfs_regions dfs_region; |
| 5782 | + unsigned int cac_time_ms; | |
| 5771 | 5783 | int err; |
| 5772 | 5784 | |
| 5773 | 5785 | dfs_region = reg_get_dfs_region(wdev->wiphy); |
| @@ -5803,11 +5815,17 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, · 29 unmodified lines | ||
| 5803 | 5815 | if (err) |
| 5804 | 5816 | return err; |
| 5805 | 5817 | |
| 5806 | − err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | |
| 5818 | + cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef); | |
| 5819 | + if (WARN_ON(!cac_time_ms)) | |
| 5820 | + cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; | |
| 5821 | + | |
| 5822 | + err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef, | |
| 5823 | + cac_time_ms); | |
| 5807 | 5824 | if (!err) { |
| 5808 | 5825 | wdev->chandef = chandef; |
| 5809 | 5826 | wdev->cac_started = true; |
| 5810 | 5827 | wdev->cac_start_time = jiffies; |
| 5828 | + wdev->cac_time_ms = cac_time_ms; | |
| 5811 | 5829 | } |
| 5812 | 5830 | return err; |
| 5813 | 5831 | } |
| @@ -91,10 +91,6 @@ static struct regulatory_request __rcu *last_request = · 90 unmodified lines | ||
| 91 | 91 | /* To trigger userspace events */ |
| 92 | 92 | static struct platform_device *reg_pdev; |
| 93 | 93 | |
| 94 | −static const struct device_type reg_device_type = { | |
| 95 | − .uevent = reg_device_uevent, | |
| 96 | −}; | |
| 97 | − | |
| 98 | 94 | /* |
| 99 | 95 | * Central wireless core regulatory domains, we only need two, |
| 100 | 96 | * the current one and a world regulatory domain in case we have no |
| @@ -244,19 +240,21 @@ static char user_alpha2[2]; · 143 unmodified lines | ||
| 244 | 240 | module_param(ieee80211_regdom, charp, 0444); |
| 245 | 241 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
| 246 | 242 | |
| 247 | −static void reg_kfree_last_request(void) | |
| 243 | +static void reg_free_request(struct regulatory_request *lr) | |
| 248 | 244 | { |
| 249 | − struct regulatory_request *lr; | |
| 250 | − | |
| 251 | − lr = get_last_request(); | |
| 252 | − | |
| 253 | 245 | if (lr != &core_request_world && lr) |
| 254 | 246 | kfree_rcu(lr, rcu_head); |
| 255 | 247 | } |
| 256 | 248 | |
| 257 | 249 | static void reg_update_last_request(struct regulatory_request *request) |
| 258 | 250 | { |
| 259 | − reg_kfree_last_request(); | |
| 251 | + struct regulatory_request *lr; | |
| 252 | + | |
| 253 | + lr = get_last_request(); | |
| 254 | + if (lr == request) | |
| 255 | + return; | |
| 256 | + | |
| 257 | + reg_free_request(lr); | |
| 260 | 258 | rcu_assign_pointer(last_request, request); |
| 261 | 259 | } |
| 262 | 260 | |
| @@ -487,11 +485,16 @@ static inline void reg_regdb_query(const char *alpha2) {} · 224 unmodified lines | ||
| 487 | 485 | |
| 488 | 486 | /* |
| 489 | 487 | * This lets us keep regulatory code which is updated on a regulatory |
| 490 | − * basis in userspace. Country information is filled in by | |
| 491 | − * reg_device_uevent | |
| 488 | + * basis in userspace. | |
| 492 | 489 | */ |
| 493 | 490 | static int call_crda(const char *alpha2) |
| 494 | 491 | { |
| 492 | + char country[12]; | |
| 493 | + char *env[] = { country, NULL }; | |
| 494 | + | |
| 495 | + snprintf(country, sizeof(country), "COUNTRY=%c%c", | |
| 496 | + alpha2[0], alpha2[1]); | |
| 497 | + | |
| 495 | 498 | if (!is_world_regdom((char *) alpha2)) |
| 496 | 499 | pr_info("Calling CRDA for country: %c%c\n", |
| 497 | 500 | alpha2[0], alpha2[1]); |
| @@ -501,7 +504,7 @@ static int call_crda(const char *alpha2) · 3 unmodified lines | ||
| 501 | 504 | /* query internal regulatory database (if it exists) */ |
| 502 | 505 | reg_regdb_query(alpha2); |
| 503 | 506 | |
| 504 | − return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE); | |
| 507 | + return kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env); | |
| 505 | 508 | } |
| 506 | 509 | |
| 507 | 510 | static enum reg_request_treatment |
| @@ -755,6 +758,9 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, · 247 unmodified lines | ||
| 755 | 758 | power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, |
| 756 | 759 | power_rule2->max_antenna_gain); |
| 757 | 760 | |
| 761 | + intersected_rule->dfs_cac_ms = max(rule1->dfs_cac_ms, | |
| 762 | + rule2->dfs_cac_ms); | |
| 763 | + | |
| 758 | 764 | if (!is_valid_reg_rule(intersected_rule)) |
| 759 | 765 | return -EINVAL; |
| 760 | 766 | |
| @@ -1077,6 +1083,14 @@ static void handle_channel(struct wiphy *wiphy, · 316 unmodified lines | ||
| 1077 | 1083 | min_t(int, chan->orig_mag, |
| 1078 | 1084 | MBI_TO_DBI(power_rule->max_antenna_gain)); |
| 1079 | 1085 | chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
| 1086 | + | |
| 1087 | + if (chan->flags & IEEE80211_CHAN_RADAR) { | |
| 1088 | + if (reg_rule->dfs_cac_ms) | |
| 1089 | + chan->dfs_cac_ms = reg_rule->dfs_cac_ms; | |
| 1090 | + else | |
| 1091 | + chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; | |
| 1092 | + } | |
| 1093 | + | |
| 1080 | 1094 | if (chan->orig_mpwr) { |
| 1081 | 1095 | /* |
| 1082 | 1096 | * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER |
| @@ -2255,9 +2269,9 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) · 1172 unmodified lines | ||
| 2255 | 2269 | const struct ieee80211_reg_rule *reg_rule = NULL; |
| 2256 | 2270 | const struct ieee80211_freq_range *freq_range = NULL; |
| 2257 | 2271 | const struct ieee80211_power_rule *power_rule = NULL; |
| 2258 | − char bw[32]; | |
| 2272 | + char bw[32], cac_time[32]; | |
| 2259 | 2273 | |
| 2260 | − pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); | |
| 2274 | + pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)\n"); | |
| 2261 | 2275 | |
| 2262 | 2276 | for (i = 0; i < rd->n_reg_rules; i++) { |
| 2263 | 2277 | reg_rule = &rd->reg_rules[i]; |
| @@ -2272,23 +2286,32 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) · 8 unmodified lines | ||
| 2272 | 2286 | snprintf(bw, sizeof(bw), "%d KHz", |
| 2273 | 2287 | freq_range->max_bandwidth_khz); |
| 2274 | 2288 | |
| 2289 | + if (reg_rule->flags & NL80211_RRF_DFS) | |
| 2290 | + scnprintf(cac_time, sizeof(cac_time), "%u s", | |
| 2291 | + reg_rule->dfs_cac_ms/1000); | |
| 2292 | + else | |
| 2293 | + scnprintf(cac_time, sizeof(cac_time), "N/A"); | |
| 2294 | + | |
| 2295 | + | |
| 2275 | 2296 | /* |
| 2276 | 2297 | * There may not be documentation for max antenna gain |
| 2277 | 2298 | * in certain regions |
| 2278 | 2299 | */ |
| 2279 | 2300 | if (power_rule->max_antenna_gain) |
| 2280 | − pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n", | |
| 2301 | + pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm), (%s)\n", | |
| 2281 | 2302 | freq_range->start_freq_khz, |
| 2282 | 2303 | freq_range->end_freq_khz, |
| 2283 | 2304 | bw, |
| 2284 | 2305 | power_rule->max_antenna_gain, |
| 2285 | − power_rule->max_eirp); | |
| 2306 | + power_rule->max_eirp, | |
| 2307 | + cac_time); | |
| 2286 | 2308 | else |
| 2287 | − pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n", | |
| 2309 | + pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm), (%s)\n", | |
| 2288 | 2310 | freq_range->start_freq_khz, |
| 2289 | 2311 | freq_range->end_freq_khz, |
| 2290 | 2312 | bw, |
| 2291 | − power_rule->max_eirp); | |
| 2313 | + power_rule->max_eirp, | |
| 2314 | + cac_time); | |
| 2292 | 2315 | } |
| 2293 | 2316 | } |
| 2294 | 2317 | |
| @@ -2361,9 +2384,6 @@ static int reg_set_rd_user(const struct ieee80211_regdomain *rd, · 66 unmodified lines | ||
| 2361 | 2384 | { |
| 2362 | 2385 | const struct ieee80211_regdomain *intersected_rd = NULL; |
| 2363 | 2386 | |
| 2364 | − if (is_world_regdom(rd->alpha2)) | |
| 2365 | − return -EINVAL; | |
| 2366 | − | |
| 2367 | 2387 | if (!regdom_changes(rd->alpha2)) |
| 2368 | 2388 | return -EALREADY; |
| 2369 | 2389 | |
| @@ -2552,26 +2572,6 @@ int set_regdom(const struct ieee80211_regdomain *rd) · 182 unmodified lines | ||
| 2552 | 2572 | return 0; |
| 2553 | 2573 | } |
| 2554 | 2574 | |
| 2555 | −int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) | |
| 2556 | −{ | |
| 2557 | − struct regulatory_request *lr; | |
| 2558 | − u8 alpha2[2]; | |
| 2559 | − bool add = false; | |
| 2560 | − | |
| 2561 | − rcu_read_lock(); | |
| 2562 | − lr = get_last_request(); | |
| 2563 | − if (lr && !lr->processed) { | |
| 2564 | − memcpy(alpha2, lr->alpha2, 2); | |
| 2565 | − add = true; | |
| 2566 | − } | |
| 2567 | − rcu_read_unlock(); | |
| 2568 | − | |
| 2569 | − if (add) | |
| 2570 | − return add_uevent_var(env, "COUNTRY=%c%c", | |
| 2571 | − alpha2[0], alpha2[1]); | |
| 2572 | − return 0; | |
| 2573 | −} | |
| 2574 | − | |
| 2575 | 2575 | void wiphy_regulatory_register(struct wiphy *wiphy) |
| 2576 | 2576 | { |
| 2577 | 2577 | struct regulatory_request *lr; |
| @@ -2622,8 +2622,6 @@ int __init regulatory_init(void) · 44 unmodified lines | ||
| 2622 | 2622 | if (IS_ERR(reg_pdev)) |
| 2623 | 2623 | return PTR_ERR(reg_pdev); |
| 2624 | 2624 | |
| 2625 | − reg_pdev->dev.type = ®_device_type; | |
| 2626 | − | |
| 2627 | 2625 | spin_lock_init(®_requests_lock); |
| 2628 | 2626 | spin_lock_init(®_pending_beacons_lock); |
| 2629 | 2627 | |
| @@ -26,7 +26,6 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); · 25 unmodified lines | ||
| 26 | 26 | int regulatory_hint_user(const char *alpha2, |
| 27 | 27 | enum nl80211_user_reg_hint_type user_reg_hint_type); |
| 28 | 28 | |
| 29 | −int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env); | |
| 30 | 29 | void wiphy_regulatory_register(struct wiphy *wiphy); |
| 31 | 30 | void wiphy_regulatory_deregister(struct wiphy *wiphy); |
| 32 | 31 | |
| @@ -659,9 +659,6 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, · 658 unmodified lines | ||
| 659 | 659 | continue; |
| 660 | 660 | if (ssidlen && ie[1] != ssidlen) |
| 661 | 661 | continue; |
| 662 | − /* that would be odd ... */ | |
| 663 | − if (bss->pub.beacon_ies) | |
| 664 | − continue; | |
| 665 | 662 | if (WARN_ON_ONCE(bss->pub.hidden_beacon_bss)) |
| 666 | 663 | continue; |
| 667 | 664 | if (WARN_ON_ONCE(!list_empty(&bss->hidden_list))) |
| @@ -680,7 +677,8 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, · 12 unmodified lines | ||
| 680 | 677 | /* Returned bss is reference counted and must be cleaned up appropriately. */ |
| 681 | 678 | static struct cfg80211_internal_bss * |
| 682 | 679 | cfg80211_bss_update(struct cfg80211_registered_device *dev, |
| 683 | − struct cfg80211_internal_bss *tmp) | |
| 680 | + struct cfg80211_internal_bss *tmp, | |
| 681 | + bool signal_valid) | |
| 684 | 682 | { |
| 685 | 683 | struct cfg80211_internal_bss *found = NULL; |
| 686 | 684 | |
| @@ -765,7 +763,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, · 78 unmodified lines | ||
| 765 | 763 | } |
| 766 | 764 | |
| 767 | 765 | found->pub.beacon_interval = tmp->pub.beacon_interval; |
| 768 | − found->pub.signal = tmp->pub.signal; | |
| 766 | + /* | |
| 767 | + * don't update the signal if beacon was heard on | |
| 768 | + * adjacent channel. | |
| 769 | + */ | |
| 770 | + if (signal_valid) | |
| 771 | + found->pub.signal = tmp->pub.signal; | |
| 769 | 772 | found->pub.capability = tmp->pub.capability; |
| 770 | 773 | found->ts = tmp->ts; |
| 771 | 774 | } else { |
| @@ -869,13 +872,14 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, · 97 unmodified lines | ||
| 869 | 872 | /* Returned bss is reference counted and must be cleaned up appropriately. */ |
| 870 | 873 | struct cfg80211_bss* |
| 871 | 874 | cfg80211_inform_bss_width(struct wiphy *wiphy, |
| 872 | − struct ieee80211_channel *channel, | |
| 875 | + struct ieee80211_channel *rx_channel, | |
| 873 | 876 | enum nl80211_bss_scan_width scan_width, |
| 874 | 877 | const u8 *bssid, u64 tsf, u16 capability, |
| 875 | 878 | u16 beacon_interval, const u8 *ie, size_t ielen, |
| 876 | 879 | s32 signal, gfp_t gfp) |
| 877 | 880 | { |
| 878 | 881 | struct cfg80211_bss_ies *ies; |
| 882 | + struct ieee80211_channel *channel; | |
| 879 | 883 | struct cfg80211_internal_bss tmp = {}, *res; |
| 880 | 884 | |
| 881 | 885 | if (WARN_ON(!wiphy)) |
| @@ -885,7 +889,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, · 3 unmodified lines | ||
| 885 | 889 | (signal < 0 || signal > 100))) |
| 886 | 890 | return NULL; |
| 887 | 891 | |
| 888 | − channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel); | |
| 892 | + channel = cfg80211_get_bss_channel(wiphy, ie, ielen, rx_channel); | |
| 889 | 893 | if (!channel) |
| 890 | 894 | return NULL; |
| 891 | 895 | |
| @@ -913,7 +917,8 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, · 21 unmodified lines | ||
| 913 | 917 | rcu_assign_pointer(tmp.pub.beacon_ies, ies); |
| 914 | 918 | rcu_assign_pointer(tmp.pub.ies, ies); |
| 915 | 919 | |
| 916 | − res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); | |
| 920 | + res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp, | |
| 921 | + rx_channel == channel); | |
| 917 | 922 | if (!res) |
| 918 | 923 | return NULL; |
| 919 | 924 | |
| @@ -929,20 +934,21 @@ EXPORT_SYMBOL(cfg80211_inform_bss_width); · 9 unmodified lines | ||
| 929 | 934 | /* Returned bss is reference counted and must be cleaned up appropriately. */ |
| 930 | 935 | struct cfg80211_bss * |
| 931 | 936 | cfg80211_inform_bss_width_frame(struct wiphy *wiphy, |
| 932 | − struct ieee80211_channel *channel, | |
| 937 | + struct ieee80211_channel *rx_channel, | |
| 933 | 938 | enum nl80211_bss_scan_width scan_width, |
| 934 | 939 | struct ieee80211_mgmt *mgmt, size_t len, |
| 935 | 940 | s32 signal, gfp_t gfp) |
| 936 | 941 | { |
| 937 | 942 | struct cfg80211_internal_bss tmp = {}, *res; |
| 938 | 943 | struct cfg80211_bss_ies *ies; |
| 944 | + struct ieee80211_channel *channel; | |
| 939 | 945 | size_t ielen = len - offsetof(struct ieee80211_mgmt, |
| 940 | 946 | u.probe_resp.variable); |
| 941 | 947 | |
| 942 | 948 | BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != |
| 943 | 949 | offsetof(struct ieee80211_mgmt, u.beacon.variable)); |
| 944 | 950 | |
| 945 | − trace_cfg80211_inform_bss_width_frame(wiphy, channel, scan_width, mgmt, | |
| 951 | + trace_cfg80211_inform_bss_width_frame(wiphy, rx_channel, scan_width, mgmt, | |
| 946 | 952 | len, signal); |
| 947 | 953 | |
| 948 | 954 | if (WARN_ON(!mgmt)) |
| @@ -959,7 +965,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, · 10 unmodified lines | ||
| 959 | 965 | return NULL; |
| 960 | 966 | |
| 961 | 967 | channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, |
| 962 | − ielen, channel); | |
| 968 | + ielen, rx_channel); | |
| 963 | 969 | if (!channel) |
| 964 | 970 | return NULL; |
| 965 | 971 | |
| @@ -983,7 +989,8 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, · 17 unmodified lines | ||
| 983 | 989 | tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); |
| 984 | 990 | tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); |
| 985 | 991 | |
| 986 | − res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); | |
| 992 | + res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp, | |
| 993 | + rx_channel == channel); | |
| 987 | 994 | if (!res) |
| 988 | 995 | return NULL; |
| 989 | 996 | |
| @@ -64,7 +64,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) · 63 unmodified lines | ||
| 64 | 64 | int n_channels, err; |
| 65 | 65 | |
| 66 | 66 | ASSERT_RTNL(); |
| 67 | − ASSERT_RDEV_LOCK(rdev); | |
| 68 | 67 | ASSERT_WDEV_LOCK(wdev); |
| 69 | 68 | |
| 70 | 69 | if (rdev->scan_req || rdev->scan_msg) |
| @@ -838,7 +838,6 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) · 837 unmodified lines | ||
| 838 | 838 | struct wireless_dev *wdev; |
| 839 | 839 | |
| 840 | 840 | ASSERT_RTNL(); |
| 841 | − ASSERT_RDEV_LOCK(rdev); | |
| 842 | 841 | |
| 843 | 842 | list_for_each_entry(wdev, &rdev->wdev_list, list) |
| 844 | 843 | cfg80211_process_wdev_events(wdev); |
| @@ -851,7 +850,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, · 6 unmodified lines | ||
| 851 | 850 | int err; |
| 852 | 851 | enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; |
| 853 | 852 | |
| 854 | − ASSERT_RDEV_LOCK(rdev); | |
| 853 | + ASSERT_RTNL(); | |
| 855 | 854 | |
| 856 | 855 | /* don't support changing VLANs, you just re-create them */ |
| 857 | 856 | if (otype == NL80211_IFTYPE_AP_VLAN) |
| @@ -886,7 +885,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, · 28 unmodified lines | ||
| 886 | 885 | |
| 887 | 886 | switch (otype) { |
| 888 | 887 | case NL80211_IFTYPE_AP: |
| 889 | − cfg80211_stop_ap(rdev, dev); | |
| 888 | + cfg80211_stop_ap(rdev, dev, true); | |
| 890 | 889 | break; |
| 891 | 890 | case NL80211_IFTYPE_ADHOC: |
| 892 | 891 | cfg80211_leave_ibss(rdev, dev, false); |
| @@ -21,7 +21,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, · 20 unmodified lines | ||
| 21 | 21 | const u8 *prev_bssid = NULL; |
| 22 | 22 | int err, i; |
| 23 | 23 | |
| 24 | − ASSERT_RDEV_LOCK(rdev); | |
| 24 | + ASSERT_RTNL(); | |
| 25 | 25 | ASSERT_WDEV_LOCK(wdev); |
| 26 | 26 | |
| 27 | 27 | if (!netif_running(wdev->netdev)) |