diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 92 | ||||
-rw-r--r-- | net/mac80211/chan.c | 5 | ||||
-rw-r--r-- | net/mac80211/debugfs.c | 55 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 27 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 608 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 30 | ||||
-rw-r--r-- | net/mac80211/iface.c | 4 | ||||
-rw-r--r-- | net/mac80211/key.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 334 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 14 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 23 | ||||
-rw-r--r-- | net/mac80211/rc80211_pid_debugfs.c | 26 | ||||
-rw-r--r-- | net/mac80211/rx.c | 39 | ||||
-rw-r--r-- | net/mac80211/scan.c | 3 | ||||
-rw-r--r-- | net/mac80211/spectmgmt.c | 162 | ||||
-rw-r--r-- | net/mac80211/trace.h | 35 | ||||
-rw-r--r-- | net/mac80211/tx.c | 39 | ||||
-rw-r--r-- | net/mac80211/util.c | 162 | ||||
-rw-r--r-- | net/mac80211/vht.c | 4 |
19 files changed, 1159 insertions, 505 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2e7855a1b10d..ac28af74a414 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2865,30 +2865,43 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
2865 | if (!ieee80211_sdata_running(sdata)) | 2865 | if (!ieee80211_sdata_running(sdata)) |
2866 | return; | 2866 | return; |
2867 | 2867 | ||
2868 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) | ||
2869 | return; | ||
2870 | |||
2871 | sdata->radar_required = sdata->csa_radar_required; | 2868 | sdata->radar_required = sdata->csa_radar_required; |
2872 | err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, | 2869 | err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, |
2873 | &changed); | 2870 | &changed); |
2874 | if (WARN_ON(err < 0)) | 2871 | if (WARN_ON(err < 0)) |
2875 | return; | 2872 | return; |
2876 | 2873 | ||
2877 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 2874 | if (!local->use_chanctx) { |
2878 | if (err < 0) | 2875 | local->_oper_chandef = local->csa_chandef; |
2879 | return; | 2876 | ieee80211_hw_config(local, 0); |
2877 | } | ||
2880 | 2878 | ||
2881 | changed |= err; | 2879 | ieee80211_bss_info_change_notify(sdata, changed); |
2882 | kfree(sdata->u.ap.next_beacon); | 2880 | |
2883 | sdata->u.ap.next_beacon = NULL; | 2881 | switch (sdata->vif.type) { |
2882 | case NL80211_IFTYPE_AP: | ||
2883 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | ||
2884 | if (err < 0) | ||
2885 | return; | ||
2886 | changed |= err; | ||
2887 | kfree(sdata->u.ap.next_beacon); | ||
2888 | sdata->u.ap.next_beacon = NULL; | ||
2889 | |||
2890 | ieee80211_bss_info_change_notify(sdata, err); | ||
2891 | break; | ||
2892 | case NL80211_IFTYPE_ADHOC: | ||
2893 | ieee80211_ibss_finish_csa(sdata); | ||
2894 | break; | ||
2895 | default: | ||
2896 | WARN_ON(1); | ||
2897 | return; | ||
2898 | } | ||
2884 | sdata->vif.csa_active = false; | 2899 | sdata->vif.csa_active = false; |
2885 | 2900 | ||
2886 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 2901 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
2887 | IEEE80211_MAX_QUEUE_MAP, | 2902 | IEEE80211_MAX_QUEUE_MAP, |
2888 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2903 | IEEE80211_QUEUE_STOP_REASON_CSA); |
2889 | 2904 | ||
2890 | ieee80211_bss_info_change_notify(sdata, changed); | ||
2891 | |||
2892 | cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); | 2905 | cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); |
2893 | } | 2906 | } |
2894 | 2907 | ||
@@ -2936,20 +2949,56 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
2936 | if (sdata->vif.csa_active) | 2949 | if (sdata->vif.csa_active) |
2937 | return -EBUSY; | 2950 | return -EBUSY; |
2938 | 2951 | ||
2939 | /* only handle AP for now. */ | ||
2940 | switch (sdata->vif.type) { | 2952 | switch (sdata->vif.type) { |
2941 | case NL80211_IFTYPE_AP: | 2953 | case NL80211_IFTYPE_AP: |
2954 | sdata->csa_counter_offset_beacon = | ||
2955 | params->counter_offset_beacon; | ||
2956 | sdata->csa_counter_offset_presp = params->counter_offset_presp; | ||
2957 | sdata->u.ap.next_beacon = | ||
2958 | cfg80211_beacon_dup(¶ms->beacon_after); | ||
2959 | if (!sdata->u.ap.next_beacon) | ||
2960 | return -ENOMEM; | ||
2961 | |||
2962 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | ||
2963 | if (err < 0) { | ||
2964 | kfree(sdata->u.ap.next_beacon); | ||
2965 | return err; | ||
2966 | } | ||
2967 | break; | ||
2968 | case NL80211_IFTYPE_ADHOC: | ||
2969 | if (!sdata->vif.bss_conf.ibss_joined) | ||
2970 | return -EINVAL; | ||
2971 | |||
2972 | if (params->chandef.width != sdata->u.ibss.chandef.width) | ||
2973 | return -EINVAL; | ||
2974 | |||
2975 | switch (params->chandef.width) { | ||
2976 | case NL80211_CHAN_WIDTH_40: | ||
2977 | if (cfg80211_get_chandef_type(¶ms->chandef) != | ||
2978 | cfg80211_get_chandef_type(&sdata->u.ibss.chandef)) | ||
2979 | return -EINVAL; | ||
2980 | case NL80211_CHAN_WIDTH_5: | ||
2981 | case NL80211_CHAN_WIDTH_10: | ||
2982 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
2983 | case NL80211_CHAN_WIDTH_20: | ||
2984 | break; | ||
2985 | default: | ||
2986 | return -EINVAL; | ||
2987 | } | ||
2988 | |||
2989 | /* changes into another band are not supported */ | ||
2990 | if (sdata->u.ibss.chandef.chan->band != | ||
2991 | params->chandef.chan->band) | ||
2992 | return -EINVAL; | ||
2993 | |||
2994 | err = ieee80211_ibss_csa_beacon(sdata, params); | ||
2995 | if (err < 0) | ||
2996 | return err; | ||
2942 | break; | 2997 | break; |
2943 | default: | 2998 | default: |
2944 | return -EOPNOTSUPP; | 2999 | return -EOPNOTSUPP; |
2945 | } | 3000 | } |
2946 | 3001 | ||
2947 | sdata->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after); | ||
2948 | if (!sdata->u.ap.next_beacon) | ||
2949 | return -ENOMEM; | ||
2950 | |||
2951 | sdata->csa_counter_offset_beacon = params->counter_offset_beacon; | ||
2952 | sdata->csa_counter_offset_presp = params->counter_offset_presp; | ||
2953 | sdata->csa_radar_required = params->radar_required; | 3002 | sdata->csa_radar_required = params->radar_required; |
2954 | 3003 | ||
2955 | if (params->block_tx) | 3004 | if (params->block_tx) |
@@ -2957,10 +3006,6 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
2957 | IEEE80211_MAX_QUEUE_MAP, | 3006 | IEEE80211_MAX_QUEUE_MAP, |
2958 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3007 | IEEE80211_QUEUE_STOP_REASON_CSA); |
2959 | 3008 | ||
2960 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | ||
2961 | if (err < 0) | ||
2962 | return err; | ||
2963 | |||
2964 | local->csa_chandef = params->chandef; | 3009 | local->csa_chandef = params->chandef; |
2965 | sdata->vif.csa_active = true; | 3010 | sdata->vif.csa_active = true; |
2966 | 3011 | ||
@@ -3014,7 +3059,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
3014 | need_offchan = true; | 3059 | need_offchan = true; |
3015 | if (!ieee80211_is_action(mgmt->frame_control) || | 3060 | if (!ieee80211_is_action(mgmt->frame_control) || |
3016 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || | 3061 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || |
3017 | mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED) | 3062 | mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED || |
3063 | mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) | ||
3018 | break; | 3064 | break; |
3019 | rcu_read_lock(); | 3065 | rcu_read_lock(); |
3020 | sta = sta_info_get(sdata, mgmt->da); | 3066 | sta = sta_info_get(sdata, mgmt->da); |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 3a4764b2869e..03ba6b5c5373 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -453,11 +453,6 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | |||
453 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; | 453 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; |
454 | drv_change_chanctx(local, ctx, chanctx_changed); | 454 | drv_change_chanctx(local, ctx, chanctx_changed); |
455 | 455 | ||
456 | if (!local->use_chanctx) { | ||
457 | local->_oper_chandef = *chandef; | ||
458 | ieee80211_hw_config(local, 0); | ||
459 | } | ||
460 | |||
461 | ieee80211_recalc_chanctx_chantype(local, ctx); | 456 | ieee80211_recalc_chanctx_chantype(local, ctx); |
462 | ieee80211_recalc_smps_chanctx(local, ctx); | 457 | ieee80211_recalc_smps_chanctx(local, ctx); |
463 | ieee80211_recalc_radar_chanctx(local, ctx); | 458 | ieee80211_recalc_radar_chanctx(local, ctx); |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index b0e32d628114..5c090e41d9bb 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -103,54 +103,57 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, | |||
103 | if (!buf) | 103 | if (!buf) |
104 | return 0; | 104 | return 0; |
105 | 105 | ||
106 | sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); | 106 | sf += scnprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); |
107 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | 107 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) |
108 | sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); | 108 | sf += scnprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); |
109 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 109 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
110 | sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); | 110 | sf += scnprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); |
111 | if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) | 111 | if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) |
112 | sf += snprintf(buf + sf, mxln - sf, | 112 | sf += scnprintf(buf + sf, mxln - sf, |
113 | "HOST_BCAST_PS_BUFFERING\n"); | 113 | "HOST_BCAST_PS_BUFFERING\n"); |
114 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) | 114 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) |
115 | sf += snprintf(buf + sf, mxln - sf, | 115 | sf += scnprintf(buf + sf, mxln - sf, |
116 | "2GHZ_SHORT_SLOT_INCAPABLE\n"); | 116 | "2GHZ_SHORT_SLOT_INCAPABLE\n"); |
117 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) | 117 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) |
118 | sf += snprintf(buf + sf, mxln - sf, | 118 | sf += scnprintf(buf + sf, mxln - sf, |
119 | "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); | 119 | "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); |
120 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 120 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
121 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); | 121 | sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); |
122 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 122 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
123 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); | 123 | sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); |
124 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC) | 124 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC) |
125 | sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_BEFORE_ASSOC\n"); | 125 | sf += scnprintf(buf + sf, mxln - sf, |
126 | "NEED_DTIM_BEFORE_ASSOC\n"); | ||
126 | if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) | 127 | if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) |
127 | sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); | 128 | sf += scnprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); |
128 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) | 129 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) |
129 | sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); | 130 | sf += scnprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); |
130 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) | 131 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) |
131 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); | 132 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); |
132 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 133 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
133 | sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); | 134 | sf += scnprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); |
134 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 135 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
135 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); | 136 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); |
136 | if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) | 137 | if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) |
137 | sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); | 138 | sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); |
138 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) | 139 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) |
139 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); | 140 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); |
140 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) | 141 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) |
141 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n"); | 142 | sf += scnprintf(buf + sf, mxln - sf, |
143 | "SUPPORTS_DYNAMIC_SMPS\n"); | ||
142 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | 144 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) |
143 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); | 145 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); |
144 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 146 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
145 | sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n"); | 147 | sf += scnprintf(buf + sf, mxln - sf, |
148 | "REPORTS_TX_ACK_STATUS\n"); | ||
146 | if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 149 | if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
147 | sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); | 150 | sf += scnprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); |
148 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) | 151 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) |
149 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); | 152 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); |
150 | if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) | 153 | if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) |
151 | sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); | 154 | sf += scnprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); |
152 | if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) | 155 | if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) |
153 | sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); | 156 | sf += scnprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); |
154 | 157 | ||
155 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | 158 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); |
156 | kfree(buf); | 159 | kfree(buf); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index b3ea11f3d526..5d03c47c0a4c 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -1085,4 +1085,31 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata, | |||
1085 | } | 1085 | } |
1086 | } | 1086 | } |
1087 | 1087 | ||
1088 | static inline int drv_join_ibss(struct ieee80211_local *local, | ||
1089 | struct ieee80211_sub_if_data *sdata) | ||
1090 | { | ||
1091 | int ret = 0; | ||
1092 | |||
1093 | might_sleep(); | ||
1094 | check_sdata_in_driver(sdata); | ||
1095 | |||
1096 | trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf); | ||
1097 | if (local->ops->join_ibss) | ||
1098 | ret = local->ops->join_ibss(&local->hw, &sdata->vif); | ||
1099 | trace_drv_return_int(local, ret); | ||
1100 | return ret; | ||
1101 | } | ||
1102 | |||
1103 | static inline void drv_leave_ibss(struct ieee80211_local *local, | ||
1104 | struct ieee80211_sub_if_data *sdata) | ||
1105 | { | ||
1106 | might_sleep(); | ||
1107 | check_sdata_in_driver(sdata); | ||
1108 | |||
1109 | trace_drv_leave_ibss(local, sdata); | ||
1110 | if (local->ops->leave_ibss) | ||
1111 | local->ops->leave_ibss(&local->hw, &sdata->vif); | ||
1112 | trace_drv_return_void(local); | ||
1113 | } | ||
1114 | |||
1088 | #endif /* __MAC80211_DRIVER_OPS */ | 1115 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a12afe77bb26..21a0b8835cb3 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -39,7 +39,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
39 | const int beacon_int, const u32 basic_rates, | 39 | const int beacon_int, const u32 basic_rates, |
40 | const u16 capability, u64 tsf, | 40 | const u16 capability, u64 tsf, |
41 | struct cfg80211_chan_def *chandef, | 41 | struct cfg80211_chan_def *chandef, |
42 | bool *have_higher_than_11mbit) | 42 | bool *have_higher_than_11mbit, |
43 | struct cfg80211_csa_settings *csa_settings) | ||
43 | { | 44 | { |
44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 45 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
45 | struct ieee80211_local *local = sdata->local; | 46 | struct ieee80211_local *local = sdata->local; |
@@ -59,6 +60,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
59 | 2 + 8 /* max Supported Rates */ + | 60 | 2 + 8 /* max Supported Rates */ + |
60 | 3 /* max DS params */ + | 61 | 3 /* max DS params */ + |
61 | 4 /* IBSS params */ + | 62 | 4 /* IBSS params */ + |
63 | 5 /* Channel Switch Announcement */ + | ||
62 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | 64 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + |
63 | 2 + sizeof(struct ieee80211_ht_cap) + | 65 | 2 + sizeof(struct ieee80211_ht_cap) + |
64 | 2 + sizeof(struct ieee80211_ht_operation) + | 66 | 2 + sizeof(struct ieee80211_ht_operation) + |
@@ -135,6 +137,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
135 | *pos++ = 0; | 137 | *pos++ = 0; |
136 | *pos++ = 0; | 138 | *pos++ = 0; |
137 | 139 | ||
140 | if (csa_settings) { | ||
141 | *pos++ = WLAN_EID_CHANNEL_SWITCH; | ||
142 | *pos++ = 3; | ||
143 | *pos++ = csa_settings->block_tx ? 1 : 0; | ||
144 | *pos++ = ieee80211_frequency_to_channel( | ||
145 | csa_settings->chandef.chan->center_freq); | ||
146 | sdata->csa_counter_offset_beacon = (pos - presp->head); | ||
147 | *pos++ = csa_settings->count; | ||
148 | } | ||
149 | |||
138 | /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */ | 150 | /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */ |
139 | if (rates_n > 8) { | 151 | if (rates_n > 8) { |
140 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 152 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
@@ -217,6 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
217 | struct beacon_data *presp; | 229 | struct beacon_data *presp; |
218 | enum nl80211_bss_scan_width scan_width; | 230 | enum nl80211_bss_scan_width scan_width; |
219 | bool have_higher_than_11mbit; | 231 | bool have_higher_than_11mbit; |
232 | int err; | ||
220 | 233 | ||
221 | sdata_assert_lock(sdata); | 234 | sdata_assert_lock(sdata); |
222 | 235 | ||
@@ -235,6 +248,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
235 | ieee80211_bss_info_change_notify(sdata, | 248 | ieee80211_bss_info_change_notify(sdata, |
236 | BSS_CHANGED_IBSS | | 249 | BSS_CHANGED_IBSS | |
237 | BSS_CHANGED_BEACON_ENABLED); | 250 | BSS_CHANGED_BEACON_ENABLED); |
251 | drv_leave_ibss(local, sdata); | ||
238 | } | 252 | } |
239 | 253 | ||
240 | presp = rcu_dereference_protected(ifibss->presp, | 254 | presp = rcu_dereference_protected(ifibss->presp, |
@@ -276,7 +290,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
276 | 290 | ||
277 | presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, | 291 | presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, |
278 | capability, tsf, &chandef, | 292 | capability, tsf, &chandef, |
279 | &have_higher_than_11mbit); | 293 | &have_higher_than_11mbit, NULL); |
280 | if (!presp) | 294 | if (!presp) |
281 | return; | 295 | return; |
282 | 296 | ||
@@ -317,11 +331,26 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
317 | else | 331 | else |
318 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 332 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
319 | 333 | ||
334 | ieee80211_set_wmm_default(sdata, true); | ||
335 | |||
320 | sdata->vif.bss_conf.ibss_joined = true; | 336 | sdata->vif.bss_conf.ibss_joined = true; |
321 | sdata->vif.bss_conf.ibss_creator = creator; | 337 | sdata->vif.bss_conf.ibss_creator = creator; |
322 | ieee80211_bss_info_change_notify(sdata, bss_change); | ||
323 | 338 | ||
324 | ieee80211_set_wmm_default(sdata, true); | 339 | err = drv_join_ibss(local, sdata); |
340 | if (err) { | ||
341 | sdata->vif.bss_conf.ibss_joined = false; | ||
342 | sdata->vif.bss_conf.ibss_creator = false; | ||
343 | sdata->vif.bss_conf.enable_beacon = false; | ||
344 | sdata->vif.bss_conf.ssid_len = 0; | ||
345 | RCU_INIT_POINTER(ifibss->presp, NULL); | ||
346 | kfree_rcu(presp, rcu_head); | ||
347 | ieee80211_vif_release_channel(sdata); | ||
348 | sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", | ||
349 | err); | ||
350 | return; | ||
351 | } | ||
352 | |||
353 | ieee80211_bss_info_change_notify(sdata, bss_change); | ||
325 | 354 | ||
326 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; | 355 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; |
327 | mod_timer(&ifibss->timer, | 356 | mod_timer(&ifibss->timer, |
@@ -416,6 +445,169 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
416 | tsf, false); | 445 | tsf, false); |
417 | } | 446 | } |
418 | 447 | ||
448 | static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | ||
449 | struct cfg80211_csa_settings *csa_settings) | ||
450 | { | ||
451 | struct sk_buff *skb; | ||
452 | struct ieee80211_mgmt *mgmt; | ||
453 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
454 | struct ieee80211_local *local = sdata->local; | ||
455 | int freq; | ||
456 | int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) + | ||
457 | sizeof(mgmt->u.action.u.chan_switch); | ||
458 | u8 *pos; | ||
459 | |||
460 | skb = dev_alloc_skb(local->tx_headroom + hdr_len + | ||
461 | 5 + /* channel switch announcement element */ | ||
462 | 3); /* secondary channel offset element */ | ||
463 | if (!skb) | ||
464 | return -1; | ||
465 | |||
466 | skb_reserve(skb, local->tx_headroom); | ||
467 | mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len); | ||
468 | memset(mgmt, 0, hdr_len); | ||
469 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
470 | IEEE80211_STYPE_ACTION); | ||
471 | |||
472 | eth_broadcast_addr(mgmt->da); | ||
473 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
474 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | ||
475 | mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
476 | mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH; | ||
477 | pos = skb_put(skb, 5); | ||
478 | *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */ | ||
479 | *pos++ = 3; /* IE length */ | ||
480 | *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */ | ||
481 | freq = csa_settings->chandef.chan->center_freq; | ||
482 | *pos++ = ieee80211_frequency_to_channel(freq); /* channel */ | ||
483 | *pos++ = csa_settings->count; /* count */ | ||
484 | |||
485 | if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) { | ||
486 | enum nl80211_channel_type ch_type; | ||
487 | |||
488 | skb_put(skb, 3); | ||
489 | *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */ | ||
490 | *pos++ = 1; /* IE length */ | ||
491 | ch_type = cfg80211_get_chandef_type(&csa_settings->chandef); | ||
492 | if (ch_type == NL80211_CHAN_HT40PLUS) | ||
493 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
494 | else | ||
495 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
496 | } | ||
497 | |||
498 | ieee80211_tx_skb(sdata, skb); | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | ||
503 | struct cfg80211_csa_settings *csa_settings) | ||
504 | { | ||
505 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
506 | struct beacon_data *presp, *old_presp; | ||
507 | struct cfg80211_bss *cbss; | ||
508 | const struct cfg80211_bss_ies *ies; | ||
509 | u16 capability; | ||
510 | u64 tsf; | ||
511 | int ret = 0; | ||
512 | |||
513 | sdata_assert_lock(sdata); | ||
514 | |||
515 | capability = WLAN_CAPABILITY_IBSS; | ||
516 | |||
517 | if (ifibss->privacy) | ||
518 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
519 | |||
520 | cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan, | ||
521 | ifibss->bssid, ifibss->ssid, | ||
522 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
523 | WLAN_CAPABILITY_PRIVACY, | ||
524 | capability); | ||
525 | |||
526 | if (WARN_ON(!cbss)) { | ||
527 | ret = -EINVAL; | ||
528 | goto out; | ||
529 | } | ||
530 | |||
531 | rcu_read_lock(); | ||
532 | ies = rcu_dereference(cbss->ies); | ||
533 | tsf = ies->tsf; | ||
534 | rcu_read_unlock(); | ||
535 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | ||
536 | |||
537 | old_presp = rcu_dereference_protected(ifibss->presp, | ||
538 | lockdep_is_held(&sdata->wdev.mtx)); | ||
539 | |||
540 | presp = ieee80211_ibss_build_presp(sdata, | ||
541 | sdata->vif.bss_conf.beacon_int, | ||
542 | sdata->vif.bss_conf.basic_rates, | ||
543 | capability, tsf, &ifibss->chandef, | ||
544 | NULL, csa_settings); | ||
545 | if (!presp) { | ||
546 | ret = -ENOMEM; | ||
547 | goto out; | ||
548 | } | ||
549 | |||
550 | rcu_assign_pointer(ifibss->presp, presp); | ||
551 | if (old_presp) | ||
552 | kfree_rcu(old_presp, rcu_head); | ||
553 | |||
554 | /* it might not send the beacon for a while. send an action frame | ||
555 | * immediately to announce the channel switch. | ||
556 | */ | ||
557 | if (csa_settings) | ||
558 | ieee80211_send_action_csa(sdata, csa_settings); | ||
559 | |||
560 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
561 | out: | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | ||
566 | { | ||
567 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
568 | struct cfg80211_bss *cbss; | ||
569 | int err; | ||
570 | u16 capability; | ||
571 | |||
572 | sdata_lock(sdata); | ||
573 | /* update cfg80211 bss information with the new channel */ | ||
574 | if (!is_zero_ether_addr(ifibss->bssid)) { | ||
575 | capability = WLAN_CAPABILITY_IBSS; | ||
576 | |||
577 | if (ifibss->privacy) | ||
578 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
579 | |||
580 | cbss = cfg80211_get_bss(sdata->local->hw.wiphy, | ||
581 | ifibss->chandef.chan, | ||
582 | ifibss->bssid, ifibss->ssid, | ||
583 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
584 | WLAN_CAPABILITY_PRIVACY, | ||
585 | capability); | ||
586 | /* XXX: should not really modify cfg80211 data */ | ||
587 | if (cbss) { | ||
588 | cbss->channel = sdata->local->csa_chandef.chan; | ||
589 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | ifibss->chandef = sdata->local->csa_chandef; | ||
594 | |||
595 | /* generate the beacon */ | ||
596 | err = ieee80211_ibss_csa_beacon(sdata, NULL); | ||
597 | sdata_unlock(sdata); | ||
598 | if (err < 0) | ||
599 | return err; | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata) | ||
605 | { | ||
606 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
607 | |||
608 | cancel_work_sync(&ifibss->csa_connection_drop_work); | ||
609 | } | ||
610 | |||
419 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) | 611 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) |
420 | __acquires(RCU) | 612 | __acquires(RCU) |
421 | { | 613 | { |
@@ -499,6 +691,295 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
499 | return ieee80211_ibss_finish_sta(sta); | 691 | return ieee80211_ibss_finish_sta(sta); |
500 | } | 692 | } |
501 | 693 | ||
694 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
695 | { | ||
696 | struct ieee80211_local *local = sdata->local; | ||
697 | int active = 0; | ||
698 | struct sta_info *sta; | ||
699 | |||
700 | sdata_assert_lock(sdata); | ||
701 | |||
702 | rcu_read_lock(); | ||
703 | |||
704 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
705 | if (sta->sdata == sdata && | ||
706 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
707 | jiffies)) { | ||
708 | active++; | ||
709 | break; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | rcu_read_unlock(); | ||
714 | |||
715 | return active; | ||
716 | } | ||
717 | |||
718 | static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) | ||
719 | { | ||
720 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
721 | struct ieee80211_local *local = sdata->local; | ||
722 | struct cfg80211_bss *cbss; | ||
723 | struct beacon_data *presp; | ||
724 | struct sta_info *sta; | ||
725 | int active_ibss; | ||
726 | u16 capability; | ||
727 | |||
728 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
729 | |||
730 | if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { | ||
731 | capability = WLAN_CAPABILITY_IBSS; | ||
732 | |||
733 | if (ifibss->privacy) | ||
734 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
735 | |||
736 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, | ||
737 | ifibss->bssid, ifibss->ssid, | ||
738 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
739 | WLAN_CAPABILITY_PRIVACY, | ||
740 | capability); | ||
741 | |||
742 | if (cbss) { | ||
743 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
744 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | ||
745 | } | ||
746 | } | ||
747 | |||
748 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
749 | |||
750 | sta_info_flush(sdata); | ||
751 | |||
752 | spin_lock_bh(&ifibss->incomplete_lock); | ||
753 | while (!list_empty(&ifibss->incomplete_stations)) { | ||
754 | sta = list_first_entry(&ifibss->incomplete_stations, | ||
755 | struct sta_info, list); | ||
756 | list_del(&sta->list); | ||
757 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
758 | |||
759 | sta_info_free(local, sta); | ||
760 | spin_lock_bh(&ifibss->incomplete_lock); | ||
761 | } | ||
762 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
763 | |||
764 | netif_carrier_off(sdata->dev); | ||
765 | |||
766 | sdata->vif.bss_conf.ibss_joined = false; | ||
767 | sdata->vif.bss_conf.ibss_creator = false; | ||
768 | sdata->vif.bss_conf.enable_beacon = false; | ||
769 | sdata->vif.bss_conf.ssid_len = 0; | ||
770 | |||
771 | /* remove beacon */ | ||
772 | presp = rcu_dereference_protected(ifibss->presp, | ||
773 | lockdep_is_held(&sdata->wdev.mtx)); | ||
774 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | ||
775 | if (presp) | ||
776 | kfree_rcu(presp, rcu_head); | ||
777 | |||
778 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | ||
779 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | ||
780 | BSS_CHANGED_IBSS); | ||
781 | drv_leave_ibss(local, sdata); | ||
782 | ieee80211_vif_release_channel(sdata); | ||
783 | } | ||
784 | |||
785 | static void ieee80211_csa_connection_drop_work(struct work_struct *work) | ||
786 | { | ||
787 | struct ieee80211_sub_if_data *sdata = | ||
788 | container_of(work, struct ieee80211_sub_if_data, | ||
789 | u.ibss.csa_connection_drop_work); | ||
790 | |||
791 | ieee80211_ibss_disconnect(sdata); | ||
792 | synchronize_rcu(); | ||
793 | skb_queue_purge(&sdata->skb_queue); | ||
794 | |||
795 | /* trigger a scan to find another IBSS network to join */ | ||
796 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | ||
797 | } | ||
798 | |||
799 | static bool | ||
800 | ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
801 | struct ieee802_11_elems *elems, | ||
802 | bool beacon) | ||
803 | { | ||
804 | struct cfg80211_csa_settings params; | ||
805 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
806 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
807 | struct ieee80211_chanctx *chanctx; | ||
808 | enum nl80211_channel_type ch_type; | ||
809 | int err, num_chanctx; | ||
810 | u32 sta_flags; | ||
811 | u8 mode; | ||
812 | |||
813 | if (sdata->vif.csa_active) | ||
814 | return true; | ||
815 | |||
816 | if (!sdata->vif.bss_conf.ibss_joined) | ||
817 | return false; | ||
818 | |||
819 | sta_flags = IEEE80211_STA_DISABLE_VHT; | ||
820 | switch (ifibss->chandef.width) { | ||
821 | case NL80211_CHAN_WIDTH_5: | ||
822 | case NL80211_CHAN_WIDTH_10: | ||
823 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
824 | sta_flags |= IEEE80211_STA_DISABLE_HT; | ||
825 | /* fall through */ | ||
826 | case NL80211_CHAN_WIDTH_20: | ||
827 | sta_flags |= IEEE80211_STA_DISABLE_40MHZ; | ||
828 | break; | ||
829 | default: | ||
830 | break; | ||
831 | } | ||
832 | |||
833 | memset(¶ms, 0, sizeof(params)); | ||
834 | err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, | ||
835 | ifibss->chandef.chan->band, | ||
836 | sta_flags, ifibss->bssid, | ||
837 | ¶ms.count, &mode, | ||
838 | ¶ms.chandef); | ||
839 | |||
840 | /* can't switch to destination channel, fail */ | ||
841 | if (err < 0) | ||
842 | goto disconnect; | ||
843 | |||
844 | /* did not contain a CSA */ | ||
845 | if (err) | ||
846 | return false; | ||
847 | |||
848 | if (ifibss->chandef.chan->band != params.chandef.chan->band) | ||
849 | goto disconnect; | ||
850 | |||
851 | switch (ifibss->chandef.width) { | ||
852 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
853 | case NL80211_CHAN_WIDTH_20: | ||
854 | case NL80211_CHAN_WIDTH_40: | ||
855 | /* keep our current HT mode (HT20/HT40+/HT40-), even if | ||
856 | * another mode has been announced. The mode is not adopted | ||
857 | * within the beacon while doing CSA and we should therefore | ||
858 | * keep the mode which we announce. | ||
859 | */ | ||
860 | ch_type = cfg80211_get_chandef_type(&ifibss->chandef); | ||
861 | cfg80211_chandef_create(¶ms.chandef, params.chandef.chan, | ||
862 | ch_type); | ||
863 | break; | ||
864 | case NL80211_CHAN_WIDTH_5: | ||
865 | case NL80211_CHAN_WIDTH_10: | ||
866 | if (params.chandef.width != ifibss->chandef.width) { | ||
867 | sdata_info(sdata, | ||
868 | "IBSS %pM received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | ||
869 | ifibss->bssid, | ||
870 | params.chandef.chan->center_freq, | ||
871 | params.chandef.width, | ||
872 | params.chandef.center_freq1, | ||
873 | params.chandef.center_freq2); | ||
874 | goto disconnect; | ||
875 | } | ||
876 | break; | ||
877 | default: | ||
878 | /* should not happen, sta_flags should prevent VHT modes. */ | ||
879 | WARN_ON(1); | ||
880 | goto disconnect; | ||
881 | } | ||
882 | |||
883 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, | ||
884 | IEEE80211_CHAN_DISABLED)) { | ||
885 | sdata_info(sdata, | ||
886 | "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | ||
887 | ifibss->bssid, | ||
888 | params.chandef.chan->center_freq, | ||
889 | params.chandef.width, | ||
890 | params.chandef.center_freq1, | ||
891 | params.chandef.center_freq2); | ||
892 | goto disconnect; | ||
893 | } | ||
894 | |||
895 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, | ||
896 | ¶ms.chandef); | ||
897 | if (err < 0) | ||
898 | goto disconnect; | ||
899 | if (err) { | ||
900 | params.radar_required = true; | ||
901 | |||
902 | /* TODO: IBSS-DFS not (yet) supported, disconnect. */ | ||
903 | goto disconnect; | ||
904 | } | ||
905 | |||
906 | rcu_read_lock(); | ||
907 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
908 | if (!chanctx_conf) { | ||
909 | rcu_read_unlock(); | ||
910 | goto disconnect; | ||
911 | } | ||
912 | |||
913 | /* don't handle for multi-VIF cases */ | ||
914 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | ||
915 | if (chanctx->refcount > 1) { | ||
916 | rcu_read_unlock(); | ||
917 | goto disconnect; | ||
918 | } | ||
919 | num_chanctx = 0; | ||
920 | list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list) | ||
921 | num_chanctx++; | ||
922 | |||
923 | if (num_chanctx > 1) { | ||
924 | rcu_read_unlock(); | ||
925 | goto disconnect; | ||
926 | } | ||
927 | rcu_read_unlock(); | ||
928 | |||
929 | /* all checks done, now perform the channel switch. */ | ||
930 | ibss_dbg(sdata, | ||
931 | "received channel switch announcement to go to channel %d MHz\n", | ||
932 | params.chandef.chan->center_freq); | ||
933 | |||
934 | params.block_tx = !!mode; | ||
935 | |||
936 | ieee80211_ibss_csa_beacon(sdata, ¶ms); | ||
937 | sdata->csa_radar_required = params.radar_required; | ||
938 | |||
939 | if (params.block_tx) | ||
940 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
941 | IEEE80211_MAX_QUEUE_MAP, | ||
942 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
943 | |||
944 | sdata->local->csa_chandef = params.chandef; | ||
945 | sdata->vif.csa_active = true; | ||
946 | |||
947 | ieee80211_bss_info_change_notify(sdata, err); | ||
948 | drv_channel_switch_beacon(sdata, ¶ms.chandef); | ||
949 | |||
950 | return true; | ||
951 | disconnect: | ||
952 | ibss_dbg(sdata, "Can't handle channel switch, disconnect\n"); | ||
953 | ieee80211_queue_work(&sdata->local->hw, | ||
954 | &ifibss->csa_connection_drop_work); | ||
955 | |||
956 | return true; | ||
957 | } | ||
958 | |||
959 | static void | ||
960 | ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata, | ||
961 | struct ieee80211_mgmt *mgmt, size_t len, | ||
962 | struct ieee80211_rx_status *rx_status, | ||
963 | struct ieee802_11_elems *elems) | ||
964 | { | ||
965 | int required_len; | ||
966 | |||
967 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
968 | return; | ||
969 | |||
970 | /* CSA is the only action we handle for now */ | ||
971 | if (mgmt->u.action.u.measurement.action_code != | ||
972 | WLAN_ACTION_SPCT_CHL_SWITCH) | ||
973 | return; | ||
974 | |||
975 | required_len = IEEE80211_MIN_ACTION_SIZE + | ||
976 | sizeof(mgmt->u.action.u.chan_switch); | ||
977 | if (len < required_len) | ||
978 | return; | ||
979 | |||
980 | ieee80211_ibss_process_chanswitch(sdata, elems, false); | ||
981 | } | ||
982 | |||
502 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | 983 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, |
503 | struct ieee80211_mgmt *mgmt, | 984 | struct ieee80211_mgmt *mgmt, |
504 | size_t len) | 985 | size_t len) |
@@ -661,10 +1142,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
661 | 1142 | ||
662 | /* check if we need to merge IBSS */ | 1143 | /* check if we need to merge IBSS */ |
663 | 1144 | ||
664 | /* we use a fixed BSSID */ | ||
665 | if (sdata->u.ibss.fixed_bssid) | ||
666 | goto put_bss; | ||
667 | |||
668 | /* not an IBSS */ | 1145 | /* not an IBSS */ |
669 | if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) | 1146 | if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) |
670 | goto put_bss; | 1147 | goto put_bss; |
@@ -680,10 +1157,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
680 | sdata->u.ibss.ssid_len)) | 1157 | sdata->u.ibss.ssid_len)) |
681 | goto put_bss; | 1158 | goto put_bss; |
682 | 1159 | ||
1160 | /* process channel switch */ | ||
1161 | if (ieee80211_ibss_process_chanswitch(sdata, elems, true)) | ||
1162 | goto put_bss; | ||
1163 | |||
683 | /* same BSSID */ | 1164 | /* same BSSID */ |
684 | if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) | 1165 | if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) |
685 | goto put_bss; | 1166 | goto put_bss; |
686 | 1167 | ||
1168 | /* we use a fixed BSSID */ | ||
1169 | if (sdata->u.ibss.fixed_bssid) | ||
1170 | goto put_bss; | ||
1171 | |||
687 | if (ieee80211_have_rx_timestamp(rx_status)) { | 1172 | if (ieee80211_have_rx_timestamp(rx_status)) { |
688 | /* time when timestamp field was received */ | 1173 | /* time when timestamp field was received */ |
689 | rx_timestamp = | 1174 | rx_timestamp = |
@@ -775,30 +1260,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
775 | ieee80211_queue_work(&local->hw, &sdata->work); | 1260 | ieee80211_queue_work(&local->hw, &sdata->work); |
776 | } | 1261 | } |
777 | 1262 | ||
778 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
779 | { | ||
780 | struct ieee80211_local *local = sdata->local; | ||
781 | int active = 0; | ||
782 | struct sta_info *sta; | ||
783 | |||
784 | sdata_assert_lock(sdata); | ||
785 | |||
786 | rcu_read_lock(); | ||
787 | |||
788 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
789 | if (sta->sdata == sdata && | ||
790 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
791 | jiffies)) { | ||
792 | active++; | ||
793 | break; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | rcu_read_unlock(); | ||
798 | |||
799 | return active; | ||
800 | } | ||
801 | |||
802 | static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) | 1263 | static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) |
803 | { | 1264 | { |
804 | struct ieee80211_local *local = sdata->local; | 1265 | struct ieee80211_local *local = sdata->local; |
@@ -1076,6 +1537,8 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1076 | struct ieee80211_rx_status *rx_status; | 1537 | struct ieee80211_rx_status *rx_status; |
1077 | struct ieee80211_mgmt *mgmt; | 1538 | struct ieee80211_mgmt *mgmt; |
1078 | u16 fc; | 1539 | u16 fc; |
1540 | struct ieee802_11_elems elems; | ||
1541 | int ies_len; | ||
1079 | 1542 | ||
1080 | rx_status = IEEE80211_SKB_RXCB(skb); | 1543 | rx_status = IEEE80211_SKB_RXCB(skb); |
1081 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1544 | mgmt = (struct ieee80211_mgmt *) skb->data; |
@@ -1101,6 +1564,27 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1101 | case IEEE80211_STYPE_DEAUTH: | 1564 | case IEEE80211_STYPE_DEAUTH: |
1102 | ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len); | 1565 | ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len); |
1103 | break; | 1566 | break; |
1567 | case IEEE80211_STYPE_ACTION: | ||
1568 | switch (mgmt->u.action.category) { | ||
1569 | case WLAN_CATEGORY_SPECTRUM_MGMT: | ||
1570 | ies_len = skb->len - | ||
1571 | offsetof(struct ieee80211_mgmt, | ||
1572 | u.action.u.chan_switch.variable); | ||
1573 | |||
1574 | if (ies_len < 0) | ||
1575 | break; | ||
1576 | |||
1577 | ieee802_11_parse_elems( | ||
1578 | mgmt->u.action.u.chan_switch.variable, | ||
1579 | ies_len, true, &elems); | ||
1580 | |||
1581 | if (elems.parse_error) | ||
1582 | break; | ||
1583 | |||
1584 | ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, | ||
1585 | rx_status, &elems); | ||
1586 | break; | ||
1587 | } | ||
1104 | } | 1588 | } |
1105 | 1589 | ||
1106 | mgmt_out: | 1590 | mgmt_out: |
@@ -1167,6 +1651,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1167 | (unsigned long) sdata); | 1651 | (unsigned long) sdata); |
1168 | INIT_LIST_HEAD(&ifibss->incomplete_stations); | 1652 | INIT_LIST_HEAD(&ifibss->incomplete_stations); |
1169 | spin_lock_init(&ifibss->incomplete_lock); | 1653 | spin_lock_init(&ifibss->incomplete_lock); |
1654 | INIT_WORK(&ifibss->csa_connection_drop_work, | ||
1655 | ieee80211_csa_connection_drop_work); | ||
1170 | } | 1656 | } |
1171 | 1657 | ||
1172 | /* scan finished notification */ | 1658 | /* scan finished notification */ |
@@ -1265,73 +1751,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1265 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | 1751 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) |
1266 | { | 1752 | { |
1267 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 1753 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
1268 | struct ieee80211_local *local = sdata->local; | ||
1269 | struct cfg80211_bss *cbss; | ||
1270 | u16 capability; | ||
1271 | int active_ibss; | ||
1272 | struct sta_info *sta; | ||
1273 | struct beacon_data *presp; | ||
1274 | |||
1275 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
1276 | |||
1277 | if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { | ||
1278 | capability = WLAN_CAPABILITY_IBSS; | ||
1279 | |||
1280 | if (ifibss->privacy) | ||
1281 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
1282 | |||
1283 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, | ||
1284 | ifibss->bssid, ifibss->ssid, | ||
1285 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
1286 | WLAN_CAPABILITY_PRIVACY, | ||
1287 | capability); | ||
1288 | 1754 | ||
1289 | if (cbss) { | 1755 | ieee80211_ibss_disconnect(sdata); |
1290 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
1291 | cfg80211_put_bss(local->hw.wiphy, cbss); | ||
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
1296 | memset(ifibss->bssid, 0, ETH_ALEN); | ||
1297 | ifibss->ssid_len = 0; | 1756 | ifibss->ssid_len = 0; |
1298 | 1757 | memset(ifibss->bssid, 0, ETH_ALEN); | |
1299 | sta_info_flush(sdata); | ||
1300 | |||
1301 | spin_lock_bh(&ifibss->incomplete_lock); | ||
1302 | while (!list_empty(&ifibss->incomplete_stations)) { | ||
1303 | sta = list_first_entry(&ifibss->incomplete_stations, | ||
1304 | struct sta_info, list); | ||
1305 | list_del(&sta->list); | ||
1306 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
1307 | |||
1308 | sta_info_free(local, sta); | ||
1309 | spin_lock_bh(&ifibss->incomplete_lock); | ||
1310 | } | ||
1311 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
1312 | |||
1313 | netif_carrier_off(sdata->dev); | ||
1314 | 1758 | ||
1315 | /* remove beacon */ | 1759 | /* remove beacon */ |
1316 | kfree(sdata->u.ibss.ie); | 1760 | kfree(sdata->u.ibss.ie); |
1317 | presp = rcu_dereference_protected(ifibss->presp, | ||
1318 | lockdep_is_held(&sdata->wdev.mtx)); | ||
1319 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | ||
1320 | 1761 | ||
1321 | /* on the next join, re-program HT parameters */ | 1762 | /* on the next join, re-program HT parameters */ |
1322 | memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa)); | 1763 | memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa)); |
1323 | memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask)); | 1764 | memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask)); |
1324 | 1765 | ||
1325 | sdata->vif.bss_conf.ibss_joined = false; | ||
1326 | sdata->vif.bss_conf.ibss_creator = false; | ||
1327 | sdata->vif.bss_conf.enable_beacon = false; | ||
1328 | sdata->vif.bss_conf.ssid_len = 0; | ||
1329 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | ||
1330 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | ||
1331 | BSS_CHANGED_IBSS); | ||
1332 | ieee80211_vif_release_channel(sdata); | ||
1333 | synchronize_rcu(); | 1766 | synchronize_rcu(); |
1334 | kfree(presp); | ||
1335 | 1767 | ||
1336 | skb_queue_purge(&sdata->skb_queue); | 1768 | skb_queue_purge(&sdata->skb_queue); |
1337 | 1769 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b6186517ec56..3a87c8976a32 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -322,7 +322,6 @@ struct ieee80211_roc_work { | |||
322 | 322 | ||
323 | /* flags used in struct ieee80211_if_managed.flags */ | 323 | /* flags used in struct ieee80211_if_managed.flags */ |
324 | enum ieee80211_sta_flags { | 324 | enum ieee80211_sta_flags { |
325 | IEEE80211_STA_BEACON_POLL = BIT(0), | ||
326 | IEEE80211_STA_CONNECTION_POLL = BIT(1), | 325 | IEEE80211_STA_CONNECTION_POLL = BIT(1), |
327 | IEEE80211_STA_CONTROL_PORT = BIT(2), | 326 | IEEE80211_STA_CONTROL_PORT = BIT(2), |
328 | IEEE80211_STA_DISABLE_HT = BIT(4), | 327 | IEEE80211_STA_DISABLE_HT = BIT(4), |
@@ -487,6 +486,7 @@ struct ieee80211_if_managed { | |||
487 | 486 | ||
488 | struct ieee80211_if_ibss { | 487 | struct ieee80211_if_ibss { |
489 | struct timer_list timer; | 488 | struct timer_list timer; |
489 | struct work_struct csa_connection_drop_work; | ||
490 | 490 | ||
491 | unsigned long last_scan_completed; | 491 | unsigned long last_scan_completed; |
492 | 492 | ||
@@ -1330,6 +1330,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | |||
1330 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); | 1330 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); |
1331 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1331 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1332 | struct sk_buff *skb); | 1332 | struct sk_buff *skb); |
1333 | int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | ||
1334 | struct cfg80211_csa_settings *csa_settings); | ||
1335 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); | ||
1336 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); | ||
1333 | 1337 | ||
1334 | /* mesh code */ | 1338 | /* mesh code */ |
1335 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); | 1339 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); |
@@ -1481,6 +1485,29 @@ void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
1481 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1485 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
1482 | struct ieee80211_mgmt *mgmt, | 1486 | struct ieee80211_mgmt *mgmt, |
1483 | size_t len); | 1487 | size_t len); |
1488 | /** | ||
1489 | * ieee80211_parse_ch_switch_ie - parses channel switch IEs | ||
1490 | * @sdata: the sdata of the interface which has received the frame | ||
1491 | * @elems: parsed 802.11 elements received with the frame | ||
1492 | * @beacon: indicates if the frame was a beacon or probe response | ||
1493 | * @current_band: indicates the current band | ||
1494 | * @sta_flags: contains information about own capabilities and restrictions | ||
1495 | * to decide which channel switch announcements can be accepted. Only the | ||
1496 | * following subset of &enum ieee80211_sta_flags are evaluated: | ||
1497 | * %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT, | ||
1498 | * %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ, | ||
1499 | * %IEEE80211_STA_DISABLE_160MHZ. | ||
1500 | * @count: to be filled with the counter until the switch (on success only) | ||
1501 | * @bssid: the currently connected bssid (for reporting) | ||
1502 | * @mode: to be filled with CSA mode (on success only) | ||
1503 | * @new_chandef: to be filled with destination chandef (on success only) | ||
1504 | * Return: 0 on success, <0 on error and >0 if there is nothing to parse. | ||
1505 | */ | ||
1506 | int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, | ||
1507 | struct ieee802_11_elems *elems, bool beacon, | ||
1508 | enum ieee80211_band current_band, | ||
1509 | u32 sta_flags, u8 *bssid, u8 *count, u8 *mode, | ||
1510 | struct cfg80211_chan_def *new_chandef); | ||
1484 | 1511 | ||
1485 | /* Suspend/resume and hw reconfiguration */ | 1512 | /* Suspend/resume and hw reconfiguration */ |
1486 | int ieee80211_reconfig(struct ieee80211_local *local); | 1513 | int ieee80211_reconfig(struct ieee80211_local *local); |
@@ -1654,6 +1681,7 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
1654 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1681 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
1655 | const struct ieee80211_ht_operation *ht_oper, | 1682 | const struct ieee80211_ht_operation *ht_oper, |
1656 | struct cfg80211_chan_def *chandef); | 1683 | struct cfg80211_chan_def *chandef); |
1684 | u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); | ||
1657 | 1685 | ||
1658 | int __must_check | 1686 | int __must_check |
1659 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | 1687 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fcecd633514e..e48f103b9ade 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -766,6 +766,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
766 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 766 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
767 | ieee80211_mgd_stop(sdata); | 767 | ieee80211_mgd_stop(sdata); |
768 | 768 | ||
769 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
770 | ieee80211_ibss_stop(sdata); | ||
771 | |||
772 | |||
769 | /* | 773 | /* |
770 | * Remove all stations associated with this interface. | 774 | * Remove all stations associated with this interface. |
771 | * | 775 | * |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 620677e897bd..3e51dd7d98b3 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -879,7 +879,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | |||
879 | keyconf->keylen, keyconf->key, | 879 | keyconf->keylen, keyconf->key, |
880 | 0, NULL); | 880 | 0, NULL); |
881 | if (IS_ERR(key)) | 881 | if (IS_ERR(key)) |
882 | return ERR_PTR(PTR_ERR(key)); | 882 | return ERR_CAST(key); |
883 | 883 | ||
884 | if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) | 884 | if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) |
885 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | 885 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86e4ad56b573..91cc8281e266 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -145,66 +145,6 @@ static int ecw2cw(int ecw) | |||
145 | return (1 << ecw) - 1; | 145 | return (1 << ecw) - 1; |
146 | } | 146 | } |
147 | 147 | ||
148 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) | ||
149 | { | ||
150 | u32 ret; | ||
151 | int tmp; | ||
152 | |||
153 | switch (c->width) { | ||
154 | case NL80211_CHAN_WIDTH_20: | ||
155 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
156 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
157 | break; | ||
158 | case NL80211_CHAN_WIDTH_40: | ||
159 | c->width = NL80211_CHAN_WIDTH_20; | ||
160 | c->center_freq1 = c->chan->center_freq; | ||
161 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
162 | IEEE80211_STA_DISABLE_VHT; | ||
163 | break; | ||
164 | case NL80211_CHAN_WIDTH_80: | ||
165 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
166 | /* n_P40 */ | ||
167 | tmp /= 2; | ||
168 | /* freq_P40 */ | ||
169 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
170 | c->width = NL80211_CHAN_WIDTH_40; | ||
171 | ret = IEEE80211_STA_DISABLE_VHT; | ||
172 | break; | ||
173 | case NL80211_CHAN_WIDTH_80P80: | ||
174 | c->center_freq2 = 0; | ||
175 | c->width = NL80211_CHAN_WIDTH_80; | ||
176 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
177 | IEEE80211_STA_DISABLE_160MHZ; | ||
178 | break; | ||
179 | case NL80211_CHAN_WIDTH_160: | ||
180 | /* n_P20 */ | ||
181 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
182 | /* n_P80 */ | ||
183 | tmp /= 4; | ||
184 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
185 | c->width = NL80211_CHAN_WIDTH_80; | ||
186 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
187 | IEEE80211_STA_DISABLE_160MHZ; | ||
188 | break; | ||
189 | default: | ||
190 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
191 | WARN_ON_ONCE(1); | ||
192 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
193 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
194 | break; | ||
195 | case NL80211_CHAN_WIDTH_5: | ||
196 | case NL80211_CHAN_WIDTH_10: | ||
197 | WARN_ON_ONCE(1); | ||
198 | /* keep c->width */ | ||
199 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | static u32 | 148 | static u32 |
209 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | 149 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, |
210 | struct ieee80211_supported_band *sband, | 150 | struct ieee80211_supported_band *sband, |
@@ -352,7 +292,7 @@ out: | |||
352 | break; | 292 | break; |
353 | } | 293 | } |
354 | 294 | ||
355 | ret |= chandef_downgrade(chandef); | 295 | ret |= ieee80211_chandef_downgrade(chandef); |
356 | } | 296 | } |
357 | 297 | ||
358 | if (chandef->width != vht_chandef.width && !tracking) | 298 | if (chandef->width != vht_chandef.width && !tracking) |
@@ -406,13 +346,13 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
406 | */ | 346 | */ |
407 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | 347 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && |
408 | chandef.width == NL80211_CHAN_WIDTH_80P80) | 348 | chandef.width == NL80211_CHAN_WIDTH_80P80) |
409 | flags |= chandef_downgrade(&chandef); | 349 | flags |= ieee80211_chandef_downgrade(&chandef); |
410 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | 350 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && |
411 | chandef.width == NL80211_CHAN_WIDTH_160) | 351 | chandef.width == NL80211_CHAN_WIDTH_160) |
412 | flags |= chandef_downgrade(&chandef); | 352 | flags |= ieee80211_chandef_downgrade(&chandef); |
413 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | 353 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && |
414 | chandef.width > NL80211_CHAN_WIDTH_20) | 354 | chandef.width > NL80211_CHAN_WIDTH_20) |
415 | flags |= chandef_downgrade(&chandef); | 355 | flags |= ieee80211_chandef_downgrade(&chandef); |
416 | 356 | ||
417 | if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef)) | 357 | if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef)) |
418 | return 0; | 358 | return 0; |
@@ -893,8 +833,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
893 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 833 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
894 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | 834 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; |
895 | 835 | ||
896 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 836 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) |
897 | IEEE80211_STA_CONNECTION_POLL)) | ||
898 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; | 837 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; |
899 | 838 | ||
900 | ieee80211_tx_skb(sdata, skb); | 839 | ieee80211_tx_skb(sdata, skb); |
@@ -937,6 +876,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
937 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 876 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
938 | struct ieee80211_local *local = sdata->local; | 877 | struct ieee80211_local *local = sdata->local; |
939 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 878 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
879 | u32 changed = 0; | ||
880 | int ret; | ||
940 | 881 | ||
941 | if (!ieee80211_sdata_running(sdata)) | 882 | if (!ieee80211_sdata_running(sdata)) |
942 | return; | 883 | return; |
@@ -945,24 +886,39 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
945 | if (!ifmgd->associated) | 886 | if (!ifmgd->associated) |
946 | goto out; | 887 | goto out; |
947 | 888 | ||
948 | local->_oper_chandef = local->csa_chandef; | 889 | ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef, |
890 | &changed); | ||
891 | if (ret) { | ||
892 | sdata_info(sdata, | ||
893 | "vif channel switch failed, disconnecting\n"); | ||
894 | ieee80211_queue_work(&sdata->local->hw, | ||
895 | &ifmgd->csa_connection_drop_work); | ||
896 | goto out; | ||
897 | } | ||
949 | 898 | ||
950 | if (!local->ops->channel_switch) { | 899 | if (!local->use_chanctx) { |
951 | /* call "hw_config" only if doing sw channel switch */ | 900 | local->_oper_chandef = local->csa_chandef; |
952 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 901 | /* Call "hw_config" only if doing sw channel switch. |
953 | } else { | 902 | * Otherwise update the channel directly |
954 | /* update the device channel directly */ | 903 | */ |
955 | local->hw.conf.chandef = local->_oper_chandef; | 904 | if (!local->ops->channel_switch) |
905 | ieee80211_hw_config(local, 0); | ||
906 | else | ||
907 | local->hw.conf.chandef = local->_oper_chandef; | ||
956 | } | 908 | } |
957 | 909 | ||
958 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 910 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
959 | ifmgd->associated->channel = local->_oper_chandef.chan; | 911 | ifmgd->associated->channel = local->csa_chandef.chan; |
960 | 912 | ||
961 | /* XXX: wait for a beacon first? */ | 913 | /* XXX: wait for a beacon first? */ |
962 | ieee80211_wake_queues_by_reason(&local->hw, | 914 | ieee80211_wake_queues_by_reason(&local->hw, |
963 | IEEE80211_MAX_QUEUE_MAP, | 915 | IEEE80211_MAX_QUEUE_MAP, |
964 | IEEE80211_QUEUE_STOP_REASON_CSA); | 916 | IEEE80211_QUEUE_STOP_REASON_CSA); |
917 | |||
918 | ieee80211_bss_info_change_notify(sdata, changed); | ||
919 | |||
965 | out: | 920 | out: |
921 | sdata->vif.csa_active = false; | ||
966 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 922 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
967 | sdata_unlock(sdata); | 923 | sdata_unlock(sdata); |
968 | } | 924 | } |
@@ -1000,20 +956,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1000 | struct ieee80211_local *local = sdata->local; | 956 | struct ieee80211_local *local = sdata->local; |
1001 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 957 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1002 | struct cfg80211_bss *cbss = ifmgd->associated; | 958 | struct cfg80211_bss *cbss = ifmgd->associated; |
1003 | struct ieee80211_bss *bss; | ||
1004 | struct ieee80211_chanctx *chanctx; | 959 | struct ieee80211_chanctx *chanctx; |
1005 | enum ieee80211_band new_band; | 960 | enum ieee80211_band current_band; |
1006 | int new_freq; | ||
1007 | u8 new_chan_no; | ||
1008 | u8 count; | 961 | u8 count; |
1009 | u8 mode; | 962 | u8 mode; |
1010 | struct ieee80211_channel *new_chan; | ||
1011 | struct cfg80211_chan_def new_chandef = {}; | 963 | struct cfg80211_chan_def new_chandef = {}; |
1012 | struct cfg80211_chan_def new_vht_chandef = {}; | 964 | int res; |
1013 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | ||
1014 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | ||
1015 | const struct ieee80211_ht_operation *ht_oper; | ||
1016 | int secondary_channel_offset = -1; | ||
1017 | 965 | ||
1018 | sdata_assert_lock(sdata); | 966 | sdata_assert_lock(sdata); |
1019 | 967 | ||
@@ -1027,162 +975,23 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1027 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 975 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
1028 | return; | 976 | return; |
1029 | 977 | ||
1030 | sec_chan_offs = elems->sec_chan_offs; | 978 | current_band = cbss->channel->band; |
1031 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; | 979 | res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band, |
1032 | ht_oper = elems->ht_operation; | 980 | ifmgd->flags, |
1033 | 981 | ifmgd->associated->bssid, &count, | |
1034 | if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | | 982 | &mode, &new_chandef); |
1035 | IEEE80211_STA_DISABLE_40MHZ)) { | 983 | if (res < 0) |
1036 | sec_chan_offs = NULL; | ||
1037 | wide_bw_chansw_ie = NULL; | ||
1038 | /* only used for bandwidth here */ | ||
1039 | ht_oper = NULL; | ||
1040 | } | ||
1041 | |||
1042 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) | ||
1043 | wide_bw_chansw_ie = NULL; | ||
1044 | |||
1045 | if (elems->ext_chansw_ie) { | ||
1046 | if (!ieee80211_operating_class_to_band( | ||
1047 | elems->ext_chansw_ie->new_operating_class, | ||
1048 | &new_band)) { | ||
1049 | sdata_info(sdata, | ||
1050 | "cannot understand ECSA IE operating class %d, disconnecting\n", | ||
1051 | elems->ext_chansw_ie->new_operating_class); | ||
1052 | ieee80211_queue_work(&local->hw, | ||
1053 | &ifmgd->csa_connection_drop_work); | ||
1054 | } | ||
1055 | new_chan_no = elems->ext_chansw_ie->new_ch_num; | ||
1056 | count = elems->ext_chansw_ie->count; | ||
1057 | mode = elems->ext_chansw_ie->mode; | ||
1058 | } else if (elems->ch_switch_ie) { | ||
1059 | new_band = cbss->channel->band; | ||
1060 | new_chan_no = elems->ch_switch_ie->new_ch_num; | ||
1061 | count = elems->ch_switch_ie->count; | ||
1062 | mode = elems->ch_switch_ie->mode; | ||
1063 | } else { | ||
1064 | /* nothing here we understand */ | ||
1065 | return; | ||
1066 | } | ||
1067 | |||
1068 | bss = (void *)cbss->priv; | ||
1069 | |||
1070 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); | ||
1071 | new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
1072 | if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) { | ||
1073 | sdata_info(sdata, | ||
1074 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
1075 | ifmgd->associated->bssid, new_freq); | ||
1076 | ieee80211_queue_work(&local->hw, | 984 | ieee80211_queue_work(&local->hw, |
1077 | &ifmgd->csa_connection_drop_work); | 985 | &ifmgd->csa_connection_drop_work); |
986 | if (res) | ||
1078 | return; | 987 | return; |
1079 | } | ||
1080 | |||
1081 | if (!beacon && sec_chan_offs) { | ||
1082 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; | ||
1083 | } else if (beacon && ht_oper) { | ||
1084 | secondary_channel_offset = | ||
1085 | ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
1086 | } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
1087 | /* | ||
1088 | * If it's not a beacon, HT is enabled and the IE not present, | ||
1089 | * it's 20 MHz, 802.11-2012 8.5.2.6: | ||
1090 | * This element [the Secondary Channel Offset Element] is | ||
1091 | * present when switching to a 40 MHz channel. It may be | ||
1092 | * present when switching to a 20 MHz channel (in which | ||
1093 | * case the secondary channel offset is set to SCN). | ||
1094 | */ | ||
1095 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
1096 | } | ||
1097 | |||
1098 | switch (secondary_channel_offset) { | ||
1099 | default: | ||
1100 | /* secondary_channel_offset was present but is invalid */ | ||
1101 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
1102 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
1103 | NL80211_CHAN_HT20); | ||
1104 | break; | ||
1105 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
1106 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
1107 | NL80211_CHAN_HT40PLUS); | ||
1108 | break; | ||
1109 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
1110 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
1111 | NL80211_CHAN_HT40MINUS); | ||
1112 | break; | ||
1113 | case -1: | ||
1114 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
1115 | NL80211_CHAN_NO_HT); | ||
1116 | /* keep width for 5/10 MHz channels */ | ||
1117 | switch (sdata->vif.bss_conf.chandef.width) { | ||
1118 | case NL80211_CHAN_WIDTH_5: | ||
1119 | case NL80211_CHAN_WIDTH_10: | ||
1120 | new_chandef.width = sdata->vif.bss_conf.chandef.width; | ||
1121 | break; | ||
1122 | default: | ||
1123 | break; | ||
1124 | } | ||
1125 | break; | ||
1126 | } | ||
1127 | |||
1128 | if (wide_bw_chansw_ie) { | ||
1129 | new_vht_chandef.chan = new_chan; | ||
1130 | new_vht_chandef.center_freq1 = | ||
1131 | ieee80211_channel_to_frequency( | ||
1132 | wide_bw_chansw_ie->new_center_freq_seg0, | ||
1133 | new_band); | ||
1134 | |||
1135 | switch (wide_bw_chansw_ie->new_channel_width) { | ||
1136 | default: | ||
1137 | /* hmmm, ignore VHT and use HT if present */ | ||
1138 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
1139 | new_vht_chandef.chan = NULL; | ||
1140 | break; | ||
1141 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
1142 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
1143 | break; | ||
1144 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
1145 | new_vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
1146 | break; | ||
1147 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
1148 | /* field is otherwise reserved */ | ||
1149 | new_vht_chandef.center_freq2 = | ||
1150 | ieee80211_channel_to_frequency( | ||
1151 | wide_bw_chansw_ie->new_center_freq_seg1, | ||
1152 | new_band); | ||
1153 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
1154 | break; | ||
1155 | } | ||
1156 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | ||
1157 | new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80) | ||
1158 | chandef_downgrade(&new_vht_chandef); | ||
1159 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | ||
1160 | new_vht_chandef.width == NL80211_CHAN_WIDTH_160) | ||
1161 | chandef_downgrade(&new_vht_chandef); | ||
1162 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | ||
1163 | new_vht_chandef.width > NL80211_CHAN_WIDTH_20) | ||
1164 | chandef_downgrade(&new_vht_chandef); | ||
1165 | } | ||
1166 | |||
1167 | /* if VHT data is there validate & use it */ | ||
1168 | if (new_vht_chandef.chan) { | ||
1169 | if (!cfg80211_chandef_compatible(&new_vht_chandef, | ||
1170 | &new_chandef)) { | ||
1171 | sdata_info(sdata, | ||
1172 | "AP %pM CSA has inconsistent channel data, disconnecting\n", | ||
1173 | ifmgd->associated->bssid); | ||
1174 | ieee80211_queue_work(&local->hw, | ||
1175 | &ifmgd->csa_connection_drop_work); | ||
1176 | return; | ||
1177 | } | ||
1178 | new_chandef = new_vht_chandef; | ||
1179 | } | ||
1180 | 988 | ||
1181 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, | 989 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, |
1182 | IEEE80211_CHAN_DISABLED)) { | 990 | IEEE80211_CHAN_DISABLED)) { |
1183 | sdata_info(sdata, | 991 | sdata_info(sdata, |
1184 | "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | 992 | "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", |
1185 | ifmgd->associated->bssid, new_freq, | 993 | ifmgd->associated->bssid, |
994 | new_chandef.chan->center_freq, | ||
1186 | new_chandef.width, new_chandef.center_freq1, | 995 | new_chandef.width, new_chandef.center_freq1, |
1187 | new_chandef.center_freq2); | 996 | new_chandef.center_freq2); |
1188 | ieee80211_queue_work(&local->hw, | 997 | ieee80211_queue_work(&local->hw, |
@@ -1191,17 +1000,28 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1191 | } | 1000 | } |
1192 | 1001 | ||
1193 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1002 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
1003 | sdata->vif.csa_active = true; | ||
1194 | 1004 | ||
1005 | mutex_lock(&local->chanctx_mtx); | ||
1195 | if (local->use_chanctx) { | 1006 | if (local->use_chanctx) { |
1196 | sdata_info(sdata, | 1007 | u32 num_chanctx = 0; |
1197 | "not handling channel switch with channel contexts\n"); | 1008 | list_for_each_entry(chanctx, &local->chanctx_list, list) |
1198 | ieee80211_queue_work(&local->hw, | 1009 | num_chanctx++; |
1199 | &ifmgd->csa_connection_drop_work); | 1010 | |
1200 | return; | 1011 | if (num_chanctx > 1 || |
1012 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { | ||
1013 | sdata_info(sdata, | ||
1014 | "not handling chan-switch with channel contexts\n"); | ||
1015 | ieee80211_queue_work(&local->hw, | ||
1016 | &ifmgd->csa_connection_drop_work); | ||
1017 | mutex_unlock(&local->chanctx_mtx); | ||
1018 | return; | ||
1019 | } | ||
1201 | } | 1020 | } |
1202 | 1021 | ||
1203 | mutex_lock(&local->chanctx_mtx); | ||
1204 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { | 1022 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { |
1023 | ieee80211_queue_work(&local->hw, | ||
1024 | &ifmgd->csa_connection_drop_work); | ||
1205 | mutex_unlock(&local->chanctx_mtx); | 1025 | mutex_unlock(&local->chanctx_mtx); |
1206 | return; | 1026 | return; |
1207 | } | 1027 | } |
@@ -1374,8 +1194,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
1374 | if (!mgd->associated) | 1194 | if (!mgd->associated) |
1375 | return false; | 1195 | return false; |
1376 | 1196 | ||
1377 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | | 1197 | if (mgd->flags & IEEE80211_STA_CONNECTION_POLL) |
1378 | IEEE80211_STA_CONNECTION_POLL)) | ||
1379 | return false; | 1198 | return false; |
1380 | 1199 | ||
1381 | if (!mgd->have_beacon) | 1200 | if (!mgd->have_beacon) |
@@ -1691,8 +1510,7 @@ static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) | |||
1691 | { | 1510 | { |
1692 | lockdep_assert_held(&sdata->local->mtx); | 1511 | lockdep_assert_held(&sdata->local->mtx); |
1693 | 1512 | ||
1694 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | | 1513 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONNECTION_POLL; |
1695 | IEEE80211_STA_BEACON_POLL); | ||
1696 | ieee80211_run_deferred_scan(sdata->local); | 1514 | ieee80211_run_deferred_scan(sdata->local); |
1697 | } | 1515 | } |
1698 | 1516 | ||
@@ -1954,11 +1772,8 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) | |||
1954 | struct ieee80211_local *local = sdata->local; | 1772 | struct ieee80211_local *local = sdata->local; |
1955 | 1773 | ||
1956 | mutex_lock(&local->mtx); | 1774 | mutex_lock(&local->mtx); |
1957 | if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1775 | if (!(ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)) |
1958 | IEEE80211_STA_CONNECTION_POLL))) { | 1776 | goto out; |
1959 | mutex_unlock(&local->mtx); | ||
1960 | return; | ||
1961 | } | ||
1962 | 1777 | ||
1963 | __ieee80211_stop_poll(sdata); | 1778 | __ieee80211_stop_poll(sdata); |
1964 | 1779 | ||
@@ -2094,15 +1909,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
2094 | * because otherwise we would reset the timer every time and | 1909 | * because otherwise we would reset the timer every time and |
2095 | * never check whether we received a probe response! | 1910 | * never check whether we received a probe response! |
2096 | */ | 1911 | */ |
2097 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1912 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) |
2098 | IEEE80211_STA_CONNECTION_POLL)) | ||
2099 | already = true; | 1913 | already = true; |
2100 | 1914 | ||
2101 | if (beacon) | ||
2102 | ifmgd->flags |= IEEE80211_STA_BEACON_POLL; | ||
2103 | else | ||
2104 | ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL; | ||
2105 | |||
2106 | mutex_unlock(&sdata->local->mtx); | 1915 | mutex_unlock(&sdata->local->mtx); |
2107 | 1916 | ||
2108 | if (already) | 1917 | if (already) |
@@ -2174,6 +1983,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2174 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 1983 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
2175 | true, frame_buf); | 1984 | true, frame_buf); |
2176 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 1985 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
1986 | sdata->vif.csa_active = false; | ||
2177 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 1987 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
2178 | IEEE80211_MAX_QUEUE_MAP, | 1988 | IEEE80211_MAX_QUEUE_MAP, |
2179 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1989 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -3061,17 +2871,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3061 | } | 2871 | } |
3062 | } | 2872 | } |
3063 | 2873 | ||
3064 | if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { | 2874 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) { |
3065 | mlme_dbg_ratelimited(sdata, | 2875 | mlme_dbg_ratelimited(sdata, |
3066 | "cancelling AP probe due to a received beacon\n"); | 2876 | "cancelling AP probe due to a received beacon\n"); |
3067 | mutex_lock(&local->mtx); | 2877 | ieee80211_reset_ap_probe(sdata); |
3068 | ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; | ||
3069 | ieee80211_run_deferred_scan(local); | ||
3070 | mutex_unlock(&local->mtx); | ||
3071 | |||
3072 | mutex_lock(&local->iflist_mtx); | ||
3073 | ieee80211_recalc_ps(local, -1); | ||
3074 | mutex_unlock(&local->iflist_mtx); | ||
3075 | } | 2878 | } |
3076 | 2879 | ||
3077 | /* | 2880 | /* |
@@ -3543,8 +3346,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3543 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) | 3346 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
3544 | run_again(sdata, ifmgd->assoc_data->timeout); | 3347 | run_again(sdata, ifmgd->assoc_data->timeout); |
3545 | 3348 | ||
3546 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 3349 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL && |
3547 | IEEE80211_STA_CONNECTION_POLL) && | ||
3548 | ifmgd->associated) { | 3350 | ifmgd->associated) { |
3549 | u8 bssid[ETH_ALEN]; | 3351 | u8 bssid[ETH_ALEN]; |
3550 | int max_tries; | 3352 | int max_tries; |
@@ -3876,7 +3678,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3876 | return ret; | 3678 | return ret; |
3877 | 3679 | ||
3878 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { | 3680 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { |
3879 | ifmgd->flags |= chandef_downgrade(&chandef); | 3681 | ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); |
3880 | ret = ieee80211_vif_use_channel(sdata, &chandef, | 3682 | ret = ieee80211_vif_use_channel(sdata, &chandef, |
3881 | IEEE80211_CHANCTX_SHARED); | 3683 | IEEE80211_CHANCTX_SHARED); |
3882 | } | 3684 | } |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 8b5f7ef7c0c9..7fa1b36e6202 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -203,6 +203,15 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
203 | memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate)); | 203 | memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate)); |
204 | mi->max_prob_rate = tmp_prob_rate; | 204 | mi->max_prob_rate = tmp_prob_rate; |
205 | 205 | ||
206 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
207 | /* use fixed index if set */ | ||
208 | if (mp->fixed_rate_idx != -1) { | ||
209 | mi->max_tp_rate[0] = mp->fixed_rate_idx; | ||
210 | mi->max_tp_rate[1] = mp->fixed_rate_idx; | ||
211 | mi->max_prob_rate = mp->fixed_rate_idx; | ||
212 | } | ||
213 | #endif | ||
214 | |||
206 | /* Reset update timer */ | 215 | /* Reset update timer */ |
207 | mi->stats_update = jiffies; | 216 | mi->stats_update = jiffies; |
208 | 217 | ||
@@ -310,6 +319,11 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
310 | /* increase sum packet counter */ | 319 | /* increase sum packet counter */ |
311 | mi->packet_count++; | 320 | mi->packet_count++; |
312 | 321 | ||
322 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
323 | if (mp->fixed_rate_idx != -1) | ||
324 | return; | ||
325 | #endif | ||
326 | |||
313 | delta = (mi->packet_count * sampling_ratio / 100) - | 327 | delta = (mi->packet_count * sampling_ratio / 100) - |
314 | (mi->sample_count + mi->sample_deferred / 2); | 328 | (mi->sample_count + mi->sample_deferred / 2); |
315 | 329 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 7c323f27ba23..5d60779a0c1b 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -365,6 +365,14 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
365 | } | 365 | } |
366 | } | 366 | } |
367 | 367 | ||
368 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
369 | /* use fixed index if set */ | ||
370 | if (mp->fixed_rate_idx != -1) { | ||
371 | mi->max_tp_rate = mp->fixed_rate_idx; | ||
372 | mi->max_tp_rate2 = mp->fixed_rate_idx; | ||
373 | mi->max_prob_rate = mp->fixed_rate_idx; | ||
374 | } | ||
375 | #endif | ||
368 | 376 | ||
369 | mi->stats_update = jiffies; | 377 | mi->stats_update = jiffies; |
370 | } | 378 | } |
@@ -774,6 +782,11 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
774 | info->flags |= mi->tx_flags; | 782 | info->flags |= mi->tx_flags; |
775 | minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble); | 783 | minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble); |
776 | 784 | ||
785 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
786 | if (mp->fixed_rate_idx != -1) | ||
787 | return; | ||
788 | #endif | ||
789 | |||
777 | /* Don't use EAPOL frames for sampling on non-mrr hw */ | 790 | /* Don't use EAPOL frames for sampling on non-mrr hw */ |
778 | if (mp->hw->max_rates == 1 && | 791 | if (mp->hw->max_rates == 1 && |
779 | (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) | 792 | (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) |
@@ -781,16 +794,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
781 | else | 794 | else |
782 | sample_idx = minstrel_get_sample_rate(mp, mi); | 795 | sample_idx = minstrel_get_sample_rate(mp, mi); |
783 | 796 | ||
784 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
785 | /* use fixed index if set */ | ||
786 | if (mp->fixed_rate_idx != -1) { | ||
787 | mi->max_tp_rate = mp->fixed_rate_idx; | ||
788 | mi->max_tp_rate2 = mp->fixed_rate_idx; | ||
789 | mi->max_prob_rate = mp->fixed_rate_idx; | ||
790 | sample_idx = -1; | ||
791 | } | ||
792 | #endif | ||
793 | |||
794 | mi->total_packets++; | 797 | mi->total_packets++; |
795 | 798 | ||
796 | /* wraparound */ | 799 | /* wraparound */ |
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index c97a0657c043..6ff134650a84 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c | |||
@@ -167,29 +167,29 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, | |||
167 | * provide large enough buffers. */ | 167 | * provide large enough buffers. */ |
168 | length = length < RC_PID_PRINT_BUF_SIZE ? | 168 | length = length < RC_PID_PRINT_BUF_SIZE ? |
169 | length : RC_PID_PRINT_BUF_SIZE; | 169 | length : RC_PID_PRINT_BUF_SIZE; |
170 | p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); | 170 | p = scnprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); |
171 | switch (ev->type) { | 171 | switch (ev->type) { |
172 | case RC_PID_EVENT_TYPE_TX_STATUS: | 172 | case RC_PID_EVENT_TYPE_TX_STATUS: |
173 | p += snprintf(pb + p, length - p, "tx_status %u %u", | 173 | p += scnprintf(pb + p, length - p, "tx_status %u %u", |
174 | !(ev->data.flags & IEEE80211_TX_STAT_ACK), | 174 | !(ev->data.flags & IEEE80211_TX_STAT_ACK), |
175 | ev->data.tx_status.status.rates[0].idx); | 175 | ev->data.tx_status.status.rates[0].idx); |
176 | break; | 176 | break; |
177 | case RC_PID_EVENT_TYPE_RATE_CHANGE: | 177 | case RC_PID_EVENT_TYPE_RATE_CHANGE: |
178 | p += snprintf(pb + p, length - p, "rate_change %d %d", | 178 | p += scnprintf(pb + p, length - p, "rate_change %d %d", |
179 | ev->data.index, ev->data.rate); | 179 | ev->data.index, ev->data.rate); |
180 | break; | 180 | break; |
181 | case RC_PID_EVENT_TYPE_TX_RATE: | 181 | case RC_PID_EVENT_TYPE_TX_RATE: |
182 | p += snprintf(pb + p, length - p, "tx_rate %d %d", | 182 | p += scnprintf(pb + p, length - p, "tx_rate %d %d", |
183 | ev->data.index, ev->data.rate); | 183 | ev->data.index, ev->data.rate); |
184 | break; | 184 | break; |
185 | case RC_PID_EVENT_TYPE_PF_SAMPLE: | 185 | case RC_PID_EVENT_TYPE_PF_SAMPLE: |
186 | p += snprintf(pb + p, length - p, | 186 | p += scnprintf(pb + p, length - p, |
187 | "pf_sample %d %d %d %d", | 187 | "pf_sample %d %d %d %d", |
188 | ev->data.pf_sample, ev->data.prop_err, | 188 | ev->data.pf_sample, ev->data.prop_err, |
189 | ev->data.int_err, ev->data.der_err); | 189 | ev->data.int_err, ev->data.der_err); |
190 | break; | 190 | break; |
191 | } | 191 | } |
192 | p += snprintf(pb + p, length - p, "\n"); | 192 | p += scnprintf(pb + p, length - p, "\n"); |
193 | 193 | ||
194 | spin_unlock_irqrestore(&events->lock, status); | 194 | spin_unlock_irqrestore(&events->lock, status); |
195 | 195 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 674eac1f996c..0011ac815097 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -995,8 +995,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
995 | rx->sta->num_duplicates++; | 995 | rx->sta->num_duplicates++; |
996 | } | 996 | } |
997 | return RX_DROP_UNUSABLE; | 997 | return RX_DROP_UNUSABLE; |
998 | } else | 998 | } else if (!(status->flag & RX_FLAG_AMSDU_MORE)) { |
999 | rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; | 999 | rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; |
1000 | } | ||
1000 | } | 1001 | } |
1001 | 1002 | ||
1002 | if (unlikely(rx->skb->len < 16)) { | 1003 | if (unlikely(rx->skb->len < 16)) { |
@@ -2402,7 +2403,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2402 | return RX_DROP_UNUSABLE; | 2403 | return RX_DROP_UNUSABLE; |
2403 | 2404 | ||
2404 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && | 2405 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && |
2405 | mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED) | 2406 | mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED && |
2407 | mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) | ||
2406 | return RX_DROP_UNUSABLE; | 2408 | return RX_DROP_UNUSABLE; |
2407 | 2409 | ||
2408 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | 2410 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
@@ -2566,31 +2568,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2566 | 2568 | ||
2567 | goto queue; | 2569 | goto queue; |
2568 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 2570 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
2569 | if (status->band != IEEE80211_BAND_5GHZ) | ||
2570 | break; | ||
2571 | |||
2572 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2573 | break; | ||
2574 | |||
2575 | /* verify action_code is present */ | 2571 | /* verify action_code is present */ |
2576 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | 2572 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) |
2577 | break; | 2573 | break; |
2578 | 2574 | ||
2579 | switch (mgmt->u.action.u.measurement.action_code) { | 2575 | switch (mgmt->u.action.u.measurement.action_code) { |
2580 | case WLAN_ACTION_SPCT_MSR_REQ: | 2576 | case WLAN_ACTION_SPCT_MSR_REQ: |
2577 | if (status->band != IEEE80211_BAND_5GHZ) | ||
2578 | break; | ||
2579 | |||
2581 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 2580 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
2582 | sizeof(mgmt->u.action.u.measurement))) | 2581 | sizeof(mgmt->u.action.u.measurement))) |
2583 | break; | 2582 | break; |
2583 | |||
2584 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2585 | break; | ||
2586 | |||
2584 | ieee80211_process_measurement_req(sdata, mgmt, len); | 2587 | ieee80211_process_measurement_req(sdata, mgmt, len); |
2585 | goto handled; | 2588 | goto handled; |
2586 | case WLAN_ACTION_SPCT_CHL_SWITCH: | 2589 | case WLAN_ACTION_SPCT_CHL_SWITCH: { |
2587 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 2590 | u8 *bssid; |
2591 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
2592 | sizeof(mgmt->u.action.u.chan_switch))) | ||
2593 | break; | ||
2594 | |||
2595 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
2596 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
2588 | break; | 2597 | break; |
2589 | 2598 | ||
2590 | if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) | 2599 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
2600 | bssid = sdata->u.mgd.bssid; | ||
2601 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
2602 | bssid = sdata->u.ibss.bssid; | ||
2603 | else | ||
2604 | break; | ||
2605 | |||
2606 | if (!ether_addr_equal(mgmt->bssid, bssid)) | ||
2591 | break; | 2607 | break; |
2592 | 2608 | ||
2593 | goto queue; | 2609 | goto queue; |
2610 | } | ||
2594 | } | 2611 | } |
2595 | break; | 2612 | break; |
2596 | case WLAN_CATEGORY_SA_QUERY: | 2613 | case WLAN_CATEGORY_SA_QUERY: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 08afe74b98f4..ecb57b0bf74a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -391,8 +391,7 @@ static bool ieee80211_can_scan(struct ieee80211_local *local, | |||
391 | return false; | 391 | return false; |
392 | 392 | ||
393 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 393 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
394 | sdata->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | 394 | sdata->u.mgd.flags & IEEE80211_STA_CONNECTION_POLL) |
395 | IEEE80211_STA_CONNECTION_POLL)) | ||
396 | return false; | 395 | return false; |
397 | 396 | ||
398 | return true; | 397 | return true; |
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 578eea3fc04d..921597e279a3 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
@@ -21,6 +21,168 @@ | |||
21 | #include "sta_info.h" | 21 | #include "sta_info.h" |
22 | #include "wme.h" | 22 | #include "wme.h" |
23 | 23 | ||
24 | int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, | ||
25 | struct ieee802_11_elems *elems, bool beacon, | ||
26 | enum ieee80211_band current_band, | ||
27 | u32 sta_flags, u8 *bssid, u8 *count, u8 *mode, | ||
28 | struct cfg80211_chan_def *new_chandef) | ||
29 | { | ||
30 | enum ieee80211_band new_band; | ||
31 | int new_freq; | ||
32 | u8 new_chan_no; | ||
33 | struct ieee80211_channel *new_chan; | ||
34 | struct cfg80211_chan_def new_vht_chandef = {}; | ||
35 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | ||
36 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | ||
37 | const struct ieee80211_ht_operation *ht_oper; | ||
38 | int secondary_channel_offset = -1; | ||
39 | |||
40 | sec_chan_offs = elems->sec_chan_offs; | ||
41 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; | ||
42 | ht_oper = elems->ht_operation; | ||
43 | |||
44 | if (sta_flags & (IEEE80211_STA_DISABLE_HT | | ||
45 | IEEE80211_STA_DISABLE_40MHZ)) { | ||
46 | sec_chan_offs = NULL; | ||
47 | wide_bw_chansw_ie = NULL; | ||
48 | /* only used for bandwidth here */ | ||
49 | ht_oper = NULL; | ||
50 | } | ||
51 | |||
52 | if (sta_flags & IEEE80211_STA_DISABLE_VHT) | ||
53 | wide_bw_chansw_ie = NULL; | ||
54 | |||
55 | if (elems->ext_chansw_ie) { | ||
56 | if (!ieee80211_operating_class_to_band( | ||
57 | elems->ext_chansw_ie->new_operating_class, | ||
58 | &new_band)) { | ||
59 | sdata_info(sdata, | ||
60 | "cannot understand ECSA IE operating class %d, disconnecting\n", | ||
61 | elems->ext_chansw_ie->new_operating_class); | ||
62 | return -EINVAL; | ||
63 | } | ||
64 | new_chan_no = elems->ext_chansw_ie->new_ch_num; | ||
65 | *count = elems->ext_chansw_ie->count; | ||
66 | *mode = elems->ext_chansw_ie->mode; | ||
67 | } else if (elems->ch_switch_ie) { | ||
68 | new_band = current_band; | ||
69 | new_chan_no = elems->ch_switch_ie->new_ch_num; | ||
70 | *count = elems->ch_switch_ie->count; | ||
71 | *mode = elems->ch_switch_ie->mode; | ||
72 | } else { | ||
73 | /* nothing here we understand */ | ||
74 | return 1; | ||
75 | } | ||
76 | |||
77 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); | ||
78 | new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
79 | if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) { | ||
80 | sdata_info(sdata, | ||
81 | "BSS %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
82 | bssid, new_freq); | ||
83 | return -EINVAL; | ||
84 | } | ||
85 | |||
86 | if (!beacon && sec_chan_offs) { | ||
87 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; | ||
88 | } else if (beacon && ht_oper) { | ||
89 | secondary_channel_offset = | ||
90 | ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
91 | } else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) { | ||
92 | /* If it's not a beacon, HT is enabled and the IE not present, | ||
93 | * it's 20 MHz, 802.11-2012 8.5.2.6: | ||
94 | * This element [the Secondary Channel Offset Element] is | ||
95 | * present when switching to a 40 MHz channel. It may be | ||
96 | * present when switching to a 20 MHz channel (in which | ||
97 | * case the secondary channel offset is set to SCN). | ||
98 | */ | ||
99 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
100 | } | ||
101 | |||
102 | switch (secondary_channel_offset) { | ||
103 | default: | ||
104 | /* secondary_channel_offset was present but is invalid */ | ||
105 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
106 | cfg80211_chandef_create(new_chandef, new_chan, | ||
107 | NL80211_CHAN_HT20); | ||
108 | break; | ||
109 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
110 | cfg80211_chandef_create(new_chandef, new_chan, | ||
111 | NL80211_CHAN_HT40PLUS); | ||
112 | break; | ||
113 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
114 | cfg80211_chandef_create(new_chandef, new_chan, | ||
115 | NL80211_CHAN_HT40MINUS); | ||
116 | break; | ||
117 | case -1: | ||
118 | cfg80211_chandef_create(new_chandef, new_chan, | ||
119 | NL80211_CHAN_NO_HT); | ||
120 | /* keep width for 5/10 MHz channels */ | ||
121 | switch (sdata->vif.bss_conf.chandef.width) { | ||
122 | case NL80211_CHAN_WIDTH_5: | ||
123 | case NL80211_CHAN_WIDTH_10: | ||
124 | new_chandef->width = sdata->vif.bss_conf.chandef.width; | ||
125 | break; | ||
126 | default: | ||
127 | break; | ||
128 | } | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | if (wide_bw_chansw_ie) { | ||
133 | new_vht_chandef.chan = new_chan; | ||
134 | new_vht_chandef.center_freq1 = | ||
135 | ieee80211_channel_to_frequency( | ||
136 | wide_bw_chansw_ie->new_center_freq_seg0, | ||
137 | new_band); | ||
138 | |||
139 | switch (wide_bw_chansw_ie->new_channel_width) { | ||
140 | default: | ||
141 | /* hmmm, ignore VHT and use HT if present */ | ||
142 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
143 | new_vht_chandef.chan = NULL; | ||
144 | break; | ||
145 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
146 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
147 | break; | ||
148 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
149 | new_vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
150 | break; | ||
151 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
152 | /* field is otherwise reserved */ | ||
153 | new_vht_chandef.center_freq2 = | ||
154 | ieee80211_channel_to_frequency( | ||
155 | wide_bw_chansw_ie->new_center_freq_seg1, | ||
156 | new_band); | ||
157 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
158 | break; | ||
159 | } | ||
160 | if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ && | ||
161 | new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80) | ||
162 | ieee80211_chandef_downgrade(&new_vht_chandef); | ||
163 | if (sta_flags & IEEE80211_STA_DISABLE_160MHZ && | ||
164 | new_vht_chandef.width == NL80211_CHAN_WIDTH_160) | ||
165 | ieee80211_chandef_downgrade(&new_vht_chandef); | ||
166 | if (sta_flags & IEEE80211_STA_DISABLE_40MHZ && | ||
167 | new_vht_chandef.width > NL80211_CHAN_WIDTH_20) | ||
168 | ieee80211_chandef_downgrade(&new_vht_chandef); | ||
169 | } | ||
170 | |||
171 | /* if VHT data is there validate & use it */ | ||
172 | if (new_vht_chandef.chan) { | ||
173 | if (!cfg80211_chandef_compatible(&new_vht_chandef, | ||
174 | new_chandef)) { | ||
175 | sdata_info(sdata, | ||
176 | "BSS %pM: CSA has inconsistent channel data, disconnecting\n", | ||
177 | bssid); | ||
178 | return -EINVAL; | ||
179 | } | ||
180 | *new_chandef = new_vht_chandef; | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
24 | static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata, | 186 | static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata, |
25 | struct ieee80211_msrment_ie *request_ie, | 187 | struct ieee80211_msrment_ie *request_ie, |
26 | const u8 *da, const u8 *bssid, | 188 | const u8 *da, const u8 *bssid, |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 3fb9dd6d02fc..d4cee98533fd 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1475,6 +1475,41 @@ DEFINE_EVENT(local_sdata_evt, drv_ipv6_addr_change, | |||
1475 | ); | 1475 | ); |
1476 | #endif | 1476 | #endif |
1477 | 1477 | ||
1478 | TRACE_EVENT(drv_join_ibss, | ||
1479 | TP_PROTO(struct ieee80211_local *local, | ||
1480 | struct ieee80211_sub_if_data *sdata, | ||
1481 | struct ieee80211_bss_conf *info), | ||
1482 | |||
1483 | TP_ARGS(local, sdata, info), | ||
1484 | |||
1485 | TP_STRUCT__entry( | ||
1486 | LOCAL_ENTRY | ||
1487 | VIF_ENTRY | ||
1488 | __field(u8, dtimper) | ||
1489 | __field(u16, bcnint) | ||
1490 | __dynamic_array(u8, ssid, info->ssid_len); | ||
1491 | ), | ||
1492 | |||
1493 | TP_fast_assign( | ||
1494 | LOCAL_ASSIGN; | ||
1495 | VIF_ASSIGN; | ||
1496 | __entry->dtimper = info->dtim_period; | ||
1497 | __entry->bcnint = info->beacon_int; | ||
1498 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); | ||
1499 | ), | ||
1500 | |||
1501 | TP_printk( | ||
1502 | LOCAL_PR_FMT VIF_PR_FMT, | ||
1503 | LOCAL_PR_ARG, VIF_PR_ARG | ||
1504 | ) | ||
1505 | ); | ||
1506 | |||
1507 | DEFINE_EVENT(local_sdata_evt, drv_leave_ibss, | ||
1508 | TP_PROTO(struct ieee80211_local *local, | ||
1509 | struct ieee80211_sub_if_data *sdata), | ||
1510 | TP_ARGS(local, sdata) | ||
1511 | ); | ||
1512 | |||
1478 | /* | 1513 | /* |
1479 | * Tracing for API calls that drivers call. | 1514 | * Tracing for API calls that drivers call. |
1480 | */ | 1515 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3456c0486b48..4fcbf634b548 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1981,7 +1981,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1981 | * EAPOL frames from the local station. | 1981 | * EAPOL frames from the local station. |
1982 | */ | 1982 | */ |
1983 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && | 1983 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && |
1984 | !is_multicast_ether_addr(hdr.addr1) && !authorized && | 1984 | !multicast && !authorized && |
1985 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || | 1985 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || |
1986 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { | 1986 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { |
1987 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1987 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -2357,15 +2357,31 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, | |||
2357 | struct probe_resp *resp; | 2357 | struct probe_resp *resp; |
2358 | int counter_offset_beacon = sdata->csa_counter_offset_beacon; | 2358 | int counter_offset_beacon = sdata->csa_counter_offset_beacon; |
2359 | int counter_offset_presp = sdata->csa_counter_offset_presp; | 2359 | int counter_offset_presp = sdata->csa_counter_offset_presp; |
2360 | u8 *beacon_data; | ||
2361 | size_t beacon_data_len; | ||
2362 | |||
2363 | switch (sdata->vif.type) { | ||
2364 | case NL80211_IFTYPE_AP: | ||
2365 | beacon_data = beacon->tail; | ||
2366 | beacon_data_len = beacon->tail_len; | ||
2367 | break; | ||
2368 | case NL80211_IFTYPE_ADHOC: | ||
2369 | beacon_data = beacon->head; | ||
2370 | beacon_data_len = beacon->head_len; | ||
2371 | break; | ||
2372 | default: | ||
2373 | return; | ||
2374 | } | ||
2375 | if (WARN_ON(counter_offset_beacon >= beacon_data_len)) | ||
2376 | return; | ||
2360 | 2377 | ||
2361 | /* warn if the driver did not check for/react to csa completeness */ | 2378 | /* warn if the driver did not check for/react to csa completeness */ |
2362 | if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0)) | 2379 | if (WARN_ON(beacon_data[counter_offset_beacon] == 0)) |
2363 | return; | 2380 | return; |
2364 | 2381 | ||
2365 | ((u8 *)beacon->tail)[counter_offset_beacon]--; | 2382 | beacon_data[counter_offset_beacon]--; |
2366 | 2383 | ||
2367 | if (sdata->vif.type == NL80211_IFTYPE_AP && | 2384 | if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) { |
2368 | counter_offset_presp) { | ||
2369 | rcu_read_lock(); | 2385 | rcu_read_lock(); |
2370 | resp = rcu_dereference(sdata->u.ap.probe_resp); | 2386 | resp = rcu_dereference(sdata->u.ap.probe_resp); |
2371 | 2387 | ||
@@ -2400,6 +2416,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
2400 | goto out; | 2416 | goto out; |
2401 | beacon_data = beacon->tail; | 2417 | beacon_data = beacon->tail; |
2402 | beacon_data_len = beacon->tail_len; | 2418 | beacon_data_len = beacon->tail_len; |
2419 | } else if (vif->type == NL80211_IFTYPE_ADHOC) { | ||
2420 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
2421 | |||
2422 | beacon = rcu_dereference(ifibss->presp); | ||
2423 | if (!beacon) | ||
2424 | goto out; | ||
2425 | |||
2426 | beacon_data = beacon->head; | ||
2427 | beacon_data_len = beacon->head_len; | ||
2403 | } else { | 2428 | } else { |
2404 | WARN_ON(1); | 2429 | WARN_ON(1); |
2405 | goto out; | 2430 | goto out; |
@@ -2484,6 +2509,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2484 | if (!presp) | 2509 | if (!presp) |
2485 | goto out; | 2510 | goto out; |
2486 | 2511 | ||
2512 | if (sdata->vif.csa_active) | ||
2513 | ieee80211_update_csa(sdata, presp); | ||
2514 | |||
2515 | |||
2487 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len); | 2516 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len); |
2488 | if (!skb) | 2517 | if (!skb) |
2489 | goto out; | 2518 | goto out; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9c3200bcfc02..1220f5afdb7e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -567,18 +567,15 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
567 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 567 | IEEE80211_QUEUE_STOP_REASON_FLUSH); |
568 | } | 568 | } |
569 | 569 | ||
570 | void ieee80211_iterate_active_interfaces( | 570 | static void __iterate_active_interfaces(struct ieee80211_local *local, |
571 | struct ieee80211_hw *hw, u32 iter_flags, | 571 | u32 iter_flags, |
572 | void (*iterator)(void *data, u8 *mac, | 572 | void (*iterator)(void *data, u8 *mac, |
573 | struct ieee80211_vif *vif), | 573 | struct ieee80211_vif *vif), |
574 | void *data) | 574 | void *data) |
575 | { | 575 | { |
576 | struct ieee80211_local *local = hw_to_local(hw); | ||
577 | struct ieee80211_sub_if_data *sdata; | 576 | struct ieee80211_sub_if_data *sdata; |
578 | 577 | ||
579 | mutex_lock(&local->iflist_mtx); | 578 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
580 | |||
581 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
582 | switch (sdata->vif.type) { | 579 | switch (sdata->vif.type) { |
583 | case NL80211_IFTYPE_MONITOR: | 580 | case NL80211_IFTYPE_MONITOR: |
584 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | 581 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) |
@@ -597,13 +594,25 @@ void ieee80211_iterate_active_interfaces( | |||
597 | &sdata->vif); | 594 | &sdata->vif); |
598 | } | 595 | } |
599 | 596 | ||
600 | sdata = rcu_dereference_protected(local->monitor_sdata, | 597 | sdata = rcu_dereference_check(local->monitor_sdata, |
601 | lockdep_is_held(&local->iflist_mtx)); | 598 | lockdep_is_held(&local->iflist_mtx) || |
599 | lockdep_rtnl_is_held()); | ||
602 | if (sdata && | 600 | if (sdata && |
603 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | 601 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || |
604 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | 602 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) |
605 | iterator(data, sdata->vif.addr, &sdata->vif); | 603 | iterator(data, sdata->vif.addr, &sdata->vif); |
604 | } | ||
605 | |||
606 | void ieee80211_iterate_active_interfaces( | ||
607 | struct ieee80211_hw *hw, u32 iter_flags, | ||
608 | void (*iterator)(void *data, u8 *mac, | ||
609 | struct ieee80211_vif *vif), | ||
610 | void *data) | ||
611 | { | ||
612 | struct ieee80211_local *local = hw_to_local(hw); | ||
606 | 613 | ||
614 | mutex_lock(&local->iflist_mtx); | ||
615 | __iterate_active_interfaces(local, iter_flags, iterator, data); | ||
607 | mutex_unlock(&local->iflist_mtx); | 616 | mutex_unlock(&local->iflist_mtx); |
608 | } | 617 | } |
609 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 618 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
@@ -615,38 +624,26 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
615 | void *data) | 624 | void *data) |
616 | { | 625 | { |
617 | struct ieee80211_local *local = hw_to_local(hw); | 626 | struct ieee80211_local *local = hw_to_local(hw); |
618 | struct ieee80211_sub_if_data *sdata; | ||
619 | 627 | ||
620 | rcu_read_lock(); | 628 | rcu_read_lock(); |
629 | __iterate_active_interfaces(local, iter_flags, iterator, data); | ||
630 | rcu_read_unlock(); | ||
631 | } | ||
632 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | ||
621 | 633 | ||
622 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 634 | void ieee80211_iterate_active_interfaces_rtnl( |
623 | switch (sdata->vif.type) { | 635 | struct ieee80211_hw *hw, u32 iter_flags, |
624 | case NL80211_IFTYPE_MONITOR: | 636 | void (*iterator)(void *data, u8 *mac, |
625 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | 637 | struct ieee80211_vif *vif), |
626 | continue; | 638 | void *data) |
627 | break; | 639 | { |
628 | case NL80211_IFTYPE_AP_VLAN: | 640 | struct ieee80211_local *local = hw_to_local(hw); |
629 | continue; | ||
630 | default: | ||
631 | break; | ||
632 | } | ||
633 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | ||
634 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
635 | continue; | ||
636 | if (ieee80211_sdata_running(sdata)) | ||
637 | iterator(data, sdata->vif.addr, | ||
638 | &sdata->vif); | ||
639 | } | ||
640 | 641 | ||
641 | sdata = rcu_dereference(local->monitor_sdata); | 642 | ASSERT_RTNL(); |
642 | if (sdata && | ||
643 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | ||
644 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
645 | iterator(data, sdata->vif.addr, &sdata->vif); | ||
646 | 643 | ||
647 | rcu_read_unlock(); | 644 | __iterate_active_interfaces(local, iter_flags, iterator, data); |
648 | } | 645 | } |
649 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | 646 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); |
650 | 647 | ||
651 | /* | 648 | /* |
652 | * Nothing should have been stuffed into the workqueue during | 649 | * Nothing should have been stuffed into the workqueue during |
@@ -1007,14 +1004,21 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1007 | */ | 1004 | */ |
1008 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); | 1005 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); |
1009 | 1006 | ||
1010 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 1007 | /* Set defaults according to 802.11-2007 Table 7-37 */ |
1011 | /* Set defaults according to 802.11-2007 Table 7-37 */ | 1008 | aCWmax = 1023; |
1012 | aCWmax = 1023; | 1009 | if (use_11b) |
1013 | if (use_11b) | 1010 | aCWmin = 31; |
1014 | aCWmin = 31; | 1011 | else |
1015 | else | 1012 | aCWmin = 15; |
1016 | aCWmin = 15; | 1013 | |
1014 | /* Confiure old 802.11b/g medium access rules. */ | ||
1015 | qparam.cw_max = aCWmax; | ||
1016 | qparam.cw_min = aCWmin; | ||
1017 | qparam.txop = 0; | ||
1018 | qparam.aifs = 2; | ||
1017 | 1019 | ||
1020 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
1021 | /* Update if QoS is enabled. */ | ||
1018 | if (enable_qos) { | 1022 | if (enable_qos) { |
1019 | switch (ac) { | 1023 | switch (ac) { |
1020 | case IEEE80211_AC_BK: | 1024 | case IEEE80211_AC_BK: |
@@ -1050,12 +1054,6 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1050 | qparam.aifs = 2; | 1054 | qparam.aifs = 2; |
1051 | break; | 1055 | break; |
1052 | } | 1056 | } |
1053 | } else { | ||
1054 | /* Confiure old 802.11b/g medium access rules. */ | ||
1055 | qparam.cw_max = aCWmax; | ||
1056 | qparam.cw_min = aCWmin; | ||
1057 | qparam.txop = 0; | ||
1058 | qparam.aifs = 2; | ||
1059 | } | 1057 | } |
1060 | 1058 | ||
1061 | qparam.uapsd = false; | 1059 | qparam.uapsd = false; |
@@ -1084,8 +1082,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
1084 | struct ieee80211_mgmt *mgmt; | 1082 | struct ieee80211_mgmt *mgmt; |
1085 | int err; | 1083 | int err; |
1086 | 1084 | ||
1087 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 1085 | /* 24 + 6 = header + auth_algo + auth_transaction + status_code */ |
1088 | sizeof(*mgmt) + 6 + extra_len); | 1086 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 6 + extra_len); |
1089 | if (!skb) | 1087 | if (!skb) |
1090 | return; | 1088 | return; |
1091 | 1089 | ||
@@ -2292,3 +2290,63 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw) | |||
2292 | ieee80211_queue_work(hw, &local->radar_detected_work); | 2290 | ieee80211_queue_work(hw, &local->radar_detected_work); |
2293 | } | 2291 | } |
2294 | EXPORT_SYMBOL(ieee80211_radar_detected); | 2292 | EXPORT_SYMBOL(ieee80211_radar_detected); |
2293 | |||
2294 | u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c) | ||
2295 | { | ||
2296 | u32 ret; | ||
2297 | int tmp; | ||
2298 | |||
2299 | switch (c->width) { | ||
2300 | case NL80211_CHAN_WIDTH_20: | ||
2301 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
2302 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
2303 | break; | ||
2304 | case NL80211_CHAN_WIDTH_40: | ||
2305 | c->width = NL80211_CHAN_WIDTH_20; | ||
2306 | c->center_freq1 = c->chan->center_freq; | ||
2307 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
2308 | IEEE80211_STA_DISABLE_VHT; | ||
2309 | break; | ||
2310 | case NL80211_CHAN_WIDTH_80: | ||
2311 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
2312 | /* n_P40 */ | ||
2313 | tmp /= 2; | ||
2314 | /* freq_P40 */ | ||
2315 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
2316 | c->width = NL80211_CHAN_WIDTH_40; | ||
2317 | ret = IEEE80211_STA_DISABLE_VHT; | ||
2318 | break; | ||
2319 | case NL80211_CHAN_WIDTH_80P80: | ||
2320 | c->center_freq2 = 0; | ||
2321 | c->width = NL80211_CHAN_WIDTH_80; | ||
2322 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
2323 | IEEE80211_STA_DISABLE_160MHZ; | ||
2324 | break; | ||
2325 | case NL80211_CHAN_WIDTH_160: | ||
2326 | /* n_P20 */ | ||
2327 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
2328 | /* n_P80 */ | ||
2329 | tmp /= 4; | ||
2330 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
2331 | c->width = NL80211_CHAN_WIDTH_80; | ||
2332 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
2333 | IEEE80211_STA_DISABLE_160MHZ; | ||
2334 | break; | ||
2335 | default: | ||
2336 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
2337 | WARN_ON_ONCE(1); | ||
2338 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
2339 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
2340 | break; | ||
2341 | case NL80211_CHAN_WIDTH_5: | ||
2342 | case NL80211_CHAN_WIDTH_10: | ||
2343 | WARN_ON_ONCE(1); | ||
2344 | /* keep c->width */ | ||
2345 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
2346 | break; | ||
2347 | } | ||
2348 | |||
2349 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
2350 | |||
2351 | return ret; | ||
2352 | } | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 97c289414e32..de0112785aae 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -185,13 +185,13 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { | 185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { |
186 | vht_cap->cap |= cap_info & | 186 | vht_cap->cap |= cap_info & |
187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | 187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | |
188 | IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX | | ||
189 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); | 188 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); |
190 | } | 189 | } |
191 | 190 | ||
192 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) | 191 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) |
193 | vht_cap->cap |= cap_info & | 192 | vht_cap->cap |= cap_info & |
194 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; | 193 | (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | |
194 | IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX); | ||
195 | 195 | ||
196 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) | 196 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) |
197 | vht_cap->cap |= cap_info & | 197 | vht_cap->cap |= cap_info & |