diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-04-30 12:04:27 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-04-30 12:04:27 -0400 |
commit | f6595444c1ee798f9c227107bb3ab14730c6497a (patch) | |
tree | e8e06d7c2057c69e19848ee3abd6720927f5f9f9 /net/mac80211 | |
parent | 0006433a5be9e0e155ad493e33c6e9bf3868a87f (diff) | |
parent | f55ee0834247c88cb6981cb11eb1870392878371 (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Conflicts:
net/mac80211/chan.c
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/aes_ccm.c | 37 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 53 | ||||
-rw-r--r-- | net/mac80211/chan.c | 614 | ||||
-rw-r--r-- | net/mac80211/debugfs.c | 2 | ||||
-rw-r--r-- | net/mac80211/debugfs.h | 2 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.h | 2 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 8 | ||||
-rw-r--r-- | net/mac80211/ht.c | 22 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 75 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 33 | ||||
-rw-r--r-- | net/mac80211/iface.c | 36 | ||||
-rw-r--r-- | net/mac80211/main.c | 8 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 36 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 5 | ||||
-rw-r--r-- | net/mac80211/michael.h | 1 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 4 | ||||
-rw-r--r-- | net/mac80211/rx.c | 19 | ||||
-rw-r--r-- | net/mac80211/scan.c | 10 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 3 | ||||
-rw-r--r-- | net/mac80211/util.c | 145 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 5 |
21 files changed, 874 insertions, 246 deletions
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 7c7df475a401..ec24378caaaf 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c | |||
@@ -23,12 +23,13 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | |||
23 | u8 *data, size_t data_len, u8 *mic) | 23 | u8 *data, size_t data_len, u8 *mic) |
24 | { | 24 | { |
25 | struct scatterlist assoc, pt, ct[2]; | 25 | struct scatterlist assoc, pt, ct[2]; |
26 | struct { | ||
27 | struct aead_request req; | ||
28 | u8 priv[crypto_aead_reqsize(tfm)]; | ||
29 | } aead_req; | ||
30 | 26 | ||
31 | memset(&aead_req, 0, sizeof(aead_req)); | 27 | char aead_req_data[sizeof(struct aead_request) + |
28 | crypto_aead_reqsize(tfm)] | ||
29 | __aligned(__alignof__(struct aead_request)); | ||
30 | struct aead_request *aead_req = (void *) aead_req_data; | ||
31 | |||
32 | memset(aead_req, 0, sizeof(aead_req_data)); | ||
32 | 33 | ||
33 | sg_init_one(&pt, data, data_len); | 34 | sg_init_one(&pt, data, data_len); |
34 | sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); | 35 | sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); |
@@ -36,23 +37,23 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | |||
36 | sg_set_buf(&ct[0], data, data_len); | 37 | sg_set_buf(&ct[0], data, data_len); |
37 | sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); | 38 | sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); |
38 | 39 | ||
39 | aead_request_set_tfm(&aead_req.req, tfm); | 40 | aead_request_set_tfm(aead_req, tfm); |
40 | aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); | 41 | aead_request_set_assoc(aead_req, &assoc, assoc.length); |
41 | aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0); | 42 | aead_request_set_crypt(aead_req, &pt, ct, data_len, b_0); |
42 | 43 | ||
43 | crypto_aead_encrypt(&aead_req.req); | 44 | crypto_aead_encrypt(aead_req); |
44 | } | 45 | } |
45 | 46 | ||
46 | int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | 47 | int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, |
47 | u8 *data, size_t data_len, u8 *mic) | 48 | u8 *data, size_t data_len, u8 *mic) |
48 | { | 49 | { |
49 | struct scatterlist assoc, pt, ct[2]; | 50 | struct scatterlist assoc, pt, ct[2]; |
50 | struct { | 51 | char aead_req_data[sizeof(struct aead_request) + |
51 | struct aead_request req; | 52 | crypto_aead_reqsize(tfm)] |
52 | u8 priv[crypto_aead_reqsize(tfm)]; | 53 | __aligned(__alignof__(struct aead_request)); |
53 | } aead_req; | 54 | struct aead_request *aead_req = (void *) aead_req_data; |
54 | 55 | ||
55 | memset(&aead_req, 0, sizeof(aead_req)); | 56 | memset(aead_req, 0, sizeof(aead_req_data)); |
56 | 57 | ||
57 | sg_init_one(&pt, data, data_len); | 58 | sg_init_one(&pt, data, data_len); |
58 | sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); | 59 | sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); |
@@ -60,12 +61,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | |||
60 | sg_set_buf(&ct[0], data, data_len); | 61 | sg_set_buf(&ct[0], data, data_len); |
61 | sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); | 62 | sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); |
62 | 63 | ||
63 | aead_request_set_tfm(&aead_req.req, tfm); | 64 | aead_request_set_tfm(aead_req, tfm); |
64 | aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); | 65 | aead_request_set_assoc(aead_req, &assoc, assoc.length); |
65 | aead_request_set_crypt(&aead_req.req, ct, &pt, | 66 | aead_request_set_crypt(aead_req, ct, &pt, |
66 | data_len + IEEE80211_CCMP_MIC_LEN, b_0); | 67 | data_len + IEEE80211_CCMP_MIC_LEN, b_0); |
67 | 68 | ||
68 | return crypto_aead_decrypt(&aead_req.req); | 69 | return crypto_aead_decrypt(aead_req); |
69 | } | 70 | } |
70 | 71 | ||
71 | struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]) | 72 | struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]) |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index aaa59d719592..7b8d3cf89574 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -109,6 +109,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
109 | static int ieee80211_start_p2p_device(struct wiphy *wiphy, | 109 | static int ieee80211_start_p2p_device(struct wiphy *wiphy, |
110 | struct wireless_dev *wdev) | 110 | struct wireless_dev *wdev) |
111 | { | 111 | { |
112 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
113 | int ret; | ||
114 | |||
115 | mutex_lock(&sdata->local->chanctx_mtx); | ||
116 | ret = ieee80211_check_combinations(sdata, NULL, 0, 0); | ||
117 | mutex_unlock(&sdata->local->chanctx_mtx); | ||
118 | if (ret < 0) | ||
119 | return ret; | ||
120 | |||
112 | return ieee80211_do_open(wdev, true); | 121 | return ieee80211_do_open(wdev, true); |
113 | } | 122 | } |
114 | 123 | ||
@@ -972,13 +981,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
972 | sdata->needed_rx_chains = sdata->local->rx_chains; | 981 | sdata->needed_rx_chains = sdata->local->rx_chains; |
973 | 982 | ||
974 | mutex_lock(&local->mtx); | 983 | mutex_lock(&local->mtx); |
975 | sdata->radar_required = params->radar_required; | ||
976 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, | 984 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, |
977 | IEEE80211_CHANCTX_SHARED); | 985 | IEEE80211_CHANCTX_SHARED); |
986 | if (!err) | ||
987 | ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | ||
978 | mutex_unlock(&local->mtx); | 988 | mutex_unlock(&local->mtx); |
979 | if (err) | 989 | if (err) |
980 | return err; | 990 | return err; |
981 | ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | ||
982 | 991 | ||
983 | /* | 992 | /* |
984 | * Apply control port protocol, this allows us to | 993 | * Apply control port protocol, this allows us to |
@@ -1131,8 +1140,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1131 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); | 1140 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); |
1132 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | 1141 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); |
1133 | 1142 | ||
1134 | ieee80211_vif_copy_chanctx_to_vlans(sdata, true); | ||
1135 | mutex_lock(&local->mtx); | 1143 | mutex_lock(&local->mtx); |
1144 | ieee80211_vif_copy_chanctx_to_vlans(sdata, true); | ||
1136 | ieee80211_vif_release_channel(sdata); | 1145 | ieee80211_vif_release_channel(sdata); |
1137 | mutex_unlock(&local->mtx); | 1146 | mutex_unlock(&local->mtx); |
1138 | 1147 | ||
@@ -1566,7 +1575,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
1566 | 1575 | ||
1567 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | 1576 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && |
1568 | sta->sdata->u.vlan.sta) { | 1577 | sta->sdata->u.vlan.sta) { |
1569 | rcu_assign_pointer(sta->sdata->u.vlan.sta, NULL); | 1578 | RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL); |
1570 | prev_4addr = true; | 1579 | prev_4addr = true; |
1571 | } | 1580 | } |
1572 | 1581 | ||
@@ -2930,7 +2939,6 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, | |||
2930 | /* whatever, but channel contexts should not complain about that one */ | 2939 | /* whatever, but channel contexts should not complain about that one */ |
2931 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 2940 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
2932 | sdata->needed_rx_chains = local->rx_chains; | 2941 | sdata->needed_rx_chains = local->rx_chains; |
2933 | sdata->radar_required = true; | ||
2934 | 2942 | ||
2935 | err = ieee80211_vif_use_channel(sdata, chandef, | 2943 | err = ieee80211_vif_use_channel(sdata, chandef, |
2936 | IEEE80211_CHANCTX_SHARED); | 2944 | IEEE80211_CHANCTX_SHARED); |
@@ -3217,7 +3225,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3217 | { | 3225 | { |
3218 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 3226 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
3219 | struct ieee80211_local *local = sdata->local; | 3227 | struct ieee80211_local *local = sdata->local; |
3220 | struct ieee80211_chanctx_conf *chanctx_conf; | 3228 | struct ieee80211_chanctx_conf *conf; |
3221 | struct ieee80211_chanctx *chanctx; | 3229 | struct ieee80211_chanctx *chanctx; |
3222 | int err, num_chanctx, changed = 0; | 3230 | int err, num_chanctx, changed = 0; |
3223 | 3231 | ||
@@ -3233,23 +3241,24 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3233 | &sdata->vif.bss_conf.chandef)) | 3241 | &sdata->vif.bss_conf.chandef)) |
3234 | return -EINVAL; | 3242 | return -EINVAL; |
3235 | 3243 | ||
3236 | rcu_read_lock(); | 3244 | mutex_lock(&local->chanctx_mtx); |
3237 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 3245 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
3238 | if (!chanctx_conf) { | 3246 | lockdep_is_held(&local->chanctx_mtx)); |
3239 | rcu_read_unlock(); | 3247 | if (!conf) { |
3248 | mutex_unlock(&local->chanctx_mtx); | ||
3240 | return -EBUSY; | 3249 | return -EBUSY; |
3241 | } | 3250 | } |
3242 | 3251 | ||
3243 | /* don't handle for multi-VIF cases */ | 3252 | /* don't handle for multi-VIF cases */ |
3244 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | 3253 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
3245 | if (chanctx->refcount > 1) { | 3254 | if (ieee80211_chanctx_refcount(local, chanctx) > 1) { |
3246 | rcu_read_unlock(); | 3255 | mutex_unlock(&local->chanctx_mtx); |
3247 | return -EBUSY; | 3256 | return -EBUSY; |
3248 | } | 3257 | } |
3249 | num_chanctx = 0; | 3258 | num_chanctx = 0; |
3250 | list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) | 3259 | list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) |
3251 | num_chanctx++; | 3260 | num_chanctx++; |
3252 | rcu_read_unlock(); | 3261 | mutex_unlock(&local->chanctx_mtx); |
3253 | 3262 | ||
3254 | if (num_chanctx > 1) | 3263 | if (num_chanctx > 1) |
3255 | return -EBUSY; | 3264 | return -EBUSY; |
@@ -3949,6 +3958,21 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy, | |||
3949 | return 0; | 3958 | return 0; |
3950 | } | 3959 | } |
3951 | 3960 | ||
3961 | static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, | ||
3962 | struct net_device *dev, | ||
3963 | struct cfg80211_chan_def *chandef) | ||
3964 | { | ||
3965 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3966 | int ret; | ||
3967 | u32 changed = 0; | ||
3968 | |||
3969 | ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed); | ||
3970 | if (ret == 0) | ||
3971 | ieee80211_bss_info_change_notify(sdata, changed); | ||
3972 | |||
3973 | return ret; | ||
3974 | } | ||
3975 | |||
3952 | const struct cfg80211_ops mac80211_config_ops = { | 3976 | const struct cfg80211_ops mac80211_config_ops = { |
3953 | .add_virtual_intf = ieee80211_add_iface, | 3977 | .add_virtual_intf = ieee80211_add_iface, |
3954 | .del_virtual_intf = ieee80211_del_iface, | 3978 | .del_virtual_intf = ieee80211_del_iface, |
@@ -4029,4 +4053,5 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
4029 | .start_radar_detection = ieee80211_start_radar_detection, | 4053 | .start_radar_detection = ieee80211_start_radar_detection, |
4030 | .channel_switch = ieee80211_channel_switch, | 4054 | .channel_switch = ieee80211_channel_switch, |
4031 | .set_qos_map = ieee80211_set_qos_map, | 4055 | .set_qos_map = ieee80211_set_qos_map, |
4056 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, | ||
4032 | }; | 4057 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 75b5dd2c9267..48e6d6f010cd 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -9,6 +9,170 @@ | |||
9 | #include "ieee80211_i.h" | 9 | #include "ieee80211_i.h" |
10 | #include "driver-ops.h" | 10 | #include "driver-ops.h" |
11 | 11 | ||
12 | static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local, | ||
13 | struct ieee80211_chanctx *ctx) | ||
14 | { | ||
15 | struct ieee80211_sub_if_data *sdata; | ||
16 | int num = 0; | ||
17 | |||
18 | lockdep_assert_held(&local->chanctx_mtx); | ||
19 | |||
20 | list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) | ||
21 | num++; | ||
22 | |||
23 | return num; | ||
24 | } | ||
25 | |||
26 | static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local, | ||
27 | struct ieee80211_chanctx *ctx) | ||
28 | { | ||
29 | struct ieee80211_sub_if_data *sdata; | ||
30 | int num = 0; | ||
31 | |||
32 | lockdep_assert_held(&local->chanctx_mtx); | ||
33 | |||
34 | list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) | ||
35 | num++; | ||
36 | |||
37 | return num; | ||
38 | } | ||
39 | |||
40 | int ieee80211_chanctx_refcount(struct ieee80211_local *local, | ||
41 | struct ieee80211_chanctx *ctx) | ||
42 | { | ||
43 | return ieee80211_chanctx_num_assigned(local, ctx) + | ||
44 | ieee80211_chanctx_num_reserved(local, ctx); | ||
45 | } | ||
46 | |||
47 | static int ieee80211_num_chanctx(struct ieee80211_local *local) | ||
48 | { | ||
49 | struct ieee80211_chanctx *ctx; | ||
50 | int num = 0; | ||
51 | |||
52 | lockdep_assert_held(&local->chanctx_mtx); | ||
53 | |||
54 | list_for_each_entry(ctx, &local->chanctx_list, list) | ||
55 | num++; | ||
56 | |||
57 | return num; | ||
58 | } | ||
59 | |||
60 | static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) | ||
61 | { | ||
62 | lockdep_assert_held(&local->chanctx_mtx); | ||
63 | return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); | ||
64 | } | ||
65 | |||
66 | static const struct cfg80211_chan_def * | ||
67 | ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, | ||
68 | struct ieee80211_chanctx *ctx, | ||
69 | const struct cfg80211_chan_def *compat) | ||
70 | { | ||
71 | struct ieee80211_sub_if_data *sdata; | ||
72 | |||
73 | lockdep_assert_held(&local->chanctx_mtx); | ||
74 | |||
75 | list_for_each_entry(sdata, &ctx->reserved_vifs, | ||
76 | reserved_chanctx_list) { | ||
77 | if (!compat) | ||
78 | compat = &sdata->reserved_chandef; | ||
79 | |||
80 | compat = cfg80211_chandef_compatible(&sdata->reserved_chandef, | ||
81 | compat); | ||
82 | if (!compat) | ||
83 | break; | ||
84 | } | ||
85 | |||
86 | return compat; | ||
87 | } | ||
88 | |||
89 | static const struct cfg80211_chan_def * | ||
90 | ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local, | ||
91 | struct ieee80211_chanctx *ctx, | ||
92 | const struct cfg80211_chan_def *compat) | ||
93 | { | ||
94 | struct ieee80211_sub_if_data *sdata; | ||
95 | |||
96 | lockdep_assert_held(&local->chanctx_mtx); | ||
97 | |||
98 | list_for_each_entry(sdata, &ctx->assigned_vifs, | ||
99 | assigned_chanctx_list) { | ||
100 | if (sdata->reserved_chanctx != NULL) | ||
101 | continue; | ||
102 | |||
103 | if (!compat) | ||
104 | compat = &sdata->vif.bss_conf.chandef; | ||
105 | |||
106 | compat = cfg80211_chandef_compatible( | ||
107 | &sdata->vif.bss_conf.chandef, compat); | ||
108 | if (!compat) | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | return compat; | ||
113 | } | ||
114 | |||
115 | static const struct cfg80211_chan_def * | ||
116 | ieee80211_chanctx_combined_chandef(struct ieee80211_local *local, | ||
117 | struct ieee80211_chanctx *ctx, | ||
118 | const struct cfg80211_chan_def *compat) | ||
119 | { | ||
120 | lockdep_assert_held(&local->chanctx_mtx); | ||
121 | |||
122 | compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat); | ||
123 | if (!compat) | ||
124 | return NULL; | ||
125 | |||
126 | compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat); | ||
127 | if (!compat) | ||
128 | return NULL; | ||
129 | |||
130 | return compat; | ||
131 | } | ||
132 | |||
133 | static bool | ||
134 | ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local, | ||
135 | struct ieee80211_chanctx *ctx, | ||
136 | const struct cfg80211_chan_def *def) | ||
137 | { | ||
138 | lockdep_assert_held(&local->chanctx_mtx); | ||
139 | |||
140 | if (ieee80211_chanctx_combined_chandef(local, ctx, def)) | ||
141 | return true; | ||
142 | |||
143 | if (!list_empty(&ctx->reserved_vifs) && | ||
144 | ieee80211_chanctx_reserved_chandef(local, ctx, def)) | ||
145 | return true; | ||
146 | |||
147 | return false; | ||
148 | } | ||
149 | |||
150 | static struct ieee80211_chanctx * | ||
151 | ieee80211_find_reservation_chanctx(struct ieee80211_local *local, | ||
152 | const struct cfg80211_chan_def *chandef, | ||
153 | enum ieee80211_chanctx_mode mode) | ||
154 | { | ||
155 | struct ieee80211_chanctx *ctx; | ||
156 | |||
157 | lockdep_assert_held(&local->chanctx_mtx); | ||
158 | |||
159 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) | ||
160 | return NULL; | ||
161 | |||
162 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
163 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | ||
164 | continue; | ||
165 | |||
166 | if (!ieee80211_chanctx_can_reserve_chandef(local, ctx, | ||
167 | chandef)) | ||
168 | continue; | ||
169 | |||
170 | return ctx; | ||
171 | } | ||
172 | |||
173 | return NULL; | ||
174 | } | ||
175 | |||
12 | static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) | 176 | static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) |
13 | { | 177 | { |
14 | switch (sta->bandwidth) { | 178 | switch (sta->bandwidth) { |
@@ -190,6 +354,11 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
190 | if (!compat) | 354 | if (!compat) |
191 | continue; | 355 | continue; |
192 | 356 | ||
357 | compat = ieee80211_chanctx_reserved_chandef(local, ctx, | ||
358 | compat); | ||
359 | if (!compat) | ||
360 | continue; | ||
361 | |||
193 | ieee80211_change_chanctx(local, ctx, compat); | 362 | ieee80211_change_chanctx(local, ctx, compat); |
194 | 363 | ||
195 | return ctx; | 364 | return ctx; |
@@ -217,62 +386,91 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local) | |||
217 | } | 386 | } |
218 | 387 | ||
219 | static struct ieee80211_chanctx * | 388 | static struct ieee80211_chanctx * |
220 | ieee80211_new_chanctx(struct ieee80211_local *local, | 389 | ieee80211_alloc_chanctx(struct ieee80211_local *local, |
221 | const struct cfg80211_chan_def *chandef, | 390 | const struct cfg80211_chan_def *chandef, |
222 | enum ieee80211_chanctx_mode mode) | 391 | enum ieee80211_chanctx_mode mode) |
223 | { | 392 | { |
224 | struct ieee80211_chanctx *ctx; | 393 | struct ieee80211_chanctx *ctx; |
225 | u32 changed; | ||
226 | int err; | ||
227 | 394 | ||
228 | lockdep_assert_held(&local->chanctx_mtx); | 395 | lockdep_assert_held(&local->chanctx_mtx); |
229 | 396 | ||
230 | ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); | 397 | ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); |
231 | if (!ctx) | 398 | if (!ctx) |
232 | return ERR_PTR(-ENOMEM); | 399 | return NULL; |
233 | 400 | ||
401 | INIT_LIST_HEAD(&ctx->assigned_vifs); | ||
402 | INIT_LIST_HEAD(&ctx->reserved_vifs); | ||
234 | ctx->conf.def = *chandef; | 403 | ctx->conf.def = *chandef; |
235 | ctx->conf.rx_chains_static = 1; | 404 | ctx->conf.rx_chains_static = 1; |
236 | ctx->conf.rx_chains_dynamic = 1; | 405 | ctx->conf.rx_chains_dynamic = 1; |
237 | ctx->mode = mode; | 406 | ctx->mode = mode; |
238 | ctx->conf.radar_enabled = ieee80211_is_radar_required(local); | 407 | ctx->conf.radar_enabled = ieee80211_is_radar_required(local); |
239 | ieee80211_recalc_chanctx_min_def(local, ctx); | 408 | ieee80211_recalc_chanctx_min_def(local, ctx); |
409 | |||
410 | return ctx; | ||
411 | } | ||
412 | |||
413 | static int ieee80211_add_chanctx(struct ieee80211_local *local, | ||
414 | struct ieee80211_chanctx *ctx) | ||
415 | { | ||
416 | u32 changed; | ||
417 | int err; | ||
418 | |||
419 | lockdep_assert_held(&local->mtx); | ||
420 | lockdep_assert_held(&local->chanctx_mtx); | ||
421 | |||
240 | if (!local->use_chanctx) | 422 | if (!local->use_chanctx) |
241 | local->hw.conf.radar_enabled = ctx->conf.radar_enabled; | 423 | local->hw.conf.radar_enabled = ctx->conf.radar_enabled; |
242 | 424 | ||
243 | /* we hold the mutex to prevent idle from changing */ | ||
244 | lockdep_assert_held(&local->mtx); | ||
245 | /* turn idle off *before* setting channel -- some drivers need that */ | 425 | /* turn idle off *before* setting channel -- some drivers need that */ |
246 | changed = ieee80211_idle_off(local); | 426 | changed = ieee80211_idle_off(local); |
247 | if (changed) | 427 | if (changed) |
248 | ieee80211_hw_config(local, changed); | 428 | ieee80211_hw_config(local, changed); |
249 | 429 | ||
250 | if (!local->use_chanctx) { | 430 | if (!local->use_chanctx) { |
251 | local->_oper_chandef = *chandef; | 431 | local->_oper_chandef = ctx->conf.def; |
252 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 432 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
253 | } else { | 433 | } else { |
254 | err = drv_add_chanctx(local, ctx); | 434 | err = drv_add_chanctx(local, ctx); |
255 | if (err) { | 435 | if (err) { |
256 | kfree(ctx); | ||
257 | ieee80211_recalc_idle(local); | 436 | ieee80211_recalc_idle(local); |
258 | return ERR_PTR(err); | 437 | return err; |
259 | } | 438 | } |
260 | } | 439 | } |
261 | 440 | ||
262 | /* and keep the mutex held until the new chanctx is on the list */ | 441 | return 0; |
263 | list_add_rcu(&ctx->list, &local->chanctx_list); | 442 | } |
443 | |||
444 | static struct ieee80211_chanctx * | ||
445 | ieee80211_new_chanctx(struct ieee80211_local *local, | ||
446 | const struct cfg80211_chan_def *chandef, | ||
447 | enum ieee80211_chanctx_mode mode) | ||
448 | { | ||
449 | struct ieee80211_chanctx *ctx; | ||
450 | int err; | ||
451 | |||
452 | lockdep_assert_held(&local->mtx); | ||
453 | lockdep_assert_held(&local->chanctx_mtx); | ||
264 | 454 | ||
455 | ctx = ieee80211_alloc_chanctx(local, chandef, mode); | ||
456 | if (!ctx) | ||
457 | return ERR_PTR(-ENOMEM); | ||
458 | |||
459 | err = ieee80211_add_chanctx(local, ctx); | ||
460 | if (err) { | ||
461 | kfree(ctx); | ||
462 | return ERR_PTR(err); | ||
463 | } | ||
464 | |||
465 | list_add_rcu(&ctx->list, &local->chanctx_list); | ||
265 | return ctx; | 466 | return ctx; |
266 | } | 467 | } |
267 | 468 | ||
268 | static void ieee80211_free_chanctx(struct ieee80211_local *local, | 469 | static void ieee80211_del_chanctx(struct ieee80211_local *local, |
269 | struct ieee80211_chanctx *ctx) | 470 | struct ieee80211_chanctx *ctx) |
270 | { | 471 | { |
271 | bool check_single_channel = false; | ||
272 | lockdep_assert_held(&local->chanctx_mtx); | 472 | lockdep_assert_held(&local->chanctx_mtx); |
273 | 473 | ||
274 | WARN_ON_ONCE(ctx->refcount != 0); | ||
275 | |||
276 | if (!local->use_chanctx) { | 474 | if (!local->use_chanctx) { |
277 | struct cfg80211_chan_def *chandef = &local->_oper_chandef; | 475 | struct cfg80211_chan_def *chandef = &local->_oper_chandef; |
278 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | 476 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; |
@@ -282,8 +480,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, | |||
282 | /* NOTE: Disabling radar is only valid here for | 480 | /* NOTE: Disabling radar is only valid here for |
283 | * single channel context. To be sure, check it ... | 481 | * single channel context. To be sure, check it ... |
284 | */ | 482 | */ |
285 | if (local->hw.conf.radar_enabled) | 483 | WARN_ON(local->hw.conf.radar_enabled && |
286 | check_single_channel = true; | 484 | !list_empty(&local->chanctx_list)); |
485 | |||
287 | local->hw.conf.radar_enabled = false; | 486 | local->hw.conf.radar_enabled = false; |
288 | 487 | ||
289 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 488 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
@@ -291,39 +490,19 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, | |||
291 | drv_remove_chanctx(local, ctx); | 490 | drv_remove_chanctx(local, ctx); |
292 | } | 491 | } |
293 | 492 | ||
294 | list_del_rcu(&ctx->list); | ||
295 | kfree_rcu(ctx, rcu_head); | ||
296 | |||
297 | /* throw a warning if this wasn't the only channel context. */ | ||
298 | WARN_ON(check_single_channel && !list_empty(&local->chanctx_list)); | ||
299 | |||
300 | ieee80211_recalc_idle(local); | 493 | ieee80211_recalc_idle(local); |
301 | } | 494 | } |
302 | 495 | ||
303 | static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 496 | static void ieee80211_free_chanctx(struct ieee80211_local *local, |
304 | struct ieee80211_chanctx *ctx) | 497 | struct ieee80211_chanctx *ctx) |
305 | { | 498 | { |
306 | struct ieee80211_local *local = sdata->local; | ||
307 | int ret; | ||
308 | |||
309 | lockdep_assert_held(&local->chanctx_mtx); | 499 | lockdep_assert_held(&local->chanctx_mtx); |
310 | 500 | ||
311 | ret = drv_assign_vif_chanctx(local, sdata, ctx); | 501 | WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0); |
312 | if (ret) | ||
313 | return ret; | ||
314 | |||
315 | rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); | ||
316 | ctx->refcount++; | ||
317 | |||
318 | ieee80211_recalc_txpower(sdata); | ||
319 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
320 | sdata->vif.bss_conf.idle = false; | ||
321 | 502 | ||
322 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | 503 | list_del_rcu(&ctx->list); |
323 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | 504 | ieee80211_del_chanctx(local, ctx); |
324 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | 505 | kfree_rcu(ctx, rcu_head); |
325 | |||
326 | return 0; | ||
327 | } | 506 | } |
328 | 507 | ||
329 | static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, | 508 | static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, |
@@ -384,30 +563,58 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | |||
384 | drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); | 563 | drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); |
385 | } | 564 | } |
386 | 565 | ||
387 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 566 | static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
388 | struct ieee80211_chanctx *ctx) | 567 | struct ieee80211_chanctx *new_ctx) |
389 | { | 568 | { |
390 | struct ieee80211_local *local = sdata->local; | 569 | struct ieee80211_local *local = sdata->local; |
570 | struct ieee80211_chanctx_conf *conf; | ||
571 | struct ieee80211_chanctx *curr_ctx = NULL; | ||
572 | int ret = 0; | ||
391 | 573 | ||
392 | lockdep_assert_held(&local->chanctx_mtx); | 574 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
575 | lockdep_is_held(&local->chanctx_mtx)); | ||
393 | 576 | ||
394 | ctx->refcount--; | 577 | if (conf) { |
395 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); | 578 | curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); |
396 | 579 | ||
397 | sdata->vif.bss_conf.idle = true; | 580 | drv_unassign_vif_chanctx(local, sdata, curr_ctx); |
581 | conf = NULL; | ||
582 | list_del(&sdata->assigned_chanctx_list); | ||
583 | } | ||
398 | 584 | ||
399 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | 585 | if (new_ctx) { |
400 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | 586 | ret = drv_assign_vif_chanctx(local, sdata, new_ctx); |
401 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | 587 | if (ret) |
588 | goto out; | ||
402 | 589 | ||
403 | drv_unassign_vif_chanctx(local, sdata, ctx); | 590 | conf = &new_ctx->conf; |
591 | list_add(&sdata->assigned_chanctx_list, | ||
592 | &new_ctx->assigned_vifs); | ||
593 | } | ||
404 | 594 | ||
405 | if (ctx->refcount > 0) { | 595 | out: |
406 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); | 596 | rcu_assign_pointer(sdata->vif.chanctx_conf, conf); |
407 | ieee80211_recalc_smps_chanctx(local, ctx); | 597 | |
408 | ieee80211_recalc_radar_chanctx(local, ctx); | 598 | sdata->vif.bss_conf.idle = !conf; |
409 | ieee80211_recalc_chanctx_min_def(local, ctx); | 599 | |
600 | if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) { | ||
601 | ieee80211_recalc_chanctx_chantype(local, curr_ctx); | ||
602 | ieee80211_recalc_smps_chanctx(local, curr_ctx); | ||
603 | ieee80211_recalc_radar_chanctx(local, curr_ctx); | ||
604 | ieee80211_recalc_chanctx_min_def(local, curr_ctx); | ||
410 | } | 605 | } |
606 | |||
607 | if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) { | ||
608 | ieee80211_recalc_txpower(sdata); | ||
609 | ieee80211_recalc_chanctx_min_def(local, new_ctx); | ||
610 | } | ||
611 | |||
612 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | ||
613 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
614 | ieee80211_bss_info_change_notify(sdata, | ||
615 | BSS_CHANGED_IDLE); | ||
616 | |||
617 | return ret; | ||
411 | } | 618 | } |
412 | 619 | ||
413 | static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | 620 | static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) |
@@ -425,8 +632,11 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
425 | 632 | ||
426 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 633 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
427 | 634 | ||
428 | ieee80211_unassign_vif_chanctx(sdata, ctx); | 635 | if (sdata->reserved_chanctx) |
429 | if (ctx->refcount == 0) | 636 | ieee80211_vif_unreserve_chanctx(sdata); |
637 | |||
638 | ieee80211_assign_vif_chanctx(sdata, NULL); | ||
639 | if (ieee80211_chanctx_refcount(local, ctx) == 0) | ||
430 | ieee80211_free_chanctx(local, ctx); | 640 | ieee80211_free_chanctx(local, ctx); |
431 | } | 641 | } |
432 | 642 | ||
@@ -526,6 +736,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
526 | { | 736 | { |
527 | struct ieee80211_local *local = sdata->local; | 737 | struct ieee80211_local *local = sdata->local; |
528 | struct ieee80211_chanctx *ctx; | 738 | struct ieee80211_chanctx *ctx; |
739 | u8 radar_detect_width = 0; | ||
529 | int ret; | 740 | int ret; |
530 | 741 | ||
531 | lockdep_assert_held(&local->mtx); | 742 | lockdep_assert_held(&local->mtx); |
@@ -533,6 +744,22 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
533 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); | 744 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); |
534 | 745 | ||
535 | mutex_lock(&local->chanctx_mtx); | 746 | mutex_lock(&local->chanctx_mtx); |
747 | |||
748 | ret = cfg80211_chandef_dfs_required(local->hw.wiphy, | ||
749 | chandef, | ||
750 | sdata->wdev.iftype); | ||
751 | if (ret < 0) | ||
752 | goto out; | ||
753 | if (ret > 0) | ||
754 | radar_detect_width = BIT(chandef->width); | ||
755 | |||
756 | sdata->radar_required = ret; | ||
757 | |||
758 | ret = ieee80211_check_combinations(sdata, chandef, mode, | ||
759 | radar_detect_width); | ||
760 | if (ret < 0) | ||
761 | goto out; | ||
762 | |||
536 | __ieee80211_vif_release_channel(sdata); | 763 | __ieee80211_vif_release_channel(sdata); |
537 | 764 | ||
538 | ctx = ieee80211_find_chanctx(local, chandef, mode); | 765 | ctx = ieee80211_find_chanctx(local, chandef, mode); |
@@ -548,7 +775,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
548 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); | 775 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); |
549 | if (ret) { | 776 | if (ret) { |
550 | /* if assign fails refcount stays the same */ | 777 | /* if assign fails refcount stays the same */ |
551 | if (ctx->refcount == 0) | 778 | if (ieee80211_chanctx_refcount(local, ctx) == 0) |
552 | ieee80211_free_chanctx(local, ctx); | 779 | ieee80211_free_chanctx(local, ctx); |
553 | goto out; | 780 | goto out; |
554 | } | 781 | } |
@@ -560,15 +787,47 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
560 | return ret; | 787 | return ret; |
561 | } | 788 | } |
562 | 789 | ||
790 | static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
791 | struct ieee80211_chanctx *ctx, | ||
792 | u32 *changed) | ||
793 | { | ||
794 | struct ieee80211_local *local = sdata->local; | ||
795 | const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; | ||
796 | u32 chanctx_changed = 0; | ||
797 | |||
798 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
799 | IEEE80211_CHAN_DISABLED)) | ||
800 | return -EINVAL; | ||
801 | |||
802 | if (ieee80211_chanctx_refcount(local, ctx) != 1) | ||
803 | return -EINVAL; | ||
804 | |||
805 | if (sdata->vif.bss_conf.chandef.width != chandef->width) { | ||
806 | chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; | ||
807 | *changed |= BSS_CHANGED_BANDWIDTH; | ||
808 | } | ||
809 | |||
810 | sdata->vif.bss_conf.chandef = *chandef; | ||
811 | ctx->conf.def = *chandef; | ||
812 | |||
813 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; | ||
814 | drv_change_chanctx(local, ctx, chanctx_changed); | ||
815 | |||
816 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
817 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
818 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
819 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
563 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | 824 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, |
564 | u32 *changed) | 825 | u32 *changed) |
565 | { | 826 | { |
566 | struct ieee80211_local *local = sdata->local; | 827 | struct ieee80211_local *local = sdata->local; |
567 | struct ieee80211_chanctx_conf *conf; | 828 | struct ieee80211_chanctx_conf *conf; |
568 | struct ieee80211_chanctx *ctx; | 829 | struct ieee80211_chanctx *ctx; |
569 | const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; | ||
570 | int ret; | 830 | int ret; |
571 | u32 chanctx_changed = 0; | ||
572 | 831 | ||
573 | lockdep_assert_held(&local->mtx); | 832 | lockdep_assert_held(&local->mtx); |
574 | 833 | ||
@@ -576,11 +835,94 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | |||
576 | if (WARN_ON(!sdata->vif.csa_active)) | 835 | if (WARN_ON(!sdata->vif.csa_active)) |
577 | return -EINVAL; | 836 | return -EINVAL; |
578 | 837 | ||
579 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | 838 | mutex_lock(&local->chanctx_mtx); |
580 | IEEE80211_CHAN_DISABLED)) | 839 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
840 | lockdep_is_held(&local->chanctx_mtx)); | ||
841 | if (!conf) { | ||
842 | ret = -EINVAL; | ||
843 | goto out; | ||
844 | } | ||
845 | |||
846 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
847 | |||
848 | ret = __ieee80211_vif_change_channel(sdata, ctx, changed); | ||
849 | out: | ||
850 | mutex_unlock(&local->chanctx_mtx); | ||
851 | return ret; | ||
852 | } | ||
853 | |||
854 | static void | ||
855 | __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | ||
856 | bool clear) | ||
857 | { | ||
858 | struct ieee80211_local *local = sdata->local; | ||
859 | struct ieee80211_sub_if_data *vlan; | ||
860 | struct ieee80211_chanctx_conf *conf; | ||
861 | |||
862 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) | ||
863 | return; | ||
864 | |||
865 | lockdep_assert_held(&local->mtx); | ||
866 | |||
867 | /* Check that conf exists, even when clearing this function | ||
868 | * must be called with the AP's channel context still there | ||
869 | * as it would otherwise cause VLANs to have an invalid | ||
870 | * channel context pointer for a while, possibly pointing | ||
871 | * to a channel context that has already been freed. | ||
872 | */ | ||
873 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
874 | lockdep_is_held(&local->chanctx_mtx)); | ||
875 | WARN_ON(!conf); | ||
876 | |||
877 | if (clear) | ||
878 | conf = NULL; | ||
879 | |||
880 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
881 | rcu_assign_pointer(vlan->vif.chanctx_conf, conf); | ||
882 | } | ||
883 | |||
884 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | ||
885 | bool clear) | ||
886 | { | ||
887 | struct ieee80211_local *local = sdata->local; | ||
888 | |||
889 | mutex_lock(&local->chanctx_mtx); | ||
890 | |||
891 | __ieee80211_vif_copy_chanctx_to_vlans(sdata, clear); | ||
892 | |||
893 | mutex_unlock(&local->chanctx_mtx); | ||
894 | } | ||
895 | |||
896 | int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) | ||
897 | { | ||
898 | struct ieee80211_chanctx *ctx = sdata->reserved_chanctx; | ||
899 | |||
900 | lockdep_assert_held(&sdata->local->chanctx_mtx); | ||
901 | |||
902 | if (WARN_ON(!ctx)) | ||
581 | return -EINVAL; | 903 | return -EINVAL; |
582 | 904 | ||
905 | list_del(&sdata->reserved_chanctx_list); | ||
906 | sdata->reserved_chanctx = NULL; | ||
907 | |||
908 | if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) | ||
909 | ieee80211_free_chanctx(sdata->local, ctx); | ||
910 | |||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, | ||
915 | const struct cfg80211_chan_def *chandef, | ||
916 | enum ieee80211_chanctx_mode mode, | ||
917 | bool radar_required) | ||
918 | { | ||
919 | struct ieee80211_local *local = sdata->local; | ||
920 | struct ieee80211_chanctx_conf *conf; | ||
921 | struct ieee80211_chanctx *new_ctx, *curr_ctx; | ||
922 | int ret = 0; | ||
923 | |||
583 | mutex_lock(&local->chanctx_mtx); | 924 | mutex_lock(&local->chanctx_mtx); |
925 | |||
584 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | 926 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
585 | lockdep_is_held(&local->chanctx_mtx)); | 927 | lockdep_is_held(&local->chanctx_mtx)); |
586 | if (!conf) { | 928 | if (!conf) { |
@@ -588,30 +930,108 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | |||
588 | goto out; | 930 | goto out; |
589 | } | 931 | } |
590 | 932 | ||
591 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 933 | curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); |
592 | if (ctx->refcount != 1) { | 934 | |
935 | new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); | ||
936 | if (!new_ctx) { | ||
937 | if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 && | ||
938 | (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) { | ||
939 | /* if we're the only users of the chanctx and | ||
940 | * the driver supports changing a running | ||
941 | * context, reserve our current context | ||
942 | */ | ||
943 | new_ctx = curr_ctx; | ||
944 | } else if (ieee80211_can_create_new_chanctx(local)) { | ||
945 | /* create a new context and reserve it */ | ||
946 | new_ctx = ieee80211_new_chanctx(local, chandef, mode); | ||
947 | if (IS_ERR(new_ctx)) { | ||
948 | ret = PTR_ERR(new_ctx); | ||
949 | goto out; | ||
950 | } | ||
951 | } else { | ||
952 | ret = -EBUSY; | ||
953 | goto out; | ||
954 | } | ||
955 | } | ||
956 | |||
957 | list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs); | ||
958 | sdata->reserved_chanctx = new_ctx; | ||
959 | sdata->reserved_chandef = *chandef; | ||
960 | sdata->reserved_radar_required = radar_required; | ||
961 | out: | ||
962 | mutex_unlock(&local->chanctx_mtx); | ||
963 | return ret; | ||
964 | } | ||
965 | |||
966 | int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, | ||
967 | u32 *changed) | ||
968 | { | ||
969 | struct ieee80211_local *local = sdata->local; | ||
970 | struct ieee80211_chanctx *ctx; | ||
971 | struct ieee80211_chanctx *old_ctx; | ||
972 | struct ieee80211_chanctx_conf *conf; | ||
973 | int ret; | ||
974 | u32 tmp_changed = *changed; | ||
975 | |||
976 | /* TODO: need to recheck if the chandef is usable etc.? */ | ||
977 | |||
978 | lockdep_assert_held(&local->mtx); | ||
979 | |||
980 | mutex_lock(&local->chanctx_mtx); | ||
981 | |||
982 | ctx = sdata->reserved_chanctx; | ||
983 | if (WARN_ON(!ctx)) { | ||
593 | ret = -EINVAL; | 984 | ret = -EINVAL; |
594 | goto out; | 985 | goto out; |
595 | } | 986 | } |
596 | 987 | ||
597 | if (sdata->vif.bss_conf.chandef.width != chandef->width) { | 988 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
598 | chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; | 989 | lockdep_is_held(&local->chanctx_mtx)); |
599 | *changed |= BSS_CHANGED_BANDWIDTH; | 990 | if (!conf) { |
991 | ret = -EINVAL; | ||
992 | goto out; | ||
600 | } | 993 | } |
601 | 994 | ||
602 | sdata->vif.bss_conf.chandef = *chandef; | 995 | old_ctx = container_of(conf, struct ieee80211_chanctx, conf); |
603 | ctx->conf.def = *chandef; | ||
604 | 996 | ||
605 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; | 997 | if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) |
606 | drv_change_chanctx(local, ctx, chanctx_changed); | 998 | tmp_changed |= BSS_CHANGED_BANDWIDTH; |
999 | |||
1000 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; | ||
1001 | |||
1002 | /* unref our reservation */ | ||
1003 | sdata->reserved_chanctx = NULL; | ||
1004 | sdata->radar_required = sdata->reserved_radar_required; | ||
1005 | list_del(&sdata->reserved_chanctx_list); | ||
1006 | |||
1007 | if (old_ctx == ctx) { | ||
1008 | /* This is our own context, just change it */ | ||
1009 | ret = __ieee80211_vif_change_channel(sdata, old_ctx, | ||
1010 | &tmp_changed); | ||
1011 | if (ret) | ||
1012 | goto out; | ||
1013 | } else { | ||
1014 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); | ||
1015 | if (ieee80211_chanctx_refcount(local, old_ctx) == 0) | ||
1016 | ieee80211_free_chanctx(local, old_ctx); | ||
1017 | if (ret) { | ||
1018 | /* if assign fails refcount stays the same */ | ||
1019 | if (ieee80211_chanctx_refcount(local, ctx) == 0) | ||
1020 | ieee80211_free_chanctx(local, ctx); | ||
1021 | goto out; | ||
1022 | } | ||
1023 | |||
1024 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
1025 | __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | ||
1026 | } | ||
1027 | |||
1028 | *changed = tmp_changed; | ||
607 | 1029 | ||
608 | ieee80211_recalc_chanctx_chantype(local, ctx); | 1030 | ieee80211_recalc_chanctx_chantype(local, ctx); |
609 | ieee80211_recalc_smps_chanctx(local, ctx); | 1031 | ieee80211_recalc_smps_chanctx(local, ctx); |
610 | ieee80211_recalc_radar_chanctx(local, ctx); | 1032 | ieee80211_recalc_radar_chanctx(local, ctx); |
611 | ieee80211_recalc_chanctx_min_def(local, ctx); | 1033 | ieee80211_recalc_chanctx_min_def(local, ctx); |
612 | 1034 | out: | |
613 | ret = 0; | ||
614 | out: | ||
615 | mutex_unlock(&local->chanctx_mtx); | 1035 | mutex_unlock(&local->chanctx_mtx); |
616 | return ret; | 1036 | return ret; |
617 | } | 1037 | } |
@@ -695,40 +1115,6 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) | |||
695 | mutex_unlock(&local->chanctx_mtx); | 1115 | mutex_unlock(&local->chanctx_mtx); |
696 | } | 1116 | } |
697 | 1117 | ||
698 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | ||
699 | bool clear) | ||
700 | { | ||
701 | struct ieee80211_local *local = sdata->local; | ||
702 | struct ieee80211_sub_if_data *vlan; | ||
703 | struct ieee80211_chanctx_conf *conf; | ||
704 | |||
705 | ASSERT_RTNL(); | ||
706 | |||
707 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) | ||
708 | return; | ||
709 | |||
710 | mutex_lock(&local->chanctx_mtx); | ||
711 | |||
712 | /* | ||
713 | * Check that conf exists, even when clearing this function | ||
714 | * must be called with the AP's channel context still there | ||
715 | * as it would otherwise cause VLANs to have an invalid | ||
716 | * channel context pointer for a while, possibly pointing | ||
717 | * to a channel context that has already been freed. | ||
718 | */ | ||
719 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
720 | lockdep_is_held(&local->chanctx_mtx)); | ||
721 | WARN_ON(!conf); | ||
722 | |||
723 | if (clear) | ||
724 | conf = NULL; | ||
725 | |||
726 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
727 | rcu_assign_pointer(vlan->vif.chanctx_conf, conf); | ||
728 | |||
729 | mutex_unlock(&local->chanctx_mtx); | ||
730 | } | ||
731 | |||
732 | void ieee80211_iter_chan_contexts_atomic( | 1118 | void ieee80211_iter_chan_contexts_atomic( |
733 | struct ieee80211_hw *hw, | 1119 | struct ieee80211_hw *hw, |
734 | void (*iter)(struct ieee80211_hw *hw, | 1120 | void (*iter)(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index fa16e54980a1..0e963bc1ceac 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -128,7 +128,7 @@ static ssize_t sta_tx_latency_stat_write(struct file *file, | |||
128 | if (!strcmp(buf, TX_LATENCY_DISABLED)) { | 128 | if (!strcmp(buf, TX_LATENCY_DISABLED)) { |
129 | if (!tx_latency) | 129 | if (!tx_latency) |
130 | goto unlock; | 130 | goto unlock; |
131 | rcu_assign_pointer(local->tx_latency, NULL); | 131 | RCU_INIT_POINTER(local->tx_latency, NULL); |
132 | synchronize_rcu(); | 132 | synchronize_rcu(); |
133 | kfree(tx_latency); | 133 | kfree(tx_latency); |
134 | goto unlock; | 134 | goto unlock; |
diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index 214ed4ecd739..60c35afee29d 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef __MAC80211_DEBUGFS_H | 1 | #ifndef __MAC80211_DEBUGFS_H |
2 | #define __MAC80211_DEBUGFS_H | 2 | #define __MAC80211_DEBUGFS_H |
3 | 3 | ||
4 | #include "ieee80211_i.h" | ||
5 | |||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | 6 | #ifdef CONFIG_MAC80211_DEBUGFS |
5 | void debugfs_hw_add(struct ieee80211_local *local); | 7 | void debugfs_hw_add(struct ieee80211_local *local); |
6 | int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count, | 8 | int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count, |
diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h index 79025e79f4d6..9f5501a9a795 100644 --- a/net/mac80211/debugfs_netdev.h +++ b/net/mac80211/debugfs_netdev.h | |||
@@ -3,6 +3,8 @@ | |||
3 | #ifndef __IEEE80211_DEBUGFS_NETDEV_H | 3 | #ifndef __IEEE80211_DEBUGFS_NETDEV_H |
4 | #define __IEEE80211_DEBUGFS_NETDEV_H | 4 | #define __IEEE80211_DEBUGFS_NETDEV_H |
5 | 5 | ||
6 | #include "ieee80211_i.h" | ||
7 | |||
6 | #ifdef CONFIG_MAC80211_DEBUGFS | 8 | #ifdef CONFIG_MAC80211_DEBUGFS |
7 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); | 9 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata); |
8 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); | 10 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index fc689f5d971e..5331582a2c81 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -726,13 +726,19 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local) | |||
726 | } | 726 | } |
727 | 727 | ||
728 | static inline void drv_flush(struct ieee80211_local *local, | 728 | static inline void drv_flush(struct ieee80211_local *local, |
729 | struct ieee80211_sub_if_data *sdata, | ||
729 | u32 queues, bool drop) | 730 | u32 queues, bool drop) |
730 | { | 731 | { |
732 | struct ieee80211_vif *vif = sdata ? &sdata->vif : NULL; | ||
733 | |||
731 | might_sleep(); | 734 | might_sleep(); |
732 | 735 | ||
736 | if (sdata) | ||
737 | check_sdata_in_driver(sdata); | ||
738 | |||
733 | trace_drv_flush(local, queues, drop); | 739 | trace_drv_flush(local, queues, drop); |
734 | if (local->ops->flush) | 740 | if (local->ops->flush) |
735 | local->ops->flush(&local->hw, queues, drop); | 741 | local->ops->flush(&local->hw, vif, queues, drop); |
736 | trace_drv_return_void(local); | 742 | trace_drv_return_void(local); |
737 | } | 743 | } |
738 | 744 | ||
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index c150b68436d7..15702ff64a4c 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -31,6 +31,18 @@ static void __check_htcap_disable(struct ieee80211_ht_cap *ht_capa, | |||
31 | } | 31 | } |
32 | } | 32 | } |
33 | 33 | ||
34 | static void __check_htcap_enable(struct ieee80211_ht_cap *ht_capa, | ||
35 | struct ieee80211_ht_cap *ht_capa_mask, | ||
36 | struct ieee80211_sta_ht_cap *ht_cap, | ||
37 | u16 flag) | ||
38 | { | ||
39 | __le16 le_flag = cpu_to_le16(flag); | ||
40 | |||
41 | if ((ht_capa_mask->cap_info & le_flag) && | ||
42 | (ht_capa->cap_info & le_flag)) | ||
43 | ht_cap->cap |= flag; | ||
44 | } | ||
45 | |||
34 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 46 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
35 | struct ieee80211_sta_ht_cap *ht_cap) | 47 | struct ieee80211_sta_ht_cap *ht_cap) |
36 | { | 48 | { |
@@ -59,7 +71,7 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
59 | smask = (u8 *)(&ht_capa_mask->mcs.rx_mask); | 71 | smask = (u8 *)(&ht_capa_mask->mcs.rx_mask); |
60 | 72 | ||
61 | /* NOTE: If you add more over-rides here, update register_hw | 73 | /* NOTE: If you add more over-rides here, update register_hw |
62 | * ht_capa_mod_msk logic in main.c as well. | 74 | * ht_capa_mod_mask logic in main.c as well. |
63 | * And, if this method can ever change ht_cap.ht_supported, fix | 75 | * And, if this method can ever change ht_cap.ht_supported, fix |
64 | * the check in ieee80211_add_ht_ie. | 76 | * the check in ieee80211_add_ht_ie. |
65 | */ | 77 | */ |
@@ -86,6 +98,14 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
86 | __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, | 98 | __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, |
87 | IEEE80211_HT_CAP_MAX_AMSDU); | 99 | IEEE80211_HT_CAP_MAX_AMSDU); |
88 | 100 | ||
101 | /* Allow user to disable LDPC */ | ||
102 | __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, | ||
103 | IEEE80211_HT_CAP_LDPC_CODING); | ||
104 | |||
105 | /* Allow user to enable 40 MHz intolerant bit. */ | ||
106 | __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap, | ||
107 | IEEE80211_HT_CAP_40MHZ_INTOLERANT); | ||
108 | |||
89 | /* Allow user to decrease AMPDU factor */ | 109 | /* Allow user to decrease AMPDU factor */ |
90 | if (ht_capa_mask->ampdu_params_info & | 110 | if (ht_capa_mask->ampdu_params_info & |
91 | IEEE80211_HT_AMPDU_PARM_FACTOR) { | 111 | IEEE80211_HT_AMPDU_PARM_FACTOR) { |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 06d28787945b..ff4d4155a84d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -228,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
228 | struct beacon_data *presp; | 228 | struct beacon_data *presp; |
229 | enum nl80211_bss_scan_width scan_width; | 229 | enum nl80211_bss_scan_width scan_width; |
230 | bool have_higher_than_11mbit; | 230 | bool have_higher_than_11mbit; |
231 | bool radar_required = false; | 231 | bool radar_required; |
232 | int err; | 232 | int err; |
233 | 233 | ||
234 | sdata_assert_lock(sdata); | 234 | sdata_assert_lock(sdata); |
@@ -253,7 +253,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
253 | 253 | ||
254 | presp = rcu_dereference_protected(ifibss->presp, | 254 | presp = rcu_dereference_protected(ifibss->presp, |
255 | lockdep_is_held(&sdata->wdev.mtx)); | 255 | lockdep_is_held(&sdata->wdev.mtx)); |
256 | rcu_assign_pointer(ifibss->presp, NULL); | 256 | RCU_INIT_POINTER(ifibss->presp, NULL); |
257 | if (presp) | 257 | if (presp) |
258 | kfree_rcu(presp, rcu_head); | 258 | kfree_rcu(presp, rcu_head); |
259 | 259 | ||
@@ -262,7 +262,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
262 | /* make a copy of the chandef, it could be modified below. */ | 262 | /* make a copy of the chandef, it could be modified below. */ |
263 | chandef = *req_chandef; | 263 | chandef = *req_chandef; |
264 | chan = chandef.chan; | 264 | chan = chandef.chan; |
265 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { | 265 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef, |
266 | NL80211_IFTYPE_ADHOC)) { | ||
266 | if (chandef.width == NL80211_CHAN_WIDTH_5 || | 267 | if (chandef.width == NL80211_CHAN_WIDTH_5 || |
267 | chandef.width == NL80211_CHAN_WIDTH_10 || | 268 | chandef.width == NL80211_CHAN_WIDTH_10 || |
268 | chandef.width == NL80211_CHAN_WIDTH_20_NOHT || | 269 | chandef.width == NL80211_CHAN_WIDTH_20_NOHT || |
@@ -274,7 +275,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
274 | chandef.width = NL80211_CHAN_WIDTH_20; | 275 | chandef.width = NL80211_CHAN_WIDTH_20; |
275 | chandef.center_freq1 = chan->center_freq; | 276 | chandef.center_freq1 = chan->center_freq; |
276 | /* check again for downgraded chandef */ | 277 | /* check again for downgraded chandef */ |
277 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { | 278 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef, |
279 | NL80211_IFTYPE_ADHOC)) { | ||
278 | sdata_info(sdata, | 280 | sdata_info(sdata, |
279 | "Failed to join IBSS, beacons forbidden\n"); | 281 | "Failed to join IBSS, beacons forbidden\n"); |
280 | return; | 282 | return; |
@@ -282,21 +284,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
282 | } | 284 | } |
283 | 285 | ||
284 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, | 286 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, |
285 | &chandef); | 287 | &chandef, NL80211_IFTYPE_ADHOC); |
286 | if (err < 0) { | 288 | if (err < 0) { |
287 | sdata_info(sdata, | 289 | sdata_info(sdata, |
288 | "Failed to join IBSS, invalid chandef\n"); | 290 | "Failed to join IBSS, invalid chandef\n"); |
289 | return; | 291 | return; |
290 | } | 292 | } |
291 | if (err > 0) { | 293 | if (err > 0 && !ifibss->userspace_handles_dfs) { |
292 | if (!ifibss->userspace_handles_dfs) { | 294 | sdata_info(sdata, |
293 | sdata_info(sdata, | 295 | "Failed to join IBSS, DFS channel without control program\n"); |
294 | "Failed to join IBSS, DFS channel without control program\n"); | 296 | return; |
295 | return; | ||
296 | } | ||
297 | radar_required = true; | ||
298 | } | 297 | } |
299 | 298 | ||
299 | radar_required = err; | ||
300 | |||
300 | mutex_lock(&local->mtx); | 301 | mutex_lock(&local->mtx); |
301 | if (ieee80211_vif_use_channel(sdata, &chandef, | 302 | if (ieee80211_vif_use_channel(sdata, &chandef, |
302 | ifibss->fixed_channel ? | 303 | ifibss->fixed_channel ? |
@@ -775,7 +776,8 @@ static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) | |||
775 | * unavailable. | 776 | * unavailable. |
776 | */ | 777 | */ |
777 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, | 778 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, |
778 | &ifibss->chandef); | 779 | &ifibss->chandef, |
780 | NL80211_IFTYPE_ADHOC); | ||
779 | if (err > 0) | 781 | if (err > 0) |
780 | cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef, | 782 | cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef, |
781 | GFP_ATOMIC); | 783 | GFP_ATOMIC); |
@@ -861,7 +863,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
861 | goto disconnect; | 863 | goto disconnect; |
862 | } | 864 | } |
863 | 865 | ||
864 | if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef)) { | 866 | if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef, |
867 | NL80211_IFTYPE_ADHOC)) { | ||
865 | sdata_info(sdata, | 868 | sdata_info(sdata, |
866 | "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | 869 | "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", |
867 | ifibss->bssid, | 870 | ifibss->bssid, |
@@ -873,17 +876,17 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
873 | } | 876 | } |
874 | 877 | ||
875 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, | 878 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, |
876 | ¶ms.chandef); | 879 | ¶ms.chandef, |
880 | NL80211_IFTYPE_ADHOC); | ||
877 | if (err < 0) | 881 | if (err < 0) |
878 | goto disconnect; | 882 | goto disconnect; |
879 | if (err) { | 883 | if (err > 0 && !ifibss->userspace_handles_dfs) { |
880 | /* IBSS-DFS only allowed with a control program */ | 884 | /* IBSS-DFS only allowed with a control program */ |
881 | if (!ifibss->userspace_handles_dfs) | 885 | goto disconnect; |
882 | goto disconnect; | ||
883 | |||
884 | params.radar_required = true; | ||
885 | } | 886 | } |
886 | 887 | ||
888 | params.radar_required = err; | ||
889 | |||
887 | if (cfg80211_chandef_identical(¶ms.chandef, | 890 | if (cfg80211_chandef_identical(¶ms.chandef, |
888 | &sdata->vif.bss_conf.chandef)) { | 891 | &sdata->vif.bss_conf.chandef)) { |
889 | ibss_dbg(sdata, | 892 | ibss_dbg(sdata, |
@@ -1636,7 +1639,33 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1636 | u32 changed = 0; | 1639 | u32 changed = 0; |
1637 | u32 rate_flags; | 1640 | u32 rate_flags; |
1638 | struct ieee80211_supported_band *sband; | 1641 | struct ieee80211_supported_band *sband; |
1642 | enum ieee80211_chanctx_mode chanmode; | ||
1643 | struct ieee80211_local *local = sdata->local; | ||
1644 | int radar_detect_width = 0; | ||
1639 | int i; | 1645 | int i; |
1646 | int ret; | ||
1647 | |||
1648 | ret = cfg80211_chandef_dfs_required(local->hw.wiphy, | ||
1649 | ¶ms->chandef, | ||
1650 | sdata->wdev.iftype); | ||
1651 | if (ret < 0) | ||
1652 | return ret; | ||
1653 | |||
1654 | if (ret > 0) { | ||
1655 | if (!params->userspace_handles_dfs) | ||
1656 | return -EINVAL; | ||
1657 | radar_detect_width = BIT(params->chandef.width); | ||
1658 | } | ||
1659 | |||
1660 | chanmode = (params->channel_fixed && !ret) ? | ||
1661 | IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE; | ||
1662 | |||
1663 | mutex_lock(&local->chanctx_mtx); | ||
1664 | ret = ieee80211_check_combinations(sdata, ¶ms->chandef, chanmode, | ||
1665 | radar_detect_width); | ||
1666 | mutex_unlock(&local->chanctx_mtx); | ||
1667 | if (ret < 0) | ||
1668 | return ret; | ||
1640 | 1669 | ||
1641 | if (params->bssid) { | 1670 | if (params->bssid) { |
1642 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); | 1671 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); |
@@ -1651,7 +1680,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1651 | 1680 | ||
1652 | /* fix basic_rates if channel does not support these rates */ | 1681 | /* fix basic_rates if channel does not support these rates */ |
1653 | rate_flags = ieee80211_chandef_rate_flags(¶ms->chandef); | 1682 | rate_flags = ieee80211_chandef_rate_flags(¶ms->chandef); |
1654 | sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band]; | 1683 | sband = local->hw.wiphy->bands[params->chandef.chan->band]; |
1655 | for (i = 0; i < sband->n_bitrates; i++) { | 1684 | for (i = 0; i < sband->n_bitrates; i++) { |
1656 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | 1685 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) |
1657 | sdata->u.ibss.basic_rates &= ~BIT(i); | 1686 | sdata->u.ibss.basic_rates &= ~BIT(i); |
@@ -1700,9 +1729,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1700 | ieee80211_bss_info_change_notify(sdata, changed); | 1729 | ieee80211_bss_info_change_notify(sdata, changed); |
1701 | 1730 | ||
1702 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 1731 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
1703 | sdata->needed_rx_chains = sdata->local->rx_chains; | 1732 | sdata->needed_rx_chains = local->rx_chains; |
1704 | 1733 | ||
1705 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 1734 | ieee80211_queue_work(&local->hw, &sdata->work); |
1706 | 1735 | ||
1707 | return 0; | 1736 | return 0; |
1708 | } | 1737 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 222c28b75315..b455f62d357a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -260,7 +260,7 @@ struct ieee80211_if_ap { | |||
260 | 260 | ||
261 | /* to be used after channel switch. */ | 261 | /* to be used after channel switch. */ |
262 | struct cfg80211_beacon_data *next_beacon; | 262 | struct cfg80211_beacon_data *next_beacon; |
263 | struct list_head vlans; | 263 | struct list_head vlans; /* write-protected with RTNL and local->mtx */ |
264 | 264 | ||
265 | struct ps_data ps; | 265 | struct ps_data ps; |
266 | atomic_t num_mcast_sta; /* number of stations receiving multicast */ | 266 | atomic_t num_mcast_sta; /* number of stations receiving multicast */ |
@@ -276,7 +276,7 @@ struct ieee80211_if_wds { | |||
276 | }; | 276 | }; |
277 | 277 | ||
278 | struct ieee80211_if_vlan { | 278 | struct ieee80211_if_vlan { |
279 | struct list_head list; | 279 | struct list_head list; /* write-protected with RTNL and local->mtx */ |
280 | 280 | ||
281 | /* used for all tx if the VLAN is configured to 4-addr mode */ | 281 | /* used for all tx if the VLAN is configured to 4-addr mode */ |
282 | struct sta_info __rcu *sta; | 282 | struct sta_info __rcu *sta; |
@@ -691,8 +691,10 @@ struct ieee80211_chanctx { | |||
691 | struct list_head list; | 691 | struct list_head list; |
692 | struct rcu_head rcu_head; | 692 | struct rcu_head rcu_head; |
693 | 693 | ||
694 | struct list_head assigned_vifs; | ||
695 | struct list_head reserved_vifs; | ||
696 | |||
694 | enum ieee80211_chanctx_mode mode; | 697 | enum ieee80211_chanctx_mode mode; |
695 | int refcount; | ||
696 | bool driver_present; | 698 | bool driver_present; |
697 | 699 | ||
698 | struct ieee80211_chanctx_conf conf; | 700 | struct ieee80211_chanctx_conf conf; |
@@ -756,6 +758,14 @@ struct ieee80211_sub_if_data { | |||
756 | bool csa_radar_required; | 758 | bool csa_radar_required; |
757 | struct cfg80211_chan_def csa_chandef; | 759 | struct cfg80211_chan_def csa_chandef; |
758 | 760 | ||
761 | struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ | ||
762 | struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ | ||
763 | |||
764 | /* context reservation -- protected with chanctx_mtx */ | ||
765 | struct ieee80211_chanctx *reserved_chanctx; | ||
766 | struct cfg80211_chan_def reserved_chandef; | ||
767 | bool reserved_radar_required; | ||
768 | |||
759 | /* used to reconfigure hardware SM PS */ | 769 | /* used to reconfigure hardware SM PS */ |
760 | struct work_struct recalc_smps; | 770 | struct work_struct recalc_smps; |
761 | 771 | ||
@@ -1771,6 +1781,16 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
1771 | const struct cfg80211_chan_def *chandef, | 1781 | const struct cfg80211_chan_def *chandef, |
1772 | enum ieee80211_chanctx_mode mode); | 1782 | enum ieee80211_chanctx_mode mode); |
1773 | int __must_check | 1783 | int __must_check |
1784 | ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, | ||
1785 | const struct cfg80211_chan_def *chandef, | ||
1786 | enum ieee80211_chanctx_mode mode, | ||
1787 | bool radar_required); | ||
1788 | int __must_check | ||
1789 | ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, | ||
1790 | u32 *changed); | ||
1791 | int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); | ||
1792 | |||
1793 | int __must_check | ||
1774 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | 1794 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, |
1775 | const struct cfg80211_chan_def *chandef, | 1795 | const struct cfg80211_chan_def *chandef, |
1776 | u32 *changed); | 1796 | u32 *changed); |
@@ -1782,6 +1802,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | |||
1782 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1802 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
1783 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | 1803 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, |
1784 | bool clear); | 1804 | bool clear); |
1805 | int ieee80211_chanctx_refcount(struct ieee80211_local *local, | ||
1806 | struct ieee80211_chanctx *ctx); | ||
1785 | 1807 | ||
1786 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 1808 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
1787 | struct ieee80211_chanctx *chanctx); | 1809 | struct ieee80211_chanctx *chanctx); |
@@ -1805,6 +1827,11 @@ int ieee80211_cs_headroom(struct ieee80211_local *local, | |||
1805 | enum nl80211_iftype iftype); | 1827 | enum nl80211_iftype iftype); |
1806 | void ieee80211_recalc_dtim(struct ieee80211_local *local, | 1828 | void ieee80211_recalc_dtim(struct ieee80211_local *local, |
1807 | struct ieee80211_sub_if_data *sdata); | 1829 | struct ieee80211_sub_if_data *sdata); |
1830 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | ||
1831 | const struct cfg80211_chan_def *chandef, | ||
1832 | enum ieee80211_chanctx_mode chanmode, | ||
1833 | u8 radar_detect); | ||
1834 | int ieee80211_max_num_channels(struct ieee80211_local *local); | ||
1808 | 1835 | ||
1809 | #ifdef CONFIG_MAC80211_NOINLINE | 1836 | #ifdef CONFIG_MAC80211_NOINLINE |
1810 | #define debug_noinline noinline | 1837 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b8d331e7d883..7fff3dcaac43 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -250,6 +250,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
250 | { | 250 | { |
251 | struct ieee80211_local *local = sdata->local; | 251 | struct ieee80211_local *local = sdata->local; |
252 | struct ieee80211_sub_if_data *nsdata; | 252 | struct ieee80211_sub_if_data *nsdata; |
253 | int ret; | ||
253 | 254 | ||
254 | ASSERT_RTNL(); | 255 | ASSERT_RTNL(); |
255 | 256 | ||
@@ -300,7 +301,10 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
300 | } | 301 | } |
301 | } | 302 | } |
302 | 303 | ||
303 | return 0; | 304 | mutex_lock(&local->chanctx_mtx); |
305 | ret = ieee80211_check_combinations(sdata, NULL, 0, 0); | ||
306 | mutex_unlock(&local->chanctx_mtx); | ||
307 | return ret; | ||
304 | } | 308 | } |
305 | 309 | ||
306 | static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, | 310 | static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, |
@@ -423,7 +427,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
423 | mutex_unlock(&local->mtx); | 427 | mutex_unlock(&local->mtx); |
424 | if (ret) { | 428 | if (ret) { |
425 | mutex_lock(&local->iflist_mtx); | 429 | mutex_lock(&local->iflist_mtx); |
426 | rcu_assign_pointer(local->monitor_sdata, NULL); | 430 | RCU_INIT_POINTER(local->monitor_sdata, NULL); |
427 | mutex_unlock(&local->iflist_mtx); | 431 | mutex_unlock(&local->iflist_mtx); |
428 | synchronize_net(); | 432 | synchronize_net(); |
429 | drv_remove_interface(local, sdata); | 433 | drv_remove_interface(local, sdata); |
@@ -452,7 +456,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | |||
452 | return; | 456 | return; |
453 | } | 457 | } |
454 | 458 | ||
455 | rcu_assign_pointer(local->monitor_sdata, NULL); | 459 | RCU_INIT_POINTER(local->monitor_sdata, NULL); |
456 | mutex_unlock(&local->iflist_mtx); | 460 | mutex_unlock(&local->iflist_mtx); |
457 | 461 | ||
458 | synchronize_net(); | 462 | synchronize_net(); |
@@ -492,7 +496,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
492 | if (!sdata->bss) | 496 | if (!sdata->bss) |
493 | return -ENOLINK; | 497 | return -ENOLINK; |
494 | 498 | ||
499 | mutex_lock(&local->mtx); | ||
495 | list_add(&sdata->u.vlan.list, &sdata->bss->vlans); | 500 | list_add(&sdata->u.vlan.list, &sdata->bss->vlans); |
501 | mutex_unlock(&local->mtx); | ||
496 | 502 | ||
497 | master = container_of(sdata->bss, | 503 | master = container_of(sdata->bss, |
498 | struct ieee80211_sub_if_data, u.ap); | 504 | struct ieee80211_sub_if_data, u.ap); |
@@ -722,8 +728,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
722 | drv_stop(local); | 728 | drv_stop(local); |
723 | err_del_bss: | 729 | err_del_bss: |
724 | sdata->bss = NULL; | 730 | sdata->bss = NULL; |
725 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 731 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
732 | mutex_lock(&local->mtx); | ||
726 | list_del(&sdata->u.vlan.list); | 733 | list_del(&sdata->u.vlan.list); |
734 | mutex_unlock(&local->mtx); | ||
735 | } | ||
727 | /* might already be clear but that doesn't matter */ | 736 | /* might already be clear but that doesn't matter */ |
728 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 737 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
729 | return res; | 738 | return res; |
@@ -875,8 +884,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
875 | 884 | ||
876 | switch (sdata->vif.type) { | 885 | switch (sdata->vif.type) { |
877 | case NL80211_IFTYPE_AP_VLAN: | 886 | case NL80211_IFTYPE_AP_VLAN: |
887 | mutex_lock(&local->mtx); | ||
878 | list_del(&sdata->u.vlan.list); | 888 | list_del(&sdata->u.vlan.list); |
879 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); | 889 | mutex_unlock(&local->mtx); |
890 | RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); | ||
880 | /* no need to tell driver */ | 891 | /* no need to tell driver */ |
881 | break; | 892 | break; |
882 | case NL80211_IFTYPE_MONITOR: | 893 | case NL80211_IFTYPE_MONITOR: |
@@ -895,7 +906,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
895 | break; | 906 | break; |
896 | case NL80211_IFTYPE_P2P_DEVICE: | 907 | case NL80211_IFTYPE_P2P_DEVICE: |
897 | /* relies on synchronize_rcu() below */ | 908 | /* relies on synchronize_rcu() below */ |
898 | rcu_assign_pointer(local->p2p_sdata, NULL); | 909 | RCU_INIT_POINTER(local->p2p_sdata, NULL); |
899 | /* fall through */ | 910 | /* fall through */ |
900 | default: | 911 | default: |
901 | cancel_work_sync(&sdata->work); | 912 | cancel_work_sync(&sdata->work); |
@@ -1280,6 +1291,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1280 | INIT_WORK(&sdata->work, ieee80211_iface_work); | 1291 | INIT_WORK(&sdata->work, ieee80211_iface_work); |
1281 | INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); | 1292 | INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); |
1282 | INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); | 1293 | INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); |
1294 | INIT_LIST_HEAD(&sdata->assigned_chanctx_list); | ||
1295 | INIT_LIST_HEAD(&sdata->reserved_chanctx_list); | ||
1283 | 1296 | ||
1284 | switch (type) { | 1297 | switch (type) { |
1285 | case NL80211_IFTYPE_P2P_GO: | 1298 | case NL80211_IFTYPE_P2P_GO: |
@@ -1774,20 +1787,19 @@ static int netdev_notify(struct notifier_block *nb, | |||
1774 | struct ieee80211_sub_if_data *sdata; | 1787 | struct ieee80211_sub_if_data *sdata; |
1775 | 1788 | ||
1776 | if (state != NETDEV_CHANGENAME) | 1789 | if (state != NETDEV_CHANGENAME) |
1777 | return 0; | 1790 | return NOTIFY_DONE; |
1778 | 1791 | ||
1779 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) | 1792 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) |
1780 | return 0; | 1793 | return NOTIFY_DONE; |
1781 | 1794 | ||
1782 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) | 1795 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) |
1783 | return 0; | 1796 | return NOTIFY_DONE; |
1784 | 1797 | ||
1785 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1798 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1786 | |||
1787 | memcpy(sdata->name, dev->name, IFNAMSIZ); | 1799 | memcpy(sdata->name, dev->name, IFNAMSIZ); |
1788 | |||
1789 | ieee80211_debugfs_rename_netdev(sdata); | 1800 | ieee80211_debugfs_rename_netdev(sdata); |
1790 | return 0; | 1801 | |
1802 | return NOTIFY_OK; | ||
1791 | } | 1803 | } |
1792 | 1804 | ||
1793 | static struct notifier_block mac80211_netdev_notifier = { | 1805 | static struct notifier_block mac80211_netdev_notifier = { |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4c1bf61bc778..27b9364cdf17 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -340,7 +340,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
340 | 340 | ||
341 | sdata_unlock(sdata); | 341 | sdata_unlock(sdata); |
342 | 342 | ||
343 | return NOTIFY_DONE; | 343 | return NOTIFY_OK; |
344 | } | 344 | } |
345 | #endif | 345 | #endif |
346 | 346 | ||
@@ -371,7 +371,7 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb, | |||
371 | 371 | ||
372 | drv_ipv6_addr_change(local, sdata, idev); | 372 | drv_ipv6_addr_change(local, sdata, idev); |
373 | 373 | ||
374 | return NOTIFY_DONE; | 374 | return NOTIFY_OK; |
375 | } | 375 | } |
376 | #endif | 376 | #endif |
377 | 377 | ||
@@ -446,7 +446,9 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | |||
446 | .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 446 | .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
447 | IEEE80211_HT_CAP_MAX_AMSDU | | 447 | IEEE80211_HT_CAP_MAX_AMSDU | |
448 | IEEE80211_HT_CAP_SGI_20 | | 448 | IEEE80211_HT_CAP_SGI_20 | |
449 | IEEE80211_HT_CAP_SGI_40), | 449 | IEEE80211_HT_CAP_SGI_40 | |
450 | IEEE80211_HT_CAP_LDPC_CODING | | ||
451 | IEEE80211_HT_CAP_40MHZ_INTOLERANT), | ||
450 | .mcs = { | 452 | .mcs = { |
451 | .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, | 453 | .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, |
452 | 0xff, 0xff, 0xff, 0xff, 0xff, }, | 454 | 0xff, 0xff, 0xff, 0xff, 0xff, }, |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f70e9cd10552..b06ddc9519ce 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -366,20 +366,15 @@ int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
366 | return 0; | 366 | return 0; |
367 | 367 | ||
368 | /* find RSN IE */ | 368 | /* find RSN IE */ |
369 | data = ifmsh->ie; | 369 | data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len); |
370 | while (data < ifmsh->ie + ifmsh->ie_len) { | 370 | if (!data) |
371 | if (*data == WLAN_EID_RSN) { | 371 | return 0; |
372 | len = data[1] + 2; | ||
373 | break; | ||
374 | } | ||
375 | data++; | ||
376 | } | ||
377 | 372 | ||
378 | if (len) { | 373 | len = data[1] + 2; |
379 | if (skb_tailroom(skb) < len) | 374 | |
380 | return -ENOMEM; | 375 | if (skb_tailroom(skb) < len) |
381 | memcpy(skb_put(skb, len), data, len); | 376 | return -ENOMEM; |
382 | } | 377 | memcpy(skb_put(skb, len), data, len); |
383 | 378 | ||
384 | return 0; | 379 | return 0; |
385 | } | 380 | } |
@@ -829,7 +824,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
829 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 824 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
830 | bcn = rcu_dereference_protected(ifmsh->beacon, | 825 | bcn = rcu_dereference_protected(ifmsh->beacon, |
831 | lockdep_is_held(&sdata->wdev.mtx)); | 826 | lockdep_is_held(&sdata->wdev.mtx)); |
832 | rcu_assign_pointer(ifmsh->beacon, NULL); | 827 | RCU_INIT_POINTER(ifmsh->beacon, NULL); |
833 | kfree_rcu(bcn, rcu_head); | 828 | kfree_rcu(bcn, rcu_head); |
834 | 829 | ||
835 | /* flush STAs and mpaths on this iface */ | 830 | /* flush STAs and mpaths on this iface */ |
@@ -903,14 +898,15 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, | |||
903 | } | 898 | } |
904 | 899 | ||
905 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, | 900 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, |
906 | ¶ms.chandef); | 901 | ¶ms.chandef, |
902 | NL80211_IFTYPE_MESH_POINT); | ||
907 | if (err < 0) | 903 | if (err < 0) |
908 | return false; | 904 | return false; |
909 | if (err) { | 905 | if (err > 0) |
910 | params.radar_required = true; | ||
911 | /* TODO: DFS not (yet) supported */ | 906 | /* TODO: DFS not (yet) supported */ |
912 | return false; | 907 | return false; |
913 | } | 908 | |
909 | params.radar_required = err; | ||
914 | 910 | ||
915 | if (cfg80211_chandef_identical(¶ms.chandef, | 911 | if (cfg80211_chandef_identical(¶ms.chandef, |
916 | &sdata->vif.bss_conf.chandef)) { | 912 | &sdata->vif.bss_conf.chandef)) { |
@@ -1068,7 +1064,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
1068 | 1064 | ||
1069 | /* Remove the CSA and MCSP elements from the beacon */ | 1065 | /* Remove the CSA and MCSP elements from the beacon */ |
1070 | tmp_csa_settings = rcu_dereference(ifmsh->csa); | 1066 | tmp_csa_settings = rcu_dereference(ifmsh->csa); |
1071 | rcu_assign_pointer(ifmsh->csa, NULL); | 1067 | RCU_INIT_POINTER(ifmsh->csa, NULL); |
1072 | if (tmp_csa_settings) | 1068 | if (tmp_csa_settings) |
1073 | kfree_rcu(tmp_csa_settings, rcu_head); | 1069 | kfree_rcu(tmp_csa_settings, rcu_head); |
1074 | ret = ieee80211_mesh_rebuild_beacon(sdata); | 1070 | ret = ieee80211_mesh_rebuild_beacon(sdata); |
@@ -1102,7 +1098,7 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
1102 | ret = ieee80211_mesh_rebuild_beacon(sdata); | 1098 | ret = ieee80211_mesh_rebuild_beacon(sdata); |
1103 | if (ret) { | 1099 | if (ret) { |
1104 | tmp_csa_settings = rcu_dereference(ifmsh->csa); | 1100 | tmp_csa_settings = rcu_dereference(ifmsh->csa); |
1105 | rcu_assign_pointer(ifmsh->csa, NULL); | 1101 | RCU_INIT_POINTER(ifmsh->csa, NULL); |
1106 | kfree_rcu(tmp_csa_settings, rcu_head); | 1102 | kfree_rcu(tmp_csa_settings, rcu_head); |
1107 | return ret; | 1103 | return ret; |
1108 | } | 1104 | } |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f9514685d45a..94758b9c9ed4 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -37,7 +37,7 @@ static inline u32 u32_field_get(const u8 *preq_elem, int offset, bool ae) | |||
37 | return get_unaligned_le32(preq_elem + offset); | 37 | return get_unaligned_le32(preq_elem + offset); |
38 | } | 38 | } |
39 | 39 | ||
40 | static inline u32 u16_field_get(const u8 *preq_elem, int offset, bool ae) | 40 | static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae) |
41 | { | 41 | { |
42 | if (ae) | 42 | if (ae) |
43 | offset += 6; | 43 | offset += 6; |
@@ -544,9 +544,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
544 | if (time_after(jiffies, ifmsh->last_sn_update + | 544 | if (time_after(jiffies, ifmsh->last_sn_update + |
545 | net_traversal_jiffies(sdata)) || | 545 | net_traversal_jiffies(sdata)) || |
546 | time_before(jiffies, ifmsh->last_sn_update)) { | 546 | time_before(jiffies, ifmsh->last_sn_update)) { |
547 | target_sn = ++ifmsh->sn; | 547 | ++ifmsh->sn; |
548 | ifmsh->last_sn_update = jiffies; | 548 | ifmsh->last_sn_update = jiffies; |
549 | } | 549 | } |
550 | target_sn = ifmsh->sn; | ||
550 | } else if (is_broadcast_ether_addr(target_addr) && | 551 | } else if (is_broadcast_ether_addr(target_addr) && |
551 | (target_flags & IEEE80211_PREQ_TO_FLAG)) { | 552 | (target_flags & IEEE80211_PREQ_TO_FLAG)) { |
552 | rcu_read_lock(); | 553 | rcu_read_lock(); |
diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h index 3b848dad9587..0e4886f881f1 100644 --- a/net/mac80211/michael.h +++ b/net/mac80211/michael.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #define MICHAEL_H | 11 | #define MICHAEL_H |
12 | 12 | ||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/ieee80211.h> | ||
14 | 15 | ||
15 | #define MICHAEL_MIC_LEN 8 | 16 | #define MICHAEL_MIC_LEN 8 |
16 | 17 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dee50aefd6e8..488826f188a7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1089,7 +1089,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1089 | } | 1089 | } |
1090 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), | 1090 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), |
1091 | struct ieee80211_chanctx, conf); | 1091 | struct ieee80211_chanctx, conf); |
1092 | if (chanctx->refcount > 1) { | 1092 | if (ieee80211_chanctx_refcount(local, chanctx) > 1) { |
1093 | sdata_info(sdata, | 1093 | sdata_info(sdata, |
1094 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); | 1094 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); |
1095 | ieee80211_queue_work(&local->hw, | 1095 | ieee80211_queue_work(&local->hw, |
@@ -3701,7 +3701,7 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
3701 | ieee80211_recalc_ps(local, latency_usec); | 3701 | ieee80211_recalc_ps(local, latency_usec); |
3702 | mutex_unlock(&local->iflist_mtx); | 3702 | mutex_unlock(&local->iflist_mtx); |
3703 | 3703 | ||
3704 | return 0; | 3704 | return NOTIFY_OK; |
3705 | } | 3705 | } |
3706 | 3706 | ||
3707 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, | 3707 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 216c45b949e5..0e5b67015650 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -54,24 +54,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
54 | return skb; | 54 | return skb; |
55 | } | 55 | } |
56 | 56 | ||
57 | static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) | 57 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) |
58 | { | 58 | { |
59 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 59 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
60 | struct ieee80211_hdr *hdr; | 60 | struct ieee80211_hdr *hdr = (void *)skb->data; |
61 | |||
62 | hdr = (void *)(skb->data); | ||
63 | 61 | ||
64 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | 62 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
65 | RX_FLAG_FAILED_PLCP_CRC | | 63 | RX_FLAG_FAILED_PLCP_CRC | |
66 | RX_FLAG_AMPDU_IS_ZEROLEN)) | 64 | RX_FLAG_AMPDU_IS_ZEROLEN)) |
67 | return 1; | 65 | return true; |
66 | |||
68 | if (unlikely(skb->len < 16 + present_fcs_len)) | 67 | if (unlikely(skb->len < 16 + present_fcs_len)) |
69 | return 1; | 68 | return true; |
69 | |||
70 | if (ieee80211_is_ctl(hdr->frame_control) && | 70 | if (ieee80211_is_ctl(hdr->frame_control) && |
71 | !ieee80211_is_pspoll(hdr->frame_control) && | 71 | !ieee80211_is_pspoll(hdr->frame_control) && |
72 | !ieee80211_is_back_req(hdr->frame_control)) | 72 | !ieee80211_is_back_req(hdr->frame_control)) |
73 | return 1; | 73 | return true; |
74 | return 0; | 74 | |
75 | return false; | ||
75 | } | 76 | } |
76 | 77 | ||
77 | static int | 78 | static int |
@@ -3190,7 +3191,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, | |||
3190 | } | 3191 | } |
3191 | 3192 | ||
3192 | /* | 3193 | /* |
3193 | * This is the actual Rx frames handler. as it blongs to Rx path it must | 3194 | * This is the actual Rx frames handler. as it belongs to Rx path it must |
3194 | * be called with rcu_read_lock protection. | 3195 | * be called with rcu_read_lock protection. |
3195 | */ | 3196 | */ |
3196 | static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | 3197 | static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 3ce7f2c8539a..28185c8dc19a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -309,7 +309,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
309 | if (local->scan_req != local->int_scan_req) | 309 | if (local->scan_req != local->int_scan_req) |
310 | cfg80211_scan_done(local->scan_req, aborted); | 310 | cfg80211_scan_done(local->scan_req, aborted); |
311 | local->scan_req = NULL; | 311 | local->scan_req = NULL; |
312 | rcu_assign_pointer(local->scan_sdata, NULL); | 312 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
313 | 313 | ||
314 | local->scanning = 0; | 314 | local->scanning = 0; |
315 | local->scan_chandef.chan = NULL; | 315 | local->scan_chandef.chan = NULL; |
@@ -559,7 +559,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
559 | ieee80211_recalc_idle(local); | 559 | ieee80211_recalc_idle(local); |
560 | 560 | ||
561 | local->scan_req = NULL; | 561 | local->scan_req = NULL; |
562 | rcu_assign_pointer(local->scan_sdata, NULL); | 562 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
563 | } | 563 | } |
564 | 564 | ||
565 | return rc; | 565 | return rc; |
@@ -773,7 +773,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
773 | int rc; | 773 | int rc; |
774 | 774 | ||
775 | local->scan_req = NULL; | 775 | local->scan_req = NULL; |
776 | rcu_assign_pointer(local->scan_sdata, NULL); | 776 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
777 | 777 | ||
778 | rc = __ieee80211_start_scan(sdata, req); | 778 | rc = __ieee80211_start_scan(sdata, req); |
779 | if (rc) { | 779 | if (rc) { |
@@ -1014,7 +1014,7 @@ out_free: | |||
1014 | 1014 | ||
1015 | if (ret) { | 1015 | if (ret) { |
1016 | /* Clean in case of failure after HW restart or upon resume. */ | 1016 | /* Clean in case of failure after HW restart or upon resume. */ |
1017 | rcu_assign_pointer(local->sched_scan_sdata, NULL); | 1017 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
1018 | local->sched_scan_req = NULL; | 1018 | local->sched_scan_req = NULL; |
1019 | } | 1019 | } |
1020 | 1020 | ||
@@ -1089,7 +1089,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) | |||
1089 | return; | 1089 | return; |
1090 | } | 1090 | } |
1091 | 1091 | ||
1092 | rcu_assign_pointer(local->sched_scan_sdata, NULL); | 1092 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
1093 | 1093 | ||
1094 | /* If sched scan was aborted by the driver. */ | 1094 | /* If sched scan was aborted by the driver. */ |
1095 | local->sched_scan_req = NULL; | 1095 | local->sched_scan_req = NULL; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 137a192e64bc..c34a5f97abc7 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -552,7 +552,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
552 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | 552 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) |
553 | { | 553 | { |
554 | struct ieee80211_local *local = sta->local; | 554 | struct ieee80211_local *local = sta->local; |
555 | int err = 0; | 555 | int err; |
556 | 556 | ||
557 | might_sleep(); | 557 | might_sleep(); |
558 | 558 | ||
@@ -570,7 +570,6 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | |||
570 | 570 | ||
571 | return 0; | 571 | return 0; |
572 | out_free: | 572 | out_free: |
573 | BUG_ON(!err); | ||
574 | sta_info_free(local, sta); | 573 | sta_info_free(local, sta); |
575 | return err; | 574 | return err; |
576 | } | 575 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 275c94f995f7..ad058759e85e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -554,7 +554,7 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
554 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 554 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, |
555 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 555 | IEEE80211_QUEUE_STOP_REASON_FLUSH); |
556 | 556 | ||
557 | drv_flush(local, queues, false); | 557 | drv_flush(local, sdata, queues, false); |
558 | 558 | ||
559 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 559 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, |
560 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 560 | IEEE80211_QUEUE_STOP_REASON_FLUSH); |
@@ -1546,7 +1546,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1546 | WARN_ON(local->resuming); | 1546 | WARN_ON(local->resuming); |
1547 | res = drv_add_interface(local, sdata); | 1547 | res = drv_add_interface(local, sdata); |
1548 | if (WARN_ON(res)) { | 1548 | if (WARN_ON(res)) { |
1549 | rcu_assign_pointer(local->monitor_sdata, NULL); | 1549 | RCU_INIT_POINTER(local->monitor_sdata, NULL); |
1550 | synchronize_net(); | 1550 | synchronize_net(); |
1551 | kfree(sdata); | 1551 | kfree(sdata); |
1552 | } | 1552 | } |
@@ -1565,17 +1565,17 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1565 | list_for_each_entry(ctx, &local->chanctx_list, list) | 1565 | list_for_each_entry(ctx, &local->chanctx_list, list) |
1566 | WARN_ON(drv_add_chanctx(local, ctx)); | 1566 | WARN_ON(drv_add_chanctx(local, ctx)); |
1567 | mutex_unlock(&local->chanctx_mtx); | 1567 | mutex_unlock(&local->chanctx_mtx); |
1568 | } | ||
1569 | 1568 | ||
1570 | list_for_each_entry(sdata, &local->interfaces, list) { | 1569 | list_for_each_entry(sdata, &local->interfaces, list) { |
1571 | if (!ieee80211_sdata_running(sdata)) | 1570 | if (!ieee80211_sdata_running(sdata)) |
1572 | continue; | 1571 | continue; |
1573 | ieee80211_assign_chanctx(local, sdata); | 1572 | ieee80211_assign_chanctx(local, sdata); |
1574 | } | 1573 | } |
1575 | 1574 | ||
1576 | sdata = rtnl_dereference(local->monitor_sdata); | 1575 | sdata = rtnl_dereference(local->monitor_sdata); |
1577 | if (sdata && ieee80211_sdata_running(sdata)) | 1576 | if (sdata && ieee80211_sdata_running(sdata)) |
1578 | ieee80211_assign_chanctx(local, sdata); | 1577 | ieee80211_assign_chanctx(local, sdata); |
1578 | } | ||
1579 | 1579 | ||
1580 | /* add STAs back */ | 1580 | /* add STAs back */ |
1581 | mutex_lock(&local->sta_mtx); | 1581 | mutex_lock(&local->sta_mtx); |
@@ -1671,13 +1671,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1671 | } | 1671 | } |
1672 | break; | 1672 | break; |
1673 | case NL80211_IFTYPE_WDS: | 1673 | case NL80211_IFTYPE_WDS: |
1674 | break; | ||
1675 | case NL80211_IFTYPE_AP_VLAN: | 1674 | case NL80211_IFTYPE_AP_VLAN: |
1676 | case NL80211_IFTYPE_MONITOR: | 1675 | case NL80211_IFTYPE_MONITOR: |
1677 | /* ignore virtual */ | ||
1678 | break; | ||
1679 | case NL80211_IFTYPE_P2P_DEVICE: | 1676 | case NL80211_IFTYPE_P2P_DEVICE: |
1680 | changed = BSS_CHANGED_IDLE; | 1677 | /* nothing to do */ |
1681 | break; | 1678 | break; |
1682 | case NL80211_IFTYPE_UNSPECIFIED: | 1679 | case NL80211_IFTYPE_UNSPECIFIED: |
1683 | case NUM_NL80211_IFTYPES: | 1680 | case NUM_NL80211_IFTYPES: |
@@ -2797,3 +2794,121 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, | |||
2797 | 2794 | ||
2798 | ps->dtim_count = dtim_count; | 2795 | ps->dtim_count = dtim_count; |
2799 | } | 2796 | } |
2797 | |||
2798 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | ||
2799 | const struct cfg80211_chan_def *chandef, | ||
2800 | enum ieee80211_chanctx_mode chanmode, | ||
2801 | u8 radar_detect) | ||
2802 | { | ||
2803 | struct ieee80211_local *local = sdata->local; | ||
2804 | struct ieee80211_sub_if_data *sdata_iter; | ||
2805 | enum nl80211_iftype iftype = sdata->wdev.iftype; | ||
2806 | int num[NUM_NL80211_IFTYPES]; | ||
2807 | struct ieee80211_chanctx *ctx; | ||
2808 | int num_different_channels = 0; | ||
2809 | int total = 1; | ||
2810 | |||
2811 | lockdep_assert_held(&local->chanctx_mtx); | ||
2812 | |||
2813 | if (WARN_ON(hweight32(radar_detect) > 1)) | ||
2814 | return -EINVAL; | ||
2815 | |||
2816 | if (WARN_ON(chandef && chanmode == IEEE80211_CHANCTX_SHARED && | ||
2817 | !chandef->chan)) | ||
2818 | return -EINVAL; | ||
2819 | |||
2820 | if (chandef) | ||
2821 | num_different_channels = 1; | ||
2822 | |||
2823 | if (WARN_ON(iftype >= NUM_NL80211_IFTYPES)) | ||
2824 | return -EINVAL; | ||
2825 | |||
2826 | /* Always allow software iftypes */ | ||
2827 | if (local->hw.wiphy->software_iftypes & BIT(iftype)) { | ||
2828 | if (radar_detect) | ||
2829 | return -EINVAL; | ||
2830 | return 0; | ||
2831 | } | ||
2832 | |||
2833 | memset(num, 0, sizeof(num)); | ||
2834 | |||
2835 | if (iftype != NL80211_IFTYPE_UNSPECIFIED) | ||
2836 | num[iftype] = 1; | ||
2837 | |||
2838 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
2839 | if (ctx->conf.radar_enabled) | ||
2840 | radar_detect |= BIT(ctx->conf.def.width); | ||
2841 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { | ||
2842 | num_different_channels++; | ||
2843 | continue; | ||
2844 | } | ||
2845 | if (chandef && chanmode == IEEE80211_CHANCTX_SHARED && | ||
2846 | cfg80211_chandef_compatible(chandef, | ||
2847 | &ctx->conf.def)) | ||
2848 | continue; | ||
2849 | num_different_channels++; | ||
2850 | } | ||
2851 | |||
2852 | list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) { | ||
2853 | struct wireless_dev *wdev_iter; | ||
2854 | |||
2855 | wdev_iter = &sdata_iter->wdev; | ||
2856 | |||
2857 | if (sdata_iter == sdata || | ||
2858 | rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL || | ||
2859 | local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype)) | ||
2860 | continue; | ||
2861 | |||
2862 | num[wdev_iter->iftype]++; | ||
2863 | total++; | ||
2864 | } | ||
2865 | |||
2866 | if (total == 1 && !radar_detect) | ||
2867 | return 0; | ||
2868 | |||
2869 | return cfg80211_check_combinations(local->hw.wiphy, | ||
2870 | num_different_channels, | ||
2871 | radar_detect, num); | ||
2872 | } | ||
2873 | |||
2874 | static void | ||
2875 | ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c, | ||
2876 | void *data) | ||
2877 | { | ||
2878 | u32 *max_num_different_channels = data; | ||
2879 | |||
2880 | *max_num_different_channels = max(*max_num_different_channels, | ||
2881 | c->num_different_channels); | ||
2882 | } | ||
2883 | |||
2884 | int ieee80211_max_num_channels(struct ieee80211_local *local) | ||
2885 | { | ||
2886 | struct ieee80211_sub_if_data *sdata; | ||
2887 | int num[NUM_NL80211_IFTYPES] = {}; | ||
2888 | struct ieee80211_chanctx *ctx; | ||
2889 | int num_different_channels = 0; | ||
2890 | u8 radar_detect = 0; | ||
2891 | u32 max_num_different_channels = 1; | ||
2892 | int err; | ||
2893 | |||
2894 | lockdep_assert_held(&local->chanctx_mtx); | ||
2895 | |||
2896 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
2897 | num_different_channels++; | ||
2898 | |||
2899 | if (ctx->conf.radar_enabled) | ||
2900 | radar_detect |= BIT(ctx->conf.def.width); | ||
2901 | } | ||
2902 | |||
2903 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
2904 | num[sdata->wdev.iftype]++; | ||
2905 | |||
2906 | err = cfg80211_iter_combinations(local->hw.wiphy, | ||
2907 | num_different_channels, radar_detect, | ||
2908 | num, ieee80211_iter_max_chans, | ||
2909 | &max_num_different_channels); | ||
2910 | if (err < 0) | ||
2911 | return err; | ||
2912 | |||
2913 | return max_num_different_channels; | ||
2914 | } | ||
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index b8600e3c29c8..9b3dcc201145 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -406,7 +406,10 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
406 | 406 | ||
407 | if (info->control.hw_key && | 407 | if (info->control.hw_key && |
408 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && | 408 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && |
409 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { | 409 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && |
410 | !((info->control.hw_key->flags & | ||
411 | IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) && | ||
412 | ieee80211_is_mgmt(hdr->frame_control))) { | ||
410 | /* | 413 | /* |
411 | * hwaccel has no need for preallocated room for CCMP | 414 | * hwaccel has no need for preallocated room for CCMP |
412 | * header or MIC fields | 415 | * header or MIC fields |