diff options
Diffstat (limited to 'net')
48 files changed, 2752 insertions, 2477 deletions
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index af4dfbadf2a..7d748542d97 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
@@ -789,12 +789,13 @@ static const void *net_netlink_ns(struct sock *sk) | |||
789 | return sock_net(sk); | 789 | return sock_net(sk); |
790 | } | 790 | } |
791 | 791 | ||
792 | static struct kobj_ns_type_operations net_ns_type_operations = { | 792 | struct kobj_ns_type_operations net_ns_type_operations = { |
793 | .type = KOBJ_NS_TYPE_NET, | 793 | .type = KOBJ_NS_TYPE_NET, |
794 | .current_ns = net_current_ns, | 794 | .current_ns = net_current_ns, |
795 | .netlink_ns = net_netlink_ns, | 795 | .netlink_ns = net_netlink_ns, |
796 | .initial_ns = net_initial_ns, | 796 | .initial_ns = net_initial_ns, |
797 | }; | 797 | }; |
798 | EXPORT_SYMBOL_GPL(net_ns_type_operations); | ||
798 | 799 | ||
799 | static void net_kobj_ns_exit(struct net *net) | 800 | static void net_kobj_ns_exit(struct net *net) |
800 | { | 801 | { |
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index a87cb3ba2df..d2b03e0851e 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c | |||
@@ -138,10 +138,8 @@ struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]) | |||
138 | struct crypto_cipher *tfm; | 138 | struct crypto_cipher *tfm; |
139 | 139 | ||
140 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | 140 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); |
141 | if (IS_ERR(tfm)) | 141 | if (!IS_ERR(tfm)) |
142 | return NULL; | 142 | crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN); |
143 | |||
144 | crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN); | ||
145 | 143 | ||
146 | return tfm; | 144 | return tfm; |
147 | } | 145 | } |
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index 3d097b3d7b6..b4d66cca76d 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c | |||
@@ -119,10 +119,8 @@ struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]) | |||
119 | struct crypto_cipher *tfm; | 119 | struct crypto_cipher *tfm; |
120 | 120 | ||
121 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | 121 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); |
122 | if (IS_ERR(tfm)) | 122 | if (!IS_ERR(tfm)) |
123 | return NULL; | 123 | crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN); |
124 | |||
125 | crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN); | ||
126 | 124 | ||
127 | return tfm; | 125 | return tfm; |
128 | } | 126 | } |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 965b272499f..58eab9e8e4e 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -86,6 +86,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
86 | tid, 0, reason); | 86 | tid, 0, reason); |
87 | 87 | ||
88 | del_timer_sync(&tid_rx->session_timer); | 88 | del_timer_sync(&tid_rx->session_timer); |
89 | del_timer_sync(&tid_rx->reorder_timer); | ||
89 | 90 | ||
90 | call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx); | 91 | call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx); |
91 | } | 92 | } |
@@ -120,6 +121,20 @@ static void sta_rx_agg_session_timer_expired(unsigned long data) | |||
120 | ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); | 121 | ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); |
121 | } | 122 | } |
122 | 123 | ||
124 | static void sta_rx_agg_reorder_timer_expired(unsigned long data) | ||
125 | { | ||
126 | u8 *ptid = (u8 *)data; | ||
127 | u8 *timer_to_id = ptid - *ptid; | ||
128 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | ||
129 | timer_to_tid[0]); | ||
130 | |||
131 | rcu_read_lock(); | ||
132 | spin_lock(&sta->lock); | ||
133 | ieee80211_release_reorder_timeout(sta, *ptid); | ||
134 | spin_unlock(&sta->lock); | ||
135 | rcu_read_unlock(); | ||
136 | } | ||
137 | |||
123 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | 138 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, |
124 | u8 dialog_token, u16 status, u16 policy, | 139 | u8 dialog_token, u16 status, u16 policy, |
125 | u16 buf_size, u16 timeout) | 140 | u16 buf_size, u16 timeout) |
@@ -251,11 +266,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
251 | goto end; | 266 | goto end; |
252 | } | 267 | } |
253 | 268 | ||
269 | spin_lock_init(&tid_agg_rx->reorder_lock); | ||
270 | |||
254 | /* rx timer */ | 271 | /* rx timer */ |
255 | tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired; | 272 | tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired; |
256 | tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | 273 | tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; |
257 | init_timer(&tid_agg_rx->session_timer); | 274 | init_timer(&tid_agg_rx->session_timer); |
258 | 275 | ||
276 | /* rx reorder timer */ | ||
277 | tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired; | ||
278 | tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | ||
279 | init_timer(&tid_agg_rx->reorder_timer); | ||
280 | |||
259 | /* prepare reordering buffer */ | 281 | /* prepare reordering buffer */ |
260 | tid_agg_rx->reorder_buf = | 282 | tid_agg_rx->reorder_buf = |
261 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); | 283 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 29ac8e1a509..94bf550bd4c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -19,33 +19,6 @@ | |||
19 | #include "rate.h" | 19 | #include "rate.h" |
20 | #include "mesh.h" | 20 | #include "mesh.h" |
21 | 21 | ||
22 | static bool nl80211_type_check(enum nl80211_iftype type) | ||
23 | { | ||
24 | switch (type) { | ||
25 | case NL80211_IFTYPE_ADHOC: | ||
26 | case NL80211_IFTYPE_STATION: | ||
27 | case NL80211_IFTYPE_MONITOR: | ||
28 | #ifdef CONFIG_MAC80211_MESH | ||
29 | case NL80211_IFTYPE_MESH_POINT: | ||
30 | #endif | ||
31 | case NL80211_IFTYPE_AP: | ||
32 | case NL80211_IFTYPE_AP_VLAN: | ||
33 | case NL80211_IFTYPE_WDS: | ||
34 | return true; | ||
35 | default: | ||
36 | return false; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | static bool nl80211_params_check(enum nl80211_iftype type, | ||
41 | struct vif_params *params) | ||
42 | { | ||
43 | if (!nl80211_type_check(type)) | ||
44 | return false; | ||
45 | |||
46 | return true; | ||
47 | } | ||
48 | |||
49 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 22 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, |
50 | enum nl80211_iftype type, u32 *flags, | 23 | enum nl80211_iftype type, u32 *flags, |
51 | struct vif_params *params) | 24 | struct vif_params *params) |
@@ -55,9 +28,6 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
55 | struct ieee80211_sub_if_data *sdata; | 28 | struct ieee80211_sub_if_data *sdata; |
56 | int err; | 29 | int err; |
57 | 30 | ||
58 | if (!nl80211_params_check(type, params)) | ||
59 | return -EINVAL; | ||
60 | |||
61 | err = ieee80211_if_add(local, name, &dev, type, params); | 31 | err = ieee80211_if_add(local, name, &dev, type, params); |
62 | if (err || type != NL80211_IFTYPE_MONITOR || !flags) | 32 | if (err || type != NL80211_IFTYPE_MONITOR || !flags) |
63 | return err; | 33 | return err; |
@@ -82,12 +52,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
82 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 52 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
83 | int ret; | 53 | int ret; |
84 | 54 | ||
85 | if (ieee80211_sdata_running(sdata)) | ||
86 | return -EBUSY; | ||
87 | |||
88 | if (!nl80211_params_check(type, params)) | ||
89 | return -EINVAL; | ||
90 | |||
91 | ret = ieee80211_if_change_type(sdata, type); | 55 | ret = ieee80211_if_change_type(sdata, type); |
92 | if (ret) | 56 | if (ret) |
93 | return ret; | 57 | return ret; |
@@ -104,8 +68,36 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
104 | params && params->use_4addr >= 0) | 68 | params && params->use_4addr >= 0) |
105 | sdata->u.mgd.use_4addr = params->use_4addr; | 69 | sdata->u.mgd.use_4addr = params->use_4addr; |
106 | 70 | ||
107 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) | 71 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) { |
108 | sdata->u.mntr_flags = *flags; | 72 | struct ieee80211_local *local = sdata->local; |
73 | |||
74 | if (ieee80211_sdata_running(sdata)) { | ||
75 | /* | ||
76 | * Prohibit MONITOR_FLAG_COOK_FRAMES to be | ||
77 | * changed while the interface is up. | ||
78 | * Else we would need to add a lot of cruft | ||
79 | * to update everything: | ||
80 | * cooked_mntrs, monitor and all fif_* counters | ||
81 | * reconfigure hardware | ||
82 | */ | ||
83 | if ((*flags & MONITOR_FLAG_COOK_FRAMES) != | ||
84 | (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) | ||
85 | return -EBUSY; | ||
86 | |||
87 | ieee80211_adjust_monitor_flags(sdata, -1); | ||
88 | sdata->u.mntr_flags = *flags; | ||
89 | ieee80211_adjust_monitor_flags(sdata, 1); | ||
90 | |||
91 | ieee80211_configure_filter(local); | ||
92 | } else { | ||
93 | /* | ||
94 | * Because the interface is down, ieee80211_do_stop | ||
95 | * and ieee80211_do_open take care of "everything" | ||
96 | * mentioned in the comment above. | ||
97 | */ | ||
98 | sdata->u.mntr_flags = *flags; | ||
99 | } | ||
100 | } | ||
109 | 101 | ||
110 | return 0; | 102 | return 0; |
111 | } | 103 | } |
@@ -114,44 +106,30 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
114 | u8 key_idx, const u8 *mac_addr, | 106 | u8 key_idx, const u8 *mac_addr, |
115 | struct key_params *params) | 107 | struct key_params *params) |
116 | { | 108 | { |
117 | struct ieee80211_sub_if_data *sdata; | 109 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
118 | struct sta_info *sta = NULL; | 110 | struct sta_info *sta = NULL; |
119 | enum ieee80211_key_alg alg; | ||
120 | struct ieee80211_key *key; | 111 | struct ieee80211_key *key; |
121 | int err; | 112 | int err; |
122 | 113 | ||
123 | if (!netif_running(dev)) | 114 | if (!ieee80211_sdata_running(sdata)) |
124 | return -ENETDOWN; | 115 | return -ENETDOWN; |
125 | 116 | ||
126 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 117 | /* reject WEP and TKIP keys if WEP failed to initialize */ |
127 | |||
128 | switch (params->cipher) { | 118 | switch (params->cipher) { |
129 | case WLAN_CIPHER_SUITE_WEP40: | 119 | case WLAN_CIPHER_SUITE_WEP40: |
130 | case WLAN_CIPHER_SUITE_WEP104: | ||
131 | alg = ALG_WEP; | ||
132 | break; | ||
133 | case WLAN_CIPHER_SUITE_TKIP: | 120 | case WLAN_CIPHER_SUITE_TKIP: |
134 | alg = ALG_TKIP; | 121 | case WLAN_CIPHER_SUITE_WEP104: |
135 | break; | 122 | if (IS_ERR(sdata->local->wep_tx_tfm)) |
136 | case WLAN_CIPHER_SUITE_CCMP: | 123 | return -EINVAL; |
137 | alg = ALG_CCMP; | ||
138 | break; | ||
139 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
140 | alg = ALG_AES_CMAC; | ||
141 | break; | 124 | break; |
142 | default: | 125 | default: |
143 | return -EINVAL; | 126 | break; |
144 | } | 127 | } |
145 | 128 | ||
146 | /* reject WEP and TKIP keys if WEP failed to initialize */ | 129 | key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, |
147 | if ((alg == ALG_WEP || alg == ALG_TKIP) && | 130 | params->key, params->seq_len, params->seq); |
148 | IS_ERR(sdata->local->wep_tx_tfm)) | 131 | if (IS_ERR(key)) |
149 | return -EINVAL; | 132 | return PTR_ERR(key); |
150 | |||
151 | key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key, | ||
152 | params->seq_len, params->seq); | ||
153 | if (!key) | ||
154 | return -ENOMEM; | ||
155 | 133 | ||
156 | mutex_lock(&sdata->local->sta_mtx); | 134 | mutex_lock(&sdata->local->sta_mtx); |
157 | 135 | ||
@@ -164,9 +142,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
164 | } | 142 | } |
165 | } | 143 | } |
166 | 144 | ||
167 | ieee80211_key_link(key, sdata, sta); | 145 | err = ieee80211_key_link(key, sdata, sta); |
146 | if (err) | ||
147 | ieee80211_key_free(sdata->local, key); | ||
168 | 148 | ||
169 | err = 0; | ||
170 | out_unlock: | 149 | out_unlock: |
171 | mutex_unlock(&sdata->local->sta_mtx); | 150 | mutex_unlock(&sdata->local->sta_mtx); |
172 | 151 | ||
@@ -247,10 +226,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
247 | 226 | ||
248 | memset(¶ms, 0, sizeof(params)); | 227 | memset(¶ms, 0, sizeof(params)); |
249 | 228 | ||
250 | switch (key->conf.alg) { | 229 | params.cipher = key->conf.cipher; |
251 | case ALG_TKIP: | ||
252 | params.cipher = WLAN_CIPHER_SUITE_TKIP; | ||
253 | 230 | ||
231 | switch (key->conf.cipher) { | ||
232 | case WLAN_CIPHER_SUITE_TKIP: | ||
254 | iv32 = key->u.tkip.tx.iv32; | 233 | iv32 = key->u.tkip.tx.iv32; |
255 | iv16 = key->u.tkip.tx.iv16; | 234 | iv16 = key->u.tkip.tx.iv16; |
256 | 235 | ||
@@ -268,8 +247,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
268 | params.seq = seq; | 247 | params.seq = seq; |
269 | params.seq_len = 6; | 248 | params.seq_len = 6; |
270 | break; | 249 | break; |
271 | case ALG_CCMP: | 250 | case WLAN_CIPHER_SUITE_CCMP: |
272 | params.cipher = WLAN_CIPHER_SUITE_CCMP; | ||
273 | seq[0] = key->u.ccmp.tx_pn[5]; | 251 | seq[0] = key->u.ccmp.tx_pn[5]; |
274 | seq[1] = key->u.ccmp.tx_pn[4]; | 252 | seq[1] = key->u.ccmp.tx_pn[4]; |
275 | seq[2] = key->u.ccmp.tx_pn[3]; | 253 | seq[2] = key->u.ccmp.tx_pn[3]; |
@@ -279,14 +257,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
279 | params.seq = seq; | 257 | params.seq = seq; |
280 | params.seq_len = 6; | 258 | params.seq_len = 6; |
281 | break; | 259 | break; |
282 | case ALG_WEP: | 260 | case WLAN_CIPHER_SUITE_AES_CMAC: |
283 | if (key->conf.keylen == 5) | ||
284 | params.cipher = WLAN_CIPHER_SUITE_WEP40; | ||
285 | else | ||
286 | params.cipher = WLAN_CIPHER_SUITE_WEP104; | ||
287 | break; | ||
288 | case ALG_AES_CMAC: | ||
289 | params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; | ||
290 | seq[0] = key->u.aes_cmac.tx_pn[5]; | 261 | seq[0] = key->u.aes_cmac.tx_pn[5]; |
291 | seq[1] = key->u.aes_cmac.tx_pn[4]; | 262 | seq[1] = key->u.aes_cmac.tx_pn[4]; |
292 | seq[2] = key->u.aes_cmac.tx_pn[3]; | 263 | seq[2] = key->u.aes_cmac.tx_pn[3]; |
@@ -634,6 +605,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
634 | struct sta_info *sta, | 605 | struct sta_info *sta, |
635 | struct station_parameters *params) | 606 | struct station_parameters *params) |
636 | { | 607 | { |
608 | unsigned long flags; | ||
637 | u32 rates; | 609 | u32 rates; |
638 | int i, j; | 610 | int i, j; |
639 | struct ieee80211_supported_band *sband; | 611 | struct ieee80211_supported_band *sband; |
@@ -642,7 +614,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
642 | 614 | ||
643 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 615 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
644 | 616 | ||
645 | spin_lock_bh(&sta->lock); | 617 | spin_lock_irqsave(&sta->flaglock, flags); |
646 | mask = params->sta_flags_mask; | 618 | mask = params->sta_flags_mask; |
647 | set = params->sta_flags_set; | 619 | set = params->sta_flags_set; |
648 | 620 | ||
@@ -669,7 +641,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
669 | if (set & BIT(NL80211_STA_FLAG_MFP)) | 641 | if (set & BIT(NL80211_STA_FLAG_MFP)) |
670 | sta->flags |= WLAN_STA_MFP; | 642 | sta->flags |= WLAN_STA_MFP; |
671 | } | 643 | } |
672 | spin_unlock_bh(&sta->lock); | 644 | spin_unlock_irqrestore(&sta->flaglock, flags); |
673 | 645 | ||
674 | /* | 646 | /* |
675 | * cfg80211 validates this (1-2007) and allows setting the AID | 647 | * cfg80211 validates this (1-2007) and allows setting the AID |
@@ -1143,9 +1115,9 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1143 | p.uapsd = false; | 1115 | p.uapsd = false; |
1144 | 1116 | ||
1145 | if (drv_conf_tx(local, params->queue, &p)) { | 1117 | if (drv_conf_tx(local, params->queue, &p)) { |
1146 | printk(KERN_DEBUG "%s: failed to set TX queue " | 1118 | wiphy_debug(local->hw.wiphy, |
1147 | "parameters for queue %d\n", | 1119 | "failed to set TX queue parameters for queue %d\n", |
1148 | wiphy_name(local->hw.wiphy), params->queue); | 1120 | params->queue); |
1149 | return -EINVAL; | 1121 | return -EINVAL; |
1150 | } | 1122 | } |
1151 | 1123 | ||
@@ -1207,15 +1179,26 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1207 | struct net_device *dev, | 1179 | struct net_device *dev, |
1208 | struct cfg80211_scan_request *req) | 1180 | struct cfg80211_scan_request *req) |
1209 | { | 1181 | { |
1210 | struct ieee80211_sub_if_data *sdata; | 1182 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1211 | |||
1212 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1213 | 1183 | ||
1214 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 1184 | switch (ieee80211_vif_type_p2p(&sdata->vif)) { |
1215 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1185 | case NL80211_IFTYPE_STATION: |
1216 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && | 1186 | case NL80211_IFTYPE_ADHOC: |
1217 | (sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon)) | 1187 | case NL80211_IFTYPE_MESH_POINT: |
1188 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1189 | break; | ||
1190 | case NL80211_IFTYPE_P2P_GO: | ||
1191 | if (sdata->local->ops->hw_scan) | ||
1192 | break; | ||
1193 | /* FIXME: implement NoA while scanning in software */ | ||
1218 | return -EOPNOTSUPP; | 1194 | return -EOPNOTSUPP; |
1195 | case NL80211_IFTYPE_AP: | ||
1196 | if (sdata->u.ap.beacon) | ||
1197 | return -EOPNOTSUPP; | ||
1198 | break; | ||
1199 | default: | ||
1200 | return -EOPNOTSUPP; | ||
1201 | } | ||
1219 | 1202 | ||
1220 | return ieee80211_request_scan(sdata, req); | 1203 | return ieee80211_request_scan(sdata, req); |
1221 | } | 1204 | } |
@@ -1411,7 +1394,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
1411 | if (!sdata->u.mgd.associated || | 1394 | if (!sdata->u.mgd.associated || |
1412 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { | 1395 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { |
1413 | mutex_lock(&sdata->local->iflist_mtx); | 1396 | mutex_lock(&sdata->local->iflist_mtx); |
1414 | ieee80211_recalc_smps(sdata->local, sdata); | 1397 | ieee80211_recalc_smps(sdata->local); |
1415 | mutex_unlock(&sdata->local->iflist_mtx); | 1398 | mutex_unlock(&sdata->local->iflist_mtx); |
1416 | return 0; | 1399 | return 0; |
1417 | } | 1400 | } |
@@ -1541,11 +1524,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | |||
1541 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | 1524 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); |
1542 | } | 1525 | } |
1543 | 1526 | ||
1544 | static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, | 1527 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, |
1545 | struct ieee80211_channel *chan, | 1528 | struct ieee80211_channel *chan, |
1546 | enum nl80211_channel_type channel_type, | 1529 | enum nl80211_channel_type channel_type, |
1547 | bool channel_type_valid, | 1530 | bool channel_type_valid, |
1548 | const u8 *buf, size_t len, u64 *cookie) | 1531 | const u8 *buf, size_t len, u64 *cookie) |
1549 | { | 1532 | { |
1550 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1533 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1551 | struct ieee80211_local *local = sdata->local; | 1534 | struct ieee80211_local *local = sdata->local; |
@@ -1566,7 +1549,11 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, | |||
1566 | 1549 | ||
1567 | switch (sdata->vif.type) { | 1550 | switch (sdata->vif.type) { |
1568 | case NL80211_IFTYPE_ADHOC: | 1551 | case NL80211_IFTYPE_ADHOC: |
1569 | if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) | 1552 | case NL80211_IFTYPE_AP: |
1553 | case NL80211_IFTYPE_AP_VLAN: | ||
1554 | case NL80211_IFTYPE_P2P_GO: | ||
1555 | if (!ieee80211_is_action(mgmt->frame_control) || | ||
1556 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) | ||
1570 | break; | 1557 | break; |
1571 | rcu_read_lock(); | 1558 | rcu_read_lock(); |
1572 | sta = sta_info_get(sdata, mgmt->da); | 1559 | sta = sta_info_get(sdata, mgmt->da); |
@@ -1575,8 +1562,7 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, | |||
1575 | return -ENOLINK; | 1562 | return -ENOLINK; |
1576 | break; | 1563 | break; |
1577 | case NL80211_IFTYPE_STATION: | 1564 | case NL80211_IFTYPE_STATION: |
1578 | if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED)) | 1565 | case NL80211_IFTYPE_P2P_CLIENT: |
1579 | flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
1580 | break; | 1566 | break; |
1581 | default: | 1567 | default: |
1582 | return -EOPNOTSUPP; | 1568 | return -EOPNOTSUPP; |
@@ -1647,6 +1633,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1647 | .set_bitrate_mask = ieee80211_set_bitrate_mask, | 1633 | .set_bitrate_mask = ieee80211_set_bitrate_mask, |
1648 | .remain_on_channel = ieee80211_remain_on_channel, | 1634 | .remain_on_channel = ieee80211_remain_on_channel, |
1649 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | 1635 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, |
1650 | .action = ieee80211_action, | 1636 | .mgmt_tx = ieee80211_mgmt_tx, |
1651 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, | 1637 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, |
1652 | }; | 1638 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 32be11e4c4d..5b24740fc0b 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -11,7 +11,7 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local, | |||
11 | { | 11 | { |
12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
13 | 13 | ||
14 | WARN_ON(!mutex_is_locked(&local->iflist_mtx)); | 14 | lockdep_assert_held(&local->iflist_mtx); |
15 | 15 | ||
16 | list_for_each_entry(sdata, &local->interfaces, list) { | 16 | list_for_each_entry(sdata, &local->interfaces, list) { |
17 | if (sdata == ignore) | 17 | if (sdata == ignore) |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index a694c593ff6..ebd5b69f562 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -85,13 +85,15 @@ static ssize_t tsf_write(struct file *file, | |||
85 | if (strncmp(buf, "reset", 5) == 0) { | 85 | if (strncmp(buf, "reset", 5) == 0) { |
86 | if (local->ops->reset_tsf) { | 86 | if (local->ops->reset_tsf) { |
87 | drv_reset_tsf(local); | 87 | drv_reset_tsf(local); |
88 | printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy)); | 88 | wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); |
89 | } | 89 | } |
90 | } else { | 90 | } else { |
91 | tsf = simple_strtoul(buf, NULL, 0); | 91 | tsf = simple_strtoul(buf, NULL, 0); |
92 | if (local->ops->set_tsf) { | 92 | if (local->ops->set_tsf) { |
93 | drv_set_tsf(local, tsf); | 93 | drv_set_tsf(local, tsf); |
94 | printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf); | 94 | wiphy_info(local->hw.wiphy, |
95 | "debugfs set TSF to %#018llx\n", tsf); | ||
96 | |||
95 | } | 97 | } |
96 | } | 98 | } |
97 | 99 | ||
@@ -366,7 +368,6 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
366 | if (!phyd) | 368 | if (!phyd) |
367 | return; | 369 | return; |
368 | 370 | ||
369 | local->debugfs.stations = debugfs_create_dir("stations", phyd); | ||
370 | local->debugfs.keys = debugfs_create_dir("keys", phyd); | 371 | local->debugfs.keys = debugfs_create_dir("keys", phyd); |
371 | 372 | ||
372 | DEBUGFS_ADD(frequency); | 373 | DEBUGFS_ADD(frequency); |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index fa5e76e658e..1647f8dc5cd 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -64,26 +64,13 @@ static ssize_t key_algorithm_read(struct file *file, | |||
64 | char __user *userbuf, | 64 | char __user *userbuf, |
65 | size_t count, loff_t *ppos) | 65 | size_t count, loff_t *ppos) |
66 | { | 66 | { |
67 | char *alg; | 67 | char buf[15]; |
68 | struct ieee80211_key *key = file->private_data; | 68 | struct ieee80211_key *key = file->private_data; |
69 | u32 c = key->conf.cipher; | ||
69 | 70 | ||
70 | switch (key->conf.alg) { | 71 | sprintf(buf, "%.2x-%.2x-%.2x:%d\n", |
71 | case ALG_WEP: | 72 | c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff); |
72 | alg = "WEP\n"; | 73 | return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); |
73 | break; | ||
74 | case ALG_TKIP: | ||
75 | alg = "TKIP\n"; | ||
76 | break; | ||
77 | case ALG_CCMP: | ||
78 | alg = "CCMP\n"; | ||
79 | break; | ||
80 | case ALG_AES_CMAC: | ||
81 | alg = "AES-128-CMAC\n"; | ||
82 | break; | ||
83 | default: | ||
84 | return 0; | ||
85 | } | ||
86 | return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg)); | ||
87 | } | 74 | } |
88 | KEY_OPS(algorithm); | 75 | KEY_OPS(algorithm); |
89 | 76 | ||
@@ -95,21 +82,22 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | |||
95 | int len; | 82 | int len; |
96 | struct ieee80211_key *key = file->private_data; | 83 | struct ieee80211_key *key = file->private_data; |
97 | 84 | ||
98 | switch (key->conf.alg) { | 85 | switch (key->conf.cipher) { |
99 | case ALG_WEP: | 86 | case WLAN_CIPHER_SUITE_WEP40: |
87 | case WLAN_CIPHER_SUITE_WEP104: | ||
100 | len = scnprintf(buf, sizeof(buf), "\n"); | 88 | len = scnprintf(buf, sizeof(buf), "\n"); |
101 | break; | 89 | break; |
102 | case ALG_TKIP: | 90 | case WLAN_CIPHER_SUITE_TKIP: |
103 | len = scnprintf(buf, sizeof(buf), "%08x %04x\n", | 91 | len = scnprintf(buf, sizeof(buf), "%08x %04x\n", |
104 | key->u.tkip.tx.iv32, | 92 | key->u.tkip.tx.iv32, |
105 | key->u.tkip.tx.iv16); | 93 | key->u.tkip.tx.iv16); |
106 | break; | 94 | break; |
107 | case ALG_CCMP: | 95 | case WLAN_CIPHER_SUITE_CCMP: |
108 | tpn = key->u.ccmp.tx_pn; | 96 | tpn = key->u.ccmp.tx_pn; |
109 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | 97 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", |
110 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); | 98 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); |
111 | break; | 99 | break; |
112 | case ALG_AES_CMAC: | 100 | case WLAN_CIPHER_SUITE_AES_CMAC: |
113 | tpn = key->u.aes_cmac.tx_pn; | 101 | tpn = key->u.aes_cmac.tx_pn; |
114 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | 102 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", |
115 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], | 103 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], |
@@ -130,11 +118,12 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
130 | int i, len; | 118 | int i, len; |
131 | const u8 *rpn; | 119 | const u8 *rpn; |
132 | 120 | ||
133 | switch (key->conf.alg) { | 121 | switch (key->conf.cipher) { |
134 | case ALG_WEP: | 122 | case WLAN_CIPHER_SUITE_WEP40: |
123 | case WLAN_CIPHER_SUITE_WEP104: | ||
135 | len = scnprintf(buf, sizeof(buf), "\n"); | 124 | len = scnprintf(buf, sizeof(buf), "\n"); |
136 | break; | 125 | break; |
137 | case ALG_TKIP: | 126 | case WLAN_CIPHER_SUITE_TKIP: |
138 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 127 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) |
139 | p += scnprintf(p, sizeof(buf)+buf-p, | 128 | p += scnprintf(p, sizeof(buf)+buf-p, |
140 | "%08x %04x\n", | 129 | "%08x %04x\n", |
@@ -142,7 +131,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
142 | key->u.tkip.rx[i].iv16); | 131 | key->u.tkip.rx[i].iv16); |
143 | len = p - buf; | 132 | len = p - buf; |
144 | break; | 133 | break; |
145 | case ALG_CCMP: | 134 | case WLAN_CIPHER_SUITE_CCMP: |
146 | for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) { | 135 | for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) { |
147 | rpn = key->u.ccmp.rx_pn[i]; | 136 | rpn = key->u.ccmp.rx_pn[i]; |
148 | p += scnprintf(p, sizeof(buf)+buf-p, | 137 | p += scnprintf(p, sizeof(buf)+buf-p, |
@@ -152,7 +141,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
152 | } | 141 | } |
153 | len = p - buf; | 142 | len = p - buf; |
154 | break; | 143 | break; |
155 | case ALG_AES_CMAC: | 144 | case WLAN_CIPHER_SUITE_AES_CMAC: |
156 | rpn = key->u.aes_cmac.rx_pn; | 145 | rpn = key->u.aes_cmac.rx_pn; |
157 | p += scnprintf(p, sizeof(buf)+buf-p, | 146 | p += scnprintf(p, sizeof(buf)+buf-p, |
158 | "%02x%02x%02x%02x%02x%02x\n", | 147 | "%02x%02x%02x%02x%02x%02x\n", |
@@ -174,11 +163,11 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf, | |||
174 | char buf[20]; | 163 | char buf[20]; |
175 | int len; | 164 | int len; |
176 | 165 | ||
177 | switch (key->conf.alg) { | 166 | switch (key->conf.cipher) { |
178 | case ALG_CCMP: | 167 | case WLAN_CIPHER_SUITE_CCMP: |
179 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | 168 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); |
180 | break; | 169 | break; |
181 | case ALG_AES_CMAC: | 170 | case WLAN_CIPHER_SUITE_AES_CMAC: |
182 | len = scnprintf(buf, sizeof(buf), "%u\n", | 171 | len = scnprintf(buf, sizeof(buf), "%u\n", |
183 | key->u.aes_cmac.replays); | 172 | key->u.aes_cmac.replays); |
184 | break; | 173 | break; |
@@ -196,8 +185,8 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, | |||
196 | char buf[20]; | 185 | char buf[20]; |
197 | int len; | 186 | int len; |
198 | 187 | ||
199 | switch (key->conf.alg) { | 188 | switch (key->conf.cipher) { |
200 | case ALG_AES_CMAC: | 189 | case WLAN_CIPHER_SUITE_AES_CMAC: |
201 | len = scnprintf(buf, sizeof(buf), "%u\n", | 190 | len = scnprintf(buf, sizeof(buf), "%u\n", |
202 | key->u.aes_cmac.icverrors); | 191 | key->u.aes_cmac.icverrors); |
203 | break; | 192 | break; |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 20b2998fa0e..3e12430591b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -409,6 +409,9 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) | |||
409 | sprintf(buf, "netdev:%s", sdata->name); | 409 | sprintf(buf, "netdev:%s", sdata->name); |
410 | sdata->debugfs.dir = debugfs_create_dir(buf, | 410 | sdata->debugfs.dir = debugfs_create_dir(buf, |
411 | sdata->local->hw.wiphy->debugfsdir); | 411 | sdata->local->hw.wiphy->debugfsdir); |
412 | if (sdata->debugfs.dir) | ||
413 | sdata->debugfs.subdir_stations = debugfs_create_dir("stations", | ||
414 | sdata->debugfs.dir); | ||
412 | add_files(sdata); | 415 | add_files(sdata); |
413 | } | 416 | } |
414 | 417 | ||
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 76839d4dfaa..6b7ff9fb460 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -300,7 +300,7 @@ STA_OPS(ht_capa); | |||
300 | 300 | ||
301 | void ieee80211_sta_debugfs_add(struct sta_info *sta) | 301 | void ieee80211_sta_debugfs_add(struct sta_info *sta) |
302 | { | 302 | { |
303 | struct dentry *stations_dir = sta->local->debugfs.stations; | 303 | struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; |
304 | u8 mac[3*ETH_ALEN]; | 304 | u8 mac[3*ETH_ALEN]; |
305 | 305 | ||
306 | sta->debugfs.add_has_run = true; | 306 | sta->debugfs.add_has_run = true; |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 14123dce544..16983825f8e 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -54,6 +54,20 @@ static inline int drv_add_interface(struct ieee80211_local *local, | |||
54 | return ret; | 54 | return ret; |
55 | } | 55 | } |
56 | 56 | ||
57 | static inline int drv_change_interface(struct ieee80211_local *local, | ||
58 | struct ieee80211_sub_if_data *sdata, | ||
59 | enum nl80211_iftype type, bool p2p) | ||
60 | { | ||
61 | int ret; | ||
62 | |||
63 | might_sleep(); | ||
64 | |||
65 | trace_drv_change_interface(local, sdata, type, p2p); | ||
66 | ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p); | ||
67 | trace_drv_return_int(local, ret); | ||
68 | return ret; | ||
69 | } | ||
70 | |||
57 | static inline void drv_remove_interface(struct ieee80211_local *local, | 71 | static inline void drv_remove_interface(struct ieee80211_local *local, |
58 | struct ieee80211_vif *vif) | 72 | struct ieee80211_vif *vif) |
59 | { | 73 | { |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 5d5d2a97466..6831fb1641c 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -25,12 +25,14 @@ static inline void trace_ ## name(proto) {} | |||
25 | #define STA_PR_FMT " sta:%pM" | 25 | #define STA_PR_FMT " sta:%pM" |
26 | #define STA_PR_ARG __entry->sta_addr | 26 | #define STA_PR_ARG __entry->sta_addr |
27 | 27 | ||
28 | #define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \ | 28 | #define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \ |
29 | __field(bool, p2p) \ | ||
29 | __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") | 30 | __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") |
30 | #define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ | 31 | #define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ |
32 | __entry->p2p = sdata->vif.p2p; \ | ||
31 | __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") | 33 | __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") |
32 | #define VIF_PR_FMT " vif:%s(%d)" | 34 | #define VIF_PR_FMT " vif:%s(%d%s)" |
33 | #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type | 35 | #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" |
34 | 36 | ||
35 | /* | 37 | /* |
36 | * Tracing for driver callbacks. | 38 | * Tracing for driver callbacks. |
@@ -136,6 +138,34 @@ TRACE_EVENT(drv_add_interface, | |||
136 | ) | 138 | ) |
137 | ); | 139 | ); |
138 | 140 | ||
141 | TRACE_EVENT(drv_change_interface, | ||
142 | TP_PROTO(struct ieee80211_local *local, | ||
143 | struct ieee80211_sub_if_data *sdata, | ||
144 | enum nl80211_iftype type, bool p2p), | ||
145 | |||
146 | TP_ARGS(local, sdata, type, p2p), | ||
147 | |||
148 | TP_STRUCT__entry( | ||
149 | LOCAL_ENTRY | ||
150 | VIF_ENTRY | ||
151 | __field(u32, new_type) | ||
152 | __field(bool, new_p2p) | ||
153 | ), | ||
154 | |||
155 | TP_fast_assign( | ||
156 | LOCAL_ASSIGN; | ||
157 | VIF_ASSIGN; | ||
158 | __entry->new_type = type; | ||
159 | __entry->new_p2p = p2p; | ||
160 | ), | ||
161 | |||
162 | TP_printk( | ||
163 | LOCAL_PR_FMT VIF_PR_FMT " new type:%d%s", | ||
164 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type, | ||
165 | __entry->new_p2p ? "/p2p" : "" | ||
166 | ) | ||
167 | ); | ||
168 | |||
139 | TRACE_EVENT(drv_remove_interface, | 169 | TRACE_EVENT(drv_remove_interface, |
140 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), | 170 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), |
141 | 171 | ||
@@ -336,7 +366,7 @@ TRACE_EVENT(drv_set_key, | |||
336 | LOCAL_ENTRY | 366 | LOCAL_ENTRY |
337 | VIF_ENTRY | 367 | VIF_ENTRY |
338 | STA_ENTRY | 368 | STA_ENTRY |
339 | __field(enum ieee80211_key_alg, alg) | 369 | __field(u32, cipher) |
340 | __field(u8, hw_key_idx) | 370 | __field(u8, hw_key_idx) |
341 | __field(u8, flags) | 371 | __field(u8, flags) |
342 | __field(s8, keyidx) | 372 | __field(s8, keyidx) |
@@ -346,7 +376,7 @@ TRACE_EVENT(drv_set_key, | |||
346 | LOCAL_ASSIGN; | 376 | LOCAL_ASSIGN; |
347 | VIF_ASSIGN; | 377 | VIF_ASSIGN; |
348 | STA_ASSIGN; | 378 | STA_ASSIGN; |
349 | __entry->alg = key->alg; | 379 | __entry->cipher = key->cipher; |
350 | __entry->flags = key->flags; | 380 | __entry->flags = key->flags; |
351 | __entry->keyidx = key->keyidx; | 381 | __entry->keyidx = key->keyidx; |
352 | __entry->hw_key_idx = key->hw_key_idx; | 382 | __entry->hw_key_idx = key->hw_key_idx; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 9d101fb3386..11f74f5f7b2 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -265,3 +265,31 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, | |||
265 | 265 | ||
266 | return 0; | 266 | return 0; |
267 | } | 267 | } |
268 | |||
269 | void ieee80211_request_smps_work(struct work_struct *work) | ||
270 | { | ||
271 | struct ieee80211_sub_if_data *sdata = | ||
272 | container_of(work, struct ieee80211_sub_if_data, | ||
273 | u.mgd.request_smps_work); | ||
274 | |||
275 | mutex_lock(&sdata->u.mgd.mtx); | ||
276 | __ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode); | ||
277 | mutex_unlock(&sdata->u.mgd.mtx); | ||
278 | } | ||
279 | |||
280 | void ieee80211_request_smps(struct ieee80211_vif *vif, | ||
281 | enum ieee80211_smps_mode smps_mode) | ||
282 | { | ||
283 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
284 | |||
285 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
286 | return; | ||
287 | |||
288 | if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) | ||
289 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
290 | |||
291 | ieee80211_queue_work(&sdata->local->hw, | ||
292 | &sdata->u.mgd.request_smps_work); | ||
293 | } | ||
294 | /* this might change ... don't want non-open drivers using it */ | ||
295 | EXPORT_SYMBOL_GPL(ieee80211_request_smps); | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c691780725a..ff60c022f51 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -173,6 +173,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
173 | memcpy(skb_put(skb, ifibss->ie_len), | 173 | memcpy(skb_put(skb, ifibss->ie_len), |
174 | ifibss->ie, ifibss->ie_len); | 174 | ifibss->ie, ifibss->ie_len); |
175 | 175 | ||
176 | if (local->hw.queues >= 4) { | ||
177 | pos = skb_put(skb, 9); | ||
178 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
179 | *pos++ = 7; /* len */ | ||
180 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
181 | *pos++ = 0x50; | ||
182 | *pos++ = 0xf2; | ||
183 | *pos++ = 2; /* WME */ | ||
184 | *pos++ = 0; /* WME info */ | ||
185 | *pos++ = 1; /* WME ver */ | ||
186 | *pos++ = 0; /* U-APSD no in use */ | ||
187 | } | ||
188 | |||
176 | rcu_assign_pointer(ifibss->presp, skb); | 189 | rcu_assign_pointer(ifibss->presp, skb); |
177 | 190 | ||
178 | sdata->vif.bss_conf.beacon_int = beacon_int; | 191 | sdata->vif.bss_conf.beacon_int = beacon_int; |
@@ -266,37 +279,45 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
266 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 279 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
267 | return; | 280 | return; |
268 | 281 | ||
269 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && | 282 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
270 | memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) { | 283 | memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) { |
271 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
272 | 284 | ||
273 | rcu_read_lock(); | 285 | rcu_read_lock(); |
274 | |||
275 | sta = sta_info_get(sdata, mgmt->sa); | 286 | sta = sta_info_get(sdata, mgmt->sa); |
276 | if (sta) { | ||
277 | u32 prev_rates; | ||
278 | 287 | ||
279 | prev_rates = sta->sta.supp_rates[band]; | 288 | if (elems->supp_rates) { |
280 | /* make sure mandatory rates are always added */ | 289 | supp_rates = ieee80211_sta_get_rates(local, elems, |
281 | sta->sta.supp_rates[band] = supp_rates | | 290 | band); |
282 | ieee80211_mandatory_rates(local, band); | 291 | if (sta) { |
292 | u32 prev_rates; | ||
293 | |||
294 | prev_rates = sta->sta.supp_rates[band]; | ||
295 | /* make sure mandatory rates are always added */ | ||
296 | sta->sta.supp_rates[band] = supp_rates | | ||
297 | ieee80211_mandatory_rates(local, band); | ||
283 | 298 | ||
284 | if (sta->sta.supp_rates[band] != prev_rates) { | 299 | if (sta->sta.supp_rates[band] != prev_rates) { |
285 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 300 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
286 | printk(KERN_DEBUG "%s: updated supp_rates set " | 301 | printk(KERN_DEBUG |
287 | "for %pM based on beacon/probe_response " | 302 | "%s: updated supp_rates set " |
288 | "(0x%x -> 0x%x)\n", | 303 | "for %pM based on beacon" |
289 | sdata->name, sta->sta.addr, | 304 | "/probe_resp (0x%x -> 0x%x)\n", |
290 | prev_rates, sta->sta.supp_rates[band]); | 305 | sdata->name, sta->sta.addr, |
306 | prev_rates, | ||
307 | sta->sta.supp_rates[band]); | ||
291 | #endif | 308 | #endif |
292 | rate_control_rate_init(sta); | 309 | rate_control_rate_init(sta); |
293 | } | 310 | } |
294 | rcu_read_unlock(); | 311 | } else |
295 | } else { | 312 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, |
296 | rcu_read_unlock(); | 313 | mgmt->sa, supp_rates, |
297 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, | 314 | GFP_ATOMIC); |
298 | supp_rates, GFP_KERNEL); | ||
299 | } | 315 | } |
316 | |||
317 | if (sta && elems->wmm_info) | ||
318 | set_sta_flags(sta, WLAN_STA_WME); | ||
319 | |||
320 | rcu_read_unlock(); | ||
300 | } | 321 | } |
301 | 322 | ||
302 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 323 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
@@ -427,8 +448,8 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
427 | return NULL; | 448 | return NULL; |
428 | 449 | ||
429 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 450 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
430 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", | 451 | wiphy_debug(local->hw.wiphy, "Adding new IBSS station %pM (dev=%s)\n", |
431 | wiphy_name(local->hw.wiphy), addr, sdata->name); | 452 | addr, sdata->name); |
432 | #endif | 453 | #endif |
433 | 454 | ||
434 | sta = sta_info_alloc(sdata, addr, gfp); | 455 | sta = sta_info_alloc(sdata, addr, gfp); |
@@ -920,12 +941,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
920 | memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); | 941 | memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); |
921 | sdata->u.ibss.ssid_len = params->ssid_len; | 942 | sdata->u.ibss.ssid_len = params->ssid_len; |
922 | 943 | ||
944 | mutex_unlock(&sdata->u.ibss.mtx); | ||
945 | |||
946 | mutex_lock(&sdata->local->mtx); | ||
923 | ieee80211_recalc_idle(sdata->local); | 947 | ieee80211_recalc_idle(sdata->local); |
948 | mutex_unlock(&sdata->local->mtx); | ||
924 | 949 | ||
925 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 950 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
926 | 951 | ||
927 | mutex_unlock(&sdata->u.ibss.mtx); | ||
928 | |||
929 | return 0; | 952 | return 0; |
930 | } | 953 | } |
931 | 954 | ||
@@ -980,7 +1003,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
980 | 1003 | ||
981 | mutex_unlock(&sdata->u.ibss.mtx); | 1004 | mutex_unlock(&sdata->u.ibss.mtx); |
982 | 1005 | ||
1006 | mutex_lock(&local->mtx); | ||
983 | ieee80211_recalc_idle(sdata->local); | 1007 | ieee80211_recalc_idle(sdata->local); |
1008 | mutex_unlock(&local->mtx); | ||
984 | 1009 | ||
985 | return 0; | 1010 | return 0; |
986 | } | 1011 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 65e0ed6c297..08509e21284 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -50,12 +50,6 @@ struct ieee80211_local; | |||
50 | * increased memory use (about 2 kB of RAM per entry). */ | 50 | * increased memory use (about 2 kB of RAM per entry). */ |
51 | #define IEEE80211_FRAGMENT_MAX 4 | 51 | #define IEEE80211_FRAGMENT_MAX 4 |
52 | 52 | ||
53 | /* | ||
54 | * Time after which we ignore scan results and no longer report/use | ||
55 | * them in any way. | ||
56 | */ | ||
57 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) | ||
58 | |||
59 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) | 53 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) |
60 | 54 | ||
61 | #define IEEE80211_DEFAULT_UAPSD_QUEUES \ | 55 | #define IEEE80211_DEFAULT_UAPSD_QUEUES \ |
@@ -165,12 +159,37 @@ typedef unsigned __bitwise__ ieee80211_rx_result; | |||
165 | #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) | 159 | #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) |
166 | #define RX_QUEUED ((__force ieee80211_rx_result) 3u) | 160 | #define RX_QUEUED ((__force ieee80211_rx_result) 3u) |
167 | 161 | ||
168 | #define IEEE80211_RX_IN_SCAN BIT(0) | 162 | /** |
169 | /* frame is destined to interface currently processed (incl. multicast frames) */ | 163 | * enum ieee80211_packet_rx_flags - packet RX flags |
170 | #define IEEE80211_RX_RA_MATCH BIT(1) | 164 | * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed |
171 | #define IEEE80211_RX_AMSDU BIT(2) | 165 | * (incl. multicast frames) |
172 | #define IEEE80211_RX_FRAGMENTED BIT(3) | 166 | * @IEEE80211_RX_IN_SCAN: received while scanning |
173 | /* only add flags here that do not change with subframes of an aMPDU */ | 167 | * @IEEE80211_RX_FRAGMENTED: fragmented frame |
168 | * @IEEE80211_RX_AMSDU: a-MSDU packet | ||
169 | * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed | ||
170 | * | ||
171 | * These are per-frame flags that are attached to a frame in the | ||
172 | * @rx_flags field of &struct ieee80211_rx_status. | ||
173 | */ | ||
174 | enum ieee80211_packet_rx_flags { | ||
175 | IEEE80211_RX_IN_SCAN = BIT(0), | ||
176 | IEEE80211_RX_RA_MATCH = BIT(1), | ||
177 | IEEE80211_RX_FRAGMENTED = BIT(2), | ||
178 | IEEE80211_RX_AMSDU = BIT(3), | ||
179 | IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4), | ||
180 | }; | ||
181 | |||
182 | /** | ||
183 | * enum ieee80211_rx_flags - RX data flags | ||
184 | * | ||
185 | * @IEEE80211_RX_CMNTR: received on cooked monitor already | ||
186 | * | ||
187 | * These flags are used across handling multiple interfaces | ||
188 | * for a single frame. | ||
189 | */ | ||
190 | enum ieee80211_rx_flags { | ||
191 | IEEE80211_RX_CMNTR = BIT(0), | ||
192 | }; | ||
174 | 193 | ||
175 | struct ieee80211_rx_data { | 194 | struct ieee80211_rx_data { |
176 | struct sk_buff *skb; | 195 | struct sk_buff *skb; |
@@ -343,10 +362,14 @@ struct ieee80211_if_managed { | |||
343 | unsigned long timers_running; /* used for quiesce/restart */ | 362 | unsigned long timers_running; /* used for quiesce/restart */ |
344 | bool powersave; /* powersave requested for this iface */ | 363 | bool powersave; /* powersave requested for this iface */ |
345 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ | 364 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ |
346 | ap_smps; /* smps mode AP thinks we're in */ | 365 | ap_smps, /* smps mode AP thinks we're in */ |
366 | driver_smps_mode; /* smps mode request */ | ||
367 | |||
368 | struct work_struct request_smps_work; | ||
347 | 369 | ||
348 | unsigned int flags; | 370 | unsigned int flags; |
349 | 371 | ||
372 | bool beacon_crc_valid; | ||
350 | u32 beacon_crc; | 373 | u32 beacon_crc; |
351 | 374 | ||
352 | enum { | 375 | enum { |
@@ -371,6 +394,13 @@ struct ieee80211_if_managed { | |||
371 | int ave_beacon_signal; | 394 | int ave_beacon_signal; |
372 | 395 | ||
373 | /* | 396 | /* |
397 | * Number of Beacon frames used in ave_beacon_signal. This can be used | ||
398 | * to avoid generating less reliable cqm events that would be based | ||
399 | * only on couple of received frames. | ||
400 | */ | ||
401 | unsigned int count_beacon_signal; | ||
402 | |||
403 | /* | ||
374 | * Last Beacon frame signal strength average (ave_beacon_signal / 16) | 404 | * Last Beacon frame signal strength average (ave_beacon_signal / 16) |
375 | * that triggered a cqm event. 0 indicates that no event has been | 405 | * that triggered a cqm event. 0 indicates that no event has been |
376 | * generated for the current association. | 406 | * generated for the current association. |
@@ -474,6 +504,19 @@ enum ieee80211_sub_if_data_flags { | |||
474 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), | 504 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), |
475 | }; | 505 | }; |
476 | 506 | ||
507 | /** | ||
508 | * enum ieee80211_sdata_state_bits - virtual interface state bits | ||
509 | * @SDATA_STATE_RUNNING: virtual interface is up & running; this | ||
510 | * mirrors netif_running() but is separate for interface type | ||
511 | * change handling while the interface is up | ||
512 | * @SDATA_STATE_OFFCHANNEL: This interface is currently in offchannel | ||
513 | * mode, so queues are stopped | ||
514 | */ | ||
515 | enum ieee80211_sdata_state_bits { | ||
516 | SDATA_STATE_RUNNING, | ||
517 | SDATA_STATE_OFFCHANNEL, | ||
518 | }; | ||
519 | |||
477 | struct ieee80211_sub_if_data { | 520 | struct ieee80211_sub_if_data { |
478 | struct list_head list; | 521 | struct list_head list; |
479 | 522 | ||
@@ -487,6 +530,8 @@ struct ieee80211_sub_if_data { | |||
487 | 530 | ||
488 | unsigned int flags; | 531 | unsigned int flags; |
489 | 532 | ||
533 | unsigned long state; | ||
534 | |||
490 | int drop_unencrypted; | 535 | int drop_unencrypted; |
491 | 536 | ||
492 | char name[IFNAMSIZ]; | 537 | char name[IFNAMSIZ]; |
@@ -497,6 +542,9 @@ struct ieee80211_sub_if_data { | |||
497 | */ | 542 | */ |
498 | bool ht_opmode_valid; | 543 | bool ht_opmode_valid; |
499 | 544 | ||
545 | /* to detect idle changes */ | ||
546 | bool old_idle; | ||
547 | |||
500 | /* Fragment table for host-based reassembly */ | 548 | /* Fragment table for host-based reassembly */ |
501 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 549 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
502 | unsigned int fragment_next; | 550 | unsigned int fragment_next; |
@@ -508,6 +556,8 @@ struct ieee80211_sub_if_data { | |||
508 | struct ieee80211_key *default_mgmt_key; | 556 | struct ieee80211_key *default_mgmt_key; |
509 | 557 | ||
510 | u16 sequence_number; | 558 | u16 sequence_number; |
559 | __be16 control_port_protocol; | ||
560 | bool control_port_no_encrypt; | ||
511 | 561 | ||
512 | struct work_struct work; | 562 | struct work_struct work; |
513 | struct sk_buff_head skb_queue; | 563 | struct sk_buff_head skb_queue; |
@@ -539,6 +589,7 @@ struct ieee80211_sub_if_data { | |||
539 | #ifdef CONFIG_MAC80211_DEBUGFS | 589 | #ifdef CONFIG_MAC80211_DEBUGFS |
540 | struct { | 590 | struct { |
541 | struct dentry *dir; | 591 | struct dentry *dir; |
592 | struct dentry *subdir_stations; | ||
542 | struct dentry *default_key; | 593 | struct dentry *default_key; |
543 | struct dentry *default_mgmt_key; | 594 | struct dentry *default_mgmt_key; |
544 | } debugfs; | 595 | } debugfs; |
@@ -595,11 +646,17 @@ enum queue_stop_reason { | |||
595 | * determine if we are on the operating channel or not | 646 | * determine if we are on the operating channel or not |
596 | * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning, | 647 | * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning, |
597 | * gets only set in conjunction with SCAN_SW_SCANNING | 648 | * gets only set in conjunction with SCAN_SW_SCANNING |
649 | * @SCAN_COMPLETED: Set for our scan work function when the driver reported | ||
650 | * that the scan completed. | ||
651 | * @SCAN_ABORTED: Set for our scan work function when the driver reported | ||
652 | * a scan complete for an aborted scan. | ||
598 | */ | 653 | */ |
599 | enum { | 654 | enum { |
600 | SCAN_SW_SCANNING, | 655 | SCAN_SW_SCANNING, |
601 | SCAN_HW_SCANNING, | 656 | SCAN_HW_SCANNING, |
602 | SCAN_OFF_CHANNEL, | 657 | SCAN_OFF_CHANNEL, |
658 | SCAN_COMPLETED, | ||
659 | SCAN_ABORTED, | ||
603 | }; | 660 | }; |
604 | 661 | ||
605 | /** | 662 | /** |
@@ -634,7 +691,6 @@ struct ieee80211_local { | |||
634 | /* | 691 | /* |
635 | * work stuff, potentially off-channel (in the future) | 692 | * work stuff, potentially off-channel (in the future) |
636 | */ | 693 | */ |
637 | struct mutex work_mtx; | ||
638 | struct list_head work_list; | 694 | struct list_head work_list; |
639 | struct timer_list work_timer; | 695 | struct timer_list work_timer; |
640 | struct work_struct work_work; | 696 | struct work_struct work_work; |
@@ -656,6 +712,8 @@ struct ieee80211_local { | |||
656 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; | 712 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; |
657 | unsigned int filter_flags; /* FIF_* */ | 713 | unsigned int filter_flags; /* FIF_* */ |
658 | 714 | ||
715 | bool wiphy_ciphers_allocated; | ||
716 | |||
659 | /* protects the aggregated multicast list and filter calls */ | 717 | /* protects the aggregated multicast list and filter calls */ |
660 | spinlock_t filter_lock; | 718 | spinlock_t filter_lock; |
661 | 719 | ||
@@ -746,9 +804,10 @@ struct ieee80211_local { | |||
746 | */ | 804 | */ |
747 | struct mutex key_mtx; | 805 | struct mutex key_mtx; |
748 | 806 | ||
807 | /* mutex for scan and work locking */ | ||
808 | struct mutex mtx; | ||
749 | 809 | ||
750 | /* Scanning and BSS list */ | 810 | /* Scanning and BSS list */ |
751 | struct mutex scan_mtx; | ||
752 | unsigned long scanning; | 811 | unsigned long scanning; |
753 | struct cfg80211_ssid scan_ssid; | 812 | struct cfg80211_ssid scan_ssid; |
754 | struct cfg80211_scan_request *int_scan_req; | 813 | struct cfg80211_scan_request *int_scan_req; |
@@ -866,10 +925,14 @@ struct ieee80211_local { | |||
866 | #ifdef CONFIG_MAC80211_DEBUGFS | 925 | #ifdef CONFIG_MAC80211_DEBUGFS |
867 | struct local_debugfsdentries { | 926 | struct local_debugfsdentries { |
868 | struct dentry *rcdir; | 927 | struct dentry *rcdir; |
869 | struct dentry *stations; | ||
870 | struct dentry *keys; | 928 | struct dentry *keys; |
871 | } debugfs; | 929 | } debugfs; |
872 | #endif | 930 | #endif |
931 | |||
932 | /* dummy netdev for use w/ NAPI */ | ||
933 | struct net_device napi_dev; | ||
934 | |||
935 | struct napi_struct napi; | ||
873 | }; | 936 | }; |
874 | 937 | ||
875 | static inline struct ieee80211_sub_if_data * | 938 | static inline struct ieee80211_sub_if_data * |
@@ -1003,6 +1066,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | |||
1003 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); | 1066 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); |
1004 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1067 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1005 | struct sk_buff *skb); | 1068 | struct sk_buff *skb); |
1069 | void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata); | ||
1070 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); | ||
1006 | 1071 | ||
1007 | /* IBSS code */ | 1072 | /* IBSS code */ |
1008 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 1073 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); |
@@ -1068,10 +1133,12 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); | |||
1068 | void ieee80211_remove_interfaces(struct ieee80211_local *local); | 1133 | void ieee80211_remove_interfaces(struct ieee80211_local *local); |
1069 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); | 1134 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); |
1070 | void ieee80211_recalc_idle(struct ieee80211_local *local); | 1135 | void ieee80211_recalc_idle(struct ieee80211_local *local); |
1136 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | ||
1137 | const int offset); | ||
1071 | 1138 | ||
1072 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1139 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) |
1073 | { | 1140 | { |
1074 | return netif_running(sdata->dev); | 1141 | return test_bit(SDATA_STATE_RUNNING, &sdata->state); |
1075 | } | 1142 | } |
1076 | 1143 | ||
1077 | /* tx handling */ | 1144 | /* tx handling */ |
@@ -1105,6 +1172,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
1105 | int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, | 1172 | int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, |
1106 | enum ieee80211_smps_mode smps, const u8 *da, | 1173 | enum ieee80211_smps_mode smps, const u8 *da, |
1107 | const u8 *bssid); | 1174 | const u8 *bssid); |
1175 | void ieee80211_request_smps_work(struct work_struct *work); | ||
1108 | 1176 | ||
1109 | void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 1177 | void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, |
1110 | u16 initiator, u16 reason); | 1178 | u16 initiator, u16 reason); |
@@ -1131,6 +1199,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); | |||
1131 | void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); | 1199 | void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); |
1132 | void ieee80211_ba_session_work(struct work_struct *work); | 1200 | void ieee80211_ba_session_work(struct work_struct *work); |
1133 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid); | 1201 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid); |
1202 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid); | ||
1134 | 1203 | ||
1135 | /* Spectrum management */ | 1204 | /* Spectrum management */ |
1136 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1205 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
@@ -1146,6 +1215,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw); | |||
1146 | 1215 | ||
1147 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) | 1216 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) |
1148 | { | 1217 | { |
1218 | struct ieee80211_local *local = hw_to_local(hw); | ||
1219 | |||
1220 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), | ||
1221 | "%s: resume with hardware scan still in progress\n", | ||
1222 | wiphy_name(hw->wiphy)); | ||
1223 | |||
1149 | return ieee80211_reconfig(hw_to_local(hw)); | 1224 | return ieee80211_reconfig(hw_to_local(hw)); |
1150 | } | 1225 | } |
1151 | #else | 1226 | #else |
@@ -1208,7 +1283,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
1208 | const u8 *key, u8 key_len, u8 key_idx); | 1283 | const u8 *key, u8 key_len, u8 key_idx); |
1209 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1284 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1210 | const u8 *ie, size_t ie_len, | 1285 | const u8 *ie, size_t ie_len, |
1211 | enum ieee80211_band band); | 1286 | enum ieee80211_band band, u32 rate_mask, |
1287 | u8 channel); | ||
1212 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1288 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
1213 | const u8 *ssid, size_t ssid_len, | 1289 | const u8 *ssid, size_t ssid_len, |
1214 | const u8 *ie, size_t ie_len); | 1290 | const u8 *ie, size_t ie_len); |
@@ -1221,8 +1297,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
1221 | enum ieee80211_band band); | 1297 | enum ieee80211_band band); |
1222 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | 1298 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, |
1223 | enum ieee80211_smps_mode smps_mode); | 1299 | enum ieee80211_smps_mode smps_mode); |
1224 | void ieee80211_recalc_smps(struct ieee80211_local *local, | 1300 | void ieee80211_recalc_smps(struct ieee80211_local *local); |
1225 | struct ieee80211_sub_if_data *forsdata); | ||
1226 | 1301 | ||
1227 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1302 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, |
1228 | const u8 *ids, int n_ids, size_t offset); | 1303 | const u8 *ids, int n_ids, size_t offset); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ebbe264e2b0..438a2f51420 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "led.h" | 24 | #include "led.h" |
25 | #include "driver-ops.h" | 25 | #include "driver-ops.h" |
26 | #include "wme.h" | 26 | #include "wme.h" |
27 | #include "rate.h" | ||
27 | 28 | ||
28 | /** | 29 | /** |
29 | * DOC: Interface list locking | 30 | * DOC: Interface list locking |
@@ -94,21 +95,14 @@ static inline int identical_mac_addr_allowed(int type1, int type2) | |||
94 | type2 == NL80211_IFTYPE_AP_VLAN)); | 95 | type2 == NL80211_IFTYPE_AP_VLAN)); |
95 | } | 96 | } |
96 | 97 | ||
97 | static int ieee80211_open(struct net_device *dev) | 98 | static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, |
99 | enum nl80211_iftype iftype) | ||
98 | { | 100 | { |
99 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
100 | struct ieee80211_sub_if_data *nsdata; | ||
101 | struct ieee80211_local *local = sdata->local; | 101 | struct ieee80211_local *local = sdata->local; |
102 | struct sta_info *sta; | 102 | struct ieee80211_sub_if_data *nsdata; |
103 | u32 changed = 0; | 103 | struct net_device *dev = sdata->dev; |
104 | int res; | ||
105 | u32 hw_reconf_flags = 0; | ||
106 | u8 null_addr[ETH_ALEN] = {0}; | ||
107 | 104 | ||
108 | /* fail early if user set an invalid address */ | 105 | ASSERT_RTNL(); |
109 | if (compare_ether_addr(dev->dev_addr, null_addr) && | ||
110 | !is_valid_ether_addr(dev->dev_addr)) | ||
111 | return -EADDRNOTAVAIL; | ||
112 | 106 | ||
113 | /* we hold the RTNL here so can safely walk the list */ | 107 | /* we hold the RTNL here so can safely walk the list */ |
114 | list_for_each_entry(nsdata, &local->interfaces, list) { | 108 | list_for_each_entry(nsdata, &local->interfaces, list) { |
@@ -125,7 +119,7 @@ static int ieee80211_open(struct net_device *dev) | |||
125 | * belonging to the same hardware. Then, however, we're | 119 | * belonging to the same hardware. Then, however, we're |
126 | * faced with having to adopt two different TSF timers... | 120 | * faced with having to adopt two different TSF timers... |
127 | */ | 121 | */ |
128 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 122 | if (iftype == NL80211_IFTYPE_ADHOC && |
129 | nsdata->vif.type == NL80211_IFTYPE_ADHOC) | 123 | nsdata->vif.type == NL80211_IFTYPE_ADHOC) |
130 | return -EBUSY; | 124 | return -EBUSY; |
131 | 125 | ||
@@ -139,19 +133,56 @@ static int ieee80211_open(struct net_device *dev) | |||
139 | /* | 133 | /* |
140 | * check whether it may have the same address | 134 | * check whether it may have the same address |
141 | */ | 135 | */ |
142 | if (!identical_mac_addr_allowed(sdata->vif.type, | 136 | if (!identical_mac_addr_allowed(iftype, |
143 | nsdata->vif.type)) | 137 | nsdata->vif.type)) |
144 | return -ENOTUNIQ; | 138 | return -ENOTUNIQ; |
145 | 139 | ||
146 | /* | 140 | /* |
147 | * can only add VLANs to enabled APs | 141 | * can only add VLANs to enabled APs |
148 | */ | 142 | */ |
149 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | 143 | if (iftype == NL80211_IFTYPE_AP_VLAN && |
150 | nsdata->vif.type == NL80211_IFTYPE_AP) | 144 | nsdata->vif.type == NL80211_IFTYPE_AP) |
151 | sdata->bss = &nsdata->u.ap; | 145 | sdata->bss = &nsdata->u.ap; |
152 | } | 146 | } |
153 | } | 147 | } |
154 | 148 | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | ||
153 | const int offset) | ||
154 | { | ||
155 | struct ieee80211_local *local = sdata->local; | ||
156 | u32 flags = sdata->u.mntr_flags; | ||
157 | |||
158 | #define ADJUST(_f, _s) do { \ | ||
159 | if (flags & MONITOR_FLAG_##_f) \ | ||
160 | local->fif_##_s += offset; \ | ||
161 | } while (0) | ||
162 | |||
163 | ADJUST(FCSFAIL, fcsfail); | ||
164 | ADJUST(PLCPFAIL, plcpfail); | ||
165 | ADJUST(CONTROL, control); | ||
166 | ADJUST(CONTROL, pspoll); | ||
167 | ADJUST(OTHER_BSS, other_bss); | ||
168 | |||
169 | #undef ADJUST | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * NOTE: Be very careful when changing this function, it must NOT return | ||
174 | * an error on interface type changes that have been pre-checked, so most | ||
175 | * checks should be in ieee80211_check_concurrent_iface. | ||
176 | */ | ||
177 | static int ieee80211_do_open(struct net_device *dev, bool coming_up) | ||
178 | { | ||
179 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
180 | struct ieee80211_local *local = sdata->local; | ||
181 | struct sta_info *sta; | ||
182 | u32 changed = 0; | ||
183 | int res; | ||
184 | u32 hw_reconf_flags = 0; | ||
185 | |||
155 | switch (sdata->vif.type) { | 186 | switch (sdata->vif.type) { |
156 | case NL80211_IFTYPE_WDS: | 187 | case NL80211_IFTYPE_WDS: |
157 | if (!is_valid_ether_addr(sdata->u.wds.remote_addr)) | 188 | if (!is_valid_ether_addr(sdata->u.wds.remote_addr)) |
@@ -177,7 +208,9 @@ static int ieee80211_open(struct net_device *dev) | |||
177 | /* no special treatment */ | 208 | /* no special treatment */ |
178 | break; | 209 | break; |
179 | case NL80211_IFTYPE_UNSPECIFIED: | 210 | case NL80211_IFTYPE_UNSPECIFIED: |
180 | case __NL80211_IFTYPE_AFTER_LAST: | 211 | case NUM_NL80211_IFTYPES: |
212 | case NL80211_IFTYPE_P2P_CLIENT: | ||
213 | case NL80211_IFTYPE_P2P_GO: | ||
181 | /* cannot happen */ | 214 | /* cannot happen */ |
182 | WARN_ON(1); | 215 | WARN_ON(1); |
183 | break; | 216 | break; |
@@ -187,39 +220,30 @@ static int ieee80211_open(struct net_device *dev) | |||
187 | res = drv_start(local); | 220 | res = drv_start(local); |
188 | if (res) | 221 | if (res) |
189 | goto err_del_bss; | 222 | goto err_del_bss; |
223 | if (local->ops->napi_poll) | ||
224 | napi_enable(&local->napi); | ||
190 | /* we're brought up, everything changes */ | 225 | /* we're brought up, everything changes */ |
191 | hw_reconf_flags = ~0; | 226 | hw_reconf_flags = ~0; |
192 | ieee80211_led_radio(local, true); | 227 | ieee80211_led_radio(local, true); |
193 | } | 228 | } |
194 | 229 | ||
195 | /* | 230 | /* |
196 | * Check all interfaces and copy the hopefully now-present | 231 | * Copy the hopefully now-present MAC address to |
197 | * MAC address to those that have the special null one. | 232 | * this interface, if it has the special null one. |
198 | */ | 233 | */ |
199 | list_for_each_entry(nsdata, &local->interfaces, list) { | 234 | if (is_zero_ether_addr(dev->dev_addr)) { |
200 | struct net_device *ndev = nsdata->dev; | 235 | memcpy(dev->dev_addr, |
201 | 236 | local->hw.wiphy->perm_addr, | |
202 | /* | 237 | ETH_ALEN); |
203 | * No need to check running since we do not allow | 238 | memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); |
204 | * it to start up with this invalid address. | 239 | |
205 | */ | 240 | if (!is_valid_ether_addr(dev->dev_addr)) { |
206 | if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { | 241 | if (!local->open_count) |
207 | memcpy(ndev->dev_addr, | 242 | drv_stop(local); |
208 | local->hw.wiphy->perm_addr, | 243 | return -EADDRNOTAVAIL; |
209 | ETH_ALEN); | ||
210 | memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); | ||
211 | } | 244 | } |
212 | } | 245 | } |
213 | 246 | ||
214 | /* | ||
215 | * Validate the MAC address for this device. | ||
216 | */ | ||
217 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
218 | if (!local->open_count) | ||
219 | drv_stop(local); | ||
220 | return -EADDRNOTAVAIL; | ||
221 | } | ||
222 | |||
223 | switch (sdata->vif.type) { | 247 | switch (sdata->vif.type) { |
224 | case NL80211_IFTYPE_AP_VLAN: | 248 | case NL80211_IFTYPE_AP_VLAN: |
225 | /* no need to tell driver */ | 249 | /* no need to tell driver */ |
@@ -237,25 +261,17 @@ static int ieee80211_open(struct net_device *dev) | |||
237 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 261 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
238 | } | 262 | } |
239 | 263 | ||
240 | if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) | 264 | ieee80211_adjust_monitor_flags(sdata, 1); |
241 | local->fif_fcsfail++; | ||
242 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) | ||
243 | local->fif_plcpfail++; | ||
244 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { | ||
245 | local->fif_control++; | ||
246 | local->fif_pspoll++; | ||
247 | } | ||
248 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | ||
249 | local->fif_other_bss++; | ||
250 | |||
251 | ieee80211_configure_filter(local); | 265 | ieee80211_configure_filter(local); |
252 | 266 | ||
253 | netif_carrier_on(dev); | 267 | netif_carrier_on(dev); |
254 | break; | 268 | break; |
255 | default: | 269 | default: |
256 | res = drv_add_interface(local, &sdata->vif); | 270 | if (coming_up) { |
257 | if (res) | 271 | res = drv_add_interface(local, &sdata->vif); |
258 | goto err_stop; | 272 | if (res) |
273 | goto err_stop; | ||
274 | } | ||
259 | 275 | ||
260 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 276 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
261 | local->fif_other_bss++; | 277 | local->fif_other_bss++; |
@@ -277,6 +293,8 @@ static int ieee80211_open(struct net_device *dev) | |||
277 | netif_carrier_on(dev); | 293 | netif_carrier_on(dev); |
278 | } | 294 | } |
279 | 295 | ||
296 | set_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
297 | |||
280 | if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 298 | if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
281 | /* Create STA entry for the WDS peer */ | 299 | /* Create STA entry for the WDS peer */ |
282 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, | 300 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, |
@@ -294,6 +312,8 @@ static int ieee80211_open(struct net_device *dev) | |||
294 | /* STA has been freed */ | 312 | /* STA has been freed */ |
295 | goto err_del_interface; | 313 | goto err_del_interface; |
296 | } | 314 | } |
315 | |||
316 | rate_control_rate_init(sta); | ||
297 | } | 317 | } |
298 | 318 | ||
299 | /* | 319 | /* |
@@ -307,9 +327,13 @@ static int ieee80211_open(struct net_device *dev) | |||
307 | if (sdata->flags & IEEE80211_SDATA_PROMISC) | 327 | if (sdata->flags & IEEE80211_SDATA_PROMISC) |
308 | atomic_inc(&local->iff_promiscs); | 328 | atomic_inc(&local->iff_promiscs); |
309 | 329 | ||
330 | mutex_lock(&local->mtx); | ||
310 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 331 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
332 | mutex_unlock(&local->mtx); | ||
333 | |||
334 | if (coming_up) | ||
335 | local->open_count++; | ||
311 | 336 | ||
312 | local->open_count++; | ||
313 | if (hw_reconf_flags) { | 337 | if (hw_reconf_flags) { |
314 | ieee80211_hw_config(local, hw_reconf_flags); | 338 | ieee80211_hw_config(local, hw_reconf_flags); |
315 | /* | 339 | /* |
@@ -334,22 +358,42 @@ static int ieee80211_open(struct net_device *dev) | |||
334 | sdata->bss = NULL; | 358 | sdata->bss = NULL; |
335 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 359 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
336 | list_del(&sdata->u.vlan.list); | 360 | list_del(&sdata->u.vlan.list); |
361 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
337 | return res; | 362 | return res; |
338 | } | 363 | } |
339 | 364 | ||
340 | static int ieee80211_stop(struct net_device *dev) | 365 | static int ieee80211_open(struct net_device *dev) |
341 | { | 366 | { |
342 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 367 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
368 | int err; | ||
369 | |||
370 | /* fail early if user set an invalid address */ | ||
371 | if (!is_zero_ether_addr(dev->dev_addr) && | ||
372 | !is_valid_ether_addr(dev->dev_addr)) | ||
373 | return -EADDRNOTAVAIL; | ||
374 | |||
375 | err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type); | ||
376 | if (err) | ||
377 | return err; | ||
378 | |||
379 | return ieee80211_do_open(dev, true); | ||
380 | } | ||
381 | |||
382 | static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||
383 | bool going_down) | ||
384 | { | ||
343 | struct ieee80211_local *local = sdata->local; | 385 | struct ieee80211_local *local = sdata->local; |
344 | unsigned long flags; | 386 | unsigned long flags; |
345 | struct sk_buff *skb, *tmp; | 387 | struct sk_buff *skb, *tmp; |
346 | u32 hw_reconf_flags = 0; | 388 | u32 hw_reconf_flags = 0; |
347 | int i; | 389 | int i; |
348 | 390 | ||
391 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
392 | |||
349 | /* | 393 | /* |
350 | * Stop TX on this interface first. | 394 | * Stop TX on this interface first. |
351 | */ | 395 | */ |
352 | netif_tx_stop_all_queues(dev); | 396 | netif_tx_stop_all_queues(sdata->dev); |
353 | 397 | ||
354 | /* | 398 | /* |
355 | * Purge work for this interface. | 399 | * Purge work for this interface. |
@@ -366,12 +410,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
366 | * (because if we remove a STA after ops->remove_interface() | 410 | * (because if we remove a STA after ops->remove_interface() |
367 | * the driver will have removed the vif info already!) | 411 | * the driver will have removed the vif info already!) |
368 | * | 412 | * |
369 | * We could relax this and only unlink the stations from the | 413 | * This is relevant only in AP, WDS and mesh modes, since in |
370 | * hash table and list but keep them on a per-sdata list that | 414 | * all other modes we've already removed all stations when |
371 | * will be inserted back again when the interface is brought | 415 | * disconnecting etc. |
372 | * up again, but I don't currently see a use case for that, | ||
373 | * except with WDS which gets a STA entry created when it is | ||
374 | * brought up. | ||
375 | */ | 416 | */ |
376 | sta_info_flush(local, sdata); | 417 | sta_info_flush(local, sdata); |
377 | 418 | ||
@@ -390,11 +431,12 @@ static int ieee80211_stop(struct net_device *dev) | |||
390 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 431 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
391 | local->fif_pspoll--; | 432 | local->fif_pspoll--; |
392 | 433 | ||
393 | netif_addr_lock_bh(dev); | 434 | netif_addr_lock_bh(sdata->dev); |
394 | spin_lock_bh(&local->filter_lock); | 435 | spin_lock_bh(&local->filter_lock); |
395 | __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len); | 436 | __hw_addr_unsync(&local->mc_list, &sdata->dev->mc, |
437 | sdata->dev->addr_len); | ||
396 | spin_unlock_bh(&local->filter_lock); | 438 | spin_unlock_bh(&local->filter_lock); |
397 | netif_addr_unlock_bh(dev); | 439 | netif_addr_unlock_bh(sdata->dev); |
398 | 440 | ||
399 | ieee80211_configure_filter(local); | 441 | ieee80211_configure_filter(local); |
400 | 442 | ||
@@ -406,11 +448,21 @@ static int ieee80211_stop(struct net_device *dev) | |||
406 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 448 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
407 | struct beacon_data *old_beacon = sdata->u.ap.beacon; | 449 | struct beacon_data *old_beacon = sdata->u.ap.beacon; |
408 | 450 | ||
451 | /* sdata_running will return false, so this will disable */ | ||
452 | ieee80211_bss_info_change_notify(sdata, | ||
453 | BSS_CHANGED_BEACON_ENABLED); | ||
454 | |||
409 | /* remove beacon */ | 455 | /* remove beacon */ |
410 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | 456 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); |
411 | synchronize_rcu(); | 457 | synchronize_rcu(); |
412 | kfree(old_beacon); | 458 | kfree(old_beacon); |
413 | 459 | ||
460 | /* free all potentially still buffered bcast frames */ | ||
461 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { | ||
462 | local->total_ps_buffered--; | ||
463 | dev_kfree_skb(skb); | ||
464 | } | ||
465 | |||
414 | /* down all dependent devices, that is VLANs */ | 466 | /* down all dependent devices, that is VLANs */ |
415 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 467 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
416 | u.vlan.list) | 468 | u.vlan.list) |
@@ -418,7 +470,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
418 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 470 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
419 | } | 471 | } |
420 | 472 | ||
421 | local->open_count--; | 473 | if (going_down) |
474 | local->open_count--; | ||
422 | 475 | ||
423 | switch (sdata->vif.type) { | 476 | switch (sdata->vif.type) { |
424 | case NL80211_IFTYPE_AP_VLAN: | 477 | case NL80211_IFTYPE_AP_VLAN: |
@@ -437,40 +490,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
437 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 490 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
438 | } | 491 | } |
439 | 492 | ||
440 | if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) | 493 | ieee80211_adjust_monitor_flags(sdata, -1); |
441 | local->fif_fcsfail--; | ||
442 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) | ||
443 | local->fif_plcpfail--; | ||
444 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { | ||
445 | local->fif_pspoll--; | ||
446 | local->fif_control--; | ||
447 | } | ||
448 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | ||
449 | local->fif_other_bss--; | ||
450 | |||
451 | ieee80211_configure_filter(local); | 494 | ieee80211_configure_filter(local); |
452 | break; | 495 | break; |
453 | case NL80211_IFTYPE_STATION: | ||
454 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | ||
455 | del_timer_sync(&sdata->u.mgd.timer); | ||
456 | del_timer_sync(&sdata->u.mgd.conn_mon_timer); | ||
457 | del_timer_sync(&sdata->u.mgd.bcn_mon_timer); | ||
458 | /* | ||
459 | * If any of the timers fired while we waited for it, it will | ||
460 | * have queued its work. Now the work will be running again | ||
461 | * but will not rearm the timer again because it checks | ||
462 | * whether the interface is running, which, at this point, | ||
463 | * it no longer is. | ||
464 | */ | ||
465 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | ||
466 | cancel_work_sync(&sdata->u.mgd.monitor_work); | ||
467 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); | ||
468 | |||
469 | /* fall through */ | ||
470 | case NL80211_IFTYPE_ADHOC: | ||
471 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
472 | del_timer_sync(&sdata->u.ibss.timer); | ||
473 | /* fall through */ | ||
474 | case NL80211_IFTYPE_MESH_POINT: | 496 | case NL80211_IFTYPE_MESH_POINT: |
475 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 497 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
476 | /* other_bss and allmulti are always set on mesh | 498 | /* other_bss and allmulti are always set on mesh |
@@ -498,27 +520,34 @@ static int ieee80211_stop(struct net_device *dev) | |||
498 | ieee80211_scan_cancel(local); | 520 | ieee80211_scan_cancel(local); |
499 | 521 | ||
500 | /* | 522 | /* |
501 | * Disable beaconing for AP and mesh, IBSS can't | 523 | * Disable beaconing here for mesh only, AP and IBSS |
502 | * still be joined to a network at this point. | 524 | * are already taken care of. |
503 | */ | 525 | */ |
504 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 526 | if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |
505 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) { | ||
506 | ieee80211_bss_info_change_notify(sdata, | 527 | ieee80211_bss_info_change_notify(sdata, |
507 | BSS_CHANGED_BEACON_ENABLED); | 528 | BSS_CHANGED_BEACON_ENABLED); |
508 | } | ||
509 | 529 | ||
510 | /* free all remaining keys, there shouldn't be any */ | 530 | /* |
531 | * Free all remaining keys, there shouldn't be any, | ||
532 | * except maybe group keys in AP more or WDS? | ||
533 | */ | ||
511 | ieee80211_free_keys(sdata); | 534 | ieee80211_free_keys(sdata); |
512 | drv_remove_interface(local, &sdata->vif); | 535 | |
536 | if (going_down) | ||
537 | drv_remove_interface(local, &sdata->vif); | ||
513 | } | 538 | } |
514 | 539 | ||
515 | sdata->bss = NULL; | 540 | sdata->bss = NULL; |
516 | 541 | ||
542 | mutex_lock(&local->mtx); | ||
517 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 543 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
544 | mutex_unlock(&local->mtx); | ||
518 | 545 | ||
519 | ieee80211_recalc_ps(local, -1); | 546 | ieee80211_recalc_ps(local, -1); |
520 | 547 | ||
521 | if (local->open_count == 0) { | 548 | if (local->open_count == 0) { |
549 | if (local->ops->napi_poll) | ||
550 | napi_disable(&local->napi); | ||
522 | ieee80211_clear_tx_pending(local); | 551 | ieee80211_clear_tx_pending(local); |
523 | ieee80211_stop_device(local); | 552 | ieee80211_stop_device(local); |
524 | 553 | ||
@@ -541,6 +570,13 @@ static int ieee80211_stop(struct net_device *dev) | |||
541 | } | 570 | } |
542 | } | 571 | } |
543 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 572 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
573 | } | ||
574 | |||
575 | static int ieee80211_stop(struct net_device *dev) | ||
576 | { | ||
577 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
578 | |||
579 | ieee80211_do_stop(sdata, true); | ||
544 | 580 | ||
545 | return 0; | 581 | return 0; |
546 | } | 582 | } |
@@ -585,8 +621,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
585 | { | 621 | { |
586 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 622 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
587 | struct ieee80211_local *local = sdata->local; | 623 | struct ieee80211_local *local = sdata->local; |
588 | struct beacon_data *beacon; | ||
589 | struct sk_buff *skb; | ||
590 | int flushed; | 624 | int flushed; |
591 | int i; | 625 | int i; |
592 | 626 | ||
@@ -599,37 +633,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
599 | __skb_queue_purge(&sdata->fragments[i].skb_list); | 633 | __skb_queue_purge(&sdata->fragments[i].skb_list); |
600 | sdata->fragment_next = 0; | 634 | sdata->fragment_next = 0; |
601 | 635 | ||
602 | switch (sdata->vif.type) { | 636 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
603 | case NL80211_IFTYPE_AP: | 637 | mesh_rmc_free(sdata); |
604 | beacon = sdata->u.ap.beacon; | ||
605 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | ||
606 | synchronize_rcu(); | ||
607 | kfree(beacon); | ||
608 | |||
609 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { | ||
610 | local->total_ps_buffered--; | ||
611 | dev_kfree_skb(skb); | ||
612 | } | ||
613 | |||
614 | break; | ||
615 | case NL80211_IFTYPE_MESH_POINT: | ||
616 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
617 | mesh_rmc_free(sdata); | ||
618 | break; | ||
619 | case NL80211_IFTYPE_ADHOC: | ||
620 | if (WARN_ON(sdata->u.ibss.presp)) | ||
621 | kfree_skb(sdata->u.ibss.presp); | ||
622 | break; | ||
623 | case NL80211_IFTYPE_STATION: | ||
624 | case NL80211_IFTYPE_WDS: | ||
625 | case NL80211_IFTYPE_AP_VLAN: | ||
626 | case NL80211_IFTYPE_MONITOR: | ||
627 | break; | ||
628 | case NL80211_IFTYPE_UNSPECIFIED: | ||
629 | case __NL80211_IFTYPE_AFTER_LAST: | ||
630 | BUG(); | ||
631 | break; | ||
632 | } | ||
633 | 638 | ||
634 | flushed = sta_info_flush(local, sdata); | 639 | flushed = sta_info_flush(local, sdata); |
635 | WARN_ON(flushed); | 640 | WARN_ON(flushed); |
@@ -844,9 +849,13 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
844 | 849 | ||
845 | /* and set some type-dependent values */ | 850 | /* and set some type-dependent values */ |
846 | sdata->vif.type = type; | 851 | sdata->vif.type = type; |
852 | sdata->vif.p2p = false; | ||
847 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; | 853 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; |
848 | sdata->wdev.iftype = type; | 854 | sdata->wdev.iftype = type; |
849 | 855 | ||
856 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | ||
857 | sdata->control_port_no_encrypt = false; | ||
858 | |||
850 | /* only monitor differs */ | 859 | /* only monitor differs */ |
851 | sdata->dev->type = ARPHRD_ETHER; | 860 | sdata->dev->type = ARPHRD_ETHER; |
852 | 861 | ||
@@ -854,10 +863,20 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
854 | INIT_WORK(&sdata->work, ieee80211_iface_work); | 863 | INIT_WORK(&sdata->work, ieee80211_iface_work); |
855 | 864 | ||
856 | switch (type) { | 865 | switch (type) { |
866 | case NL80211_IFTYPE_P2P_GO: | ||
867 | type = NL80211_IFTYPE_AP; | ||
868 | sdata->vif.type = type; | ||
869 | sdata->vif.p2p = true; | ||
870 | /* fall through */ | ||
857 | case NL80211_IFTYPE_AP: | 871 | case NL80211_IFTYPE_AP: |
858 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); | 872 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); |
859 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 873 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
860 | break; | 874 | break; |
875 | case NL80211_IFTYPE_P2P_CLIENT: | ||
876 | type = NL80211_IFTYPE_STATION; | ||
877 | sdata->vif.type = type; | ||
878 | sdata->vif.p2p = true; | ||
879 | /* fall through */ | ||
861 | case NL80211_IFTYPE_STATION: | 880 | case NL80211_IFTYPE_STATION: |
862 | ieee80211_sta_setup_sdata(sdata); | 881 | ieee80211_sta_setup_sdata(sdata); |
863 | break; | 882 | break; |
@@ -878,7 +897,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
878 | case NL80211_IFTYPE_AP_VLAN: | 897 | case NL80211_IFTYPE_AP_VLAN: |
879 | break; | 898 | break; |
880 | case NL80211_IFTYPE_UNSPECIFIED: | 899 | case NL80211_IFTYPE_UNSPECIFIED: |
881 | case __NL80211_IFTYPE_AFTER_LAST: | 900 | case NUM_NL80211_IFTYPES: |
882 | BUG(); | 901 | BUG(); |
883 | break; | 902 | break; |
884 | } | 903 | } |
@@ -886,12 +905,85 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
886 | ieee80211_debugfs_add_netdev(sdata); | 905 | ieee80211_debugfs_add_netdev(sdata); |
887 | } | 906 | } |
888 | 907 | ||
908 | static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | ||
909 | enum nl80211_iftype type) | ||
910 | { | ||
911 | struct ieee80211_local *local = sdata->local; | ||
912 | int ret, err; | ||
913 | enum nl80211_iftype internal_type = type; | ||
914 | bool p2p = false; | ||
915 | |||
916 | ASSERT_RTNL(); | ||
917 | |||
918 | if (!local->ops->change_interface) | ||
919 | return -EBUSY; | ||
920 | |||
921 | switch (sdata->vif.type) { | ||
922 | case NL80211_IFTYPE_AP: | ||
923 | case NL80211_IFTYPE_STATION: | ||
924 | case NL80211_IFTYPE_ADHOC: | ||
925 | /* | ||
926 | * Could maybe also all others here? | ||
927 | * Just not sure how that interacts | ||
928 | * with the RX/config path e.g. for | ||
929 | * mesh. | ||
930 | */ | ||
931 | break; | ||
932 | default: | ||
933 | return -EBUSY; | ||
934 | } | ||
935 | |||
936 | switch (type) { | ||
937 | case NL80211_IFTYPE_AP: | ||
938 | case NL80211_IFTYPE_STATION: | ||
939 | case NL80211_IFTYPE_ADHOC: | ||
940 | /* | ||
941 | * Could probably support everything | ||
942 | * but WDS here (WDS do_open can fail | ||
943 | * under memory pressure, which this | ||
944 | * code isn't prepared to handle). | ||
945 | */ | ||
946 | break; | ||
947 | case NL80211_IFTYPE_P2P_CLIENT: | ||
948 | p2p = true; | ||
949 | internal_type = NL80211_IFTYPE_STATION; | ||
950 | break; | ||
951 | case NL80211_IFTYPE_P2P_GO: | ||
952 | p2p = true; | ||
953 | internal_type = NL80211_IFTYPE_AP; | ||
954 | break; | ||
955 | default: | ||
956 | return -EBUSY; | ||
957 | } | ||
958 | |||
959 | ret = ieee80211_check_concurrent_iface(sdata, internal_type); | ||
960 | if (ret) | ||
961 | return ret; | ||
962 | |||
963 | ieee80211_do_stop(sdata, false); | ||
964 | |||
965 | ieee80211_teardown_sdata(sdata->dev); | ||
966 | |||
967 | ret = drv_change_interface(local, sdata, internal_type, p2p); | ||
968 | if (ret) | ||
969 | type = sdata->vif.type; | ||
970 | |||
971 | ieee80211_setup_sdata(sdata, type); | ||
972 | |||
973 | err = ieee80211_do_open(sdata->dev, false); | ||
974 | WARN(err, "type change: do_open returned %d", err); | ||
975 | |||
976 | return ret; | ||
977 | } | ||
978 | |||
889 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | 979 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, |
890 | enum nl80211_iftype type) | 980 | enum nl80211_iftype type) |
891 | { | 981 | { |
982 | int ret; | ||
983 | |||
892 | ASSERT_RTNL(); | 984 | ASSERT_RTNL(); |
893 | 985 | ||
894 | if (type == sdata->vif.type) | 986 | if (type == ieee80211_vif_type_p2p(&sdata->vif)) |
895 | return 0; | 987 | return 0; |
896 | 988 | ||
897 | /* Setting ad-hoc mode on non-IBSS channel is not supported. */ | 989 | /* Setting ad-hoc mode on non-IBSS channel is not supported. */ |
@@ -899,18 +991,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
899 | type == NL80211_IFTYPE_ADHOC) | 991 | type == NL80211_IFTYPE_ADHOC) |
900 | return -EOPNOTSUPP; | 992 | return -EOPNOTSUPP; |
901 | 993 | ||
902 | /* | 994 | if (ieee80211_sdata_running(sdata)) { |
903 | * We could, here, on changes between IBSS/STA/MESH modes, | 995 | ret = ieee80211_runtime_change_iftype(sdata, type); |
904 | * invoke an MLME function instead that disassociates etc. | 996 | if (ret) |
905 | * and goes into the requested mode. | 997 | return ret; |
906 | */ | 998 | } else { |
907 | 999 | /* Purge and reset type-dependent state. */ | |
908 | if (ieee80211_sdata_running(sdata)) | 1000 | ieee80211_teardown_sdata(sdata->dev); |
909 | return -EBUSY; | 1001 | ieee80211_setup_sdata(sdata, type); |
910 | 1002 | } | |
911 | /* Purge and reset type-dependent state. */ | ||
912 | ieee80211_teardown_sdata(sdata->dev); | ||
913 | ieee80211_setup_sdata(sdata, type); | ||
914 | 1003 | ||
915 | /* reset some values that shouldn't be kept across type changes */ | 1004 | /* reset some values that shouldn't be kept across type changes */ |
916 | sdata->vif.bss_conf.basic_rates = | 1005 | sdata->vif.bss_conf.basic_rates = |
@@ -1167,8 +1256,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local, | |||
1167 | return 0; | 1256 | return 0; |
1168 | 1257 | ||
1169 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1258 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1170 | printk(KERN_DEBUG "%s: device no longer idle - %s\n", | 1259 | wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason); |
1171 | wiphy_name(local->hw.wiphy), reason); | ||
1172 | #endif | 1260 | #endif |
1173 | 1261 | ||
1174 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | 1262 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; |
@@ -1181,8 +1269,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) | |||
1181 | return 0; | 1269 | return 0; |
1182 | 1270 | ||
1183 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1271 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1184 | printk(KERN_DEBUG "%s: device now idle\n", | 1272 | wiphy_debug(local->hw.wiphy, "device now idle\n"); |
1185 | wiphy_name(local->hw.wiphy)); | ||
1186 | #endif | 1273 | #endif |
1187 | 1274 | ||
1188 | drv_flush(local, false); | 1275 | drv_flush(local, false); |
@@ -1195,28 +1282,61 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1195 | { | 1282 | { |
1196 | struct ieee80211_sub_if_data *sdata; | 1283 | struct ieee80211_sub_if_data *sdata; |
1197 | int count = 0; | 1284 | int count = 0; |
1285 | bool working = false, scanning = false; | ||
1286 | struct ieee80211_work *wk; | ||
1198 | 1287 | ||
1199 | if (!list_empty(&local->work_list)) | 1288 | #ifdef CONFIG_PROVE_LOCKING |
1200 | return ieee80211_idle_off(local, "working"); | 1289 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && |
1201 | 1290 | !lockdep_is_held(&local->iflist_mtx)); | |
1202 | if (local->scanning) | 1291 | #endif |
1203 | return ieee80211_idle_off(local, "scanning"); | 1292 | lockdep_assert_held(&local->mtx); |
1204 | 1293 | ||
1205 | list_for_each_entry(sdata, &local->interfaces, list) { | 1294 | list_for_each_entry(sdata, &local->interfaces, list) { |
1206 | if (!ieee80211_sdata_running(sdata)) | 1295 | if (!ieee80211_sdata_running(sdata)) { |
1296 | sdata->vif.bss_conf.idle = true; | ||
1207 | continue; | 1297 | continue; |
1298 | } | ||
1299 | |||
1300 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
1301 | |||
1208 | /* do not count disabled managed interfaces */ | 1302 | /* do not count disabled managed interfaces */ |
1209 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1303 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
1210 | !sdata->u.mgd.associated) | 1304 | !sdata->u.mgd.associated) { |
1305 | sdata->vif.bss_conf.idle = true; | ||
1211 | continue; | 1306 | continue; |
1307 | } | ||
1212 | /* do not count unused IBSS interfaces */ | 1308 | /* do not count unused IBSS interfaces */ |
1213 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 1309 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
1214 | !sdata->u.ibss.ssid_len) | 1310 | !sdata->u.ibss.ssid_len) { |
1311 | sdata->vif.bss_conf.idle = true; | ||
1215 | continue; | 1312 | continue; |
1313 | } | ||
1216 | /* count everything else */ | 1314 | /* count everything else */ |
1217 | count++; | 1315 | count++; |
1218 | } | 1316 | } |
1219 | 1317 | ||
1318 | list_for_each_entry(wk, &local->work_list, list) { | ||
1319 | working = true; | ||
1320 | wk->sdata->vif.bss_conf.idle = false; | ||
1321 | } | ||
1322 | |||
1323 | if (local->scan_sdata) { | ||
1324 | scanning = true; | ||
1325 | local->scan_sdata->vif.bss_conf.idle = false; | ||
1326 | } | ||
1327 | |||
1328 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1329 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
1330 | continue; | ||
1331 | if (!ieee80211_sdata_running(sdata)) | ||
1332 | continue; | ||
1333 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
1334 | } | ||
1335 | |||
1336 | if (working) | ||
1337 | return ieee80211_idle_off(local, "working"); | ||
1338 | if (scanning) | ||
1339 | return ieee80211_idle_off(local, "scanning"); | ||
1220 | if (!count) | 1340 | if (!count) |
1221 | return ieee80211_idle_on(local); | 1341 | return ieee80211_idle_on(local); |
1222 | else | 1342 | else |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 1b9d87ed143..6a63d1abd14 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -49,7 +49,7 @@ static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | |||
49 | 49 | ||
50 | static void assert_key_lock(struct ieee80211_local *local) | 50 | static void assert_key_lock(struct ieee80211_local *local) |
51 | { | 51 | { |
52 | WARN_ON(!mutex_is_locked(&local->key_mtx)); | 52 | lockdep_assert_held(&local->key_mtx); |
53 | } | 53 | } |
54 | 54 | ||
55 | static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) | 55 | static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) |
@@ -60,7 +60,7 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) | |||
60 | return NULL; | 60 | return NULL; |
61 | } | 61 | } |
62 | 62 | ||
63 | static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | 63 | static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) |
64 | { | 64 | { |
65 | struct ieee80211_sub_if_data *sdata; | 65 | struct ieee80211_sub_if_data *sdata; |
66 | struct ieee80211_sta *sta; | 66 | struct ieee80211_sta *sta; |
@@ -68,8 +68,10 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
68 | 68 | ||
69 | might_sleep(); | 69 | might_sleep(); |
70 | 70 | ||
71 | if (!key->local->ops->set_key) | 71 | if (!key->local->ops->set_key) { |
72 | return; | 72 | ret = -EOPNOTSUPP; |
73 | goto out_unsupported; | ||
74 | } | ||
73 | 75 | ||
74 | assert_key_lock(key->local); | 76 | assert_key_lock(key->local); |
75 | 77 | ||
@@ -87,10 +89,27 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
87 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 89 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
88 | 90 | ||
89 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) | 91 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) |
90 | printk(KERN_ERR "mac80211-%s: failed to set key " | 92 | wiphy_err(key->local->hw.wiphy, |
91 | "(%d, %pM) to hardware (%d)\n", | 93 | "failed to set key (%d, %pM) to hardware (%d)\n", |
92 | wiphy_name(key->local->hw.wiphy), | 94 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
93 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | 95 | |
96 | out_unsupported: | ||
97 | if (ret) { | ||
98 | switch (key->conf.cipher) { | ||
99 | case WLAN_CIPHER_SUITE_WEP40: | ||
100 | case WLAN_CIPHER_SUITE_WEP104: | ||
101 | case WLAN_CIPHER_SUITE_TKIP: | ||
102 | case WLAN_CIPHER_SUITE_CCMP: | ||
103 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
104 | /* all of these we can do in software */ | ||
105 | ret = 0; | ||
106 | break; | ||
107 | default: | ||
108 | ret = -EINVAL; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | return ret; | ||
94 | } | 113 | } |
95 | 114 | ||
96 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 115 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
@@ -121,10 +140,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
121 | sta, &key->conf); | 140 | sta, &key->conf); |
122 | 141 | ||
123 | if (ret) | 142 | if (ret) |
124 | printk(KERN_ERR "mac80211-%s: failed to remove key " | 143 | wiphy_err(key->local->hw.wiphy, |
125 | "(%d, %pM) from hardware (%d)\n", | 144 | "failed to remove key (%d, %pM) from hardware (%d)\n", |
126 | wiphy_name(key->local->hw.wiphy), | 145 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
127 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | ||
128 | 146 | ||
129 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 147 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
130 | } | 148 | } |
@@ -227,20 +245,18 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
227 | } | 245 | } |
228 | } | 246 | } |
229 | 247 | ||
230 | struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | 248 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
231 | int idx, | ||
232 | size_t key_len, | ||
233 | const u8 *key_data, | 249 | const u8 *key_data, |
234 | size_t seq_len, const u8 *seq) | 250 | size_t seq_len, const u8 *seq) |
235 | { | 251 | { |
236 | struct ieee80211_key *key; | 252 | struct ieee80211_key *key; |
237 | int i, j; | 253 | int i, j, err; |
238 | 254 | ||
239 | BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS); | 255 | BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS); |
240 | 256 | ||
241 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); | 257 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); |
242 | if (!key) | 258 | if (!key) |
243 | return NULL; | 259 | return ERR_PTR(-ENOMEM); |
244 | 260 | ||
245 | /* | 261 | /* |
246 | * Default to software encryption; we'll later upload the | 262 | * Default to software encryption; we'll later upload the |
@@ -249,15 +265,16 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
249 | key->conf.flags = 0; | 265 | key->conf.flags = 0; |
250 | key->flags = 0; | 266 | key->flags = 0; |
251 | 267 | ||
252 | key->conf.alg = alg; | 268 | key->conf.cipher = cipher; |
253 | key->conf.keyidx = idx; | 269 | key->conf.keyidx = idx; |
254 | key->conf.keylen = key_len; | 270 | key->conf.keylen = key_len; |
255 | switch (alg) { | 271 | switch (cipher) { |
256 | case ALG_WEP: | 272 | case WLAN_CIPHER_SUITE_WEP40: |
273 | case WLAN_CIPHER_SUITE_WEP104: | ||
257 | key->conf.iv_len = WEP_IV_LEN; | 274 | key->conf.iv_len = WEP_IV_LEN; |
258 | key->conf.icv_len = WEP_ICV_LEN; | 275 | key->conf.icv_len = WEP_ICV_LEN; |
259 | break; | 276 | break; |
260 | case ALG_TKIP: | 277 | case WLAN_CIPHER_SUITE_TKIP: |
261 | key->conf.iv_len = TKIP_IV_LEN; | 278 | key->conf.iv_len = TKIP_IV_LEN; |
262 | key->conf.icv_len = TKIP_ICV_LEN; | 279 | key->conf.icv_len = TKIP_ICV_LEN; |
263 | if (seq) { | 280 | if (seq) { |
@@ -269,7 +286,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
269 | } | 286 | } |
270 | } | 287 | } |
271 | break; | 288 | break; |
272 | case ALG_CCMP: | 289 | case WLAN_CIPHER_SUITE_CCMP: |
273 | key->conf.iv_len = CCMP_HDR_LEN; | 290 | key->conf.iv_len = CCMP_HDR_LEN; |
274 | key->conf.icv_len = CCMP_MIC_LEN; | 291 | key->conf.icv_len = CCMP_MIC_LEN; |
275 | if (seq) { | 292 | if (seq) { |
@@ -278,42 +295,38 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
278 | key->u.ccmp.rx_pn[i][j] = | 295 | key->u.ccmp.rx_pn[i][j] = |
279 | seq[CCMP_PN_LEN - j - 1]; | 296 | seq[CCMP_PN_LEN - j - 1]; |
280 | } | 297 | } |
281 | break; | ||
282 | case ALG_AES_CMAC: | ||
283 | key->conf.iv_len = 0; | ||
284 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | ||
285 | if (seq) | ||
286 | for (j = 0; j < 6; j++) | ||
287 | key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; | ||
288 | break; | ||
289 | } | ||
290 | memcpy(key->conf.key, key_data, key_len); | ||
291 | INIT_LIST_HEAD(&key->list); | ||
292 | |||
293 | if (alg == ALG_CCMP) { | ||
294 | /* | 298 | /* |
295 | * Initialize AES key state here as an optimization so that | 299 | * Initialize AES key state here as an optimization so that |
296 | * it does not need to be initialized for every packet. | 300 | * it does not need to be initialized for every packet. |
297 | */ | 301 | */ |
298 | key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); | 302 | key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); |
299 | if (!key->u.ccmp.tfm) { | 303 | if (IS_ERR(key->u.ccmp.tfm)) { |
304 | err = PTR_ERR(key->u.ccmp.tfm); | ||
300 | kfree(key); | 305 | kfree(key); |
301 | return NULL; | 306 | key = ERR_PTR(err); |
302 | } | 307 | } |
303 | } | 308 | break; |
304 | 309 | case WLAN_CIPHER_SUITE_AES_CMAC: | |
305 | if (alg == ALG_AES_CMAC) { | 310 | key->conf.iv_len = 0; |
311 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | ||
312 | if (seq) | ||
313 | for (j = 0; j < 6; j++) | ||
314 | key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; | ||
306 | /* | 315 | /* |
307 | * Initialize AES key state here as an optimization so that | 316 | * Initialize AES key state here as an optimization so that |
308 | * it does not need to be initialized for every packet. | 317 | * it does not need to be initialized for every packet. |
309 | */ | 318 | */ |
310 | key->u.aes_cmac.tfm = | 319 | key->u.aes_cmac.tfm = |
311 | ieee80211_aes_cmac_key_setup(key_data); | 320 | ieee80211_aes_cmac_key_setup(key_data); |
312 | if (!key->u.aes_cmac.tfm) { | 321 | if (IS_ERR(key->u.aes_cmac.tfm)) { |
322 | err = PTR_ERR(key->u.aes_cmac.tfm); | ||
313 | kfree(key); | 323 | kfree(key); |
314 | return NULL; | 324 | key = ERR_PTR(err); |
315 | } | 325 | } |
326 | break; | ||
316 | } | 327 | } |
328 | memcpy(key->conf.key, key_data, key_len); | ||
329 | INIT_LIST_HEAD(&key->list); | ||
317 | 330 | ||
318 | return key; | 331 | return key; |
319 | } | 332 | } |
@@ -326,9 +339,9 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
326 | if (key->local) | 339 | if (key->local) |
327 | ieee80211_key_disable_hw_accel(key); | 340 | ieee80211_key_disable_hw_accel(key); |
328 | 341 | ||
329 | if (key->conf.alg == ALG_CCMP) | 342 | if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP) |
330 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 343 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
331 | if (key->conf.alg == ALG_AES_CMAC) | 344 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
332 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 345 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
333 | if (key->local) | 346 | if (key->local) |
334 | ieee80211_debugfs_key_remove(key); | 347 | ieee80211_debugfs_key_remove(key); |
@@ -336,12 +349,12 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
336 | kfree(key); | 349 | kfree(key); |
337 | } | 350 | } |
338 | 351 | ||
339 | void ieee80211_key_link(struct ieee80211_key *key, | 352 | int ieee80211_key_link(struct ieee80211_key *key, |
340 | struct ieee80211_sub_if_data *sdata, | 353 | struct ieee80211_sub_if_data *sdata, |
341 | struct sta_info *sta) | 354 | struct sta_info *sta) |
342 | { | 355 | { |
343 | struct ieee80211_key *old_key; | 356 | struct ieee80211_key *old_key; |
344 | int idx; | 357 | int idx, ret; |
345 | 358 | ||
346 | BUG_ON(!sdata); | 359 | BUG_ON(!sdata); |
347 | BUG_ON(!key); | 360 | BUG_ON(!key); |
@@ -396,9 +409,11 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
396 | 409 | ||
397 | ieee80211_debugfs_key_add(key); | 410 | ieee80211_debugfs_key_add(key); |
398 | 411 | ||
399 | ieee80211_key_enable_hw_accel(key); | 412 | ret = ieee80211_key_enable_hw_accel(key); |
400 | 413 | ||
401 | mutex_unlock(&sdata->local->key_mtx); | 414 | mutex_unlock(&sdata->local->key_mtx); |
415 | |||
416 | return ret; | ||
402 | } | 417 | } |
403 | 418 | ||
404 | static void __ieee80211_key_free(struct ieee80211_key *key) | 419 | static void __ieee80211_key_free(struct ieee80211_key *key) |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index b665bbb7a47..cb9a4a65cc6 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -123,18 +123,16 @@ struct ieee80211_key { | |||
123 | struct ieee80211_key_conf conf; | 123 | struct ieee80211_key_conf conf; |
124 | }; | 124 | }; |
125 | 125 | ||
126 | struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | 126 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
127 | int idx, | ||
128 | size_t key_len, | ||
129 | const u8 *key_data, | 127 | const u8 *key_data, |
130 | size_t seq_len, const u8 *seq); | 128 | size_t seq_len, const u8 *seq); |
131 | /* | 129 | /* |
132 | * Insert a key into data structures (sdata, sta if necessary) | 130 | * Insert a key into data structures (sdata, sta if necessary) |
133 | * to make it used, free old key. | 131 | * to make it used, free old key. |
134 | */ | 132 | */ |
135 | void ieee80211_key_link(struct ieee80211_key *key, | 133 | int __must_check ieee80211_key_link(struct ieee80211_key *key, |
136 | struct ieee80211_sub_if_data *sdata, | 134 | struct ieee80211_sub_if_data *sdata, |
137 | struct sta_info *sta); | 135 | struct sta_info *sta); |
138 | void ieee80211_key_free(struct ieee80211_local *local, | 136 | void ieee80211_key_free(struct ieee80211_local *local, |
139 | struct ieee80211_key *key); | 137 | struct ieee80211_key *key); |
140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); | 138 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ded5c3843e0..e3717092115 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -99,16 +99,19 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
99 | int ret = 0; | 99 | int ret = 0; |
100 | int power; | 100 | int power; |
101 | enum nl80211_channel_type channel_type; | 101 | enum nl80211_channel_type channel_type; |
102 | u32 offchannel_flag; | ||
102 | 103 | ||
103 | might_sleep(); | 104 | might_sleep(); |
104 | 105 | ||
105 | scan_chan = local->scan_channel; | 106 | scan_chan = local->scan_channel; |
106 | 107 | ||
108 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; | ||
107 | if (scan_chan) { | 109 | if (scan_chan) { |
108 | chan = scan_chan; | 110 | chan = scan_chan; |
109 | channel_type = NL80211_CHAN_NO_HT; | 111 | channel_type = NL80211_CHAN_NO_HT; |
110 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | 112 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; |
111 | } else if (local->tmp_channel) { | 113 | } else if (local->tmp_channel && |
114 | local->oper_channel != local->tmp_channel) { | ||
112 | chan = scan_chan = local->tmp_channel; | 115 | chan = scan_chan = local->tmp_channel; |
113 | channel_type = local->tmp_channel_type; | 116 | channel_type = local->tmp_channel_type; |
114 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | 117 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; |
@@ -117,8 +120,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
117 | channel_type = local->_oper_channel_type; | 120 | channel_type = local->_oper_channel_type; |
118 | local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; | 121 | local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; |
119 | } | 122 | } |
123 | offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; | ||
120 | 124 | ||
121 | if (chan != local->hw.conf.channel || | 125 | if (offchannel_flag || chan != local->hw.conf.channel || |
122 | channel_type != local->hw.conf.channel_type) { | 126 | channel_type != local->hw.conf.channel_type) { |
123 | local->hw.conf.channel = chan; | 127 | local->hw.conf.channel = chan; |
124 | local->hw.conf.channel_type = channel_type; | 128 | local->hw.conf.channel_type = channel_type; |
@@ -197,6 +201,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
197 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 201 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
198 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 202 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
199 | sdata->vif.bss_conf.bssid = sdata->vif.addr; | 203 | sdata->vif.bss_conf.bssid = sdata->vif.addr; |
204 | else if (sdata->vif.type == NL80211_IFTYPE_WDS) | ||
205 | sdata->vif.bss_conf.bssid = NULL; | ||
200 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 206 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
201 | sdata->vif.bss_conf.bssid = zero; | 207 | sdata->vif.bss_conf.bssid = zero; |
202 | } else { | 208 | } else { |
@@ -207,6 +213,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
207 | switch (sdata->vif.type) { | 213 | switch (sdata->vif.type) { |
208 | case NL80211_IFTYPE_AP: | 214 | case NL80211_IFTYPE_AP: |
209 | case NL80211_IFTYPE_ADHOC: | 215 | case NL80211_IFTYPE_ADHOC: |
216 | case NL80211_IFTYPE_WDS: | ||
210 | case NL80211_IFTYPE_MESH_POINT: | 217 | case NL80211_IFTYPE_MESH_POINT: |
211 | break; | 218 | break; |
212 | default: | 219 | default: |
@@ -291,7 +298,17 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
291 | struct ieee80211_local *local = | 298 | struct ieee80211_local *local = |
292 | container_of(work, struct ieee80211_local, restart_work); | 299 | container_of(work, struct ieee80211_local, restart_work); |
293 | 300 | ||
301 | /* wait for scan work complete */ | ||
302 | flush_workqueue(local->workqueue); | ||
303 | |||
304 | mutex_lock(&local->mtx); | ||
305 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), | ||
306 | "%s called with hardware scan in progress\n", __func__); | ||
307 | mutex_unlock(&local->mtx); | ||
308 | |||
294 | rtnl_lock(); | 309 | rtnl_lock(); |
310 | if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) | ||
311 | ieee80211_scan_cancel(local); | ||
295 | ieee80211_reconfig(local); | 312 | ieee80211_reconfig(local); |
296 | rtnl_unlock(); | 313 | rtnl_unlock(); |
297 | } | 314 | } |
@@ -302,7 +319,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
302 | 319 | ||
303 | trace_api_restart_hw(local); | 320 | trace_api_restart_hw(local); |
304 | 321 | ||
305 | /* use this reason, __ieee80211_resume will unblock it */ | 322 | /* use this reason, ieee80211_reconfig will unblock it */ |
306 | ieee80211_stop_queues_by_reason(hw, | 323 | ieee80211_stop_queues_by_reason(hw, |
307 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 324 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
308 | 325 | ||
@@ -316,7 +333,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
316 | container_of(work, struct ieee80211_local, recalc_smps); | 333 | container_of(work, struct ieee80211_local, recalc_smps); |
317 | 334 | ||
318 | mutex_lock(&local->iflist_mtx); | 335 | mutex_lock(&local->iflist_mtx); |
319 | ieee80211_recalc_smps(local, NULL); | 336 | ieee80211_recalc_smps(local); |
320 | mutex_unlock(&local->iflist_mtx); | 337 | mutex_unlock(&local->iflist_mtx); |
321 | } | 338 | } |
322 | 339 | ||
@@ -336,9 +353,6 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
336 | struct ieee80211_if_managed *ifmgd; | 353 | struct ieee80211_if_managed *ifmgd; |
337 | int c = 0; | 354 | int c = 0; |
338 | 355 | ||
339 | if (!netif_running(ndev)) | ||
340 | return NOTIFY_DONE; | ||
341 | |||
342 | /* Make sure it's our interface that got changed */ | 356 | /* Make sure it's our interface that got changed */ |
343 | if (!wdev) | 357 | if (!wdev) |
344 | return NOTIFY_DONE; | 358 | return NOTIFY_DONE; |
@@ -349,6 +363,9 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
349 | sdata = IEEE80211_DEV_TO_SUB_IF(ndev); | 363 | sdata = IEEE80211_DEV_TO_SUB_IF(ndev); |
350 | bss_conf = &sdata->vif.bss_conf; | 364 | bss_conf = &sdata->vif.bss_conf; |
351 | 365 | ||
366 | if (!ieee80211_sdata_running(sdata)) | ||
367 | return NOTIFY_DONE; | ||
368 | |||
352 | /* ARP filtering is only supported in managed mode */ | 369 | /* ARP filtering is only supported in managed mode */ |
353 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 370 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
354 | return NOTIFY_DONE; | 371 | return NOTIFY_DONE; |
@@ -390,6 +407,80 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
390 | } | 407 | } |
391 | #endif | 408 | #endif |
392 | 409 | ||
410 | static int ieee80211_napi_poll(struct napi_struct *napi, int budget) | ||
411 | { | ||
412 | struct ieee80211_local *local = | ||
413 | container_of(napi, struct ieee80211_local, napi); | ||
414 | |||
415 | return local->ops->napi_poll(&local->hw, budget); | ||
416 | } | ||
417 | |||
418 | void ieee80211_napi_schedule(struct ieee80211_hw *hw) | ||
419 | { | ||
420 | struct ieee80211_local *local = hw_to_local(hw); | ||
421 | |||
422 | napi_schedule(&local->napi); | ||
423 | } | ||
424 | EXPORT_SYMBOL(ieee80211_napi_schedule); | ||
425 | |||
426 | void ieee80211_napi_complete(struct ieee80211_hw *hw) | ||
427 | { | ||
428 | struct ieee80211_local *local = hw_to_local(hw); | ||
429 | |||
430 | napi_complete(&local->napi); | ||
431 | } | ||
432 | EXPORT_SYMBOL(ieee80211_napi_complete); | ||
433 | |||
434 | /* There isn't a lot of sense in it, but you can transmit anything you like */ | ||
435 | static const struct ieee80211_txrx_stypes | ||
436 | ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | ||
437 | [NL80211_IFTYPE_ADHOC] = { | ||
438 | .tx = 0xffff, | ||
439 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4), | ||
440 | }, | ||
441 | [NL80211_IFTYPE_STATION] = { | ||
442 | .tx = 0xffff, | ||
443 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
444 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4), | ||
445 | }, | ||
446 | [NL80211_IFTYPE_AP] = { | ||
447 | .tx = 0xffff, | ||
448 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
449 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
450 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
451 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
452 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
453 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
454 | BIT(IEEE80211_STYPE_ACTION >> 4), | ||
455 | }, | ||
456 | [NL80211_IFTYPE_AP_VLAN] = { | ||
457 | /* copy AP */ | ||
458 | .tx = 0xffff, | ||
459 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
460 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
461 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
462 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
463 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
464 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
465 | BIT(IEEE80211_STYPE_ACTION >> 4), | ||
466 | }, | ||
467 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
468 | .tx = 0xffff, | ||
469 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
470 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4), | ||
471 | }, | ||
472 | [NL80211_IFTYPE_P2P_GO] = { | ||
473 | .tx = 0xffff, | ||
474 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
475 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
476 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
477 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
478 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
479 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
480 | BIT(IEEE80211_STYPE_ACTION >> 4), | ||
481 | }, | ||
482 | }; | ||
483 | |||
393 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 484 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
394 | const struct ieee80211_ops *ops) | 485 | const struct ieee80211_ops *ops) |
395 | { | 486 | { |
@@ -419,6 +510,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
419 | if (!wiphy) | 510 | if (!wiphy) |
420 | return NULL; | 511 | return NULL; |
421 | 512 | ||
513 | wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes; | ||
514 | |||
422 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | | 515 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | |
423 | WIPHY_FLAG_4ADDR_AP | | 516 | WIPHY_FLAG_4ADDR_AP | |
424 | WIPHY_FLAG_4ADDR_STATION; | 517 | WIPHY_FLAG_4ADDR_STATION; |
@@ -444,6 +537,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
444 | /* set up some defaults */ | 537 | /* set up some defaults */ |
445 | local->hw.queues = 1; | 538 | local->hw.queues = 1; |
446 | local->hw.max_rates = 1; | 539 | local->hw.max_rates = 1; |
540 | local->hw.max_report_rates = 0; | ||
447 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 541 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
448 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 542 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
449 | local->user_power_level = -1; | 543 | local->user_power_level = -1; |
@@ -455,7 +549,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
455 | __hw_addr_init(&local->mc_list); | 549 | __hw_addr_init(&local->mc_list); |
456 | 550 | ||
457 | mutex_init(&local->iflist_mtx); | 551 | mutex_init(&local->iflist_mtx); |
458 | mutex_init(&local->scan_mtx); | 552 | mutex_init(&local->mtx); |
459 | 553 | ||
460 | mutex_init(&local->key_mtx); | 554 | mutex_init(&local->key_mtx); |
461 | spin_lock_init(&local->filter_lock); | 555 | spin_lock_init(&local->filter_lock); |
@@ -494,6 +588,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
494 | skb_queue_head_init(&local->skb_queue); | 588 | skb_queue_head_init(&local->skb_queue); |
495 | skb_queue_head_init(&local->skb_queue_unreliable); | 589 | skb_queue_head_init(&local->skb_queue_unreliable); |
496 | 590 | ||
591 | /* init dummy netdev for use w/ NAPI */ | ||
592 | init_dummy_netdev(&local->napi_dev); | ||
593 | |||
497 | return local_to_hw(local); | 594 | return local_to_hw(local); |
498 | } | 595 | } |
499 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 596 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
@@ -506,6 +603,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
506 | int channels, max_bitrates; | 603 | int channels, max_bitrates; |
507 | bool supp_ht; | 604 | bool supp_ht; |
508 | static const u32 cipher_suites[] = { | 605 | static const u32 cipher_suites[] = { |
606 | /* keep WEP first, it may be removed below */ | ||
509 | WLAN_CIPHER_SUITE_WEP40, | 607 | WLAN_CIPHER_SUITE_WEP40, |
510 | WLAN_CIPHER_SUITE_WEP104, | 608 | WLAN_CIPHER_SUITE_WEP104, |
511 | WLAN_CIPHER_SUITE_TKIP, | 609 | WLAN_CIPHER_SUITE_TKIP, |
@@ -515,6 +613,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
515 | WLAN_CIPHER_SUITE_AES_CMAC | 613 | WLAN_CIPHER_SUITE_AES_CMAC |
516 | }; | 614 | }; |
517 | 615 | ||
616 | if (hw->max_report_rates == 0) | ||
617 | hw->max_report_rates = hw->max_rates; | ||
618 | |||
518 | /* | 619 | /* |
519 | * generic code guarantees at least one band, | 620 | * generic code guarantees at least one band, |
520 | * set this very early because much code assumes | 621 | * set this very early because much code assumes |
@@ -554,6 +655,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
554 | /* mac80211 always supports monitor */ | 655 | /* mac80211 always supports monitor */ |
555 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 656 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
556 | 657 | ||
658 | #ifndef CONFIG_MAC80211_MESH | ||
659 | /* mesh depends on Kconfig, but drivers should set it if they want */ | ||
660 | local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); | ||
661 | #endif | ||
662 | |||
663 | /* mac80211 supports control port protocol changing */ | ||
664 | local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; | ||
665 | |||
557 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 666 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
558 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 667 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
559 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 668 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
@@ -589,10 +698,41 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
589 | if (local->hw.wiphy->max_scan_ie_len) | 698 | if (local->hw.wiphy->max_scan_ie_len) |
590 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; | 699 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; |
591 | 700 | ||
592 | local->hw.wiphy->cipher_suites = cipher_suites; | 701 | /* Set up cipher suites unless driver already did */ |
593 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 702 | if (!local->hw.wiphy->cipher_suites) { |
594 | if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) | 703 | local->hw.wiphy->cipher_suites = cipher_suites; |
595 | local->hw.wiphy->n_cipher_suites--; | 704 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
705 | if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) | ||
706 | local->hw.wiphy->n_cipher_suites--; | ||
707 | } | ||
708 | if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { | ||
709 | if (local->hw.wiphy->cipher_suites == cipher_suites) { | ||
710 | local->hw.wiphy->cipher_suites += 2; | ||
711 | local->hw.wiphy->n_cipher_suites -= 2; | ||
712 | } else { | ||
713 | u32 *suites; | ||
714 | int r, w = 0; | ||
715 | |||
716 | /* Filter out WEP */ | ||
717 | |||
718 | suites = kmemdup( | ||
719 | local->hw.wiphy->cipher_suites, | ||
720 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
721 | GFP_KERNEL); | ||
722 | if (!suites) | ||
723 | return -ENOMEM; | ||
724 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
725 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
726 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
727 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
728 | continue; | ||
729 | suites[w++] = suite; | ||
730 | } | ||
731 | local->hw.wiphy->cipher_suites = suites; | ||
732 | local->hw.wiphy->n_cipher_suites = w; | ||
733 | local->wiphy_ciphers_allocated = true; | ||
734 | } | ||
735 | } | ||
596 | 736 | ||
597 | result = wiphy_register(local->hw.wiphy); | 737 | result = wiphy_register(local->hw.wiphy); |
598 | if (result < 0) | 738 | if (result < 0) |
@@ -641,16 +781,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
641 | 781 | ||
642 | result = ieee80211_wep_init(local); | 782 | result = ieee80211_wep_init(local); |
643 | if (result < 0) | 783 | if (result < 0) |
644 | printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", | 784 | wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", |
645 | wiphy_name(local->hw.wiphy), result); | 785 | result); |
646 | 786 | ||
647 | rtnl_lock(); | 787 | rtnl_lock(); |
648 | 788 | ||
649 | result = ieee80211_init_rate_ctrl_alg(local, | 789 | result = ieee80211_init_rate_ctrl_alg(local, |
650 | hw->rate_control_algorithm); | 790 | hw->rate_control_algorithm); |
651 | if (result < 0) { | 791 | if (result < 0) { |
652 | printk(KERN_DEBUG "%s: Failed to initialize rate control " | 792 | wiphy_debug(local->hw.wiphy, |
653 | "algorithm\n", wiphy_name(local->hw.wiphy)); | 793 | "Failed to initialize rate control algorithm\n"); |
654 | goto fail_rate; | 794 | goto fail_rate; |
655 | } | 795 | } |
656 | 796 | ||
@@ -659,8 +799,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
659 | result = ieee80211_if_add(local, "wlan%d", NULL, | 799 | result = ieee80211_if_add(local, "wlan%d", NULL, |
660 | NL80211_IFTYPE_STATION, NULL); | 800 | NL80211_IFTYPE_STATION, NULL); |
661 | if (result) | 801 | if (result) |
662 | printk(KERN_WARNING "%s: Failed to add default virtual iface\n", | 802 | wiphy_warn(local->hw.wiphy, |
663 | wiphy_name(local->hw.wiphy)); | 803 | "Failed to add default virtual iface\n"); |
664 | } | 804 | } |
665 | 805 | ||
666 | rtnl_unlock(); | 806 | rtnl_unlock(); |
@@ -683,6 +823,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
683 | goto fail_ifa; | 823 | goto fail_ifa; |
684 | #endif | 824 | #endif |
685 | 825 | ||
826 | netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, | ||
827 | local->hw.napi_weight); | ||
828 | |||
686 | return 0; | 829 | return 0; |
687 | 830 | ||
688 | #ifdef CONFIG_INET | 831 | #ifdef CONFIG_INET |
@@ -703,6 +846,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
703 | fail_workqueue: | 846 | fail_workqueue: |
704 | wiphy_unregister(local->hw.wiphy); | 847 | wiphy_unregister(local->hw.wiphy); |
705 | fail_wiphy_register: | 848 | fail_wiphy_register: |
849 | if (local->wiphy_ciphers_allocated) | ||
850 | kfree(local->hw.wiphy->cipher_suites); | ||
706 | kfree(local->int_scan_req); | 851 | kfree(local->int_scan_req); |
707 | return result; | 852 | return result; |
708 | } | 853 | } |
@@ -738,6 +883,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
738 | */ | 883 | */ |
739 | del_timer_sync(&local->work_timer); | 884 | del_timer_sync(&local->work_timer); |
740 | 885 | ||
886 | cancel_work_sync(&local->restart_work); | ||
741 | cancel_work_sync(&local->reconfig_filter); | 887 | cancel_work_sync(&local->reconfig_filter); |
742 | 888 | ||
743 | ieee80211_clear_tx_pending(local); | 889 | ieee80211_clear_tx_pending(local); |
@@ -746,8 +892,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
746 | 892 | ||
747 | if (skb_queue_len(&local->skb_queue) || | 893 | if (skb_queue_len(&local->skb_queue) || |
748 | skb_queue_len(&local->skb_queue_unreliable)) | 894 | skb_queue_len(&local->skb_queue_unreliable)) |
749 | printk(KERN_WARNING "%s: skb_queue not empty\n", | 895 | wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); |
750 | wiphy_name(local->hw.wiphy)); | ||
751 | skb_queue_purge(&local->skb_queue); | 896 | skb_queue_purge(&local->skb_queue); |
752 | skb_queue_purge(&local->skb_queue_unreliable); | 897 | skb_queue_purge(&local->skb_queue_unreliable); |
753 | 898 | ||
@@ -764,7 +909,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
764 | struct ieee80211_local *local = hw_to_local(hw); | 909 | struct ieee80211_local *local = hw_to_local(hw); |
765 | 910 | ||
766 | mutex_destroy(&local->iflist_mtx); | 911 | mutex_destroy(&local->iflist_mtx); |
767 | mutex_destroy(&local->scan_mtx); | 912 | mutex_destroy(&local->mtx); |
913 | |||
914 | if (local->wiphy_ciphers_allocated) | ||
915 | kfree(local->hw.wiphy->cipher_suites); | ||
768 | 916 | ||
769 | wiphy_free(local->hw.wiphy); | 917 | wiphy_free(local->hw.wiphy); |
770 | } | 918 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b6c163ac22d..cd13aa82f83 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -54,6 +54,12 @@ | |||
54 | */ | 54 | */ |
55 | #define IEEE80211_SIGNAL_AVE_WEIGHT 3 | 55 | #define IEEE80211_SIGNAL_AVE_WEIGHT 3 |
56 | 56 | ||
57 | /* | ||
58 | * How many Beacon frames need to have been used in average signal strength | ||
59 | * before starting to indicate signal change events. | ||
60 | */ | ||
61 | #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 | ||
62 | |||
57 | #define TMR_RUNNING_TIMER 0 | 63 | #define TMR_RUNNING_TIMER 0 |
58 | #define TMR_RUNNING_CHANSW 1 | 64 | #define TMR_RUNNING_CHANSW 1 |
59 | 65 | ||
@@ -86,7 +92,7 @@ enum rx_mgmt_action { | |||
86 | /* utils */ | 92 | /* utils */ |
87 | static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) | 93 | static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) |
88 | { | 94 | { |
89 | WARN_ON(!mutex_is_locked(&ifmgd->mtx)); | 95 | lockdep_assert_held(&ifmgd->mtx); |
90 | } | 96 | } |
91 | 97 | ||
92 | /* | 98 | /* |
@@ -109,7 +115,7 @@ static void run_again(struct ieee80211_if_managed *ifmgd, | |||
109 | mod_timer(&ifmgd->timer, timeout); | 115 | mod_timer(&ifmgd->timer, timeout); |
110 | } | 116 | } |
111 | 117 | ||
112 | static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata) | 118 | void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) |
113 | { | 119 | { |
114 | if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) | 120 | if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) |
115 | return; | 121 | return; |
@@ -118,6 +124,19 @@ static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata) | |||
118 | round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); | 124 | round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); |
119 | } | 125 | } |
120 | 126 | ||
127 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) | ||
128 | { | ||
129 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
130 | |||
131 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
132 | return; | ||
133 | |||
134 | mod_timer(&sdata->u.mgd.conn_mon_timer, | ||
135 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | ||
136 | |||
137 | ifmgd->probe_send_count = 0; | ||
138 | } | ||
139 | |||
121 | static int ecw2cw(int ecw) | 140 | static int ecw2cw(int ecw) |
122 | { | 141 | { |
123 | return (1 << ecw) - 1; | 142 | return (1 << ecw) - 1; |
@@ -778,16 +797,17 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
778 | params.uapsd = uapsd; | 797 | params.uapsd = uapsd; |
779 | 798 | ||
780 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 799 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
781 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " | 800 | wiphy_debug(local->hw.wiphy, |
782 | "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", | 801 | "WMM queue=%d aci=%d acm=%d aifs=%d " |
783 | wiphy_name(local->hw.wiphy), queue, aci, acm, | 802 | "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", |
784 | params.aifs, params.cw_min, params.cw_max, params.txop, | 803 | queue, aci, acm, |
785 | params.uapsd); | 804 | params.aifs, params.cw_min, params.cw_max, |
805 | params.txop, params.uapsd); | ||
786 | #endif | 806 | #endif |
787 | if (drv_conf_tx(local, queue, ¶ms)) | 807 | if (drv_conf_tx(local, queue, ¶ms)) |
788 | printk(KERN_DEBUG "%s: failed to set TX queue " | 808 | wiphy_debug(local->hw.wiphy, |
789 | "parameters for queue %d\n", | 809 | "failed to set TX queue parameters for queue %d\n", |
790 | wiphy_name(local->hw.wiphy), queue); | 810 | queue); |
791 | } | 811 | } |
792 | 812 | ||
793 | /* enable WMM or activate new settings */ | 813 | /* enable WMM or activate new settings */ |
@@ -860,14 +880,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
860 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | | 880 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
861 | IEEE80211_STA_BEACON_POLL); | 881 | IEEE80211_STA_BEACON_POLL); |
862 | 882 | ||
863 | /* | ||
864 | * Always handle WMM once after association regardless | ||
865 | * of the first value the AP uses. Setting -1 here has | ||
866 | * that effect because the AP values is an unsigned | ||
867 | * 4-bit value. | ||
868 | */ | ||
869 | sdata->u.mgd.wmm_last_param_set = -1; | ||
870 | |||
871 | ieee80211_led_assoc(local, 1); | 883 | ieee80211_led_assoc(local, 1); |
872 | 884 | ||
873 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | 885 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) |
@@ -901,7 +913,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
901 | 913 | ||
902 | mutex_lock(&local->iflist_mtx); | 914 | mutex_lock(&local->iflist_mtx); |
903 | ieee80211_recalc_ps(local, -1); | 915 | ieee80211_recalc_ps(local, -1); |
904 | ieee80211_recalc_smps(local, sdata); | 916 | ieee80211_recalc_smps(local); |
905 | mutex_unlock(&local->iflist_mtx); | 917 | mutex_unlock(&local->iflist_mtx); |
906 | 918 | ||
907 | netif_tx_start_all_queues(sdata->dev); | 919 | netif_tx_start_all_queues(sdata->dev); |
@@ -990,6 +1002,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
990 | 1002 | ||
991 | if (remove_sta) | 1003 | if (remove_sta) |
992 | sta_info_destroy_addr(sdata, bssid); | 1004 | sta_info_destroy_addr(sdata, bssid); |
1005 | |||
1006 | del_timer_sync(&sdata->u.mgd.conn_mon_timer); | ||
1007 | del_timer_sync(&sdata->u.mgd.bcn_mon_timer); | ||
1008 | del_timer_sync(&sdata->u.mgd.timer); | ||
1009 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | ||
993 | } | 1010 | } |
994 | 1011 | ||
995 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1012 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -1006,21 +1023,26 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
1006 | if (is_multicast_ether_addr(hdr->addr1)) | 1023 | if (is_multicast_ether_addr(hdr->addr1)) |
1007 | return; | 1024 | return; |
1008 | 1025 | ||
1009 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 1026 | ieee80211_sta_reset_conn_monitor(sdata); |
1010 | return; | ||
1011 | |||
1012 | mod_timer(&sdata->u.mgd.conn_mon_timer, | ||
1013 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | ||
1014 | } | 1027 | } |
1015 | 1028 | ||
1016 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | 1029 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
1017 | { | 1030 | { |
1018 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1031 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1019 | const u8 *ssid; | 1032 | const u8 *ssid; |
1033 | u8 *dst = ifmgd->associated->bssid; | ||
1034 | u8 unicast_limit = max(1, IEEE80211_MAX_PROBE_TRIES - 3); | ||
1035 | |||
1036 | /* | ||
1037 | * Try sending broadcast probe requests for the last three | ||
1038 | * probe requests after the first ones failed since some | ||
1039 | * buggy APs only support broadcast probe requests. | ||
1040 | */ | ||
1041 | if (ifmgd->probe_send_count >= unicast_limit) | ||
1042 | dst = NULL; | ||
1020 | 1043 | ||
1021 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1044 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1022 | ieee80211_send_probe_req(sdata, ifmgd->associated->bssid, | 1045 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); |
1023 | ssid + 2, ssid[1], NULL, 0); | ||
1024 | 1046 | ||
1025 | ifmgd->probe_send_count++; | 1047 | ifmgd->probe_send_count++; |
1026 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | 1048 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; |
@@ -1103,8 +1125,11 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1103 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); | 1125 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); |
1104 | 1126 | ||
1105 | ieee80211_set_disassoc(sdata, true); | 1127 | ieee80211_set_disassoc(sdata, true); |
1106 | ieee80211_recalc_idle(local); | ||
1107 | mutex_unlock(&ifmgd->mtx); | 1128 | mutex_unlock(&ifmgd->mtx); |
1129 | |||
1130 | mutex_lock(&local->mtx); | ||
1131 | ieee80211_recalc_idle(local); | ||
1132 | mutex_unlock(&local->mtx); | ||
1108 | /* | 1133 | /* |
1109 | * must be outside lock due to cfg80211, | 1134 | * must be outside lock due to cfg80211, |
1110 | * but that's not a problem. | 1135 | * but that's not a problem. |
@@ -1173,7 +1198,9 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1173 | sdata->name, bssid, reason_code); | 1198 | sdata->name, bssid, reason_code); |
1174 | 1199 | ||
1175 | ieee80211_set_disassoc(sdata, true); | 1200 | ieee80211_set_disassoc(sdata, true); |
1201 | mutex_lock(&sdata->local->mtx); | ||
1176 | ieee80211_recalc_idle(sdata->local); | 1202 | ieee80211_recalc_idle(sdata->local); |
1203 | mutex_unlock(&sdata->local->mtx); | ||
1177 | 1204 | ||
1178 | return RX_MGMT_CFG80211_DEAUTH; | 1205 | return RX_MGMT_CFG80211_DEAUTH; |
1179 | } | 1206 | } |
@@ -1203,7 +1230,9 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1203 | sdata->name, mgmt->sa, reason_code); | 1230 | sdata->name, mgmt->sa, reason_code); |
1204 | 1231 | ||
1205 | ieee80211_set_disassoc(sdata, true); | 1232 | ieee80211_set_disassoc(sdata, true); |
1233 | mutex_lock(&sdata->local->mtx); | ||
1206 | ieee80211_recalc_idle(sdata->local); | 1234 | ieee80211_recalc_idle(sdata->local); |
1235 | mutex_unlock(&sdata->local->mtx); | ||
1207 | return RX_MGMT_CFG80211_DISASSOC; | 1236 | return RX_MGMT_CFG80211_DISASSOC; |
1208 | } | 1237 | } |
1209 | 1238 | ||
@@ -1262,7 +1291,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1262 | 1291 | ||
1263 | rates = 0; | 1292 | rates = 0; |
1264 | basic_rates = 0; | 1293 | basic_rates = 0; |
1265 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1294 | sband = local->hw.wiphy->bands[wk->chan->band]; |
1266 | 1295 | ||
1267 | for (i = 0; i < elems.supp_rates_len; i++) { | 1296 | for (i = 0; i < elems.supp_rates_len; i++) { |
1268 | int rate = (elems.supp_rates[i] & 0x7f) * 5; | 1297 | int rate = (elems.supp_rates[i] & 0x7f) * 5; |
@@ -1298,11 +1327,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1298 | } | 1327 | } |
1299 | } | 1328 | } |
1300 | 1329 | ||
1301 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 1330 | sta->sta.supp_rates[wk->chan->band] = rates; |
1302 | sdata->vif.bss_conf.basic_rates = basic_rates; | 1331 | sdata->vif.bss_conf.basic_rates = basic_rates; |
1303 | 1332 | ||
1304 | /* cf. IEEE 802.11 9.2.12 */ | 1333 | /* cf. IEEE 802.11 9.2.12 */ |
1305 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | 1334 | if (wk->chan->band == IEEE80211_BAND_2GHZ && |
1306 | have_higher_than_11mbit) | 1335 | have_higher_than_11mbit) |
1307 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 1336 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
1308 | else | 1337 | else |
@@ -1330,6 +1359,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1330 | return false; | 1359 | return false; |
1331 | } | 1360 | } |
1332 | 1361 | ||
1362 | /* | ||
1363 | * Always handle WMM once after association regardless | ||
1364 | * of the first value the AP uses. Setting -1 here has | ||
1365 | * that effect because the AP values is an unsigned | ||
1366 | * 4-bit value. | ||
1367 | */ | ||
1368 | ifmgd->wmm_last_param_set = -1; | ||
1369 | |||
1333 | if (elems.wmm_param) | 1370 | if (elems.wmm_param) |
1334 | ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, | 1371 | ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, |
1335 | elems.wmm_param_len); | 1372 | elems.wmm_param_len); |
@@ -1362,7 +1399,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1362 | * Also start the timer that will detect beacon loss. | 1399 | * Also start the timer that will detect beacon loss. |
1363 | */ | 1400 | */ |
1364 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 1401 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1365 | mod_beacon_timer(sdata); | 1402 | ieee80211_sta_reset_beacon_monitor(sdata); |
1366 | 1403 | ||
1367 | return true; | 1404 | return true; |
1368 | } | 1405 | } |
@@ -1465,7 +1502,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1465 | * we have or will be receiving any beacons or data, so let's | 1502 | * we have or will be receiving any beacons or data, so let's |
1466 | * schedule the timers again, just in case. | 1503 | * schedule the timers again, just in case. |
1467 | */ | 1504 | */ |
1468 | mod_beacon_timer(sdata); | 1505 | ieee80211_sta_reset_beacon_monitor(sdata); |
1469 | 1506 | ||
1470 | mod_timer(&ifmgd->conn_mon_timer, | 1507 | mod_timer(&ifmgd->conn_mon_timer, |
1471 | round_jiffies_up(jiffies + | 1508 | round_jiffies_up(jiffies + |
@@ -1540,15 +1577,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1540 | ifmgd->last_beacon_signal = rx_status->signal; | 1577 | ifmgd->last_beacon_signal = rx_status->signal; |
1541 | if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) { | 1578 | if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) { |
1542 | ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE; | 1579 | ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE; |
1543 | ifmgd->ave_beacon_signal = rx_status->signal; | 1580 | ifmgd->ave_beacon_signal = rx_status->signal * 16; |
1544 | ifmgd->last_cqm_event_signal = 0; | 1581 | ifmgd->last_cqm_event_signal = 0; |
1582 | ifmgd->count_beacon_signal = 1; | ||
1545 | } else { | 1583 | } else { |
1546 | ifmgd->ave_beacon_signal = | 1584 | ifmgd->ave_beacon_signal = |
1547 | (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + | 1585 | (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + |
1548 | (16 - IEEE80211_SIGNAL_AVE_WEIGHT) * | 1586 | (16 - IEEE80211_SIGNAL_AVE_WEIGHT) * |
1549 | ifmgd->ave_beacon_signal) / 16; | 1587 | ifmgd->ave_beacon_signal) / 16; |
1588 | ifmgd->count_beacon_signal++; | ||
1550 | } | 1589 | } |
1551 | if (bss_conf->cqm_rssi_thold && | 1590 | if (bss_conf->cqm_rssi_thold && |
1591 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && | ||
1552 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { | 1592 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { |
1553 | int sig = ifmgd->ave_beacon_signal / 16; | 1593 | int sig = ifmgd->ave_beacon_signal / 16; |
1554 | int last_event = ifmgd->last_cqm_event_signal; | 1594 | int last_event = ifmgd->last_cqm_event_signal; |
@@ -1588,7 +1628,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1588 | * Push the beacon loss detection into the future since | 1628 | * Push the beacon loss detection into the future since |
1589 | * we are processing a beacon from the AP just now. | 1629 | * we are processing a beacon from the AP just now. |
1590 | */ | 1630 | */ |
1591 | mod_beacon_timer(sdata); | 1631 | ieee80211_sta_reset_beacon_monitor(sdata); |
1592 | 1632 | ||
1593 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); | 1633 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
1594 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, | 1634 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, |
@@ -1599,7 +1639,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1599 | directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, | 1639 | directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, |
1600 | ifmgd->aid); | 1640 | ifmgd->aid); |
1601 | 1641 | ||
1602 | if (ncrc != ifmgd->beacon_crc) { | 1642 | if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) { |
1603 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, | 1643 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, |
1604 | true); | 1644 | true); |
1605 | 1645 | ||
@@ -1630,9 +1670,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1630 | } | 1670 | } |
1631 | } | 1671 | } |
1632 | 1672 | ||
1633 | if (ncrc == ifmgd->beacon_crc) | 1673 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
1634 | return; | 1674 | return; |
1635 | ifmgd->beacon_crc = ncrc; | 1675 | ifmgd->beacon_crc = ncrc; |
1676 | ifmgd->beacon_crc_valid = true; | ||
1636 | 1677 | ||
1637 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1678 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1638 | erp_valid = true; | 1679 | erp_valid = true; |
@@ -1751,7 +1792,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1751 | struct ieee80211_local *local = sdata->local; | 1792 | struct ieee80211_local *local = sdata->local; |
1752 | struct ieee80211_work *wk; | 1793 | struct ieee80211_work *wk; |
1753 | 1794 | ||
1754 | mutex_lock(&local->work_mtx); | 1795 | mutex_lock(&local->mtx); |
1755 | list_for_each_entry(wk, &local->work_list, list) { | 1796 | list_for_each_entry(wk, &local->work_list, list) { |
1756 | if (wk->sdata != sdata) | 1797 | if (wk->sdata != sdata) |
1757 | continue; | 1798 | continue; |
@@ -1783,7 +1824,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1783 | free_work(wk); | 1824 | free_work(wk); |
1784 | break; | 1825 | break; |
1785 | } | 1826 | } |
1786 | mutex_unlock(&local->work_mtx); | 1827 | mutex_unlock(&local->mtx); |
1787 | 1828 | ||
1788 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 1829 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); |
1789 | } | 1830 | } |
@@ -1840,8 +1881,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1840 | " after %dms, disconnecting.\n", | 1881 | " after %dms, disconnecting.\n", |
1841 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 1882 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
1842 | ieee80211_set_disassoc(sdata, true); | 1883 | ieee80211_set_disassoc(sdata, true); |
1843 | ieee80211_recalc_idle(local); | ||
1844 | mutex_unlock(&ifmgd->mtx); | 1884 | mutex_unlock(&ifmgd->mtx); |
1885 | mutex_lock(&local->mtx); | ||
1886 | ieee80211_recalc_idle(local); | ||
1887 | mutex_unlock(&local->mtx); | ||
1845 | /* | 1888 | /* |
1846 | * must be outside lock due to cfg80211, | 1889 | * must be outside lock due to cfg80211, |
1847 | * but that's not a problem. | 1890 | * but that's not a problem. |
@@ -1917,6 +1960,8 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
1917 | * time -- the code here is properly synchronised. | 1960 | * time -- the code here is properly synchronised. |
1918 | */ | 1961 | */ |
1919 | 1962 | ||
1963 | cancel_work_sync(&ifmgd->request_smps_work); | ||
1964 | |||
1920 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 1965 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
1921 | if (del_timer_sync(&ifmgd->timer)) | 1966 | if (del_timer_sync(&ifmgd->timer)) |
1922 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 1967 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
@@ -1952,6 +1997,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1952 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 1997 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1953 | INIT_WORK(&ifmgd->beacon_connection_loss_work, | 1998 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
1954 | ieee80211_beacon_connection_loss_work); | 1999 | ieee80211_beacon_connection_loss_work); |
2000 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); | ||
1955 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 2001 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
1956 | (unsigned long) sdata); | 2002 | (unsigned long) sdata); |
1957 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | 2003 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, |
@@ -2169,6 +2215,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2169 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 2215 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
2170 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 2216 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; |
2171 | 2217 | ||
2218 | ifmgd->beacon_crc_valid = false; | ||
2219 | |||
2172 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) | 2220 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) |
2173 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | 2221 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || |
2174 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | 2222 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || |
@@ -2249,6 +2297,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2249 | else | 2297 | else |
2250 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; | 2298 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; |
2251 | 2299 | ||
2300 | sdata->control_port_protocol = req->crypto.control_port_ethertype; | ||
2301 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; | ||
2302 | |||
2252 | ieee80211_add_work(wk); | 2303 | ieee80211_add_work(wk); |
2253 | return 0; | 2304 | return 0; |
2254 | } | 2305 | } |
@@ -2275,7 +2326,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2275 | 2326 | ||
2276 | mutex_unlock(&ifmgd->mtx); | 2327 | mutex_unlock(&ifmgd->mtx); |
2277 | 2328 | ||
2278 | mutex_lock(&local->work_mtx); | 2329 | mutex_lock(&local->mtx); |
2279 | list_for_each_entry(wk, &local->work_list, list) { | 2330 | list_for_each_entry(wk, &local->work_list, list) { |
2280 | if (wk->sdata != sdata) | 2331 | if (wk->sdata != sdata) |
2281 | continue; | 2332 | continue; |
@@ -2294,7 +2345,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2294 | free_work(wk); | 2345 | free_work(wk); |
2295 | break; | 2346 | break; |
2296 | } | 2347 | } |
2297 | mutex_unlock(&local->work_mtx); | 2348 | mutex_unlock(&local->mtx); |
2298 | 2349 | ||
2299 | /* | 2350 | /* |
2300 | * If somebody requests authentication and we haven't | 2351 | * If somebody requests authentication and we haven't |
@@ -2319,7 +2370,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2319 | if (assoc_bss) | 2370 | if (assoc_bss) |
2320 | sta_info_destroy_addr(sdata, bssid); | 2371 | sta_info_destroy_addr(sdata, bssid); |
2321 | 2372 | ||
2373 | mutex_lock(&sdata->local->mtx); | ||
2322 | ieee80211_recalc_idle(sdata->local); | 2374 | ieee80211_recalc_idle(sdata->local); |
2375 | mutex_unlock(&sdata->local->mtx); | ||
2323 | 2376 | ||
2324 | return 0; | 2377 | return 0; |
2325 | } | 2378 | } |
@@ -2357,7 +2410,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2357 | cookie, !req->local_state_change); | 2410 | cookie, !req->local_state_change); |
2358 | sta_info_destroy_addr(sdata, bssid); | 2411 | sta_info_destroy_addr(sdata, bssid); |
2359 | 2412 | ||
2413 | mutex_lock(&sdata->local->mtx); | ||
2360 | ieee80211_recalc_idle(sdata->local); | 2414 | ieee80211_recalc_idle(sdata->local); |
2415 | mutex_unlock(&sdata->local->mtx); | ||
2361 | 2416 | ||
2362 | return 0; | 2417 | return 0; |
2363 | } | 2418 | } |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index c36b1911987..4b564091e51 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -22,12 +22,16 @@ | |||
22 | static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) | 22 | static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) |
23 | { | 23 | { |
24 | struct ieee80211_local *local = sdata->local; | 24 | struct ieee80211_local *local = sdata->local; |
25 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
25 | 26 | ||
26 | local->offchannel_ps_enabled = false; | 27 | local->offchannel_ps_enabled = false; |
27 | 28 | ||
28 | /* FIXME: what to do when local->pspolling is true? */ | 29 | /* FIXME: what to do when local->pspolling is true? */ |
29 | 30 | ||
30 | del_timer_sync(&local->dynamic_ps_timer); | 31 | del_timer_sync(&local->dynamic_ps_timer); |
32 | del_timer_sync(&ifmgd->bcn_mon_timer); | ||
33 | del_timer_sync(&ifmgd->conn_mon_timer); | ||
34 | |||
31 | cancel_work_sync(&local->dynamic_ps_enable_work); | 35 | cancel_work_sync(&local->dynamic_ps_enable_work); |
32 | 36 | ||
33 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | 37 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
@@ -85,6 +89,9 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) | |||
85 | mod_timer(&local->dynamic_ps_timer, jiffies + | 89 | mod_timer(&local->dynamic_ps_timer, jiffies + |
86 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | 90 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); |
87 | } | 91 | } |
92 | |||
93 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
94 | ieee80211_sta_reset_conn_monitor(sdata); | ||
88 | } | 95 | } |
89 | 96 | ||
90 | void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) | 97 | void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) |
@@ -112,8 +119,10 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) | |||
112 | * used from user space controlled off-channel operations. | 119 | * used from user space controlled off-channel operations. |
113 | */ | 120 | */ |
114 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 121 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
115 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | 122 | sdata->vif.type != NL80211_IFTYPE_MONITOR) { |
123 | set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||
116 | netif_tx_stop_all_queues(sdata->dev); | 124 | netif_tx_stop_all_queues(sdata->dev); |
125 | } | ||
117 | } | 126 | } |
118 | mutex_unlock(&local->iflist_mtx); | 127 | mutex_unlock(&local->iflist_mtx); |
119 | } | 128 | } |
@@ -131,6 +140,7 @@ void ieee80211_offchannel_stop_station(struct ieee80211_local *local) | |||
131 | continue; | 140 | continue; |
132 | 141 | ||
133 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 142 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
143 | set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||
134 | netif_tx_stop_all_queues(sdata->dev); | 144 | netif_tx_stop_all_queues(sdata->dev); |
135 | if (sdata->u.mgd.associated) | 145 | if (sdata->u.mgd.associated) |
136 | ieee80211_offchannel_ps_enable(sdata); | 146 | ieee80211_offchannel_ps_enable(sdata); |
@@ -155,8 +165,20 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
155 | ieee80211_offchannel_ps_disable(sdata); | 165 | ieee80211_offchannel_ps_disable(sdata); |
156 | } | 166 | } |
157 | 167 | ||
158 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 168 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { |
169 | clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||
170 | /* | ||
171 | * This may wake up queues even though the driver | ||
172 | * currently has them stopped. This is not very | ||
173 | * likely, since the driver won't have gotten any | ||
174 | * (or hardly any) new packets while we weren't | ||
175 | * on the right channel, and even if it happens | ||
176 | * it will at most lead to queueing up one more | ||
177 | * packet per queue in mac80211 rather than on | ||
178 | * the interface qdisc. | ||
179 | */ | ||
159 | netif_tx_wake_all_queues(sdata->dev); | 180 | netif_tx_wake_all_queues(sdata->dev); |
181 | } | ||
160 | 182 | ||
161 | /* re-enable beaconing */ | 183 | /* re-enable beaconing */ |
162 | if (enable_beaconing && | 184 | if (enable_beaconing && |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index d287fde0431..ce671dfd238 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -12,7 +12,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
13 | struct sta_info *sta; | 13 | struct sta_info *sta; |
14 | 14 | ||
15 | ieee80211_scan_cancel(local); | 15 | if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) |
16 | ieee80211_scan_cancel(local); | ||
16 | 17 | ||
17 | ieee80211_stop_queues_by_reason(hw, | 18 | ieee80211_stop_queues_by_reason(hw, |
18 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 19 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 6d0bd198af1..f77a45625c0 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -366,8 +366,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | |||
366 | 366 | ||
367 | ref = rate_control_alloc(name, local); | 367 | ref = rate_control_alloc(name, local); |
368 | if (!ref) { | 368 | if (!ref) { |
369 | printk(KERN_WARNING "%s: Failed to select rate control " | 369 | wiphy_warn(local->hw.wiphy, |
370 | "algorithm\n", wiphy_name(local->hw.wiphy)); | 370 | "Failed to select rate control algorithm\n"); |
371 | return -ENOENT; | 371 | return -ENOENT; |
372 | } | 372 | } |
373 | 373 | ||
@@ -378,9 +378,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | |||
378 | sta_info_flush(local, NULL); | 378 | sta_info_flush(local, NULL); |
379 | } | 379 | } |
380 | 380 | ||
381 | printk(KERN_DEBUG "%s: Selected rate control " | 381 | wiphy_debug(local->hw.wiphy, "Selected rate control algorithm '%s'\n", |
382 | "algorithm '%s'\n", wiphy_name(local->hw.wiphy), | 382 | ref->ops->name); |
383 | ref->ops->name); | ||
384 | 383 | ||
385 | return 0; | 384 | return 0; |
386 | } | 385 | } |
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index 47438b4a9af..135f36fd4d5 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c | |||
@@ -162,7 +162,7 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, | |||
162 | file_info->next_entry = (file_info->next_entry + 1) % | 162 | file_info->next_entry = (file_info->next_entry + 1) % |
163 | RC_PID_EVENT_RING_SIZE; | 163 | RC_PID_EVENT_RING_SIZE; |
164 | 164 | ||
165 | /* Print information about the event. Note that userpace needs to | 165 | /* Print information about the event. Note that userspace needs to |
166 | * provide large enough buffers. */ | 166 | * provide large enough buffers. */ |
167 | length = length < RC_PID_PRINT_BUF_SIZE ? | 167 | length = length < RC_PID_PRINT_BUF_SIZE ? |
168 | length : RC_PID_PRINT_BUF_SIZE; | 168 | length : RC_PID_PRINT_BUF_SIZE; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 28624282c5f..b3e161ffa4b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -315,6 +315,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
315 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | 315 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) |
316 | { | 316 | { |
317 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 317 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
318 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
318 | int tid; | 319 | int tid; |
319 | 320 | ||
320 | /* does the frame have a qos control field? */ | 321 | /* does the frame have a qos control field? */ |
@@ -323,9 +324,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
323 | /* frame has qos control */ | 324 | /* frame has qos control */ |
324 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; | 325 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; |
325 | if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) | 326 | if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) |
326 | rx->flags |= IEEE80211_RX_AMSDU; | 327 | status->rx_flags |= IEEE80211_RX_AMSDU; |
327 | else | ||
328 | rx->flags &= ~IEEE80211_RX_AMSDU; | ||
329 | } else { | 328 | } else { |
330 | /* | 329 | /* |
331 | * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): | 330 | * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): |
@@ -387,26 +386,25 @@ static ieee80211_rx_result debug_noinline | |||
387 | ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) | 386 | ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) |
388 | { | 387 | { |
389 | struct ieee80211_local *local = rx->local; | 388 | struct ieee80211_local *local = rx->local; |
389 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
390 | struct sk_buff *skb = rx->skb; | 390 | struct sk_buff *skb = rx->skb; |
391 | 391 | ||
392 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning))) | 392 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) |
393 | return RX_CONTINUE; | ||
394 | |||
395 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) | ||
393 | return ieee80211_scan_rx(rx->sdata, skb); | 396 | return ieee80211_scan_rx(rx->sdata, skb); |
394 | 397 | ||
395 | if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) && | 398 | if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { |
396 | (rx->flags & IEEE80211_RX_IN_SCAN))) { | ||
397 | /* drop all the other packets during a software scan anyway */ | 399 | /* drop all the other packets during a software scan anyway */ |
398 | if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) | 400 | if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) |
399 | dev_kfree_skb(skb); | 401 | dev_kfree_skb(skb); |
400 | return RX_QUEUED; | 402 | return RX_QUEUED; |
401 | } | 403 | } |
402 | 404 | ||
403 | if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) { | 405 | /* scanning finished during invoking of handlers */ |
404 | /* scanning finished during invoking of handlers */ | 406 | I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); |
405 | I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); | 407 | return RX_DROP_UNUSABLE; |
406 | return RX_DROP_UNUSABLE; | ||
407 | } | ||
408 | |||
409 | return RX_CONTINUE; | ||
410 | } | 408 | } |
411 | 409 | ||
412 | 410 | ||
@@ -538,20 +536,12 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, | |||
538 | int index, | 536 | int index, |
539 | struct sk_buff_head *frames) | 537 | struct sk_buff_head *frames) |
540 | { | 538 | { |
541 | struct ieee80211_supported_band *sband; | ||
542 | struct ieee80211_rate *rate = NULL; | ||
543 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; | 539 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; |
544 | struct ieee80211_rx_status *status; | ||
545 | 540 | ||
546 | if (!skb) | 541 | if (!skb) |
547 | goto no_frame; | 542 | goto no_frame; |
548 | 543 | ||
549 | status = IEEE80211_SKB_RXCB(skb); | 544 | /* release the frame from the reorder ring buffer */ |
550 | |||
551 | /* release the reordered frames to stack */ | ||
552 | sband = hw->wiphy->bands[status->band]; | ||
553 | if (!(status->flag & RX_FLAG_HT)) | ||
554 | rate = &sband->bitrates[status->rate_idx]; | ||
555 | tid_agg_rx->stored_mpdu_num--; | 545 | tid_agg_rx->stored_mpdu_num--; |
556 | tid_agg_rx->reorder_buf[index] = NULL; | 546 | tid_agg_rx->reorder_buf[index] = NULL; |
557 | __skb_queue_tail(frames, skb); | 547 | __skb_queue_tail(frames, skb); |
@@ -580,9 +570,78 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | |||
580 | * frames that have not yet been received are assumed to be lost and the skb | 570 | * frames that have not yet been received are assumed to be lost and the skb |
581 | * can be released for processing. This may also release other skb's from the | 571 | * can be released for processing. This may also release other skb's from the |
582 | * reorder buffer if there are no additional gaps between the frames. | 572 | * reorder buffer if there are no additional gaps between the frames. |
573 | * | ||
574 | * Callers must hold tid_agg_rx->reorder_lock. | ||
583 | */ | 575 | */ |
584 | #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) | 576 | #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) |
585 | 577 | ||
578 | static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, | ||
579 | struct tid_ampdu_rx *tid_agg_rx, | ||
580 | struct sk_buff_head *frames) | ||
581 | { | ||
582 | int index, j; | ||
583 | |||
584 | /* release the buffer until next missing frame */ | ||
585 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | ||
586 | tid_agg_rx->buf_size; | ||
587 | if (!tid_agg_rx->reorder_buf[index] && | ||
588 | tid_agg_rx->stored_mpdu_num > 1) { | ||
589 | /* | ||
590 | * No buffers ready to be released, but check whether any | ||
591 | * frames in the reorder buffer have timed out. | ||
592 | */ | ||
593 | int skipped = 1; | ||
594 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; | ||
595 | j = (j + 1) % tid_agg_rx->buf_size) { | ||
596 | if (!tid_agg_rx->reorder_buf[j]) { | ||
597 | skipped++; | ||
598 | continue; | ||
599 | } | ||
600 | if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + | ||
601 | HT_RX_REORDER_BUF_TIMEOUT)) | ||
602 | goto set_release_timer; | ||
603 | |||
604 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
605 | if (net_ratelimit()) | ||
606 | wiphy_debug(hw->wiphy, | ||
607 | "release an RX reorder frame due to timeout on earlier frames\n"); | ||
608 | #endif | ||
609 | ieee80211_release_reorder_frame(hw, tid_agg_rx, | ||
610 | j, frames); | ||
611 | |||
612 | /* | ||
613 | * Increment the head seq# also for the skipped slots. | ||
614 | */ | ||
615 | tid_agg_rx->head_seq_num = | ||
616 | (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; | ||
617 | skipped = 0; | ||
618 | } | ||
619 | } else while (tid_agg_rx->reorder_buf[index]) { | ||
620 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); | ||
621 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | ||
622 | tid_agg_rx->buf_size; | ||
623 | } | ||
624 | |||
625 | if (tid_agg_rx->stored_mpdu_num) { | ||
626 | j = index = seq_sub(tid_agg_rx->head_seq_num, | ||
627 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | ||
628 | |||
629 | for (; j != (index - 1) % tid_agg_rx->buf_size; | ||
630 | j = (j + 1) % tid_agg_rx->buf_size) { | ||
631 | if (tid_agg_rx->reorder_buf[j]) | ||
632 | break; | ||
633 | } | ||
634 | |||
635 | set_release_timer: | ||
636 | |||
637 | mod_timer(&tid_agg_rx->reorder_timer, | ||
638 | tid_agg_rx->reorder_time[j] + | ||
639 | HT_RX_REORDER_BUF_TIMEOUT); | ||
640 | } else { | ||
641 | del_timer(&tid_agg_rx->reorder_timer); | ||
642 | } | ||
643 | } | ||
644 | |||
586 | /* | 645 | /* |
587 | * As this function belongs to the RX path it must be under | 646 | * As this function belongs to the RX path it must be under |
588 | * rcu_read_lock protection. It returns false if the frame | 647 | * rcu_read_lock protection. It returns false if the frame |
@@ -598,14 +657,16 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
598 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | 657 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; |
599 | u16 head_seq_num, buf_size; | 658 | u16 head_seq_num, buf_size; |
600 | int index; | 659 | int index; |
660 | bool ret = true; | ||
601 | 661 | ||
602 | buf_size = tid_agg_rx->buf_size; | 662 | buf_size = tid_agg_rx->buf_size; |
603 | head_seq_num = tid_agg_rx->head_seq_num; | 663 | head_seq_num = tid_agg_rx->head_seq_num; |
604 | 664 | ||
665 | spin_lock(&tid_agg_rx->reorder_lock); | ||
605 | /* frame with out of date sequence number */ | 666 | /* frame with out of date sequence number */ |
606 | if (seq_less(mpdu_seq_num, head_seq_num)) { | 667 | if (seq_less(mpdu_seq_num, head_seq_num)) { |
607 | dev_kfree_skb(skb); | 668 | dev_kfree_skb(skb); |
608 | return true; | 669 | goto out; |
609 | } | 670 | } |
610 | 671 | ||
611 | /* | 672 | /* |
@@ -626,7 +687,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
626 | /* check if we already stored this frame */ | 687 | /* check if we already stored this frame */ |
627 | if (tid_agg_rx->reorder_buf[index]) { | 688 | if (tid_agg_rx->reorder_buf[index]) { |
628 | dev_kfree_skb(skb); | 689 | dev_kfree_skb(skb); |
629 | return true; | 690 | goto out; |
630 | } | 691 | } |
631 | 692 | ||
632 | /* | 693 | /* |
@@ -636,58 +697,19 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
636 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && | 697 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && |
637 | tid_agg_rx->stored_mpdu_num == 0) { | 698 | tid_agg_rx->stored_mpdu_num == 0) { |
638 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 699 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); |
639 | return false; | 700 | ret = false; |
701 | goto out; | ||
640 | } | 702 | } |
641 | 703 | ||
642 | /* put the frame in the reordering buffer */ | 704 | /* put the frame in the reordering buffer */ |
643 | tid_agg_rx->reorder_buf[index] = skb; | 705 | tid_agg_rx->reorder_buf[index] = skb; |
644 | tid_agg_rx->reorder_time[index] = jiffies; | 706 | tid_agg_rx->reorder_time[index] = jiffies; |
645 | tid_agg_rx->stored_mpdu_num++; | 707 | tid_agg_rx->stored_mpdu_num++; |
646 | /* release the buffer until next missing frame */ | 708 | ieee80211_sta_reorder_release(hw, tid_agg_rx, frames); |
647 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | ||
648 | tid_agg_rx->buf_size; | ||
649 | if (!tid_agg_rx->reorder_buf[index] && | ||
650 | tid_agg_rx->stored_mpdu_num > 1) { | ||
651 | /* | ||
652 | * No buffers ready to be released, but check whether any | ||
653 | * frames in the reorder buffer have timed out. | ||
654 | */ | ||
655 | int j; | ||
656 | int skipped = 1; | ||
657 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; | ||
658 | j = (j + 1) % tid_agg_rx->buf_size) { | ||
659 | if (!tid_agg_rx->reorder_buf[j]) { | ||
660 | skipped++; | ||
661 | continue; | ||
662 | } | ||
663 | if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + | ||
664 | HT_RX_REORDER_BUF_TIMEOUT)) | ||
665 | break; | ||
666 | |||
667 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
668 | if (net_ratelimit()) | ||
669 | printk(KERN_DEBUG "%s: release an RX reorder " | ||
670 | "frame due to timeout on earlier " | ||
671 | "frames\n", | ||
672 | wiphy_name(hw->wiphy)); | ||
673 | #endif | ||
674 | ieee80211_release_reorder_frame(hw, tid_agg_rx, | ||
675 | j, frames); | ||
676 | 709 | ||
677 | /* | 710 | out: |
678 | * Increment the head seq# also for the skipped slots. | 711 | spin_unlock(&tid_agg_rx->reorder_lock); |
679 | */ | 712 | return ret; |
680 | tid_agg_rx->head_seq_num = | ||
681 | (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; | ||
682 | skipped = 0; | ||
683 | } | ||
684 | } else while (tid_agg_rx->reorder_buf[index]) { | ||
685 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); | ||
686 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | ||
687 | tid_agg_rx->buf_size; | ||
688 | } | ||
689 | |||
690 | return true; | ||
691 | } | 713 | } |
692 | 714 | ||
693 | /* | 715 | /* |
@@ -761,13 +783,14 @@ static ieee80211_rx_result debug_noinline | |||
761 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | 783 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) |
762 | { | 784 | { |
763 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 785 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
786 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
764 | 787 | ||
765 | /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ | 788 | /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ |
766 | if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { | 789 | if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { |
767 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && | 790 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && |
768 | rx->sta->last_seq_ctrl[rx->queue] == | 791 | rx->sta->last_seq_ctrl[rx->queue] == |
769 | hdr->seq_ctrl)) { | 792 | hdr->seq_ctrl)) { |
770 | if (rx->flags & IEEE80211_RX_RA_MATCH) { | 793 | if (status->rx_flags & IEEE80211_RX_RA_MATCH) { |
771 | rx->local->dot11FrameDuplicateCount++; | 794 | rx->local->dot11FrameDuplicateCount++; |
772 | rx->sta->num_duplicates++; | 795 | rx->sta->num_duplicates++; |
773 | } | 796 | } |
@@ -796,11 +819,12 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
796 | if (unlikely((ieee80211_is_data(hdr->frame_control) || | 819 | if (unlikely((ieee80211_is_data(hdr->frame_control) || |
797 | ieee80211_is_pspoll(hdr->frame_control)) && | 820 | ieee80211_is_pspoll(hdr->frame_control)) && |
798 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 821 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
822 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && | ||
799 | (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { | 823 | (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { |
800 | if ((!ieee80211_has_fromds(hdr->frame_control) && | 824 | if ((!ieee80211_has_fromds(hdr->frame_control) && |
801 | !ieee80211_has_tods(hdr->frame_control) && | 825 | !ieee80211_has_tods(hdr->frame_control) && |
802 | ieee80211_is_data(hdr->frame_control)) || | 826 | ieee80211_is_data(hdr->frame_control)) || |
803 | !(rx->flags & IEEE80211_RX_RA_MATCH)) { | 827 | !(status->rx_flags & IEEE80211_RX_RA_MATCH)) { |
804 | /* Drop IBSS frames and frames for other hosts | 828 | /* Drop IBSS frames and frames for other hosts |
805 | * silently. */ | 829 | * silently. */ |
806 | return RX_DROP_MONITOR; | 830 | return RX_DROP_MONITOR; |
@@ -857,7 +881,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
857 | * No point in finding a key and decrypting if the frame is neither | 881 | * No point in finding a key and decrypting if the frame is neither |
858 | * addressed to us nor a multicast frame. | 882 | * addressed to us nor a multicast frame. |
859 | */ | 883 | */ |
860 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 884 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
861 | return RX_CONTINUE; | 885 | return RX_CONTINUE; |
862 | 886 | ||
863 | /* start without a key */ | 887 | /* start without a key */ |
@@ -873,6 +897,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
873 | 897 | ||
874 | if (!is_multicast_ether_addr(hdr->addr1) && stakey) { | 898 | if (!is_multicast_ether_addr(hdr->addr1) && stakey) { |
875 | rx->key = stakey; | 899 | rx->key = stakey; |
900 | if ((status->flag & RX_FLAG_DECRYPTED) && | ||
901 | (status->flag & RX_FLAG_IV_STRIPPED)) | ||
902 | return RX_CONTINUE; | ||
876 | /* Skip decryption if the frame is not protected. */ | 903 | /* Skip decryption if the frame is not protected. */ |
877 | if (!ieee80211_has_protected(fc)) | 904 | if (!ieee80211_has_protected(fc)) |
878 | return RX_CONTINUE; | 905 | return RX_CONTINUE; |
@@ -935,7 +962,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
935 | * pairwise or station-to-station keys, but for WEP we allow | 962 | * pairwise or station-to-station keys, but for WEP we allow |
936 | * using a key index as well. | 963 | * using a key index as well. |
937 | */ | 964 | */ |
938 | if (rx->key && rx->key->conf.alg != ALG_WEP && | 965 | if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && |
966 | rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && | ||
939 | !is_multicast_ether_addr(hdr->addr1)) | 967 | !is_multicast_ether_addr(hdr->addr1)) |
940 | rx->key = NULL; | 968 | rx->key = NULL; |
941 | } | 969 | } |
@@ -951,8 +979,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
951 | return RX_DROP_UNUSABLE; | 979 | return RX_DROP_UNUSABLE; |
952 | /* the hdr variable is invalid now! */ | 980 | /* the hdr variable is invalid now! */ |
953 | 981 | ||
954 | switch (rx->key->conf.alg) { | 982 | switch (rx->key->conf.cipher) { |
955 | case ALG_WEP: | 983 | case WLAN_CIPHER_SUITE_WEP40: |
984 | case WLAN_CIPHER_SUITE_WEP104: | ||
956 | /* Check for weak IVs if possible */ | 985 | /* Check for weak IVs if possible */ |
957 | if (rx->sta && ieee80211_is_data(fc) && | 986 | if (rx->sta && ieee80211_is_data(fc) && |
958 | (!(status->flag & RX_FLAG_IV_STRIPPED) || | 987 | (!(status->flag & RX_FLAG_IV_STRIPPED) || |
@@ -962,15 +991,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
962 | 991 | ||
963 | result = ieee80211_crypto_wep_decrypt(rx); | 992 | result = ieee80211_crypto_wep_decrypt(rx); |
964 | break; | 993 | break; |
965 | case ALG_TKIP: | 994 | case WLAN_CIPHER_SUITE_TKIP: |
966 | result = ieee80211_crypto_tkip_decrypt(rx); | 995 | result = ieee80211_crypto_tkip_decrypt(rx); |
967 | break; | 996 | break; |
968 | case ALG_CCMP: | 997 | case WLAN_CIPHER_SUITE_CCMP: |
969 | result = ieee80211_crypto_ccmp_decrypt(rx); | 998 | result = ieee80211_crypto_ccmp_decrypt(rx); |
970 | break; | 999 | break; |
971 | case ALG_AES_CMAC: | 1000 | case WLAN_CIPHER_SUITE_AES_CMAC: |
972 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | 1001 | result = ieee80211_crypto_aes_cmac_decrypt(rx); |
973 | break; | 1002 | break; |
1003 | default: | ||
1004 | /* | ||
1005 | * We can reach here only with HW-only algorithms | ||
1006 | * but why didn't it decrypt the frame?! | ||
1007 | */ | ||
1008 | return RX_DROP_UNUSABLE; | ||
974 | } | 1009 | } |
975 | 1010 | ||
976 | /* either the frame has been decrypted or will be dropped */ | 1011 | /* either the frame has been decrypted or will be dropped */ |
@@ -1079,7 +1114,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1079 | sta->last_rx = jiffies; | 1114 | sta->last_rx = jiffies; |
1080 | } | 1115 | } |
1081 | 1116 | ||
1082 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 1117 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
1083 | return RX_CONTINUE; | 1118 | return RX_CONTINUE; |
1084 | 1119 | ||
1085 | if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) | 1120 | if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) |
@@ -1236,6 +1271,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1236 | unsigned int frag, seq; | 1271 | unsigned int frag, seq; |
1237 | struct ieee80211_fragment_entry *entry; | 1272 | struct ieee80211_fragment_entry *entry; |
1238 | struct sk_buff *skb; | 1273 | struct sk_buff *skb; |
1274 | struct ieee80211_rx_status *status; | ||
1239 | 1275 | ||
1240 | hdr = (struct ieee80211_hdr *)rx->skb->data; | 1276 | hdr = (struct ieee80211_hdr *)rx->skb->data; |
1241 | fc = hdr->frame_control; | 1277 | fc = hdr->frame_control; |
@@ -1265,7 +1301,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1265 | /* This is the first fragment of a new frame. */ | 1301 | /* This is the first fragment of a new frame. */ |
1266 | entry = ieee80211_reassemble_add(rx->sdata, frag, seq, | 1302 | entry = ieee80211_reassemble_add(rx->sdata, frag, seq, |
1267 | rx->queue, &(rx->skb)); | 1303 | rx->queue, &(rx->skb)); |
1268 | if (rx->key && rx->key->conf.alg == ALG_CCMP && | 1304 | if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP && |
1269 | ieee80211_has_protected(fc)) { | 1305 | ieee80211_has_protected(fc)) { |
1270 | int queue = ieee80211_is_mgmt(fc) ? | 1306 | int queue = ieee80211_is_mgmt(fc) ? |
1271 | NUM_RX_DATA_QUEUES : rx->queue; | 1307 | NUM_RX_DATA_QUEUES : rx->queue; |
@@ -1294,7 +1330,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1294 | int i; | 1330 | int i; |
1295 | u8 pn[CCMP_PN_LEN], *rpn; | 1331 | u8 pn[CCMP_PN_LEN], *rpn; |
1296 | int queue; | 1332 | int queue; |
1297 | if (!rx->key || rx->key->conf.alg != ALG_CCMP) | 1333 | if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP) |
1298 | return RX_DROP_UNUSABLE; | 1334 | return RX_DROP_UNUSABLE; |
1299 | memcpy(pn, entry->last_pn, CCMP_PN_LEN); | 1335 | memcpy(pn, entry->last_pn, CCMP_PN_LEN); |
1300 | for (i = CCMP_PN_LEN - 1; i >= 0; i--) { | 1336 | for (i = CCMP_PN_LEN - 1; i >= 0; i--) { |
@@ -1335,7 +1371,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1335 | } | 1371 | } |
1336 | 1372 | ||
1337 | /* Complete frame has been reassembled - process it now */ | 1373 | /* Complete frame has been reassembled - process it now */ |
1338 | rx->flags |= IEEE80211_RX_FRAGMENTED; | 1374 | status = IEEE80211_SKB_RXCB(rx->skb); |
1375 | status->rx_flags |= IEEE80211_RX_FRAGMENTED; | ||
1339 | 1376 | ||
1340 | out: | 1377 | out: |
1341 | if (rx->sta) | 1378 | if (rx->sta) |
@@ -1352,9 +1389,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) | |||
1352 | { | 1389 | { |
1353 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1390 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
1354 | __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; | 1391 | __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; |
1392 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
1355 | 1393 | ||
1356 | if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || | 1394 | if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || |
1357 | !(rx->flags & IEEE80211_RX_RA_MATCH))) | 1395 | !(status->rx_flags & IEEE80211_RX_RA_MATCH))) |
1358 | return RX_CONTINUE; | 1396 | return RX_CONTINUE; |
1359 | 1397 | ||
1360 | if ((sdata->vif.type != NL80211_IFTYPE_AP) && | 1398 | if ((sdata->vif.type != NL80211_IFTYPE_AP) && |
@@ -1492,7 +1530,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) | |||
1492 | * Allow EAPOL frames to us/the PAE group address regardless | 1530 | * Allow EAPOL frames to us/the PAE group address regardless |
1493 | * of whether the frame was encrypted or not. | 1531 | * of whether the frame was encrypted or not. |
1494 | */ | 1532 | */ |
1495 | if (ehdr->h_proto == htons(ETH_P_PAE) && | 1533 | if (ehdr->h_proto == rx->sdata->control_port_protocol && |
1496 | (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 || | 1534 | (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 || |
1497 | compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) | 1535 | compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) |
1498 | return true; | 1536 | return true; |
@@ -1515,6 +1553,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1515 | struct sk_buff *skb, *xmit_skb; | 1553 | struct sk_buff *skb, *xmit_skb; |
1516 | struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; | 1554 | struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; |
1517 | struct sta_info *dsta; | 1555 | struct sta_info *dsta; |
1556 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
1518 | 1557 | ||
1519 | skb = rx->skb; | 1558 | skb = rx->skb; |
1520 | xmit_skb = NULL; | 1559 | xmit_skb = NULL; |
@@ -1522,7 +1561,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1522 | if ((sdata->vif.type == NL80211_IFTYPE_AP || | 1561 | if ((sdata->vif.type == NL80211_IFTYPE_AP || |
1523 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && | 1562 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && |
1524 | !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && | 1563 | !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && |
1525 | (rx->flags & IEEE80211_RX_RA_MATCH) && | 1564 | (status->rx_flags & IEEE80211_RX_RA_MATCH) && |
1526 | (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { | 1565 | (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { |
1527 | if (is_multicast_ether_addr(ehdr->h_dest)) { | 1566 | if (is_multicast_ether_addr(ehdr->h_dest)) { |
1528 | /* | 1567 | /* |
@@ -1599,6 +1638,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1599 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1638 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
1600 | __le16 fc = hdr->frame_control; | 1639 | __le16 fc = hdr->frame_control; |
1601 | struct sk_buff_head frame_list; | 1640 | struct sk_buff_head frame_list; |
1641 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
1602 | 1642 | ||
1603 | if (unlikely(!ieee80211_is_data(fc))) | 1643 | if (unlikely(!ieee80211_is_data(fc))) |
1604 | return RX_CONTINUE; | 1644 | return RX_CONTINUE; |
@@ -1606,7 +1646,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1606 | if (unlikely(!ieee80211_is_data_present(fc))) | 1646 | if (unlikely(!ieee80211_is_data_present(fc))) |
1607 | return RX_DROP_MONITOR; | 1647 | return RX_DROP_MONITOR; |
1608 | 1648 | ||
1609 | if (!(rx->flags & IEEE80211_RX_AMSDU)) | 1649 | if (!(status->rx_flags & IEEE80211_RX_AMSDU)) |
1610 | return RX_CONTINUE; | 1650 | return RX_CONTINUE; |
1611 | 1651 | ||
1612 | if (ieee80211_has_a4(hdr->frame_control) && | 1652 | if (ieee80211_has_a4(hdr->frame_control) && |
@@ -1657,6 +1697,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1657 | struct sk_buff *skb = rx->skb, *fwd_skb; | 1697 | struct sk_buff *skb = rx->skb, *fwd_skb; |
1658 | struct ieee80211_local *local = rx->local; | 1698 | struct ieee80211_local *local = rx->local; |
1659 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1699 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
1700 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
1660 | 1701 | ||
1661 | hdr = (struct ieee80211_hdr *) skb->data; | 1702 | hdr = (struct ieee80211_hdr *) skb->data; |
1662 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 1703 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
@@ -1702,7 +1743,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1702 | 1743 | ||
1703 | mesh_hdr->ttl--; | 1744 | mesh_hdr->ttl--; |
1704 | 1745 | ||
1705 | if (rx->flags & IEEE80211_RX_RA_MATCH) { | 1746 | if (status->rx_flags & IEEE80211_RX_RA_MATCH) { |
1706 | if (!mesh_hdr->ttl) | 1747 | if (!mesh_hdr->ttl) |
1707 | IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh, | 1748 | IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh, |
1708 | dropped_frames_ttl); | 1749 | dropped_frames_ttl); |
@@ -1909,13 +1950,38 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
1909 | } | 1950 | } |
1910 | 1951 | ||
1911 | static ieee80211_rx_result debug_noinline | 1952 | static ieee80211_rx_result debug_noinline |
1953 | ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) | ||
1954 | { | ||
1955 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | ||
1956 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
1957 | |||
1958 | /* | ||
1959 | * From here on, look only at management frames. | ||
1960 | * Data and control frames are already handled, | ||
1961 | * and unknown (reserved) frames are useless. | ||
1962 | */ | ||
1963 | if (rx->skb->len < 24) | ||
1964 | return RX_DROP_MONITOR; | ||
1965 | |||
1966 | if (!ieee80211_is_mgmt(mgmt->frame_control)) | ||
1967 | return RX_DROP_MONITOR; | ||
1968 | |||
1969 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | ||
1970 | return RX_DROP_MONITOR; | ||
1971 | |||
1972 | if (ieee80211_drop_unencrypted_mgmt(rx)) | ||
1973 | return RX_DROP_UNUSABLE; | ||
1974 | |||
1975 | return RX_CONTINUE; | ||
1976 | } | ||
1977 | |||
1978 | static ieee80211_rx_result debug_noinline | ||
1912 | ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | 1979 | ieee80211_rx_h_action(struct ieee80211_rx_data *rx) |
1913 | { | 1980 | { |
1914 | struct ieee80211_local *local = rx->local; | 1981 | struct ieee80211_local *local = rx->local; |
1915 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1982 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
1916 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | 1983 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
1917 | struct sk_buff *nskb; | 1984 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
1918 | struct ieee80211_rx_status *status; | ||
1919 | int len = rx->skb->len; | 1985 | int len = rx->skb->len; |
1920 | 1986 | ||
1921 | if (!ieee80211_is_action(mgmt->frame_control)) | 1987 | if (!ieee80211_is_action(mgmt->frame_control)) |
@@ -1928,10 +1994,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1928 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) | 1994 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) |
1929 | return RX_DROP_UNUSABLE; | 1995 | return RX_DROP_UNUSABLE; |
1930 | 1996 | ||
1931 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 1997 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
1932 | return RX_DROP_UNUSABLE; | ||
1933 | |||
1934 | if (ieee80211_drop_unencrypted_mgmt(rx)) | ||
1935 | return RX_DROP_UNUSABLE; | 1998 | return RX_DROP_UNUSABLE; |
1936 | 1999 | ||
1937 | switch (mgmt->u.action.category) { | 2000 | switch (mgmt->u.action.category) { |
@@ -2024,17 +2087,36 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2024 | goto queue; | 2087 | goto queue; |
2025 | } | 2088 | } |
2026 | 2089 | ||
2090 | return RX_CONTINUE; | ||
2091 | |||
2027 | invalid: | 2092 | invalid: |
2028 | /* | 2093 | status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM; |
2029 | * For AP mode, hostapd is responsible for handling any action | 2094 | /* will return in the next handlers */ |
2030 | * frames that we didn't handle, including returning unknown | 2095 | return RX_CONTINUE; |
2031 | * ones. For all other modes we will return them to the sender, | 2096 | |
2032 | * setting the 0x80 bit in the action category, as required by | 2097 | handled: |
2033 | * 802.11-2007 7.3.1.11. | 2098 | if (rx->sta) |
2034 | */ | 2099 | rx->sta->rx_packets++; |
2035 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 2100 | dev_kfree_skb(rx->skb); |
2036 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 2101 | return RX_QUEUED; |
2037 | return RX_DROP_MONITOR; | 2102 | |
2103 | queue: | ||
2104 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; | ||
2105 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
2106 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
2107 | if (rx->sta) | ||
2108 | rx->sta->rx_packets++; | ||
2109 | return RX_QUEUED; | ||
2110 | } | ||
2111 | |||
2112 | static ieee80211_rx_result debug_noinline | ||
2113 | ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) | ||
2114 | { | ||
2115 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
2116 | |||
2117 | /* skip known-bad action frames and return them in the next handler */ | ||
2118 | if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) | ||
2119 | return RX_CONTINUE; | ||
2038 | 2120 | ||
2039 | /* | 2121 | /* |
2040 | * Getting here means the kernel doesn't know how to handle | 2122 | * Getting here means the kernel doesn't know how to handle |
@@ -2042,12 +2124,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2042 | * so userspace can register for those to know whether ones | 2124 | * so userspace can register for those to know whether ones |
2043 | * it transmitted were processed or returned. | 2125 | * it transmitted were processed or returned. |
2044 | */ | 2126 | */ |
2045 | status = IEEE80211_SKB_RXCB(rx->skb); | ||
2046 | 2127 | ||
2047 | if (cfg80211_rx_action(rx->sdata->dev, status->freq, | 2128 | if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, |
2048 | rx->skb->data, rx->skb->len, | 2129 | rx->skb->data, rx->skb->len, |
2049 | GFP_ATOMIC)) | 2130 | GFP_ATOMIC)) { |
2050 | goto handled; | 2131 | if (rx->sta) |
2132 | rx->sta->rx_packets++; | ||
2133 | dev_kfree_skb(rx->skb); | ||
2134 | return RX_QUEUED; | ||
2135 | } | ||
2136 | |||
2137 | |||
2138 | return RX_CONTINUE; | ||
2139 | } | ||
2140 | |||
2141 | static ieee80211_rx_result debug_noinline | ||
2142 | ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) | ||
2143 | { | ||
2144 | struct ieee80211_local *local = rx->local; | ||
2145 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | ||
2146 | struct sk_buff *nskb; | ||
2147 | struct ieee80211_sub_if_data *sdata = rx->sdata; | ||
2148 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
2149 | |||
2150 | if (!ieee80211_is_action(mgmt->frame_control)) | ||
2151 | return RX_CONTINUE; | ||
2152 | |||
2153 | /* | ||
2154 | * For AP mode, hostapd is responsible for handling any action | ||
2155 | * frames that we didn't handle, including returning unknown | ||
2156 | * ones. For all other modes we will return them to the sender, | ||
2157 | * setting the 0x80 bit in the action category, as required by | ||
2158 | * 802.11-2007 7.3.1.11. | ||
2159 | * Newer versions of hostapd shall also use the management frame | ||
2160 | * registration mechanisms, but older ones still use cooked | ||
2161 | * monitor interfaces so push all frames there. | ||
2162 | */ | ||
2163 | if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) && | ||
2164 | (sdata->vif.type == NL80211_IFTYPE_AP || | ||
2165 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) | ||
2166 | return RX_DROP_MONITOR; | ||
2051 | 2167 | ||
2052 | /* do not return rejected action frames */ | 2168 | /* do not return rejected action frames */ |
2053 | if (mgmt->u.action.category & 0x80) | 2169 | if (mgmt->u.action.category & 0x80) |
@@ -2066,20 +2182,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2066 | 2182 | ||
2067 | ieee80211_tx_skb(rx->sdata, nskb); | 2183 | ieee80211_tx_skb(rx->sdata, nskb); |
2068 | } | 2184 | } |
2069 | |||
2070 | handled: | ||
2071 | if (rx->sta) | ||
2072 | rx->sta->rx_packets++; | ||
2073 | dev_kfree_skb(rx->skb); | 2185 | dev_kfree_skb(rx->skb); |
2074 | return RX_QUEUED; | 2186 | return RX_QUEUED; |
2075 | |||
2076 | queue: | ||
2077 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; | ||
2078 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
2079 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
2080 | if (rx->sta) | ||
2081 | rx->sta->rx_packets++; | ||
2082 | return RX_QUEUED; | ||
2083 | } | 2187 | } |
2084 | 2188 | ||
2085 | static ieee80211_rx_result debug_noinline | 2189 | static ieee80211_rx_result debug_noinline |
@@ -2090,15 +2194,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2090 | struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; | 2194 | struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; |
2091 | __le16 stype; | 2195 | __le16 stype; |
2092 | 2196 | ||
2093 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | ||
2094 | return RX_DROP_MONITOR; | ||
2095 | |||
2096 | if (rx->skb->len < 24) | ||
2097 | return RX_DROP_MONITOR; | ||
2098 | |||
2099 | if (ieee80211_drop_unencrypted_mgmt(rx)) | ||
2100 | return RX_DROP_UNUSABLE; | ||
2101 | |||
2102 | rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); | 2197 | rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); |
2103 | if (rxs != RX_CONTINUE) | 2198 | if (rxs != RX_CONTINUE) |
2104 | return rxs; | 2199 | return rxs; |
@@ -2199,6 +2294,14 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
2199 | struct net_device *prev_dev = NULL; | 2294 | struct net_device *prev_dev = NULL; |
2200 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 2295 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
2201 | 2296 | ||
2297 | /* | ||
2298 | * If cooked monitor has been processed already, then | ||
2299 | * don't do it again. If not, set the flag. | ||
2300 | */ | ||
2301 | if (rx->flags & IEEE80211_RX_CMNTR) | ||
2302 | goto out_free_skb; | ||
2303 | rx->flags |= IEEE80211_RX_CMNTR; | ||
2304 | |||
2202 | if (skb_headroom(skb) < sizeof(*rthdr) && | 2305 | if (skb_headroom(skb) < sizeof(*rthdr) && |
2203 | pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) | 2306 | pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) |
2204 | goto out_free_skb; | 2307 | goto out_free_skb; |
@@ -2253,29 +2356,53 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
2253 | if (prev_dev) { | 2356 | if (prev_dev) { |
2254 | skb->dev = prev_dev; | 2357 | skb->dev = prev_dev; |
2255 | netif_receive_skb(skb); | 2358 | netif_receive_skb(skb); |
2256 | skb = NULL; | 2359 | return; |
2257 | } else | 2360 | } |
2258 | goto out_free_skb; | ||
2259 | |||
2260 | return; | ||
2261 | 2361 | ||
2262 | out_free_skb: | 2362 | out_free_skb: |
2263 | dev_kfree_skb(skb); | 2363 | dev_kfree_skb(skb); |
2264 | } | 2364 | } |
2265 | 2365 | ||
2366 | static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, | ||
2367 | ieee80211_rx_result res) | ||
2368 | { | ||
2369 | switch (res) { | ||
2370 | case RX_DROP_MONITOR: | ||
2371 | I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); | ||
2372 | if (rx->sta) | ||
2373 | rx->sta->rx_dropped++; | ||
2374 | /* fall through */ | ||
2375 | case RX_CONTINUE: { | ||
2376 | struct ieee80211_rate *rate = NULL; | ||
2377 | struct ieee80211_supported_band *sband; | ||
2378 | struct ieee80211_rx_status *status; | ||
2379 | |||
2380 | status = IEEE80211_SKB_RXCB((rx->skb)); | ||
2381 | |||
2382 | sband = rx->local->hw.wiphy->bands[status->band]; | ||
2383 | if (!(status->flag & RX_FLAG_HT)) | ||
2384 | rate = &sband->bitrates[status->rate_idx]; | ||
2385 | |||
2386 | ieee80211_rx_cooked_monitor(rx, rate); | ||
2387 | break; | ||
2388 | } | ||
2389 | case RX_DROP_UNUSABLE: | ||
2390 | I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); | ||
2391 | if (rx->sta) | ||
2392 | rx->sta->rx_dropped++; | ||
2393 | dev_kfree_skb(rx->skb); | ||
2394 | break; | ||
2395 | case RX_QUEUED: | ||
2396 | I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued); | ||
2397 | break; | ||
2398 | } | ||
2399 | } | ||
2266 | 2400 | ||
2267 | static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | 2401 | static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, |
2268 | struct ieee80211_rx_data *rx, | 2402 | struct sk_buff_head *frames) |
2269 | struct sk_buff *skb, | ||
2270 | struct ieee80211_rate *rate) | ||
2271 | { | 2403 | { |
2272 | struct sk_buff_head reorder_release; | ||
2273 | ieee80211_rx_result res = RX_DROP_MONITOR; | 2404 | ieee80211_rx_result res = RX_DROP_MONITOR; |
2274 | 2405 | struct sk_buff *skb; | |
2275 | __skb_queue_head_init(&reorder_release); | ||
2276 | |||
2277 | rx->skb = skb; | ||
2278 | rx->sdata = sdata; | ||
2279 | 2406 | ||
2280 | #define CALL_RXH(rxh) \ | 2407 | #define CALL_RXH(rxh) \ |
2281 | do { \ | 2408 | do { \ |
@@ -2284,23 +2411,14 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
2284 | goto rxh_next; \ | 2411 | goto rxh_next; \ |
2285 | } while (0); | 2412 | } while (0); |
2286 | 2413 | ||
2287 | /* | 2414 | while ((skb = __skb_dequeue(frames))) { |
2288 | * NB: the rxh_next label works even if we jump | ||
2289 | * to it from here because then the list will | ||
2290 | * be empty, which is a trivial check | ||
2291 | */ | ||
2292 | CALL_RXH(ieee80211_rx_h_passive_scan) | ||
2293 | CALL_RXH(ieee80211_rx_h_check) | ||
2294 | |||
2295 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); | ||
2296 | |||
2297 | while ((skb = __skb_dequeue(&reorder_release))) { | ||
2298 | /* | 2415 | /* |
2299 | * all the other fields are valid across frames | 2416 | * all the other fields are valid across frames |
2300 | * that belong to an aMPDU since they are on the | 2417 | * that belong to an aMPDU since they are on the |
2301 | * same TID from the same station | 2418 | * same TID from the same station |
2302 | */ | 2419 | */ |
2303 | rx->skb = skb; | 2420 | rx->skb = skb; |
2421 | rx->flags = 0; | ||
2304 | 2422 | ||
2305 | CALL_RXH(ieee80211_rx_h_decrypt) | 2423 | CALL_RXH(ieee80211_rx_h_decrypt) |
2306 | CALL_RXH(ieee80211_rx_h_check_more_data) | 2424 | CALL_RXH(ieee80211_rx_h_check_more_data) |
@@ -2312,50 +2430,92 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
2312 | CALL_RXH(ieee80211_rx_h_remove_qos_control) | 2430 | CALL_RXH(ieee80211_rx_h_remove_qos_control) |
2313 | CALL_RXH(ieee80211_rx_h_amsdu) | 2431 | CALL_RXH(ieee80211_rx_h_amsdu) |
2314 | #ifdef CONFIG_MAC80211_MESH | 2432 | #ifdef CONFIG_MAC80211_MESH |
2315 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 2433 | if (ieee80211_vif_is_mesh(&rx->sdata->vif)) |
2316 | CALL_RXH(ieee80211_rx_h_mesh_fwding); | 2434 | CALL_RXH(ieee80211_rx_h_mesh_fwding); |
2317 | #endif | 2435 | #endif |
2318 | CALL_RXH(ieee80211_rx_h_data) | 2436 | CALL_RXH(ieee80211_rx_h_data) |
2319 | 2437 | ||
2320 | /* special treatment -- needs the queue */ | 2438 | /* special treatment -- needs the queue */ |
2321 | res = ieee80211_rx_h_ctrl(rx, &reorder_release); | 2439 | res = ieee80211_rx_h_ctrl(rx, frames); |
2322 | if (res != RX_CONTINUE) | 2440 | if (res != RX_CONTINUE) |
2323 | goto rxh_next; | 2441 | goto rxh_next; |
2324 | 2442 | ||
2443 | CALL_RXH(ieee80211_rx_h_mgmt_check) | ||
2325 | CALL_RXH(ieee80211_rx_h_action) | 2444 | CALL_RXH(ieee80211_rx_h_action) |
2445 | CALL_RXH(ieee80211_rx_h_userspace_mgmt) | ||
2446 | CALL_RXH(ieee80211_rx_h_action_return) | ||
2326 | CALL_RXH(ieee80211_rx_h_mgmt) | 2447 | CALL_RXH(ieee80211_rx_h_mgmt) |
2327 | 2448 | ||
2449 | rxh_next: | ||
2450 | ieee80211_rx_handlers_result(rx, res); | ||
2451 | |||
2328 | #undef CALL_RXH | 2452 | #undef CALL_RXH |
2453 | } | ||
2454 | } | ||
2455 | |||
2456 | static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | ||
2457 | { | ||
2458 | struct sk_buff_head reorder_release; | ||
2459 | ieee80211_rx_result res = RX_DROP_MONITOR; | ||
2460 | |||
2461 | __skb_queue_head_init(&reorder_release); | ||
2462 | |||
2463 | #define CALL_RXH(rxh) \ | ||
2464 | do { \ | ||
2465 | res = rxh(rx); \ | ||
2466 | if (res != RX_CONTINUE) \ | ||
2467 | goto rxh_next; \ | ||
2468 | } while (0); | ||
2469 | |||
2470 | CALL_RXH(ieee80211_rx_h_passive_scan) | ||
2471 | CALL_RXH(ieee80211_rx_h_check) | ||
2472 | |||
2473 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); | ||
2474 | |||
2475 | ieee80211_rx_handlers(rx, &reorder_release); | ||
2476 | return; | ||
2329 | 2477 | ||
2330 | rxh_next: | 2478 | rxh_next: |
2331 | switch (res) { | 2479 | ieee80211_rx_handlers_result(rx, res); |
2332 | case RX_DROP_MONITOR: | 2480 | |
2333 | I802_DEBUG_INC(sdata->local->rx_handlers_drop); | 2481 | #undef CALL_RXH |
2334 | if (rx->sta) | 2482 | } |
2335 | rx->sta->rx_dropped++; | 2483 | |
2336 | /* fall through */ | 2484 | /* |
2337 | case RX_CONTINUE: | 2485 | * This function makes calls into the RX path. Therefore the |
2338 | ieee80211_rx_cooked_monitor(rx, rate); | 2486 | * caller must hold the sta_info->lock and everything has to |
2339 | break; | 2487 | * be under rcu_read_lock protection as well. |
2340 | case RX_DROP_UNUSABLE: | 2488 | */ |
2341 | I802_DEBUG_INC(sdata->local->rx_handlers_drop); | 2489 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) |
2342 | if (rx->sta) | 2490 | { |
2343 | rx->sta->rx_dropped++; | 2491 | struct sk_buff_head frames; |
2344 | dev_kfree_skb(rx->skb); | 2492 | struct ieee80211_rx_data rx = { |
2345 | break; | 2493 | .sta = sta, |
2346 | case RX_QUEUED: | 2494 | .sdata = sta->sdata, |
2347 | I802_DEBUG_INC(sdata->local->rx_handlers_queued); | 2495 | .local = sta->local, |
2348 | break; | 2496 | .queue = tid, |
2349 | } | 2497 | }; |
2350 | } | 2498 | struct tid_ampdu_rx *tid_agg_rx; |
2499 | |||
2500 | tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); | ||
2501 | if (!tid_agg_rx) | ||
2502 | return; | ||
2503 | |||
2504 | __skb_queue_head_init(&frames); | ||
2505 | |||
2506 | spin_lock(&tid_agg_rx->reorder_lock); | ||
2507 | ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames); | ||
2508 | spin_unlock(&tid_agg_rx->reorder_lock); | ||
2509 | |||
2510 | ieee80211_rx_handlers(&rx, &frames); | ||
2351 | } | 2511 | } |
2352 | 2512 | ||
2353 | /* main receive path */ | 2513 | /* main receive path */ |
2354 | 2514 | ||
2355 | static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | 2515 | static int prepare_for_handlers(struct ieee80211_rx_data *rx, |
2356 | struct ieee80211_rx_data *rx, | ||
2357 | struct ieee80211_hdr *hdr) | 2516 | struct ieee80211_hdr *hdr) |
2358 | { | 2517 | { |
2518 | struct ieee80211_sub_if_data *sdata = rx->sdata; | ||
2359 | struct sk_buff *skb = rx->skb; | 2519 | struct sk_buff *skb = rx->skb; |
2360 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 2520 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
2361 | u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); | 2521 | u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); |
@@ -2369,7 +2529,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2369 | compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { | 2529 | compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { |
2370 | if (!(sdata->dev->flags & IFF_PROMISC)) | 2530 | if (!(sdata->dev->flags & IFF_PROMISC)) |
2371 | return 0; | 2531 | return 0; |
2372 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2532 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
2373 | } | 2533 | } |
2374 | break; | 2534 | break; |
2375 | case NL80211_IFTYPE_ADHOC: | 2535 | case NL80211_IFTYPE_ADHOC: |
@@ -2379,15 +2539,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2379 | return 1; | 2539 | return 1; |
2380 | } | 2540 | } |
2381 | else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { | 2541 | else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { |
2382 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) | 2542 | if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) |
2383 | return 0; | 2543 | return 0; |
2384 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2544 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
2385 | } else if (!multicast && | 2545 | } else if (!multicast && |
2386 | compare_ether_addr(sdata->vif.addr, | 2546 | compare_ether_addr(sdata->vif.addr, |
2387 | hdr->addr1) != 0) { | 2547 | hdr->addr1) != 0) { |
2388 | if (!(sdata->dev->flags & IFF_PROMISC)) | 2548 | if (!(sdata->dev->flags & IFF_PROMISC)) |
2389 | return 0; | 2549 | return 0; |
2390 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2550 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
2391 | } else if (!rx->sta) { | 2551 | } else if (!rx->sta) { |
2392 | int rate_idx; | 2552 | int rate_idx; |
2393 | if (status->flag & RX_FLAG_HT) | 2553 | if (status->flag & RX_FLAG_HT) |
@@ -2405,7 +2565,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2405 | if (!(sdata->dev->flags & IFF_PROMISC)) | 2565 | if (!(sdata->dev->flags & IFF_PROMISC)) |
2406 | return 0; | 2566 | return 0; |
2407 | 2567 | ||
2408 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2568 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
2409 | } | 2569 | } |
2410 | break; | 2570 | break; |
2411 | case NL80211_IFTYPE_AP_VLAN: | 2571 | case NL80211_IFTYPE_AP_VLAN: |
@@ -2416,9 +2576,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2416 | return 0; | 2576 | return 0; |
2417 | } else if (!ieee80211_bssid_match(bssid, | 2577 | } else if (!ieee80211_bssid_match(bssid, |
2418 | sdata->vif.addr)) { | 2578 | sdata->vif.addr)) { |
2419 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) | 2579 | if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) |
2420 | return 0; | 2580 | return 0; |
2421 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2581 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
2422 | } | 2582 | } |
2423 | break; | 2583 | break; |
2424 | case NL80211_IFTYPE_WDS: | 2584 | case NL80211_IFTYPE_WDS: |
@@ -2427,9 +2587,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2427 | if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2)) | 2587 | if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2)) |
2428 | return 0; | 2588 | return 0; |
2429 | break; | 2589 | break; |
2430 | case NL80211_IFTYPE_MONITOR: | 2590 | default: |
2431 | case NL80211_IFTYPE_UNSPECIFIED: | ||
2432 | case __NL80211_IFTYPE_AFTER_LAST: | ||
2433 | /* should never get here */ | 2591 | /* should never get here */ |
2434 | WARN_ON(1); | 2592 | WARN_ON(1); |
2435 | break; | 2593 | break; |
@@ -2439,12 +2597,56 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2439 | } | 2597 | } |
2440 | 2598 | ||
2441 | /* | 2599 | /* |
2600 | * This function returns whether or not the SKB | ||
2601 | * was destined for RX processing or not, which, | ||
2602 | * if consume is true, is equivalent to whether | ||
2603 | * or not the skb was consumed. | ||
2604 | */ | ||
2605 | static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, | ||
2606 | struct sk_buff *skb, bool consume) | ||
2607 | { | ||
2608 | struct ieee80211_local *local = rx->local; | ||
2609 | struct ieee80211_sub_if_data *sdata = rx->sdata; | ||
2610 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
2611 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
2612 | int prepares; | ||
2613 | |||
2614 | rx->skb = skb; | ||
2615 | status->rx_flags |= IEEE80211_RX_RA_MATCH; | ||
2616 | prepares = prepare_for_handlers(rx, hdr); | ||
2617 | |||
2618 | if (!prepares) | ||
2619 | return false; | ||
2620 | |||
2621 | if (status->flag & RX_FLAG_MMIC_ERROR) { | ||
2622 | if (status->rx_flags & IEEE80211_RX_RA_MATCH) | ||
2623 | ieee80211_rx_michael_mic_report(hdr, rx); | ||
2624 | return false; | ||
2625 | } | ||
2626 | |||
2627 | if (!consume) { | ||
2628 | skb = skb_copy(skb, GFP_ATOMIC); | ||
2629 | if (!skb) { | ||
2630 | if (net_ratelimit()) | ||
2631 | wiphy_debug(local->hw.wiphy, | ||
2632 | "failed to copy multicast frame for %s\n", | ||
2633 | sdata->name); | ||
2634 | return true; | ||
2635 | } | ||
2636 | |||
2637 | rx->skb = skb; | ||
2638 | } | ||
2639 | |||
2640 | ieee80211_invoke_rx_handlers(rx); | ||
2641 | return true; | ||
2642 | } | ||
2643 | |||
2644 | /* | ||
2442 | * This is the actual Rx frames handler. as it blongs to Rx path it must | 2645 | * This is the actual Rx frames handler. as it blongs to Rx path it must |
2443 | * be called with rcu_read_lock protection. | 2646 | * be called with rcu_read_lock protection. |
2444 | */ | 2647 | */ |
2445 | static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | 2648 | static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, |
2446 | struct sk_buff *skb, | 2649 | struct sk_buff *skb) |
2447 | struct ieee80211_rate *rate) | ||
2448 | { | 2650 | { |
2449 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 2651 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
2450 | struct ieee80211_local *local = hw_to_local(hw); | 2652 | struct ieee80211_local *local = hw_to_local(hw); |
@@ -2452,11 +2654,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2452 | struct ieee80211_hdr *hdr; | 2654 | struct ieee80211_hdr *hdr; |
2453 | __le16 fc; | 2655 | __le16 fc; |
2454 | struct ieee80211_rx_data rx; | 2656 | struct ieee80211_rx_data rx; |
2455 | int prepares; | 2657 | struct ieee80211_sub_if_data *prev; |
2456 | struct ieee80211_sub_if_data *prev = NULL; | 2658 | struct sta_info *sta, *tmp, *prev_sta; |
2457 | struct sk_buff *skb_new; | ||
2458 | struct sta_info *sta, *tmp; | ||
2459 | bool found_sta = false; | ||
2460 | int err = 0; | 2659 | int err = 0; |
2461 | 2660 | ||
2462 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; | 2661 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; |
@@ -2469,7 +2668,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2469 | 2668 | ||
2470 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || | 2669 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || |
2471 | test_bit(SCAN_OFF_CHANNEL, &local->scanning))) | 2670 | test_bit(SCAN_OFF_CHANNEL, &local->scanning))) |
2472 | rx.flags |= IEEE80211_RX_IN_SCAN; | 2671 | status->rx_flags |= IEEE80211_RX_IN_SCAN; |
2473 | 2672 | ||
2474 | if (ieee80211_is_mgmt(fc)) | 2673 | if (ieee80211_is_mgmt(fc)) |
2475 | err = skb_linearize(skb); | 2674 | err = skb_linearize(skb); |
@@ -2486,91 +2685,67 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2486 | ieee80211_verify_alignment(&rx); | 2685 | ieee80211_verify_alignment(&rx); |
2487 | 2686 | ||
2488 | if (ieee80211_is_data(fc)) { | 2687 | if (ieee80211_is_data(fc)) { |
2688 | prev_sta = NULL; | ||
2689 | |||
2489 | for_each_sta_info(local, hdr->addr2, sta, tmp) { | 2690 | for_each_sta_info(local, hdr->addr2, sta, tmp) { |
2490 | rx.sta = sta; | 2691 | if (!prev_sta) { |
2491 | found_sta = true; | 2692 | prev_sta = sta; |
2492 | rx.sdata = sta->sdata; | ||
2493 | |||
2494 | rx.flags |= IEEE80211_RX_RA_MATCH; | ||
2495 | prepares = prepare_for_handlers(rx.sdata, &rx, hdr); | ||
2496 | if (prepares) { | ||
2497 | if (status->flag & RX_FLAG_MMIC_ERROR) { | ||
2498 | if (rx.flags & IEEE80211_RX_RA_MATCH) | ||
2499 | ieee80211_rx_michael_mic_report(hdr, &rx); | ||
2500 | } else | ||
2501 | prev = rx.sdata; | ||
2502 | } | ||
2503 | } | ||
2504 | } | ||
2505 | if (!found_sta) { | ||
2506 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
2507 | if (!ieee80211_sdata_running(sdata)) | ||
2508 | continue; | 2693 | continue; |
2694 | } | ||
2509 | 2695 | ||
2510 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | 2696 | rx.sta = prev_sta; |
2511 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 2697 | rx.sdata = prev_sta->sdata; |
2512 | continue; | 2698 | ieee80211_prepare_and_rx_handle(&rx, skb, false); |
2513 | 2699 | ||
2514 | /* | 2700 | prev_sta = sta; |
2515 | * frame is destined for this interface, but if it's | 2701 | } |
2516 | * not also for the previous one we handle that after | ||
2517 | * the loop to avoid copying the SKB once too much | ||
2518 | */ | ||
2519 | 2702 | ||
2520 | if (!prev) { | 2703 | if (prev_sta) { |
2521 | prev = sdata; | 2704 | rx.sta = prev_sta; |
2522 | continue; | 2705 | rx.sdata = prev_sta->sdata; |
2523 | } | ||
2524 | 2706 | ||
2525 | rx.sta = sta_info_get_bss(prev, hdr->addr2); | 2707 | if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) |
2708 | return; | ||
2709 | } | ||
2710 | } | ||
2526 | 2711 | ||
2527 | rx.flags |= IEEE80211_RX_RA_MATCH; | 2712 | prev = NULL; |
2528 | prepares = prepare_for_handlers(prev, &rx, hdr); | ||
2529 | 2713 | ||
2530 | if (!prepares) | 2714 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
2531 | goto next; | 2715 | if (!ieee80211_sdata_running(sdata)) |
2716 | continue; | ||
2532 | 2717 | ||
2533 | if (status->flag & RX_FLAG_MMIC_ERROR) { | 2718 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || |
2534 | rx.sdata = prev; | 2719 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
2535 | if (rx.flags & IEEE80211_RX_RA_MATCH) | 2720 | continue; |
2536 | ieee80211_rx_michael_mic_report(hdr, | ||
2537 | &rx); | ||
2538 | goto next; | ||
2539 | } | ||
2540 | 2721 | ||
2541 | /* | 2722 | /* |
2542 | * frame was destined for the previous interface | 2723 | * frame is destined for this interface, but if it's |
2543 | * so invoke RX handlers for it | 2724 | * not also for the previous one we handle that after |
2544 | */ | 2725 | * the loop to avoid copying the SKB once too much |
2726 | */ | ||
2545 | 2727 | ||
2546 | skb_new = skb_copy(skb, GFP_ATOMIC); | 2728 | if (!prev) { |
2547 | if (!skb_new) { | ||
2548 | if (net_ratelimit()) | ||
2549 | printk(KERN_DEBUG "%s: failed to copy " | ||
2550 | "multicast frame for %s\n", | ||
2551 | wiphy_name(local->hw.wiphy), | ||
2552 | prev->name); | ||
2553 | goto next; | ||
2554 | } | ||
2555 | ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); | ||
2556 | next: | ||
2557 | prev = sdata; | 2729 | prev = sdata; |
2730 | continue; | ||
2558 | } | 2731 | } |
2559 | 2732 | ||
2560 | if (prev) { | 2733 | rx.sta = sta_info_get_bss(prev, hdr->addr2); |
2561 | rx.sta = sta_info_get_bss(prev, hdr->addr2); | 2734 | rx.sdata = prev; |
2735 | ieee80211_prepare_and_rx_handle(&rx, skb, false); | ||
2562 | 2736 | ||
2563 | rx.flags |= IEEE80211_RX_RA_MATCH; | 2737 | prev = sdata; |
2564 | prepares = prepare_for_handlers(prev, &rx, hdr); | 2738 | } |
2565 | 2739 | ||
2566 | if (!prepares) | 2740 | if (prev) { |
2567 | prev = NULL; | 2741 | rx.sta = sta_info_get_bss(prev, hdr->addr2); |
2568 | } | 2742 | rx.sdata = prev; |
2743 | |||
2744 | if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) | ||
2745 | return; | ||
2569 | } | 2746 | } |
2570 | if (prev) | 2747 | |
2571 | ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); | 2748 | dev_kfree_skb(skb); |
2572 | else | ||
2573 | dev_kfree_skb(skb); | ||
2574 | } | 2749 | } |
2575 | 2750 | ||
2576 | /* | 2751 | /* |
@@ -2611,30 +2786,41 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2611 | if (WARN_ON(!local->started)) | 2786 | if (WARN_ON(!local->started)) |
2612 | goto drop; | 2787 | goto drop; |
2613 | 2788 | ||
2614 | if (status->flag & RX_FLAG_HT) { | 2789 | if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) { |
2615 | /* | 2790 | /* |
2616 | * rate_idx is MCS index, which can be [0-76] as documented on: | 2791 | * Validate the rate, unless a PLCP error means that |
2617 | * | 2792 | * we probably can't have a valid rate here anyway. |
2618 | * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n | ||
2619 | * | ||
2620 | * Anything else would be some sort of driver or hardware error. | ||
2621 | * The driver should catch hardware errors. | ||
2622 | */ | 2793 | */ |
2623 | if (WARN((status->rate_idx < 0 || | 2794 | |
2624 | status->rate_idx > 76), | 2795 | if (status->flag & RX_FLAG_HT) { |
2625 | "Rate marked as an HT rate but passed " | 2796 | /* |
2626 | "status->rate_idx is not " | 2797 | * rate_idx is MCS index, which can be [0-76] |
2627 | "an MCS index [0-76]: %d (0x%02x)\n", | 2798 | * as documented on: |
2628 | status->rate_idx, | 2799 | * |
2629 | status->rate_idx)) | 2800 | * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n |
2630 | goto drop; | 2801 | * |
2631 | } else { | 2802 | * Anything else would be some sort of driver or |
2632 | if (WARN_ON(status->rate_idx < 0 || | 2803 | * hardware error. The driver should catch hardware |
2633 | status->rate_idx >= sband->n_bitrates)) | 2804 | * errors. |
2634 | goto drop; | 2805 | */ |
2635 | rate = &sband->bitrates[status->rate_idx]; | 2806 | if (WARN((status->rate_idx < 0 || |
2807 | status->rate_idx > 76), | ||
2808 | "Rate marked as an HT rate but passed " | ||
2809 | "status->rate_idx is not " | ||
2810 | "an MCS index [0-76]: %d (0x%02x)\n", | ||
2811 | status->rate_idx, | ||
2812 | status->rate_idx)) | ||
2813 | goto drop; | ||
2814 | } else { | ||
2815 | if (WARN_ON(status->rate_idx < 0 || | ||
2816 | status->rate_idx >= sband->n_bitrates)) | ||
2817 | goto drop; | ||
2818 | rate = &sband->bitrates[status->rate_idx]; | ||
2819 | } | ||
2636 | } | 2820 | } |
2637 | 2821 | ||
2822 | status->rx_flags = 0; | ||
2823 | |||
2638 | /* | 2824 | /* |
2639 | * key references and virtual interfaces are protected using RCU | 2825 | * key references and virtual interfaces are protected using RCU |
2640 | * and this requires that we are in a read-side RCU section during | 2826 | * and this requires that we are in a read-side RCU section during |
@@ -2654,7 +2840,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2654 | return; | 2840 | return; |
2655 | } | 2841 | } |
2656 | 2842 | ||
2657 | __ieee80211_rx_handle_packet(hw, skb, rate); | 2843 | __ieee80211_rx_handle_packet(hw, skb); |
2658 | 2844 | ||
2659 | rcu_read_unlock(); | 2845 | rcu_read_unlock(); |
2660 | 2846 | ||
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 872d7b6ef6b..5171a958163 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -242,20 +242,19 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
242 | local->hw_scan_req->n_channels = n_chans; | 242 | local->hw_scan_req->n_channels = n_chans; |
243 | 243 | ||
244 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, | 244 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, |
245 | req->ie, req->ie_len, band); | 245 | req->ie, req->ie_len, band, (u32) -1, |
246 | 0); | ||
246 | local->hw_scan_req->ie_len = ielen; | 247 | local->hw_scan_req->ie_len = ielen; |
247 | 248 | ||
248 | return true; | 249 | return true; |
249 | } | 250 | } |
250 | 251 | ||
251 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 252 | static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
252 | { | 253 | { |
253 | struct ieee80211_local *local = hw_to_local(hw); | 254 | struct ieee80211_local *local = hw_to_local(hw); |
254 | bool was_hw_scan; | 255 | bool was_hw_scan; |
255 | 256 | ||
256 | trace_api_scan_completed(local, aborted); | 257 | mutex_lock(&local->mtx); |
257 | |||
258 | mutex_lock(&local->scan_mtx); | ||
259 | 258 | ||
260 | /* | 259 | /* |
261 | * It's ok to abort a not-yet-running scan (that | 260 | * It's ok to abort a not-yet-running scan (that |
@@ -267,7 +266,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
267 | aborted = true; | 266 | aborted = true; |
268 | 267 | ||
269 | if (WARN_ON(!local->scan_req)) { | 268 | if (WARN_ON(!local->scan_req)) { |
270 | mutex_unlock(&local->scan_mtx); | 269 | mutex_unlock(&local->mtx); |
271 | return; | 270 | return; |
272 | } | 271 | } |
273 | 272 | ||
@@ -275,7 +274,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
275 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { | 274 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { |
276 | ieee80211_queue_delayed_work(&local->hw, | 275 | ieee80211_queue_delayed_work(&local->hw, |
277 | &local->scan_work, 0); | 276 | &local->scan_work, 0); |
278 | mutex_unlock(&local->scan_mtx); | 277 | mutex_unlock(&local->mtx); |
279 | return; | 278 | return; |
280 | } | 279 | } |
281 | 280 | ||
@@ -291,7 +290,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
291 | local->scan_channel = NULL; | 290 | local->scan_channel = NULL; |
292 | 291 | ||
293 | /* we only have to protect scan_req and hw/sw scan */ | 292 | /* we only have to protect scan_req and hw/sw scan */ |
294 | mutex_unlock(&local->scan_mtx); | 293 | mutex_unlock(&local->mtx); |
295 | 294 | ||
296 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 295 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
297 | if (was_hw_scan) | 296 | if (was_hw_scan) |
@@ -304,12 +303,26 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
304 | ieee80211_offchannel_return(local, true); | 303 | ieee80211_offchannel_return(local, true); |
305 | 304 | ||
306 | done: | 305 | done: |
306 | mutex_lock(&local->mtx); | ||
307 | ieee80211_recalc_idle(local); | 307 | ieee80211_recalc_idle(local); |
308 | mutex_unlock(&local->mtx); | ||
308 | ieee80211_mlme_notify_scan_completed(local); | 309 | ieee80211_mlme_notify_scan_completed(local); |
309 | ieee80211_ibss_notify_scan_completed(local); | 310 | ieee80211_ibss_notify_scan_completed(local); |
310 | ieee80211_mesh_notify_scan_completed(local); | 311 | ieee80211_mesh_notify_scan_completed(local); |
311 | ieee80211_queue_work(&local->hw, &local->work_work); | 312 | ieee80211_queue_work(&local->hw, &local->work_work); |
312 | } | 313 | } |
314 | |||
315 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | ||
316 | { | ||
317 | struct ieee80211_local *local = hw_to_local(hw); | ||
318 | |||
319 | trace_api_scan_completed(local, aborted); | ||
320 | |||
321 | set_bit(SCAN_COMPLETED, &local->scanning); | ||
322 | if (aborted) | ||
323 | set_bit(SCAN_ABORTED, &local->scanning); | ||
324 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0); | ||
325 | } | ||
313 | EXPORT_SYMBOL(ieee80211_scan_completed); | 326 | EXPORT_SYMBOL(ieee80211_scan_completed); |
314 | 327 | ||
315 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) | 328 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) |
@@ -447,7 +460,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
447 | 460 | ||
448 | /* if no more bands/channels left, complete scan and advance to the idle state */ | 461 | /* if no more bands/channels left, complete scan and advance to the idle state */ |
449 | if (local->scan_channel_idx >= local->scan_req->n_channels) { | 462 | if (local->scan_channel_idx >= local->scan_req->n_channels) { |
450 | ieee80211_scan_completed(&local->hw, false); | 463 | __ieee80211_scan_completed(&local->hw, false); |
451 | return 1; | 464 | return 1; |
452 | } | 465 | } |
453 | 466 | ||
@@ -639,17 +652,25 @@ void ieee80211_scan_work(struct work_struct *work) | |||
639 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 652 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
640 | unsigned long next_delay = 0; | 653 | unsigned long next_delay = 0; |
641 | 654 | ||
642 | mutex_lock(&local->scan_mtx); | 655 | if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { |
656 | bool aborted; | ||
657 | |||
658 | aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); | ||
659 | __ieee80211_scan_completed(&local->hw, aborted); | ||
660 | return; | ||
661 | } | ||
662 | |||
663 | mutex_lock(&local->mtx); | ||
643 | if (!sdata || !local->scan_req) { | 664 | if (!sdata || !local->scan_req) { |
644 | mutex_unlock(&local->scan_mtx); | 665 | mutex_unlock(&local->mtx); |
645 | return; | 666 | return; |
646 | } | 667 | } |
647 | 668 | ||
648 | if (local->hw_scan_req) { | 669 | if (local->hw_scan_req) { |
649 | int rc = drv_hw_scan(local, sdata, local->hw_scan_req); | 670 | int rc = drv_hw_scan(local, sdata, local->hw_scan_req); |
650 | mutex_unlock(&local->scan_mtx); | 671 | mutex_unlock(&local->mtx); |
651 | if (rc) | 672 | if (rc) |
652 | ieee80211_scan_completed(&local->hw, true); | 673 | __ieee80211_scan_completed(&local->hw, true); |
653 | return; | 674 | return; |
654 | } | 675 | } |
655 | 676 | ||
@@ -661,20 +682,20 @@ void ieee80211_scan_work(struct work_struct *work) | |||
661 | local->scan_sdata = NULL; | 682 | local->scan_sdata = NULL; |
662 | 683 | ||
663 | rc = __ieee80211_start_scan(sdata, req); | 684 | rc = __ieee80211_start_scan(sdata, req); |
664 | mutex_unlock(&local->scan_mtx); | 685 | mutex_unlock(&local->mtx); |
665 | 686 | ||
666 | if (rc) | 687 | if (rc) |
667 | ieee80211_scan_completed(&local->hw, true); | 688 | __ieee80211_scan_completed(&local->hw, true); |
668 | return; | 689 | return; |
669 | } | 690 | } |
670 | 691 | ||
671 | mutex_unlock(&local->scan_mtx); | 692 | mutex_unlock(&local->mtx); |
672 | 693 | ||
673 | /* | 694 | /* |
674 | * Avoid re-scheduling when the sdata is going away. | 695 | * Avoid re-scheduling when the sdata is going away. |
675 | */ | 696 | */ |
676 | if (!ieee80211_sdata_running(sdata)) { | 697 | if (!ieee80211_sdata_running(sdata)) { |
677 | ieee80211_scan_completed(&local->hw, true); | 698 | __ieee80211_scan_completed(&local->hw, true); |
678 | return; | 699 | return; |
679 | } | 700 | } |
680 | 701 | ||
@@ -711,9 +732,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
711 | { | 732 | { |
712 | int res; | 733 | int res; |
713 | 734 | ||
714 | mutex_lock(&sdata->local->scan_mtx); | 735 | mutex_lock(&sdata->local->mtx); |
715 | res = __ieee80211_start_scan(sdata, req); | 736 | res = __ieee80211_start_scan(sdata, req); |
716 | mutex_unlock(&sdata->local->scan_mtx); | 737 | mutex_unlock(&sdata->local->mtx); |
717 | 738 | ||
718 | return res; | 739 | return res; |
719 | } | 740 | } |
@@ -726,7 +747,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
726 | int ret = -EBUSY; | 747 | int ret = -EBUSY; |
727 | enum ieee80211_band band; | 748 | enum ieee80211_band band; |
728 | 749 | ||
729 | mutex_lock(&local->scan_mtx); | 750 | mutex_lock(&local->mtx); |
730 | 751 | ||
731 | /* busy scanning */ | 752 | /* busy scanning */ |
732 | if (local->scan_req) | 753 | if (local->scan_req) |
@@ -761,7 +782,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
761 | 782 | ||
762 | ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req); | 783 | ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req); |
763 | unlock: | 784 | unlock: |
764 | mutex_unlock(&local->scan_mtx); | 785 | mutex_unlock(&local->mtx); |
765 | return ret; | 786 | return ret; |
766 | } | 787 | } |
767 | 788 | ||
@@ -775,11 +796,11 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
775 | * Only call this function when a scan can't be | 796 | * Only call this function when a scan can't be |
776 | * queued -- mostly at suspend under RTNL. | 797 | * queued -- mostly at suspend under RTNL. |
777 | */ | 798 | */ |
778 | mutex_lock(&local->scan_mtx); | 799 | mutex_lock(&local->mtx); |
779 | abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || | 800 | abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || |
780 | (!local->scanning && local->scan_req); | 801 | (!local->scanning && local->scan_req); |
781 | mutex_unlock(&local->scan_mtx); | 802 | mutex_unlock(&local->mtx); |
782 | 803 | ||
783 | if (abortscan) | 804 | if (abortscan) |
784 | ieee80211_scan_completed(&local->hw, true); | 805 | __ieee80211_scan_completed(&local->hw, true); |
785 | } | 806 | } |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 6d86f0c1ad0..ca2cba9cea8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -125,7 +125,7 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | |||
125 | lockdep_is_held(&local->sta_mtx)); | 125 | lockdep_is_held(&local->sta_mtx)); |
126 | while (sta) { | 126 | while (sta) { |
127 | if ((sta->sdata == sdata || | 127 | if ((sta->sdata == sdata || |
128 | sta->sdata->bss == sdata->bss) && | 128 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && |
129 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 129 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
130 | break; | 130 | break; |
131 | sta = rcu_dereference_check(sta->hnext, | 131 | sta = rcu_dereference_check(sta->hnext, |
@@ -174,8 +174,7 @@ static void __sta_info_free(struct ieee80211_local *local, | |||
174 | } | 174 | } |
175 | 175 | ||
176 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 176 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
177 | printk(KERN_DEBUG "%s: Destroyed STA %pM\n", | 177 | wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr); |
178 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
179 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 178 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
180 | 179 | ||
181 | kfree(sta); | 180 | kfree(sta); |
@@ -262,8 +261,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
262 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); | 261 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); |
263 | 262 | ||
264 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 263 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
265 | printk(KERN_DEBUG "%s: Allocated STA %pM\n", | 264 | wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr); |
266 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
267 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 265 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
268 | 266 | ||
269 | #ifdef CONFIG_MAC80211_MESH | 267 | #ifdef CONFIG_MAC80211_MESH |
@@ -282,7 +280,7 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async) | |||
282 | unsigned long flags; | 280 | unsigned long flags; |
283 | int err = 0; | 281 | int err = 0; |
284 | 282 | ||
285 | WARN_ON(!mutex_is_locked(&local->sta_mtx)); | 283 | lockdep_assert_held(&local->sta_mtx); |
286 | 284 | ||
287 | /* notify driver */ | 285 | /* notify driver */ |
288 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 286 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
@@ -300,8 +298,9 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async) | |||
300 | sta->uploaded = true; | 298 | sta->uploaded = true; |
301 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 299 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
302 | if (async) | 300 | if (async) |
303 | printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n", | 301 | wiphy_debug(local->hw.wiphy, |
304 | wiphy_name(local->hw.wiphy), sta->sta.addr); | 302 | "Finished adding IBSS STA %pM\n", |
303 | sta->sta.addr); | ||
305 | #endif | 304 | #endif |
306 | } | 305 | } |
307 | 306 | ||
@@ -411,8 +410,8 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | |||
411 | spin_unlock_irqrestore(&local->sta_lock, flags); | 410 | spin_unlock_irqrestore(&local->sta_lock, flags); |
412 | 411 | ||
413 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 412 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
414 | printk(KERN_DEBUG "%s: Added IBSS STA %pM\n", | 413 | wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n", |
415 | wiphy_name(local->hw.wiphy), sta->sta.addr); | 414 | sta->sta.addr); |
416 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 415 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
417 | 416 | ||
418 | ieee80211_queue_work(&local->hw, &local->sta_finish_work); | 417 | ieee80211_queue_work(&local->hw, &local->sta_finish_work); |
@@ -459,8 +458,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | |||
459 | } | 458 | } |
460 | 459 | ||
461 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 460 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
462 | printk(KERN_DEBUG "%s: Inserted STA %pM\n", | 461 | wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); |
463 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
464 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 462 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
465 | 463 | ||
466 | /* move reference to rcu-protected */ | 464 | /* move reference to rcu-protected */ |
@@ -690,8 +688,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
690 | #endif | 688 | #endif |
691 | 689 | ||
692 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 690 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
693 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | 691 | wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr); |
694 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
695 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 692 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
696 | cancel_work_sync(&sta->drv_unblock_wk); | 693 | cancel_work_sync(&sta->drv_unblock_wk); |
697 | 694 | ||
@@ -841,13 +838,20 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
841 | mutex_unlock(&local->sta_mtx); | 838 | mutex_unlock(&local->sta_mtx); |
842 | } | 839 | } |
843 | 840 | ||
844 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, | 841 | struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw, |
845 | const u8 *addr) | 842 | const u8 *addr, |
843 | const u8 *localaddr) | ||
846 | { | 844 | { |
847 | struct sta_info *sta, *nxt; | 845 | struct sta_info *sta, *nxt; |
848 | 846 | ||
849 | /* Just return a random station ... first in list ... */ | 847 | /* |
848 | * Just return a random station if localaddr is NULL | ||
849 | * ... first in list. | ||
850 | */ | ||
850 | for_each_sta_info(hw_to_local(hw), addr, sta, nxt) { | 851 | for_each_sta_info(hw_to_local(hw), addr, sta, nxt) { |
852 | if (localaddr && | ||
853 | compare_ether_addr(sta->sdata->vif.addr, localaddr) != 0) | ||
854 | continue; | ||
851 | if (!sta->uploaded) | 855 | if (!sta->uploaded) |
852 | return NULL; | 856 | return NULL; |
853 | return &sta->sta; | 857 | return &sta->sta; |
@@ -855,7 +859,7 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, | |||
855 | 859 | ||
856 | return NULL; | 860 | return NULL; |
857 | } | 861 | } |
858 | EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); | 862 | EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_ifaddr); |
859 | 863 | ||
860 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, | 864 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, |
861 | const u8 *addr) | 865 | const u8 *addr) |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 54262e72376..810c5ce9831 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -103,6 +103,7 @@ struct tid_ampdu_tx { | |||
103 | * @reorder_buf: buffer to reorder incoming aggregated MPDUs | 103 | * @reorder_buf: buffer to reorder incoming aggregated MPDUs |
104 | * @reorder_time: jiffies when skb was added | 104 | * @reorder_time: jiffies when skb was added |
105 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) | 105 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) |
106 | * @reorder_timer: releases expired frames from the reorder buffer. | ||
106 | * @head_seq_num: head sequence number in reordering buffer. | 107 | * @head_seq_num: head sequence number in reordering buffer. |
107 | * @stored_mpdu_num: number of MPDUs in reordering buffer | 108 | * @stored_mpdu_num: number of MPDUs in reordering buffer |
108 | * @ssn: Starting Sequence Number expected to be aggregated. | 109 | * @ssn: Starting Sequence Number expected to be aggregated. |
@@ -110,20 +111,25 @@ struct tid_ampdu_tx { | |||
110 | * @timeout: reset timer value (in TUs). | 111 | * @timeout: reset timer value (in TUs). |
111 | * @dialog_token: dialog token for aggregation session | 112 | * @dialog_token: dialog token for aggregation session |
112 | * @rcu_head: RCU head used for freeing this struct | 113 | * @rcu_head: RCU head used for freeing this struct |
114 | * @reorder_lock: serializes access to reorder buffer, see below. | ||
113 | * | 115 | * |
114 | * This structure is protected by RCU and the per-station | 116 | * This structure is protected by RCU and the per-station |
115 | * spinlock. Assignments to the array holding it must hold | 117 | * spinlock. Assignments to the array holding it must hold |
116 | * the spinlock, only the RX path can access it under RCU | 118 | * the spinlock. |
117 | * lock-free. The RX path, since it is single-threaded, | 119 | * |
118 | * can even modify the structure without locking since the | 120 | * The @reorder_lock is used to protect the variables and |
119 | * only other modifications to it are done when the struct | 121 | * arrays such as @reorder_buf, @reorder_time, @head_seq_num, |
120 | * can not yet or no longer be found by the RX path. | 122 | * @stored_mpdu_num and @reorder_time from being corrupted by |
123 | * concurrent access of the RX path and the expired frame | ||
124 | * release timer. | ||
121 | */ | 125 | */ |
122 | struct tid_ampdu_rx { | 126 | struct tid_ampdu_rx { |
123 | struct rcu_head rcu_head; | 127 | struct rcu_head rcu_head; |
128 | spinlock_t reorder_lock; | ||
124 | struct sk_buff **reorder_buf; | 129 | struct sk_buff **reorder_buf; |
125 | unsigned long *reorder_time; | 130 | unsigned long *reorder_time; |
126 | struct timer_list session_timer; | 131 | struct timer_list session_timer; |
132 | struct timer_list reorder_timer; | ||
127 | u16 head_seq_num; | 133 | u16 head_seq_num; |
128 | u16 stored_mpdu_num; | 134 | u16 stored_mpdu_num; |
129 | u16 ssn; | 135 | u16 ssn; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 10caec5ea8f..95763e03697 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -58,6 +58,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
58 | info->control.vif = &sta->sdata->vif; | 58 | info->control.vif = &sta->sdata->vif; |
59 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | | 59 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | |
60 | IEEE80211_TX_INTFL_RETRANSMISSION; | 60 | IEEE80211_TX_INTFL_RETRANSMISSION; |
61 | info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; | ||
61 | 62 | ||
62 | sta->tx_filtered_count++; | 63 | sta->tx_filtered_count++; |
63 | 64 | ||
@@ -114,11 +115,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
114 | 115 | ||
115 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 116 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
116 | if (net_ratelimit()) | 117 | if (net_ratelimit()) |
117 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " | 118 | wiphy_debug(local->hw.wiphy, |
118 | "queue_len=%d PS=%d @%lu\n", | 119 | "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", |
119 | wiphy_name(local->hw.wiphy), | 120 | skb_queue_len(&sta->tx_filtered), |
120 | skb_queue_len(&sta->tx_filtered), | 121 | !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies); |
121 | !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies); | ||
122 | #endif | 122 | #endif |
123 | dev_kfree_skb(skb); | 123 | dev_kfree_skb(skb); |
124 | } | 124 | } |
@@ -176,7 +176,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
176 | 176 | ||
177 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 177 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
178 | /* the HW cannot have attempted that rate */ | 178 | /* the HW cannot have attempted that rate */ |
179 | if (i >= hw->max_rates) { | 179 | if (i >= hw->max_report_rates) { |
180 | info->status.rates[i].idx = -1; | 180 | info->status.rates[i].idx = -1; |
181 | info->status.rates[i].count = 0; | 181 | info->status.rates[i].count = 0; |
182 | } else if (info->status.rates[i].idx >= 0) { | 182 | } else if (info->status.rates[i].idx >= 0) { |
@@ -296,7 +296,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
296 | } | 296 | } |
297 | 297 | ||
298 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) | 298 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) |
299 | cfg80211_action_tx_status( | 299 | cfg80211_mgmt_tx_status( |
300 | skb->dev, (unsigned long) skb, skb->data, skb->len, | 300 | skb->dev, (unsigned long) skb, skb->data, skb->len, |
301 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); | 301 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); |
302 | 302 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c54db966926..258fbdbedbd 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -273,6 +273,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
273 | */ | 273 | */ |
274 | return TX_DROP; | 274 | return TX_DROP; |
275 | 275 | ||
276 | if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) | ||
277 | return TX_CONTINUE; | ||
278 | |||
276 | if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | 279 | if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |
277 | return TX_CONTINUE; | 280 | return TX_CONTINUE; |
278 | 281 | ||
@@ -351,8 +354,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
351 | 354 | ||
352 | local->total_ps_buffered = total; | 355 | local->total_ps_buffered = total; |
353 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 356 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
354 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", | 357 | wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n", |
355 | wiphy_name(local->hw.wiphy), purged); | 358 | purged); |
356 | #endif | 359 | #endif |
357 | } | 360 | } |
358 | 361 | ||
@@ -509,6 +512,18 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) | |||
509 | } | 512 | } |
510 | 513 | ||
511 | static ieee80211_tx_result debug_noinline | 514 | static ieee80211_tx_result debug_noinline |
515 | ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx) | ||
516 | { | ||
517 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
518 | |||
519 | if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol && | ||
520 | tx->sdata->control_port_no_encrypt)) | ||
521 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
522 | |||
523 | return TX_CONTINUE; | ||
524 | } | ||
525 | |||
526 | static ieee80211_tx_result debug_noinline | ||
512 | ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | 527 | ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) |
513 | { | 528 | { |
514 | struct ieee80211_key *key = NULL; | 529 | struct ieee80211_key *key = NULL; |
@@ -527,7 +542,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
527 | else if ((key = rcu_dereference(tx->sdata->default_key))) | 542 | else if ((key = rcu_dereference(tx->sdata->default_key))) |
528 | tx->key = key; | 543 | tx->key = key; |
529 | else if (tx->sdata->drop_unencrypted && | 544 | else if (tx->sdata->drop_unencrypted && |
530 | (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) && | 545 | (tx->skb->protocol != tx->sdata->control_port_protocol) && |
531 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && | 546 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && |
532 | (!ieee80211_is_robust_mgmt_frame(hdr) || | 547 | (!ieee80211_is_robust_mgmt_frame(hdr) || |
533 | (ieee80211_is_action(hdr->frame_control) && | 548 | (ieee80211_is_action(hdr->frame_control) && |
@@ -543,15 +558,16 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
543 | tx->key->tx_rx_count++; | 558 | tx->key->tx_rx_count++; |
544 | /* TODO: add threshold stuff again */ | 559 | /* TODO: add threshold stuff again */ |
545 | 560 | ||
546 | switch (tx->key->conf.alg) { | 561 | switch (tx->key->conf.cipher) { |
547 | case ALG_WEP: | 562 | case WLAN_CIPHER_SUITE_WEP40: |
563 | case WLAN_CIPHER_SUITE_WEP104: | ||
548 | if (ieee80211_is_auth(hdr->frame_control)) | 564 | if (ieee80211_is_auth(hdr->frame_control)) |
549 | break; | 565 | break; |
550 | case ALG_TKIP: | 566 | case WLAN_CIPHER_SUITE_TKIP: |
551 | if (!ieee80211_is_data_present(hdr->frame_control)) | 567 | if (!ieee80211_is_data_present(hdr->frame_control)) |
552 | tx->key = NULL; | 568 | tx->key = NULL; |
553 | break; | 569 | break; |
554 | case ALG_CCMP: | 570 | case WLAN_CIPHER_SUITE_CCMP: |
555 | if (!ieee80211_is_data_present(hdr->frame_control) && | 571 | if (!ieee80211_is_data_present(hdr->frame_control) && |
556 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, | 572 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, |
557 | tx->skb)) | 573 | tx->skb)) |
@@ -561,7 +577,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
561 | IEEE80211_KEY_FLAG_SW_MGMT) && | 577 | IEEE80211_KEY_FLAG_SW_MGMT) && |
562 | ieee80211_is_mgmt(hdr->frame_control); | 578 | ieee80211_is_mgmt(hdr->frame_control); |
563 | break; | 579 | break; |
564 | case ALG_AES_CMAC: | 580 | case WLAN_CIPHER_SUITE_AES_CMAC: |
565 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 581 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
566 | tx->key = NULL; | 582 | tx->key = NULL; |
567 | break; | 583 | break; |
@@ -946,22 +962,31 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | |||
946 | static ieee80211_tx_result debug_noinline | 962 | static ieee80211_tx_result debug_noinline |
947 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | 963 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) |
948 | { | 964 | { |
965 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
966 | |||
949 | if (!tx->key) | 967 | if (!tx->key) |
950 | return TX_CONTINUE; | 968 | return TX_CONTINUE; |
951 | 969 | ||
952 | switch (tx->key->conf.alg) { | 970 | switch (tx->key->conf.cipher) { |
953 | case ALG_WEP: | 971 | case WLAN_CIPHER_SUITE_WEP40: |
972 | case WLAN_CIPHER_SUITE_WEP104: | ||
954 | return ieee80211_crypto_wep_encrypt(tx); | 973 | return ieee80211_crypto_wep_encrypt(tx); |
955 | case ALG_TKIP: | 974 | case WLAN_CIPHER_SUITE_TKIP: |
956 | return ieee80211_crypto_tkip_encrypt(tx); | 975 | return ieee80211_crypto_tkip_encrypt(tx); |
957 | case ALG_CCMP: | 976 | case WLAN_CIPHER_SUITE_CCMP: |
958 | return ieee80211_crypto_ccmp_encrypt(tx); | 977 | return ieee80211_crypto_ccmp_encrypt(tx); |
959 | case ALG_AES_CMAC: | 978 | case WLAN_CIPHER_SUITE_AES_CMAC: |
960 | return ieee80211_crypto_aes_cmac_encrypt(tx); | 979 | return ieee80211_crypto_aes_cmac_encrypt(tx); |
980 | default: | ||
981 | /* handle hw-only algorithm */ | ||
982 | if (info->control.hw_key) { | ||
983 | ieee80211_tx_set_protected(tx); | ||
984 | return TX_CONTINUE; | ||
985 | } | ||
986 | break; | ||
987 | |||
961 | } | 988 | } |
962 | 989 | ||
963 | /* not reached */ | ||
964 | WARN_ON(1); | ||
965 | return TX_DROP; | 990 | return TX_DROP; |
966 | } | 991 | } |
967 | 992 | ||
@@ -1339,6 +1364,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1339 | CALL_TXH(ieee80211_tx_h_dynamic_ps); | 1364 | CALL_TXH(ieee80211_tx_h_dynamic_ps); |
1340 | CALL_TXH(ieee80211_tx_h_check_assoc); | 1365 | CALL_TXH(ieee80211_tx_h_check_assoc); |
1341 | CALL_TXH(ieee80211_tx_h_ps_buf); | 1366 | CALL_TXH(ieee80211_tx_h_ps_buf); |
1367 | CALL_TXH(ieee80211_tx_h_check_control_port_protocol); | ||
1342 | CALL_TXH(ieee80211_tx_h_select_key); | 1368 | CALL_TXH(ieee80211_tx_h_select_key); |
1343 | if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) | 1369 | if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) |
1344 | CALL_TXH(ieee80211_tx_h_rate_ctrl); | 1370 | CALL_TXH(ieee80211_tx_h_rate_ctrl); |
@@ -1511,8 +1537,8 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, | |||
1511 | I802_DEBUG_INC(local->tx_expand_skb_head); | 1537 | I802_DEBUG_INC(local->tx_expand_skb_head); |
1512 | 1538 | ||
1513 | if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) { | 1539 | if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) { |
1514 | printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n", | 1540 | wiphy_debug(local->hw.wiphy, |
1515 | wiphy_name(local->hw.wiphy)); | 1541 | "failed to reallocate TX buffer\n"); |
1516 | return -ENOMEM; | 1542 | return -ENOMEM; |
1517 | } | 1543 | } |
1518 | 1544 | ||
@@ -1586,6 +1612,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1586 | return; | 1612 | return; |
1587 | } | 1613 | } |
1588 | 1614 | ||
1615 | hdr = (struct ieee80211_hdr *) skb->data; | ||
1589 | info->control.vif = &sdata->vif; | 1616 | info->control.vif = &sdata->vif; |
1590 | 1617 | ||
1591 | if (ieee80211_vif_is_mesh(&sdata->vif) && | 1618 | if (ieee80211_vif_is_mesh(&sdata->vif) && |
@@ -1699,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1699 | u16 ethertype, hdrlen, meshhdrlen = 0; | 1726 | u16 ethertype, hdrlen, meshhdrlen = 0; |
1700 | __le16 fc; | 1727 | __le16 fc; |
1701 | struct ieee80211_hdr hdr; | 1728 | struct ieee80211_hdr hdr; |
1702 | struct ieee80211s_hdr mesh_hdr; | 1729 | struct ieee80211s_hdr mesh_hdr __maybe_unused; |
1703 | const u8 *encaps_data; | 1730 | const u8 *encaps_data; |
1704 | int encaps_len, skip_header_bytes; | 1731 | int encaps_len, skip_header_bytes; |
1705 | int nh_pos, h_pos; | 1732 | int nh_pos, h_pos; |
@@ -1816,7 +1843,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1816 | #endif | 1843 | #endif |
1817 | case NL80211_IFTYPE_STATION: | 1844 | case NL80211_IFTYPE_STATION: |
1818 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); | 1845 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); |
1819 | if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) { | 1846 | if (sdata->u.mgd.use_4addr && |
1847 | cpu_to_be16(ethertype) != sdata->control_port_protocol) { | ||
1820 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1848 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
1821 | /* RA TA DA SA */ | 1849 | /* RA TA DA SA */ |
1822 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); | 1850 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); |
@@ -1869,7 +1897,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1869 | if (!ieee80211_vif_is_mesh(&sdata->vif) && | 1897 | if (!ieee80211_vif_is_mesh(&sdata->vif) && |
1870 | unlikely(!is_multicast_ether_addr(hdr.addr1) && | 1898 | unlikely(!is_multicast_ether_addr(hdr.addr1) && |
1871 | !(sta_flags & WLAN_STA_AUTHORIZED) && | 1899 | !(sta_flags & WLAN_STA_AUTHORIZED) && |
1872 | !(ethertype == ETH_P_PAE && | 1900 | !(cpu_to_be16(ethertype) == sdata->control_port_protocol && |
1873 | compare_ether_addr(sdata->vif.addr, | 1901 | compare_ether_addr(sdata->vif.addr, |
1874 | skb->data + ETH_ALEN) == 0))) { | 1902 | skb->data + ETH_ALEN) == 0))) { |
1875 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1903 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -2068,8 +2096,7 @@ void ieee80211_tx_pending(unsigned long data) | |||
2068 | 2096 | ||
2069 | if (skb_queue_empty(&local->pending[i])) | 2097 | if (skb_queue_empty(&local->pending[i])) |
2070 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 2098 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
2071 | netif_tx_wake_queue( | 2099 | netif_wake_subqueue(sdata->dev, i); |
2072 | netdev_get_tx_queue(sdata->dev, i)); | ||
2073 | } | 2100 | } |
2074 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 2101 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
2075 | 2102 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 748387d45bc..4ee8f2b53cb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -283,8 +283,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
283 | 283 | ||
284 | if (skb_queue_empty(&local->pending[queue])) { | 284 | if (skb_queue_empty(&local->pending[queue])) { |
285 | rcu_read_lock(); | 285 | rcu_read_lock(); |
286 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 286 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
287 | netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); | 287 | if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) |
288 | continue; | ||
289 | netif_wake_subqueue(sdata->dev, queue); | ||
290 | } | ||
288 | rcu_read_unlock(); | 291 | rcu_read_unlock(); |
289 | } else | 292 | } else |
290 | tasklet_schedule(&local->tx_pending_tasklet); | 293 | tasklet_schedule(&local->tx_pending_tasklet); |
@@ -323,7 +326,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
323 | 326 | ||
324 | rcu_read_lock(); | 327 | rcu_read_lock(); |
325 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 328 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
326 | netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue)); | 329 | netif_stop_subqueue(sdata->dev, queue); |
327 | rcu_read_unlock(); | 330 | rcu_read_unlock(); |
328 | } | 331 | } |
329 | 332 | ||
@@ -471,16 +474,10 @@ void ieee80211_iterate_active_interfaces( | |||
471 | 474 | ||
472 | list_for_each_entry(sdata, &local->interfaces, list) { | 475 | list_for_each_entry(sdata, &local->interfaces, list) { |
473 | switch (sdata->vif.type) { | 476 | switch (sdata->vif.type) { |
474 | case __NL80211_IFTYPE_AFTER_LAST: | ||
475 | case NL80211_IFTYPE_UNSPECIFIED: | ||
476 | case NL80211_IFTYPE_MONITOR: | 477 | case NL80211_IFTYPE_MONITOR: |
477 | case NL80211_IFTYPE_AP_VLAN: | 478 | case NL80211_IFTYPE_AP_VLAN: |
478 | continue; | 479 | continue; |
479 | case NL80211_IFTYPE_AP: | 480 | default: |
480 | case NL80211_IFTYPE_STATION: | ||
481 | case NL80211_IFTYPE_ADHOC: | ||
482 | case NL80211_IFTYPE_WDS: | ||
483 | case NL80211_IFTYPE_MESH_POINT: | ||
484 | break; | 481 | break; |
485 | } | 482 | } |
486 | if (ieee80211_sdata_running(sdata)) | 483 | if (ieee80211_sdata_running(sdata)) |
@@ -505,16 +502,10 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
505 | 502 | ||
506 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 503 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
507 | switch (sdata->vif.type) { | 504 | switch (sdata->vif.type) { |
508 | case __NL80211_IFTYPE_AFTER_LAST: | ||
509 | case NL80211_IFTYPE_UNSPECIFIED: | ||
510 | case NL80211_IFTYPE_MONITOR: | 505 | case NL80211_IFTYPE_MONITOR: |
511 | case NL80211_IFTYPE_AP_VLAN: | 506 | case NL80211_IFTYPE_AP_VLAN: |
512 | continue; | 507 | continue; |
513 | case NL80211_IFTYPE_AP: | 508 | default: |
514 | case NL80211_IFTYPE_STATION: | ||
515 | case NL80211_IFTYPE_ADHOC: | ||
516 | case NL80211_IFTYPE_WDS: | ||
517 | case NL80211_IFTYPE_MESH_POINT: | ||
518 | break; | 509 | break; |
519 | } | 510 | } |
520 | if (ieee80211_sdata_running(sdata)) | 511 | if (ieee80211_sdata_running(sdata)) |
@@ -904,26 +895,34 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
904 | 895 | ||
905 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 896 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
906 | const u8 *ie, size_t ie_len, | 897 | const u8 *ie, size_t ie_len, |
907 | enum ieee80211_band band) | 898 | enum ieee80211_band band, u32 rate_mask, |
899 | u8 channel) | ||
908 | { | 900 | { |
909 | struct ieee80211_supported_band *sband; | 901 | struct ieee80211_supported_band *sband; |
910 | u8 *pos; | 902 | u8 *pos; |
911 | size_t offset = 0, noffset; | 903 | size_t offset = 0, noffset; |
912 | int supp_rates_len, i; | 904 | int supp_rates_len, i; |
905 | u8 rates[32]; | ||
906 | int num_rates; | ||
907 | int ext_rates_len; | ||
913 | 908 | ||
914 | sband = local->hw.wiphy->bands[band]; | 909 | sband = local->hw.wiphy->bands[band]; |
915 | 910 | ||
916 | pos = buffer; | 911 | pos = buffer; |
917 | 912 | ||
918 | supp_rates_len = min_t(int, sband->n_bitrates, 8); | 913 | num_rates = 0; |
914 | for (i = 0; i < sband->n_bitrates; i++) { | ||
915 | if ((BIT(i) & rate_mask) == 0) | ||
916 | continue; /* skip rate */ | ||
917 | rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5); | ||
918 | } | ||
919 | |||
920 | supp_rates_len = min_t(int, num_rates, 8); | ||
919 | 921 | ||
920 | *pos++ = WLAN_EID_SUPP_RATES; | 922 | *pos++ = WLAN_EID_SUPP_RATES; |
921 | *pos++ = supp_rates_len; | 923 | *pos++ = supp_rates_len; |
922 | 924 | memcpy(pos, rates, supp_rates_len); | |
923 | for (i = 0; i < supp_rates_len; i++) { | 925 | pos += supp_rates_len; |
924 | int rate = sband->bitrates[i].bitrate; | ||
925 | *pos++ = (u8) (rate / 5); | ||
926 | } | ||
927 | 926 | ||
928 | /* insert "request information" if in custom IEs */ | 927 | /* insert "request information" if in custom IEs */ |
929 | if (ie && ie_len) { | 928 | if (ie && ie_len) { |
@@ -941,14 +940,18 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
941 | offset = noffset; | 940 | offset = noffset; |
942 | } | 941 | } |
943 | 942 | ||
944 | if (sband->n_bitrates > i) { | 943 | ext_rates_len = num_rates - supp_rates_len; |
944 | if (ext_rates_len > 0) { | ||
945 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 945 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
946 | *pos++ = sband->n_bitrates - i; | 946 | *pos++ = ext_rates_len; |
947 | memcpy(pos, rates + supp_rates_len, ext_rates_len); | ||
948 | pos += ext_rates_len; | ||
949 | } | ||
947 | 950 | ||
948 | for (; i < sband->n_bitrates; i++) { | 951 | if (channel && sband->band == IEEE80211_BAND_2GHZ) { |
949 | int rate = sband->bitrates[i].bitrate; | 952 | *pos++ = WLAN_EID_DS_PARAMS; |
950 | *pos++ = (u8) (rate / 5); | 953 | *pos++ = 1; |
951 | } | 954 | *pos++ = channel; |
952 | } | 955 | } |
953 | 956 | ||
954 | /* insert custom IEs that go before HT */ | 957 | /* insert custom IEs that go before HT */ |
@@ -1017,6 +1020,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1017 | struct ieee80211_mgmt *mgmt; | 1020 | struct ieee80211_mgmt *mgmt; |
1018 | size_t buf_len; | 1021 | size_t buf_len; |
1019 | u8 *buf; | 1022 | u8 *buf; |
1023 | u8 chan; | ||
1020 | 1024 | ||
1021 | /* FIXME: come up with a proper value */ | 1025 | /* FIXME: come up with a proper value */ |
1022 | buf = kmalloc(200 + ie_len, GFP_KERNEL); | 1026 | buf = kmalloc(200 + ie_len, GFP_KERNEL); |
@@ -1026,8 +1030,14 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1026 | return; | 1030 | return; |
1027 | } | 1031 | } |
1028 | 1032 | ||
1033 | chan = ieee80211_frequency_to_channel( | ||
1034 | local->hw.conf.channel->center_freq); | ||
1035 | |||
1029 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, | 1036 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, |
1030 | local->hw.conf.channel->band); | 1037 | local->hw.conf.channel->band, |
1038 | sdata->rc_rateidx_mask | ||
1039 | [local->hw.conf.channel->band], | ||
1040 | chan); | ||
1031 | 1041 | ||
1032 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 1042 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
1033 | ssid, ssid_len, | 1043 | ssid, ssid_len, |
@@ -1189,7 +1199,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1189 | /* ignore virtual */ | 1199 | /* ignore virtual */ |
1190 | break; | 1200 | break; |
1191 | case NL80211_IFTYPE_UNSPECIFIED: | 1201 | case NL80211_IFTYPE_UNSPECIFIED: |
1192 | case __NL80211_IFTYPE_AFTER_LAST: | 1202 | case NUM_NL80211_IFTYPES: |
1203 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1204 | case NL80211_IFTYPE_P2P_GO: | ||
1193 | WARN_ON(1); | 1205 | WARN_ON(1); |
1194 | break; | 1206 | break; |
1195 | } | 1207 | } |
@@ -1285,17 +1297,13 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | |||
1285 | } | 1297 | } |
1286 | 1298 | ||
1287 | /* must hold iflist_mtx */ | 1299 | /* must hold iflist_mtx */ |
1288 | void ieee80211_recalc_smps(struct ieee80211_local *local, | 1300 | void ieee80211_recalc_smps(struct ieee80211_local *local) |
1289 | struct ieee80211_sub_if_data *forsdata) | ||
1290 | { | 1301 | { |
1291 | struct ieee80211_sub_if_data *sdata; | 1302 | struct ieee80211_sub_if_data *sdata; |
1292 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | 1303 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; |
1293 | int count = 0; | 1304 | int count = 0; |
1294 | 1305 | ||
1295 | if (forsdata) | 1306 | lockdep_assert_held(&local->iflist_mtx); |
1296 | WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx)); | ||
1297 | |||
1298 | WARN_ON(!mutex_is_locked(&local->iflist_mtx)); | ||
1299 | 1307 | ||
1300 | /* | 1308 | /* |
1301 | * This function could be improved to handle multiple | 1309 | * This function could be improved to handle multiple |
@@ -1308,22 +1316,12 @@ void ieee80211_recalc_smps(struct ieee80211_local *local, | |||
1308 | */ | 1316 | */ |
1309 | 1317 | ||
1310 | list_for_each_entry(sdata, &local->interfaces, list) { | 1318 | list_for_each_entry(sdata, &local->interfaces, list) { |
1311 | if (!netif_running(sdata->dev)) | 1319 | if (!ieee80211_sdata_running(sdata)) |
1312 | continue; | 1320 | continue; |
1313 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1321 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
1314 | goto set; | 1322 | goto set; |
1315 | if (sdata != forsdata) { | 1323 | |
1316 | /* | 1324 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); |
1317 | * This nested is ok -- we are holding the iflist_mtx | ||
1318 | * so can't get here twice or so. But it's required | ||
1319 | * since normally we acquire it first and then the | ||
1320 | * iflist_mtx. | ||
1321 | */ | ||
1322 | mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); | ||
1323 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1324 | mutex_unlock(&sdata->u.mgd.mtx); | ||
1325 | } else | ||
1326 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1327 | 1325 | ||
1328 | if (count > 1) { | 1326 | if (count > 1) { |
1329 | smps_mode = IEEE80211_SMPS_OFF; | 1327 | smps_mode = IEEE80211_SMPS_OFF; |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 9ebc8d8a1f5..f27484c22b9 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -240,7 +240,7 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, | |||
240 | 240 | ||
241 | keyidx = skb->data[hdrlen + 3] >> 6; | 241 | keyidx = skb->data[hdrlen + 3] >> 6; |
242 | 242 | ||
243 | if (!key || keyidx != key->conf.keyidx || key->conf.alg != ALG_WEP) | 243 | if (!key || keyidx != key->conf.keyidx) |
244 | return -1; | 244 | return -1; |
245 | 245 | ||
246 | klen = 3 + key->conf.keylen; | 246 | klen = 3 + key->conf.keylen; |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 81d4ad64184..ae344d1ba05 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -43,7 +43,7 @@ enum work_action { | |||
43 | /* utils */ | 43 | /* utils */ |
44 | static inline void ASSERT_WORK_MTX(struct ieee80211_local *local) | 44 | static inline void ASSERT_WORK_MTX(struct ieee80211_local *local) |
45 | { | 45 | { |
46 | WARN_ON(!mutex_is_locked(&local->work_mtx)); | 46 | lockdep_assert_held(&local->mtx); |
47 | } | 47 | } |
48 | 48 | ||
49 | /* | 49 | /* |
@@ -757,7 +757,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
757 | mgmt = (struct ieee80211_mgmt *) skb->data; | 757 | mgmt = (struct ieee80211_mgmt *) skb->data; |
758 | fc = le16_to_cpu(mgmt->frame_control); | 758 | fc = le16_to_cpu(mgmt->frame_control); |
759 | 759 | ||
760 | mutex_lock(&local->work_mtx); | 760 | mutex_lock(&local->mtx); |
761 | 761 | ||
762 | list_for_each_entry(wk, &local->work_list, list) { | 762 | list_for_each_entry(wk, &local->work_list, list) { |
763 | const u8 *bssid = NULL; | 763 | const u8 *bssid = NULL; |
@@ -833,7 +833,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
833 | WARN(1, "unexpected: %d", rma); | 833 | WARN(1, "unexpected: %d", rma); |
834 | } | 834 | } |
835 | 835 | ||
836 | mutex_unlock(&local->work_mtx); | 836 | mutex_unlock(&local->mtx); |
837 | 837 | ||
838 | if (rma != WORK_ACT_DONE) | 838 | if (rma != WORK_ACT_DONE) |
839 | goto out; | 839 | goto out; |
@@ -845,9 +845,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
845 | case WORK_DONE_REQUEUE: | 845 | case WORK_DONE_REQUEUE: |
846 | synchronize_rcu(); | 846 | synchronize_rcu(); |
847 | wk->started = false; /* restart */ | 847 | wk->started = false; /* restart */ |
848 | mutex_lock(&local->work_mtx); | 848 | mutex_lock(&local->mtx); |
849 | list_add_tail(&wk->list, &local->work_list); | 849 | list_add_tail(&wk->list, &local->work_list); |
850 | mutex_unlock(&local->work_mtx); | 850 | mutex_unlock(&local->mtx); |
851 | } | 851 | } |
852 | 852 | ||
853 | out: | 853 | out: |
@@ -888,9 +888,9 @@ static void ieee80211_work_work(struct work_struct *work) | |||
888 | while ((skb = skb_dequeue(&local->work_skb_queue))) | 888 | while ((skb = skb_dequeue(&local->work_skb_queue))) |
889 | ieee80211_work_rx_queued_mgmt(local, skb); | 889 | ieee80211_work_rx_queued_mgmt(local, skb); |
890 | 890 | ||
891 | ieee80211_recalc_idle(local); | 891 | mutex_lock(&local->mtx); |
892 | 892 | ||
893 | mutex_lock(&local->work_mtx); | 893 | ieee80211_recalc_idle(local); |
894 | 894 | ||
895 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { | 895 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { |
896 | bool started = wk->started; | 896 | bool started = wk->started; |
@@ -995,20 +995,16 @@ static void ieee80211_work_work(struct work_struct *work) | |||
995 | run_again(local, jiffies + HZ/2); | 995 | run_again(local, jiffies + HZ/2); |
996 | } | 996 | } |
997 | 997 | ||
998 | mutex_lock(&local->scan_mtx); | ||
999 | |||
1000 | if (list_empty(&local->work_list) && local->scan_req && | 998 | if (list_empty(&local->work_list) && local->scan_req && |
1001 | !local->scanning) | 999 | !local->scanning) |
1002 | ieee80211_queue_delayed_work(&local->hw, | 1000 | ieee80211_queue_delayed_work(&local->hw, |
1003 | &local->scan_work, | 1001 | &local->scan_work, |
1004 | round_jiffies_relative(0)); | 1002 | round_jiffies_relative(0)); |
1005 | 1003 | ||
1006 | mutex_unlock(&local->scan_mtx); | ||
1007 | |||
1008 | mutex_unlock(&local->work_mtx); | ||
1009 | |||
1010 | ieee80211_recalc_idle(local); | 1004 | ieee80211_recalc_idle(local); |
1011 | 1005 | ||
1006 | mutex_unlock(&local->mtx); | ||
1007 | |||
1012 | list_for_each_entry_safe(wk, tmp, &free_work, list) { | 1008 | list_for_each_entry_safe(wk, tmp, &free_work, list) { |
1013 | wk->done(wk, NULL); | 1009 | wk->done(wk, NULL); |
1014 | list_del(&wk->list); | 1010 | list_del(&wk->list); |
@@ -1035,16 +1031,15 @@ void ieee80211_add_work(struct ieee80211_work *wk) | |||
1035 | wk->started = false; | 1031 | wk->started = false; |
1036 | 1032 | ||
1037 | local = wk->sdata->local; | 1033 | local = wk->sdata->local; |
1038 | mutex_lock(&local->work_mtx); | 1034 | mutex_lock(&local->mtx); |
1039 | list_add_tail(&wk->list, &local->work_list); | 1035 | list_add_tail(&wk->list, &local->work_list); |
1040 | mutex_unlock(&local->work_mtx); | 1036 | mutex_unlock(&local->mtx); |
1041 | 1037 | ||
1042 | ieee80211_queue_work(&local->hw, &local->work_work); | 1038 | ieee80211_queue_work(&local->hw, &local->work_work); |
1043 | } | 1039 | } |
1044 | 1040 | ||
1045 | void ieee80211_work_init(struct ieee80211_local *local) | 1041 | void ieee80211_work_init(struct ieee80211_local *local) |
1046 | { | 1042 | { |
1047 | mutex_init(&local->work_mtx); | ||
1048 | INIT_LIST_HEAD(&local->work_list); | 1043 | INIT_LIST_HEAD(&local->work_list); |
1049 | setup_timer(&local->work_timer, ieee80211_work_timer, | 1044 | setup_timer(&local->work_timer, ieee80211_work_timer, |
1050 | (unsigned long)local); | 1045 | (unsigned long)local); |
@@ -1057,7 +1052,7 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) | |||
1057 | struct ieee80211_local *local = sdata->local; | 1052 | struct ieee80211_local *local = sdata->local; |
1058 | struct ieee80211_work *wk; | 1053 | struct ieee80211_work *wk; |
1059 | 1054 | ||
1060 | mutex_lock(&local->work_mtx); | 1055 | mutex_lock(&local->mtx); |
1061 | list_for_each_entry(wk, &local->work_list, list) { | 1056 | list_for_each_entry(wk, &local->work_list, list) { |
1062 | if (wk->sdata != sdata) | 1057 | if (wk->sdata != sdata) |
1063 | continue; | 1058 | continue; |
@@ -1065,19 +1060,19 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) | |||
1065 | wk->started = true; | 1060 | wk->started = true; |
1066 | wk->timeout = jiffies; | 1061 | wk->timeout = jiffies; |
1067 | } | 1062 | } |
1068 | mutex_unlock(&local->work_mtx); | 1063 | mutex_unlock(&local->mtx); |
1069 | 1064 | ||
1070 | /* run cleanups etc. */ | 1065 | /* run cleanups etc. */ |
1071 | ieee80211_work_work(&local->work_work); | 1066 | ieee80211_work_work(&local->work_work); |
1072 | 1067 | ||
1073 | mutex_lock(&local->work_mtx); | 1068 | mutex_lock(&local->mtx); |
1074 | list_for_each_entry(wk, &local->work_list, list) { | 1069 | list_for_each_entry(wk, &local->work_list, list) { |
1075 | if (wk->sdata != sdata) | 1070 | if (wk->sdata != sdata) |
1076 | continue; | 1071 | continue; |
1077 | WARN_ON(1); | 1072 | WARN_ON(1); |
1078 | break; | 1073 | break; |
1079 | } | 1074 | } |
1080 | mutex_unlock(&local->work_mtx); | 1075 | mutex_unlock(&local->mtx); |
1081 | } | 1076 | } |
1082 | 1077 | ||
1083 | ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, | 1078 | ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, |
@@ -1163,7 +1158,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, | |||
1163 | struct ieee80211_work *wk, *tmp; | 1158 | struct ieee80211_work *wk, *tmp; |
1164 | bool found = false; | 1159 | bool found = false; |
1165 | 1160 | ||
1166 | mutex_lock(&local->work_mtx); | 1161 | mutex_lock(&local->mtx); |
1167 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { | 1162 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { |
1168 | if ((unsigned long) wk == cookie) { | 1163 | if ((unsigned long) wk == cookie) { |
1169 | wk->timeout = jiffies; | 1164 | wk->timeout = jiffies; |
@@ -1171,7 +1166,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, | |||
1171 | break; | 1166 | break; |
1172 | } | 1167 | } |
1173 | } | 1168 | } |
1174 | mutex_unlock(&local->work_mtx); | 1169 | mutex_unlock(&local->mtx); |
1175 | 1170 | ||
1176 | if (!found) | 1171 | if (!found) |
1177 | return -ENOENT; | 1172 | return -ENOENT; |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 8d59d27d887..bee230d8fd1 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -36,8 +36,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
36 | int tail; | 36 | int tail; |
37 | 37 | ||
38 | hdr = (struct ieee80211_hdr *)skb->data; | 38 | hdr = (struct ieee80211_hdr *)skb->data; |
39 | if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 || | 39 | if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || |
40 | !ieee80211_is_data_present(hdr->frame_control)) | 40 | skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control)) |
41 | return TX_CONTINUE; | 41 | return TX_CONTINUE; |
42 | 42 | ||
43 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 43 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
@@ -94,7 +94,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
94 | if (status->flag & RX_FLAG_MMIC_STRIPPED) | 94 | if (status->flag & RX_FLAG_MMIC_STRIPPED) |
95 | return RX_CONTINUE; | 95 | return RX_CONTINUE; |
96 | 96 | ||
97 | if (!rx->key || rx->key->conf.alg != ALG_TKIP || | 97 | if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || |
98 | !ieee80211_has_protected(hdr->frame_control) || | 98 | !ieee80211_has_protected(hdr->frame_control) || |
99 | !ieee80211_is_data_present(hdr->frame_control)) | 99 | !ieee80211_is_data_present(hdr->frame_control)) |
100 | return RX_CONTINUE; | 100 | return RX_CONTINUE; |
@@ -117,7 +117,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
117 | key = &rx->key->conf.key[key_offset]; | 117 | key = &rx->key->conf.key[key_offset]; |
118 | michael_mic(key, hdr, data, data_len, mic); | 118 | michael_mic(key, hdr, data, data_len, mic); |
119 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { | 119 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { |
120 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 120 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
121 | return RX_DROP_UNUSABLE; | 121 | return RX_DROP_UNUSABLE; |
122 | 122 | ||
123 | mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, | 123 | mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, |
@@ -221,19 +221,13 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) | |||
221 | if (!rx->sta || skb->len - hdrlen < 12) | 221 | if (!rx->sta || skb->len - hdrlen < 12) |
222 | return RX_DROP_UNUSABLE; | 222 | return RX_DROP_UNUSABLE; |
223 | 223 | ||
224 | if (status->flag & RX_FLAG_DECRYPTED) { | 224 | /* |
225 | if (status->flag & RX_FLAG_IV_STRIPPED) { | 225 | * Let TKIP code verify IV, but skip decryption. |
226 | /* | 226 | * In the case where hardware checks the IV as well, |
227 | * Hardware took care of all processing, including | 227 | * we don't even get here, see ieee80211_rx_h_decrypt() |
228 | * replay protection, and stripped the ICV/IV so | 228 | */ |
229 | * we cannot do any checks here. | 229 | if (status->flag & RX_FLAG_DECRYPTED) |
230 | */ | ||
231 | return RX_CONTINUE; | ||
232 | } | ||
233 | |||
234 | /* let TKIP code verify IV, but skip decryption */ | ||
235 | hwaccel = 1; | 230 | hwaccel = 1; |
236 | } | ||
237 | 231 | ||
238 | res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, | 232 | res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, |
239 | key, skb->data + hdrlen, | 233 | key, skb->data + hdrlen, |
@@ -447,10 +441,6 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
447 | if (!rx->sta || data_len < 0) | 441 | if (!rx->sta || data_len < 0) |
448 | return RX_DROP_UNUSABLE; | 442 | return RX_DROP_UNUSABLE; |
449 | 443 | ||
450 | if ((status->flag & RX_FLAG_DECRYPTED) && | ||
451 | (status->flag & RX_FLAG_IV_STRIPPED)) | ||
452 | return RX_CONTINUE; | ||
453 | |||
454 | ccmp_hdr2pn(pn, skb->data + hdrlen); | 444 | ccmp_hdr2pn(pn, skb->data + hdrlen); |
455 | 445 | ||
456 | queue = ieee80211_is_mgmt(hdr->frame_control) ? | 446 | queue = ieee80211_is_mgmt(hdr->frame_control) ? |
@@ -564,10 +554,6 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) | |||
564 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 554 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
565 | return RX_CONTINUE; | 555 | return RX_CONTINUE; |
566 | 556 | ||
567 | if ((status->flag & RX_FLAG_DECRYPTED) && | ||
568 | (status->flag & RX_FLAG_IV_STRIPPED)) | ||
569 | return RX_CONTINUE; | ||
570 | |||
571 | if (skb->len < 24 + sizeof(*mmie)) | 557 | if (skb->len < 24 + sizeof(*mmie)) |
572 | return RX_DROP_UNUSABLE; | 558 | return RX_DROP_UNUSABLE; |
573 | 559 | ||
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 26ed3e8587c..1781d99145e 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -547,8 +547,20 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
547 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; | 547 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; |
548 | info.attrs = family->attrbuf; | 548 | info.attrs = family->attrbuf; |
549 | genl_info_net_set(&info, net); | 549 | genl_info_net_set(&info, net); |
550 | memset(&info.user_ptr, 0, sizeof(info.user_ptr)); | ||
550 | 551 | ||
551 | return ops->doit(skb, &info); | 552 | if (family->pre_doit) { |
553 | err = family->pre_doit(ops, skb, &info); | ||
554 | if (err) | ||
555 | return err; | ||
556 | } | ||
557 | |||
558 | err = ops->doit(skb, &info); | ||
559 | |||
560 | if (family->post_doit) | ||
561 | family->post_doit(ops, skb, &info); | ||
562 | |||
563 | return err; | ||
552 | } | 564 | } |
553 | 565 | ||
554 | static void genl_rcv(struct sk_buff *skb) | 566 | static void genl_rcv(struct sk_buff *skb) |
diff --git a/net/wireless/core.c b/net/wireless/core.c index d6d046b9f6f..1684ad91763 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -178,26 +178,10 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
178 | char *newname) | 178 | char *newname) |
179 | { | 179 | { |
180 | struct cfg80211_registered_device *rdev2; | 180 | struct cfg80211_registered_device *rdev2; |
181 | int wiphy_idx, taken = -1, result, digits; | 181 | int result; |
182 | 182 | ||
183 | assert_cfg80211_lock(); | 183 | assert_cfg80211_lock(); |
184 | 184 | ||
185 | /* prohibit calling the thing phy%d when %d is not its number */ | ||
186 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); | ||
187 | if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { | ||
188 | /* count number of places needed to print wiphy_idx */ | ||
189 | digits = 1; | ||
190 | while (wiphy_idx /= 10) | ||
191 | digits++; | ||
192 | /* | ||
193 | * deny the name if it is phy<idx> where <idx> is printed | ||
194 | * without leading zeroes. taken == strlen(newname) here | ||
195 | */ | ||
196 | if (taken == strlen(PHY_NAME) + digits) | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | |||
201 | /* Ignore nop renames */ | 185 | /* Ignore nop renames */ |
202 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) | 186 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) |
203 | return 0; | 187 | return 0; |
@@ -205,7 +189,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
205 | /* Ensure another device does not already have this name. */ | 189 | /* Ensure another device does not already have this name. */ |
206 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) | 190 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) |
207 | if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) | 191 | if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) |
208 | return -EINVAL; | 192 | return -EEXIST; |
209 | 193 | ||
210 | result = device_rename(&rdev->wiphy.dev, newname); | 194 | result = device_rename(&rdev->wiphy.dev, newname); |
211 | if (result) | 195 | if (result) |
@@ -253,11 +237,16 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
253 | WARN_ON(err); | 237 | WARN_ON(err); |
254 | wdev->netdev->features |= NETIF_F_NETNS_LOCAL; | 238 | wdev->netdev->features |= NETIF_F_NETNS_LOCAL; |
255 | } | 239 | } |
240 | |||
241 | return err; | ||
256 | } | 242 | } |
257 | 243 | ||
258 | wiphy_net_set(&rdev->wiphy, net); | 244 | wiphy_net_set(&rdev->wiphy, net); |
259 | 245 | ||
260 | return err; | 246 | err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); |
247 | WARN_ON(err); | ||
248 | |||
249 | return 0; | ||
261 | } | 250 | } |
262 | 251 | ||
263 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | 252 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) |
@@ -315,9 +304,11 @@ static void cfg80211_event_work(struct work_struct *work) | |||
315 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 304 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
316 | { | 305 | { |
317 | static int wiphy_counter; | 306 | static int wiphy_counter; |
318 | 307 | int i; | |
319 | struct cfg80211_registered_device *rdev; | 308 | struct cfg80211_registered_device *rdev, *rdev2; |
320 | int alloc_size; | 309 | int alloc_size; |
310 | char nname[IFNAMSIZ + 1]; | ||
311 | bool found = false; | ||
321 | 312 | ||
322 | WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); | 313 | WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); |
323 | WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); | 314 | WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); |
@@ -341,16 +332,36 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
341 | 332 | ||
342 | if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { | 333 | if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { |
343 | wiphy_counter--; | 334 | wiphy_counter--; |
335 | goto too_many_devs; | ||
336 | } | ||
337 | |||
338 | /* 64k wiphy devices is enough for anyone! */ | ||
339 | for (i = 0; i < 0xFFFF; i++) { | ||
340 | found = false; | ||
341 | snprintf(nname, sizeof(nname)-1, PHY_NAME "%d", i); | ||
342 | nname[sizeof(nname)-1] = 0; | ||
343 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) | ||
344 | if (strcmp(nname, dev_name(&rdev2->wiphy.dev)) == 0) { | ||
345 | found = true; | ||
346 | break; | ||
347 | } | ||
348 | |||
349 | if (!found) | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | if (unlikely(found)) { | ||
354 | too_many_devs: | ||
344 | mutex_unlock(&cfg80211_mutex); | 355 | mutex_unlock(&cfg80211_mutex); |
345 | /* ugh, wrapped! */ | 356 | /* ugh, too many devices already! */ |
346 | kfree(rdev); | 357 | kfree(rdev); |
347 | return NULL; | 358 | return NULL; |
348 | } | 359 | } |
349 | 360 | ||
350 | mutex_unlock(&cfg80211_mutex); | ||
351 | |||
352 | /* give it a proper name */ | 361 | /* give it a proper name */ |
353 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | 362 | dev_set_name(&rdev->wiphy.dev, "%s", nname); |
363 | |||
364 | mutex_unlock(&cfg80211_mutex); | ||
354 | 365 | ||
355 | mutex_init(&rdev->mtx); | 366 | mutex_init(&rdev->mtx); |
356 | mutex_init(&rdev->devlist_mtx); | 367 | mutex_init(&rdev->devlist_mtx); |
@@ -428,7 +439,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
428 | 439 | ||
429 | /* sanity check ifmodes */ | 440 | /* sanity check ifmodes */ |
430 | WARN_ON(!ifmodes); | 441 | WARN_ON(!ifmodes); |
431 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; | 442 | ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1; |
432 | if (WARN_ON(ifmodes != wiphy->interface_modes)) | 443 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
433 | wiphy->interface_modes = ifmodes; | 444 | wiphy->interface_modes = ifmodes; |
434 | 445 | ||
@@ -683,8 +694,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
683 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | 694 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); |
684 | INIT_LIST_HEAD(&wdev->event_list); | 695 | INIT_LIST_HEAD(&wdev->event_list); |
685 | spin_lock_init(&wdev->event_lock); | 696 | spin_lock_init(&wdev->event_lock); |
686 | INIT_LIST_HEAD(&wdev->action_registrations); | 697 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
687 | spin_lock_init(&wdev->action_registrations_lock); | 698 | spin_lock_init(&wdev->mgmt_registrations_lock); |
688 | 699 | ||
689 | mutex_lock(&rdev->devlist_mtx); | 700 | mutex_lock(&rdev->devlist_mtx); |
690 | list_add_rcu(&wdev->list, &rdev->netdev_list); | 701 | list_add_rcu(&wdev->list, &rdev->netdev_list); |
@@ -724,6 +735,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
724 | dev->ethtool_ops = &cfg80211_ethtool_ops; | 735 | dev->ethtool_ops = &cfg80211_ethtool_ops; |
725 | 736 | ||
726 | if ((wdev->iftype == NL80211_IFTYPE_STATION || | 737 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
738 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || | ||
727 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) | 739 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) |
728 | dev->priv_flags |= IFF_DONT_BRIDGE; | 740 | dev->priv_flags |= IFF_DONT_BRIDGE; |
729 | break; | 741 | break; |
@@ -732,6 +744,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
732 | case NL80211_IFTYPE_ADHOC: | 744 | case NL80211_IFTYPE_ADHOC: |
733 | cfg80211_leave_ibss(rdev, dev, true); | 745 | cfg80211_leave_ibss(rdev, dev, true); |
734 | break; | 746 | break; |
747 | case NL80211_IFTYPE_P2P_CLIENT: | ||
735 | case NL80211_IFTYPE_STATION: | 748 | case NL80211_IFTYPE_STATION: |
736 | wdev_lock(wdev); | 749 | wdev_lock(wdev); |
737 | #ifdef CONFIG_CFG80211_WEXT | 750 | #ifdef CONFIG_CFG80211_WEXT |
@@ -804,7 +817,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
804 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 817 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
805 | list_del_rcu(&wdev->list); | 818 | list_del_rcu(&wdev->list); |
806 | rdev->devlist_generation++; | 819 | rdev->devlist_generation++; |
807 | cfg80211_mlme_purge_actions(wdev); | 820 | cfg80211_mlme_purge_registrations(wdev); |
808 | #ifdef CONFIG_CFG80211_WEXT | 821 | #ifdef CONFIG_CFG80211_WEXT |
809 | kfree(wdev->wext.keys); | 822 | kfree(wdev->wext.keys); |
810 | #endif | 823 | #endif |
@@ -910,52 +923,3 @@ static void __exit cfg80211_exit(void) | |||
910 | destroy_workqueue(cfg80211_wq); | 923 | destroy_workqueue(cfg80211_wq); |
911 | } | 924 | } |
912 | module_exit(cfg80211_exit); | 925 | module_exit(cfg80211_exit); |
913 | |||
914 | static int ___wiphy_printk(const char *level, const struct wiphy *wiphy, | ||
915 | struct va_format *vaf) | ||
916 | { | ||
917 | if (!wiphy) | ||
918 | return printk("%s(NULL wiphy *): %pV", level, vaf); | ||
919 | |||
920 | return printk("%s%s: %pV", level, wiphy_name(wiphy), vaf); | ||
921 | } | ||
922 | |||
923 | int __wiphy_printk(const char *level, const struct wiphy *wiphy, | ||
924 | const char *fmt, ...) | ||
925 | { | ||
926 | struct va_format vaf; | ||
927 | va_list args; | ||
928 | int r; | ||
929 | |||
930 | va_start(args, fmt); | ||
931 | |||
932 | vaf.fmt = fmt; | ||
933 | vaf.va = &args; | ||
934 | |||
935 | r = ___wiphy_printk(level, wiphy, &vaf); | ||
936 | va_end(args); | ||
937 | |||
938 | return r; | ||
939 | } | ||
940 | EXPORT_SYMBOL(__wiphy_printk); | ||
941 | |||
942 | #define define_wiphy_printk_level(func, kern_level) \ | ||
943 | int func(const struct wiphy *wiphy, const char *fmt, ...) \ | ||
944 | { \ | ||
945 | struct va_format vaf; \ | ||
946 | va_list args; \ | ||
947 | int r; \ | ||
948 | \ | ||
949 | va_start(args, fmt); \ | ||
950 | \ | ||
951 | vaf.fmt = fmt; \ | ||
952 | vaf.va = &args; \ | ||
953 | \ | ||
954 | r = ___wiphy_printk(kern_level, wiphy, &vaf); \ | ||
955 | va_end(args); \ | ||
956 | \ | ||
957 | return r; \ | ||
958 | } \ | ||
959 | EXPORT_SYMBOL(func); | ||
960 | |||
961 | define_wiphy_printk_level(wiphy_debug, KERN_DEBUG); | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 63d57ae399c..37580e090a3 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -95,7 +95,10 @@ extern struct mutex cfg80211_mutex; | |||
95 | extern struct list_head cfg80211_rdev_list; | 95 | extern struct list_head cfg80211_rdev_list; |
96 | extern int cfg80211_rdev_list_generation; | 96 | extern int cfg80211_rdev_list_generation; |
97 | 97 | ||
98 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) | 98 | static inline void assert_cfg80211_lock(void) |
99 | { | ||
100 | lockdep_assert_held(&cfg80211_mutex); | ||
101 | } | ||
99 | 102 | ||
100 | /* | 103 | /* |
101 | * You can use this to mark a wiphy_idx as not having an associated wiphy. | 104 | * You can use this to mark a wiphy_idx as not having an associated wiphy. |
@@ -202,8 +205,8 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
202 | mutex_unlock(&wdev->mtx); | 205 | mutex_unlock(&wdev->mtx); |
203 | } | 206 | } |
204 | 207 | ||
205 | #define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx)); | 208 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) |
206 | #define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx)); | 209 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
207 | 210 | ||
208 | enum cfg80211_event_type { | 211 | enum cfg80211_event_type { |
209 | EVENT_CONNECT_RESULT, | 212 | EVENT_CONNECT_RESULT, |
@@ -331,16 +334,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
331 | const u8 *resp_ie, size_t resp_ie_len, | 334 | const u8 *resp_ie, size_t resp_ie_len, |
332 | u16 status, bool wextev, | 335 | u16 status, bool wextev, |
333 | struct cfg80211_bss *bss); | 336 | struct cfg80211_bss *bss); |
334 | int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | 337 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
335 | const u8 *match_data, int match_len); | 338 | u16 frame_type, const u8 *match_data, |
336 | void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid); | 339 | int match_len); |
337 | void cfg80211_mlme_purge_actions(struct wireless_dev *wdev); | 340 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); |
338 | int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | 341 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
339 | struct net_device *dev, | 342 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
340 | struct ieee80211_channel *chan, | 343 | struct net_device *dev, |
341 | enum nl80211_channel_type channel_type, | 344 | struct ieee80211_channel *chan, |
342 | bool channel_type_valid, | 345 | enum nl80211_channel_type channel_type, |
343 | const u8 *buf, size_t len, u64 *cookie); | 346 | bool channel_type_valid, |
347 | const u8 *buf, size_t len, u64 *cookie); | ||
344 | 348 | ||
345 | /* SME */ | 349 | /* SME */ |
346 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 350 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 27a8ce9343c..8cb6e08373b 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -88,6 +88,25 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
88 | if (wdev->ssid_len) | 88 | if (wdev->ssid_len) |
89 | return -EALREADY; | 89 | return -EALREADY; |
90 | 90 | ||
91 | if (!params->basic_rates) { | ||
92 | /* | ||
93 | * If no rates were explicitly configured, | ||
94 | * use the mandatory rate set for 11b or | ||
95 | * 11a for maximum compatibility. | ||
96 | */ | ||
97 | struct ieee80211_supported_band *sband = | ||
98 | rdev->wiphy.bands[params->channel->band]; | ||
99 | int j; | ||
100 | u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ? | ||
101 | IEEE80211_RATE_MANDATORY_A : | ||
102 | IEEE80211_RATE_MANDATORY_B; | ||
103 | |||
104 | for (j = 0; j < sband->n_bitrates; j++) { | ||
105 | if (sband->bitrates[j].flags & flag) | ||
106 | params->basic_rates |= BIT(j); | ||
107 | } | ||
108 | } | ||
109 | |||
91 | if (WARN_ON(wdev->connect_keys)) | 110 | if (WARN_ON(wdev->connect_keys)) |
92 | kfree(wdev->connect_keys); | 111 | kfree(wdev->connect_keys); |
93 | wdev->connect_keys = connkeys; | 112 | wdev->connect_keys = connkeys; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index d1a3fb99fdf..caf11a42750 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -149,7 +149,7 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
149 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 149 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
150 | const u8 *bssid = mgmt->bssid; | 150 | const u8 *bssid = mgmt->bssid; |
151 | int i; | 151 | int i; |
152 | bool found = false; | 152 | bool found = false, was_current = false; |
153 | 153 | ||
154 | ASSERT_WDEV_LOCK(wdev); | 154 | ASSERT_WDEV_LOCK(wdev); |
155 | 155 | ||
@@ -159,6 +159,7 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
159 | cfg80211_put_bss(&wdev->current_bss->pub); | 159 | cfg80211_put_bss(&wdev->current_bss->pub); |
160 | wdev->current_bss = NULL; | 160 | wdev->current_bss = NULL; |
161 | found = true; | 161 | found = true; |
162 | was_current = true; | ||
162 | } else for (i = 0; i < MAX_AUTH_BSSES; i++) { | 163 | } else for (i = 0; i < MAX_AUTH_BSSES; i++) { |
163 | if (wdev->auth_bsses[i] && | 164 | if (wdev->auth_bsses[i] && |
164 | memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { | 165 | memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { |
@@ -183,7 +184,7 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
183 | 184 | ||
184 | nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); | 185 | nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); |
185 | 186 | ||
186 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { | 187 | if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { |
187 | u16 reason_code; | 188 | u16 reason_code; |
188 | bool from_ap; | 189 | bool from_ap; |
189 | 190 | ||
@@ -747,31 +748,51 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
747 | } | 748 | } |
748 | EXPORT_SYMBOL(cfg80211_new_sta); | 749 | EXPORT_SYMBOL(cfg80211_new_sta); |
749 | 750 | ||
750 | struct cfg80211_action_registration { | 751 | struct cfg80211_mgmt_registration { |
751 | struct list_head list; | 752 | struct list_head list; |
752 | 753 | ||
753 | u32 nlpid; | 754 | u32 nlpid; |
754 | 755 | ||
755 | int match_len; | 756 | int match_len; |
756 | 757 | ||
758 | __le16 frame_type; | ||
759 | |||
757 | u8 match[]; | 760 | u8 match[]; |
758 | }; | 761 | }; |
759 | 762 | ||
760 | int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | 763 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
761 | const u8 *match_data, int match_len) | 764 | u16 frame_type, const u8 *match_data, |
765 | int match_len) | ||
762 | { | 766 | { |
763 | struct cfg80211_action_registration *reg, *nreg; | 767 | struct cfg80211_mgmt_registration *reg, *nreg; |
764 | int err = 0; | 768 | int err = 0; |
769 | u16 mgmt_type; | ||
770 | |||
771 | if (!wdev->wiphy->mgmt_stypes) | ||
772 | return -EOPNOTSUPP; | ||
773 | |||
774 | if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) | ||
775 | return -EINVAL; | ||
776 | |||
777 | if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) | ||
778 | return -EINVAL; | ||
779 | |||
780 | mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | ||
781 | if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) | ||
782 | return -EINVAL; | ||
765 | 783 | ||
766 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); | 784 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); |
767 | if (!nreg) | 785 | if (!nreg) |
768 | return -ENOMEM; | 786 | return -ENOMEM; |
769 | 787 | ||
770 | spin_lock_bh(&wdev->action_registrations_lock); | 788 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
771 | 789 | ||
772 | list_for_each_entry(reg, &wdev->action_registrations, list) { | 790 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { |
773 | int mlen = min(match_len, reg->match_len); | 791 | int mlen = min(match_len, reg->match_len); |
774 | 792 | ||
793 | if (frame_type != le16_to_cpu(reg->frame_type)) | ||
794 | continue; | ||
795 | |||
775 | if (memcmp(reg->match, match_data, mlen) == 0) { | 796 | if (memcmp(reg->match, match_data, mlen) == 0) { |
776 | err = -EALREADY; | 797 | err = -EALREADY; |
777 | break; | 798 | break; |
@@ -786,140 +807,197 @@ int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | |||
786 | memcpy(nreg->match, match_data, match_len); | 807 | memcpy(nreg->match, match_data, match_len); |
787 | nreg->match_len = match_len; | 808 | nreg->match_len = match_len; |
788 | nreg->nlpid = snd_pid; | 809 | nreg->nlpid = snd_pid; |
789 | list_add(&nreg->list, &wdev->action_registrations); | 810 | nreg->frame_type = cpu_to_le16(frame_type); |
811 | list_add(&nreg->list, &wdev->mgmt_registrations); | ||
790 | 812 | ||
791 | out: | 813 | out: |
792 | spin_unlock_bh(&wdev->action_registrations_lock); | 814 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
793 | return err; | 815 | return err; |
794 | } | 816 | } |
795 | 817 | ||
796 | void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid) | 818 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) |
797 | { | 819 | { |
798 | struct cfg80211_action_registration *reg, *tmp; | 820 | struct cfg80211_mgmt_registration *reg, *tmp; |
799 | 821 | ||
800 | spin_lock_bh(&wdev->action_registrations_lock); | 822 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
801 | 823 | ||
802 | list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { | 824 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
803 | if (reg->nlpid == nlpid) { | 825 | if (reg->nlpid == nlpid) { |
804 | list_del(®->list); | 826 | list_del(®->list); |
805 | kfree(reg); | 827 | kfree(reg); |
806 | } | 828 | } |
807 | } | 829 | } |
808 | 830 | ||
809 | spin_unlock_bh(&wdev->action_registrations_lock); | 831 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
810 | } | 832 | } |
811 | 833 | ||
812 | void cfg80211_mlme_purge_actions(struct wireless_dev *wdev) | 834 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) |
813 | { | 835 | { |
814 | struct cfg80211_action_registration *reg, *tmp; | 836 | struct cfg80211_mgmt_registration *reg, *tmp; |
815 | 837 | ||
816 | spin_lock_bh(&wdev->action_registrations_lock); | 838 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
817 | 839 | ||
818 | list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { | 840 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
819 | list_del(®->list); | 841 | list_del(®->list); |
820 | kfree(reg); | 842 | kfree(reg); |
821 | } | 843 | } |
822 | 844 | ||
823 | spin_unlock_bh(&wdev->action_registrations_lock); | 845 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
824 | } | 846 | } |
825 | 847 | ||
826 | int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | 848 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
827 | struct net_device *dev, | 849 | struct net_device *dev, |
828 | struct ieee80211_channel *chan, | 850 | struct ieee80211_channel *chan, |
829 | enum nl80211_channel_type channel_type, | 851 | enum nl80211_channel_type channel_type, |
830 | bool channel_type_valid, | 852 | bool channel_type_valid, |
831 | const u8 *buf, size_t len, u64 *cookie) | 853 | const u8 *buf, size_t len, u64 *cookie) |
832 | { | 854 | { |
833 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 855 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
834 | const struct ieee80211_mgmt *mgmt; | 856 | const struct ieee80211_mgmt *mgmt; |
857 | u16 stype; | ||
858 | |||
859 | if (!wdev->wiphy->mgmt_stypes) | ||
860 | return -EOPNOTSUPP; | ||
835 | 861 | ||
836 | if (rdev->ops->action == NULL) | 862 | if (!rdev->ops->mgmt_tx) |
837 | return -EOPNOTSUPP; | 863 | return -EOPNOTSUPP; |
864 | |||
838 | if (len < 24 + 1) | 865 | if (len < 24 + 1) |
839 | return -EINVAL; | 866 | return -EINVAL; |
840 | 867 | ||
841 | mgmt = (const struct ieee80211_mgmt *) buf; | 868 | mgmt = (const struct ieee80211_mgmt *) buf; |
842 | if (!ieee80211_is_action(mgmt->frame_control)) | 869 | |
870 | if (!ieee80211_is_mgmt(mgmt->frame_control)) | ||
871 | return -EINVAL; | ||
872 | |||
873 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; | ||
874 | if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4))) | ||
843 | return -EINVAL; | 875 | return -EINVAL; |
844 | if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | 876 | |
845 | /* Verify that we are associated with the destination AP */ | 877 | if (ieee80211_is_action(mgmt->frame_control) && |
878 | mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | ||
879 | int err = 0; | ||
880 | |||
846 | wdev_lock(wdev); | 881 | wdev_lock(wdev); |
847 | 882 | ||
848 | if (!wdev->current_bss || | 883 | switch (wdev->iftype) { |
849 | memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, | 884 | case NL80211_IFTYPE_ADHOC: |
850 | ETH_ALEN) != 0 || | 885 | case NL80211_IFTYPE_STATION: |
851 | (wdev->iftype == NL80211_IFTYPE_STATION && | 886 | case NL80211_IFTYPE_P2P_CLIENT: |
852 | memcmp(wdev->current_bss->pub.bssid, mgmt->da, | 887 | if (!wdev->current_bss) { |
853 | ETH_ALEN) != 0)) { | 888 | err = -ENOTCONN; |
854 | wdev_unlock(wdev); | 889 | break; |
855 | return -ENOTCONN; | 890 | } |
856 | } | 891 | |
892 | if (memcmp(wdev->current_bss->pub.bssid, | ||
893 | mgmt->bssid, ETH_ALEN)) { | ||
894 | err = -ENOTCONN; | ||
895 | break; | ||
896 | } | ||
897 | |||
898 | /* | ||
899 | * check for IBSS DA must be done by driver as | ||
900 | * cfg80211 doesn't track the stations | ||
901 | */ | ||
902 | if (wdev->iftype == NL80211_IFTYPE_ADHOC) | ||
903 | break; | ||
857 | 904 | ||
905 | /* for station, check that DA is the AP */ | ||
906 | if (memcmp(wdev->current_bss->pub.bssid, | ||
907 | mgmt->da, ETH_ALEN)) { | ||
908 | err = -ENOTCONN; | ||
909 | break; | ||
910 | } | ||
911 | break; | ||
912 | case NL80211_IFTYPE_AP: | ||
913 | case NL80211_IFTYPE_P2P_GO: | ||
914 | case NL80211_IFTYPE_AP_VLAN: | ||
915 | if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) | ||
916 | err = -EINVAL; | ||
917 | break; | ||
918 | default: | ||
919 | err = -EOPNOTSUPP; | ||
920 | break; | ||
921 | } | ||
858 | wdev_unlock(wdev); | 922 | wdev_unlock(wdev); |
923 | |||
924 | if (err) | ||
925 | return err; | ||
859 | } | 926 | } |
860 | 927 | ||
861 | if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) | 928 | if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) |
862 | return -EINVAL; | 929 | return -EINVAL; |
863 | 930 | ||
864 | /* Transmit the Action frame as requested by user space */ | 931 | /* Transmit the Action frame as requested by user space */ |
865 | return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, | 932 | return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type, |
866 | channel_type_valid, buf, len, cookie); | 933 | channel_type_valid, buf, len, cookie); |
867 | } | 934 | } |
868 | 935 | ||
869 | bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, | 936 | bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, |
870 | size_t len, gfp_t gfp) | 937 | size_t len, gfp_t gfp) |
871 | { | 938 | { |
872 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 939 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
873 | struct wiphy *wiphy = wdev->wiphy; | 940 | struct wiphy *wiphy = wdev->wiphy; |
874 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 941 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
875 | struct cfg80211_action_registration *reg; | 942 | struct cfg80211_mgmt_registration *reg; |
876 | const u8 *action_data; | 943 | const struct ieee80211_txrx_stypes *stypes = |
877 | int action_data_len; | 944 | &wiphy->mgmt_stypes[wdev->iftype]; |
945 | struct ieee80211_mgmt *mgmt = (void *)buf; | ||
946 | const u8 *data; | ||
947 | int data_len; | ||
878 | bool result = false; | 948 | bool result = false; |
949 | __le16 ftype = mgmt->frame_control & | ||
950 | cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); | ||
951 | u16 stype; | ||
952 | |||
953 | stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; | ||
879 | 954 | ||
880 | /* frame length - min size excluding category */ | 955 | if (!(stypes->rx & BIT(stype))) |
881 | action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1); | 956 | return false; |
882 | 957 | ||
883 | /* action data starts with category */ | 958 | data = buf + ieee80211_hdrlen(mgmt->frame_control); |
884 | action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1; | 959 | data_len = len - ieee80211_hdrlen(mgmt->frame_control); |
885 | 960 | ||
886 | spin_lock_bh(&wdev->action_registrations_lock); | 961 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
962 | |||
963 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { | ||
964 | if (reg->frame_type != ftype) | ||
965 | continue; | ||
887 | 966 | ||
888 | list_for_each_entry(reg, &wdev->action_registrations, list) { | 967 | if (reg->match_len > data_len) |
889 | if (reg->match_len > action_data_len) | ||
890 | continue; | 968 | continue; |
891 | 969 | ||
892 | if (memcmp(reg->match, action_data, reg->match_len)) | 970 | if (memcmp(reg->match, data, reg->match_len)) |
893 | continue; | 971 | continue; |
894 | 972 | ||
895 | /* found match! */ | 973 | /* found match! */ |
896 | 974 | ||
897 | /* Indicate the received Action frame to user space */ | 975 | /* Indicate the received Action frame to user space */ |
898 | if (nl80211_send_action(rdev, dev, reg->nlpid, freq, | 976 | if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq, |
899 | buf, len, gfp)) | 977 | buf, len, gfp)) |
900 | continue; | 978 | continue; |
901 | 979 | ||
902 | result = true; | 980 | result = true; |
903 | break; | 981 | break; |
904 | } | 982 | } |
905 | 983 | ||
906 | spin_unlock_bh(&wdev->action_registrations_lock); | 984 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
907 | 985 | ||
908 | return result; | 986 | return result; |
909 | } | 987 | } |
910 | EXPORT_SYMBOL(cfg80211_rx_action); | 988 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
911 | 989 | ||
912 | void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, | 990 | void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, |
913 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | 991 | const u8 *buf, size_t len, bool ack, gfp_t gfp) |
914 | { | 992 | { |
915 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 993 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
916 | struct wiphy *wiphy = wdev->wiphy; | 994 | struct wiphy *wiphy = wdev->wiphy; |
917 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 995 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
918 | 996 | ||
919 | /* Indicate TX status of the Action frame to user space */ | 997 | /* Indicate TX status of the Action frame to user space */ |
920 | nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp); | 998 | nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); |
921 | } | 999 | } |
922 | EXPORT_SYMBOL(cfg80211_action_tx_status); | 1000 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
923 | 1001 | ||
924 | void cfg80211_cqm_rssi_notify(struct net_device *dev, | 1002 | void cfg80211_cqm_rssi_notify(struct net_device *dev, |
925 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 1003 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 37902a54e9c..0c9497170f1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -23,6 +23,11 @@ | |||
23 | #include "nl80211.h" | 23 | #include "nl80211.h" |
24 | #include "reg.h" | 24 | #include "reg.h" |
25 | 25 | ||
26 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
27 | struct genl_info *info); | ||
28 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
29 | struct genl_info *info); | ||
30 | |||
26 | /* the netlink family */ | 31 | /* the netlink family */ |
27 | static struct genl_family nl80211_fam = { | 32 | static struct genl_family nl80211_fam = { |
28 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ | 33 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ |
@@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = { | |||
31 | .version = 1, /* no particular meaning now */ | 36 | .version = 1, /* no particular meaning now */ |
32 | .maxattr = NL80211_ATTR_MAX, | 37 | .maxattr = NL80211_ATTR_MAX, |
33 | .netnsok = true, | 38 | .netnsok = true, |
39 | .pre_doit = nl80211_pre_doit, | ||
40 | .post_doit = nl80211_post_doit, | ||
34 | }; | 41 | }; |
35 | 42 | ||
36 | /* internal helper: get rdev and dev */ | 43 | /* internal helper: get rdev and dev */ |
@@ -136,6 +143,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
136 | .len = sizeof(struct nl80211_sta_flag_update), | 143 | .len = sizeof(struct nl80211_sta_flag_update), |
137 | }, | 144 | }, |
138 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, | 145 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, |
146 | [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 }, | ||
147 | [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG }, | ||
139 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, | 148 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, |
140 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, | 149 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, |
141 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 150 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
@@ -156,6 +165,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
156 | 165 | ||
157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, | 166 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, |
158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, | 167 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, |
168 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, | ||
159 | }; | 169 | }; |
160 | 170 | ||
161 | /* policy for the attributes */ | 171 | /* policy for the attributes */ |
@@ -188,6 +198,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb) | |||
188 | return res; | 198 | return res; |
189 | } | 199 | } |
190 | 200 | ||
201 | static int nl80211_prepare_netdev_dump(struct sk_buff *skb, | ||
202 | struct netlink_callback *cb, | ||
203 | struct cfg80211_registered_device **rdev, | ||
204 | struct net_device **dev) | ||
205 | { | ||
206 | int ifidx = cb->args[0]; | ||
207 | int err; | ||
208 | |||
209 | if (!ifidx) | ||
210 | ifidx = nl80211_get_ifidx(cb); | ||
211 | if (ifidx < 0) | ||
212 | return ifidx; | ||
213 | |||
214 | cb->args[0] = ifidx; | ||
215 | |||
216 | rtnl_lock(); | ||
217 | |||
218 | *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
219 | if (!*dev) { | ||
220 | err = -ENODEV; | ||
221 | goto out_rtnl; | ||
222 | } | ||
223 | |||
224 | *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
225 | if (IS_ERR(dev)) { | ||
226 | err = PTR_ERR(dev); | ||
227 | goto out_rtnl; | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | out_rtnl: | ||
232 | rtnl_unlock(); | ||
233 | return err; | ||
234 | } | ||
235 | |||
236 | static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) | ||
237 | { | ||
238 | cfg80211_unlock_rdev(rdev); | ||
239 | rtnl_unlock(); | ||
240 | } | ||
241 | |||
191 | /* IE validation */ | 242 | /* IE validation */ |
192 | static bool is_valid_ie_attr(const struct nlattr *attr) | 243 | static bool is_valid_ie_attr(const struct nlattr *attr) |
193 | { | 244 | { |
@@ -401,18 +452,17 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
401 | { | 452 | { |
402 | ASSERT_WDEV_LOCK(wdev); | 453 | ASSERT_WDEV_LOCK(wdev); |
403 | 454 | ||
404 | if (!netif_running(wdev->netdev)) | ||
405 | return -ENETDOWN; | ||
406 | |||
407 | switch (wdev->iftype) { | 455 | switch (wdev->iftype) { |
408 | case NL80211_IFTYPE_AP: | 456 | case NL80211_IFTYPE_AP: |
409 | case NL80211_IFTYPE_AP_VLAN: | 457 | case NL80211_IFTYPE_AP_VLAN: |
458 | case NL80211_IFTYPE_P2P_GO: | ||
410 | break; | 459 | break; |
411 | case NL80211_IFTYPE_ADHOC: | 460 | case NL80211_IFTYPE_ADHOC: |
412 | if (!wdev->current_bss) | 461 | if (!wdev->current_bss) |
413 | return -ENOLINK; | 462 | return -ENOLINK; |
414 | break; | 463 | break; |
415 | case NL80211_IFTYPE_STATION: | 464 | case NL80211_IFTYPE_STATION: |
465 | case NL80211_IFTYPE_P2P_CLIENT: | ||
416 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 466 | if (wdev->sme_state != CFG80211_SME_CONNECTED) |
417 | return -ENOLINK; | 467 | return -ENOLINK; |
418 | break; | 468 | break; |
@@ -437,6 +487,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
437 | struct ieee80211_rate *rate; | 487 | struct ieee80211_rate *rate; |
438 | int i; | 488 | int i; |
439 | u16 ifmodes = dev->wiphy.interface_modes; | 489 | u16 ifmodes = dev->wiphy.interface_modes; |
490 | const struct ieee80211_txrx_stypes *mgmt_stypes = | ||
491 | dev->wiphy.mgmt_stypes; | ||
440 | 492 | ||
441 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); | 493 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); |
442 | if (!hdr) | 494 | if (!hdr) |
@@ -471,6 +523,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
471 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, | 523 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, |
472 | dev->wiphy.max_num_pmkids); | 524 | dev->wiphy.max_num_pmkids); |
473 | 525 | ||
526 | if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) | ||
527 | NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); | ||
528 | |||
474 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 529 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
475 | if (!nl_modes) | 530 | if (!nl_modes) |
476 | goto nla_put_failure; | 531 | goto nla_put_failure; |
@@ -587,12 +642,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
587 | CMD(flush_pmksa, FLUSH_PMKSA); | 642 | CMD(flush_pmksa, FLUSH_PMKSA); |
588 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 643 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); |
589 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | 644 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); |
590 | CMD(action, ACTION); | 645 | CMD(mgmt_tx, FRAME); |
591 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 646 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
592 | i++; | 647 | i++; |
593 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 648 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
594 | } | 649 | } |
595 | CMD(set_channel, SET_CHANNEL); | 650 | CMD(set_channel, SET_CHANNEL); |
651 | CMD(set_wds_peer, SET_WDS_PEER); | ||
596 | 652 | ||
597 | #undef CMD | 653 | #undef CMD |
598 | 654 | ||
@@ -608,6 +664,55 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
608 | 664 | ||
609 | nla_nest_end(msg, nl_cmds); | 665 | nla_nest_end(msg, nl_cmds); |
610 | 666 | ||
667 | if (mgmt_stypes) { | ||
668 | u16 stypes; | ||
669 | struct nlattr *nl_ftypes, *nl_ifs; | ||
670 | enum nl80211_iftype ift; | ||
671 | |||
672 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); | ||
673 | if (!nl_ifs) | ||
674 | goto nla_put_failure; | ||
675 | |||
676 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
677 | nl_ftypes = nla_nest_start(msg, ift); | ||
678 | if (!nl_ftypes) | ||
679 | goto nla_put_failure; | ||
680 | i = 0; | ||
681 | stypes = mgmt_stypes[ift].tx; | ||
682 | while (stypes) { | ||
683 | if (stypes & 1) | ||
684 | NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, | ||
685 | (i << 4) | IEEE80211_FTYPE_MGMT); | ||
686 | stypes >>= 1; | ||
687 | i++; | ||
688 | } | ||
689 | nla_nest_end(msg, nl_ftypes); | ||
690 | } | ||
691 | |||
692 | nla_nest_end(msg, nl_ifs); | ||
693 | |||
694 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); | ||
695 | if (!nl_ifs) | ||
696 | goto nla_put_failure; | ||
697 | |||
698 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
699 | nl_ftypes = nla_nest_start(msg, ift); | ||
700 | if (!nl_ftypes) | ||
701 | goto nla_put_failure; | ||
702 | i = 0; | ||
703 | stypes = mgmt_stypes[ift].rx; | ||
704 | while (stypes) { | ||
705 | if (stypes & 1) | ||
706 | NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, | ||
707 | (i << 4) | IEEE80211_FTYPE_MGMT); | ||
708 | stypes >>= 1; | ||
709 | i++; | ||
710 | } | ||
711 | nla_nest_end(msg, nl_ftypes); | ||
712 | } | ||
713 | nla_nest_end(msg, nl_ifs); | ||
714 | } | ||
715 | |||
611 | return genlmsg_end(msg, hdr); | 716 | return genlmsg_end(msg, hdr); |
612 | 717 | ||
613 | nla_put_failure: | 718 | nla_put_failure: |
@@ -644,28 +749,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
644 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 749 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
645 | { | 750 | { |
646 | struct sk_buff *msg; | 751 | struct sk_buff *msg; |
647 | struct cfg80211_registered_device *dev; | 752 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
648 | |||
649 | dev = cfg80211_get_dev_from_info(info); | ||
650 | if (IS_ERR(dev)) | ||
651 | return PTR_ERR(dev); | ||
652 | 753 | ||
653 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 754 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
654 | if (!msg) | 755 | if (!msg) |
655 | goto out_err; | 756 | return -ENOMEM; |
656 | |||
657 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) | ||
658 | goto out_free; | ||
659 | 757 | ||
660 | cfg80211_unlock_rdev(dev); | 758 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) { |
759 | nlmsg_free(msg); | ||
760 | return -ENOBUFS; | ||
761 | } | ||
661 | 762 | ||
662 | return genlmsg_reply(msg, info); | 763 | return genlmsg_reply(msg, info); |
663 | |||
664 | out_free: | ||
665 | nlmsg_free(msg); | ||
666 | out_err: | ||
667 | cfg80211_unlock_rdev(dev); | ||
668 | return -ENOBUFS; | ||
669 | } | 764 | } |
670 | 765 | ||
671 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { | 766 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { |
@@ -709,7 +804,8 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | |||
709 | wdev->iftype == NL80211_IFTYPE_AP || | 804 | wdev->iftype == NL80211_IFTYPE_AP || |
710 | wdev->iftype == NL80211_IFTYPE_WDS || | 805 | wdev->iftype == NL80211_IFTYPE_WDS || |
711 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || | 806 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || |
712 | wdev->iftype == NL80211_IFTYPE_MONITOR; | 807 | wdev->iftype == NL80211_IFTYPE_MONITOR || |
808 | wdev->iftype == NL80211_IFTYPE_P2P_GO; | ||
713 | } | 809 | } |
714 | 810 | ||
715 | static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | 811 | static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, |
@@ -753,38 +849,71 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
753 | 849 | ||
754 | static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) | 850 | static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) |
755 | { | 851 | { |
852 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
853 | struct net_device *netdev = info->user_ptr[1]; | ||
854 | |||
855 | return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); | ||
856 | } | ||
857 | |||
858 | static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) | ||
859 | { | ||
756 | struct cfg80211_registered_device *rdev; | 860 | struct cfg80211_registered_device *rdev; |
757 | struct net_device *netdev; | 861 | struct wireless_dev *wdev; |
758 | int result; | 862 | struct net_device *dev; |
863 | u8 *bssid; | ||
864 | int err; | ||
865 | |||
866 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
867 | return -EINVAL; | ||
759 | 868 | ||
760 | rtnl_lock(); | 869 | rtnl_lock(); |
761 | 870 | ||
762 | result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); | 871 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
763 | if (result) | 872 | if (err) |
764 | goto unlock; | 873 | goto unlock_rtnl; |
874 | |||
875 | wdev = dev->ieee80211_ptr; | ||
765 | 876 | ||
766 | result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); | 877 | if (netif_running(dev)) { |
878 | err = -EBUSY; | ||
879 | goto out; | ||
880 | } | ||
767 | 881 | ||
768 | unlock: | 882 | if (!rdev->ops->set_wds_peer) { |
883 | err = -EOPNOTSUPP; | ||
884 | goto out; | ||
885 | } | ||
886 | |||
887 | if (wdev->iftype != NL80211_IFTYPE_WDS) { | ||
888 | err = -EOPNOTSUPP; | ||
889 | goto out; | ||
890 | } | ||
891 | |||
892 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
893 | err = rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); | ||
894 | |||
895 | out: | ||
896 | cfg80211_unlock_rdev(rdev); | ||
897 | dev_put(dev); | ||
898 | unlock_rtnl: | ||
769 | rtnl_unlock(); | 899 | rtnl_unlock(); |
770 | 900 | ||
771 | return result; | 901 | return err; |
772 | } | 902 | } |
773 | 903 | ||
904 | |||
774 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | 905 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) |
775 | { | 906 | { |
776 | struct cfg80211_registered_device *rdev; | 907 | struct cfg80211_registered_device *rdev; |
777 | struct net_device *netdev = NULL; | 908 | struct net_device *netdev = NULL; |
778 | struct wireless_dev *wdev; | 909 | struct wireless_dev *wdev; |
779 | int result, rem_txq_params = 0; | 910 | int result = 0, rem_txq_params = 0; |
780 | struct nlattr *nl_txq_params; | 911 | struct nlattr *nl_txq_params; |
781 | u32 changed; | 912 | u32 changed; |
782 | u8 retry_short = 0, retry_long = 0; | 913 | u8 retry_short = 0, retry_long = 0; |
783 | u32 frag_threshold = 0, rts_threshold = 0; | 914 | u32 frag_threshold = 0, rts_threshold = 0; |
784 | u8 coverage_class = 0; | 915 | u8 coverage_class = 0; |
785 | 916 | ||
786 | rtnl_lock(); | ||
787 | |||
788 | /* | 917 | /* |
789 | * Try to find the wiphy and netdev. Normally this | 918 | * Try to find the wiphy and netdev. Normally this |
790 | * function shouldn't need the netdev, but this is | 919 | * function shouldn't need the netdev, but this is |
@@ -811,8 +940,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
811 | rdev = __cfg80211_rdev_from_info(info); | 940 | rdev = __cfg80211_rdev_from_info(info); |
812 | if (IS_ERR(rdev)) { | 941 | if (IS_ERR(rdev)) { |
813 | mutex_unlock(&cfg80211_mutex); | 942 | mutex_unlock(&cfg80211_mutex); |
814 | result = PTR_ERR(rdev); | 943 | return PTR_ERR(rdev); |
815 | goto unlock; | ||
816 | } | 944 | } |
817 | wdev = NULL; | 945 | wdev = NULL; |
818 | netdev = NULL; | 946 | netdev = NULL; |
@@ -994,8 +1122,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
994 | mutex_unlock(&rdev->mtx); | 1122 | mutex_unlock(&rdev->mtx); |
995 | if (netdev) | 1123 | if (netdev) |
996 | dev_put(netdev); | 1124 | dev_put(netdev); |
997 | unlock: | ||
998 | rtnl_unlock(); | ||
999 | return result; | 1125 | return result; |
1000 | } | 1126 | } |
1001 | 1127 | ||
@@ -1075,33 +1201,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1075 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | 1201 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) |
1076 | { | 1202 | { |
1077 | struct sk_buff *msg; | 1203 | struct sk_buff *msg; |
1078 | struct cfg80211_registered_device *dev; | 1204 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1079 | struct net_device *netdev; | 1205 | struct net_device *netdev = info->user_ptr[1]; |
1080 | int err; | ||
1081 | |||
1082 | err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); | ||
1083 | if (err) | ||
1084 | return err; | ||
1085 | 1206 | ||
1086 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1207 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1087 | if (!msg) | 1208 | if (!msg) |
1088 | goto out_err; | 1209 | return -ENOMEM; |
1089 | 1210 | ||
1090 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, | 1211 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
1091 | dev, netdev) < 0) | 1212 | dev, netdev) < 0) { |
1092 | goto out_free; | 1213 | nlmsg_free(msg); |
1093 | 1214 | return -ENOBUFS; | |
1094 | dev_put(netdev); | 1215 | } |
1095 | cfg80211_unlock_rdev(dev); | ||
1096 | 1216 | ||
1097 | return genlmsg_reply(msg, info); | 1217 | return genlmsg_reply(msg, info); |
1098 | |||
1099 | out_free: | ||
1100 | nlmsg_free(msg); | ||
1101 | out_err: | ||
1102 | dev_put(netdev); | ||
1103 | cfg80211_unlock_rdev(dev); | ||
1104 | return -ENOBUFS; | ||
1105 | } | 1218 | } |
1106 | 1219 | ||
1107 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { | 1220 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { |
@@ -1161,39 +1274,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, | |||
1161 | 1274 | ||
1162 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 1275 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
1163 | { | 1276 | { |
1164 | struct cfg80211_registered_device *rdev; | 1277 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1165 | struct vif_params params; | 1278 | struct vif_params params; |
1166 | int err; | 1279 | int err; |
1167 | enum nl80211_iftype otype, ntype; | 1280 | enum nl80211_iftype otype, ntype; |
1168 | struct net_device *dev; | 1281 | struct net_device *dev = info->user_ptr[1]; |
1169 | u32 _flags, *flags = NULL; | 1282 | u32 _flags, *flags = NULL; |
1170 | bool change = false; | 1283 | bool change = false; |
1171 | 1284 | ||
1172 | memset(¶ms, 0, sizeof(params)); | 1285 | memset(¶ms, 0, sizeof(params)); |
1173 | 1286 | ||
1174 | rtnl_lock(); | ||
1175 | |||
1176 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1177 | if (err) | ||
1178 | goto unlock_rtnl; | ||
1179 | |||
1180 | otype = ntype = dev->ieee80211_ptr->iftype; | 1287 | otype = ntype = dev->ieee80211_ptr->iftype; |
1181 | 1288 | ||
1182 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 1289 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
1183 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 1290 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
1184 | if (otype != ntype) | 1291 | if (otype != ntype) |
1185 | change = true; | 1292 | change = true; |
1186 | if (ntype > NL80211_IFTYPE_MAX) { | 1293 | if (ntype > NL80211_IFTYPE_MAX) |
1187 | err = -EINVAL; | 1294 | return -EINVAL; |
1188 | goto unlock; | ||
1189 | } | ||
1190 | } | 1295 | } |
1191 | 1296 | ||
1192 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 1297 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
1193 | if (ntype != NL80211_IFTYPE_MESH_POINT) { | 1298 | if (ntype != NL80211_IFTYPE_MESH_POINT) |
1194 | err = -EINVAL; | 1299 | return -EINVAL; |
1195 | goto unlock; | ||
1196 | } | ||
1197 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1300 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
1198 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1301 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
1199 | change = true; | 1302 | change = true; |
@@ -1204,20 +1307,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1204 | change = true; | 1307 | change = true; |
1205 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); | 1308 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); |
1206 | if (err) | 1309 | if (err) |
1207 | goto unlock; | 1310 | return err; |
1208 | } else { | 1311 | } else { |
1209 | params.use_4addr = -1; | 1312 | params.use_4addr = -1; |
1210 | } | 1313 | } |
1211 | 1314 | ||
1212 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 1315 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
1213 | if (ntype != NL80211_IFTYPE_MONITOR) { | 1316 | if (ntype != NL80211_IFTYPE_MONITOR) |
1214 | err = -EINVAL; | 1317 | return -EINVAL; |
1215 | goto unlock; | ||
1216 | } | ||
1217 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | 1318 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], |
1218 | &_flags); | 1319 | &_flags); |
1219 | if (err) | 1320 | if (err) |
1220 | goto unlock; | 1321 | return err; |
1221 | 1322 | ||
1222 | flags = &_flags; | 1323 | flags = &_flags; |
1223 | change = true; | 1324 | change = true; |
@@ -1231,17 +1332,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1231 | if (!err && params.use_4addr != -1) | 1332 | if (!err && params.use_4addr != -1) |
1232 | dev->ieee80211_ptr->use_4addr = params.use_4addr; | 1333 | dev->ieee80211_ptr->use_4addr = params.use_4addr; |
1233 | 1334 | ||
1234 | unlock: | ||
1235 | dev_put(dev); | ||
1236 | cfg80211_unlock_rdev(rdev); | ||
1237 | unlock_rtnl: | ||
1238 | rtnl_unlock(); | ||
1239 | return err; | 1335 | return err; |
1240 | } | 1336 | } |
1241 | 1337 | ||
1242 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | 1338 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) |
1243 | { | 1339 | { |
1244 | struct cfg80211_registered_device *rdev; | 1340 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1245 | struct vif_params params; | 1341 | struct vif_params params; |
1246 | int err; | 1342 | int err; |
1247 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1343 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
@@ -1258,19 +1354,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1258 | return -EINVAL; | 1354 | return -EINVAL; |
1259 | } | 1355 | } |
1260 | 1356 | ||
1261 | rtnl_lock(); | ||
1262 | |||
1263 | rdev = cfg80211_get_dev_from_info(info); | ||
1264 | if (IS_ERR(rdev)) { | ||
1265 | err = PTR_ERR(rdev); | ||
1266 | goto unlock_rtnl; | ||
1267 | } | ||
1268 | |||
1269 | if (!rdev->ops->add_virtual_intf || | 1357 | if (!rdev->ops->add_virtual_intf || |
1270 | !(rdev->wiphy.interface_modes & (1 << type))) { | 1358 | !(rdev->wiphy.interface_modes & (1 << type))) |
1271 | err = -EOPNOTSUPP; | 1359 | return -EOPNOTSUPP; |
1272 | goto unlock; | ||
1273 | } | ||
1274 | 1360 | ||
1275 | if (type == NL80211_IFTYPE_MESH_POINT && | 1361 | if (type == NL80211_IFTYPE_MESH_POINT && |
1276 | info->attrs[NL80211_ATTR_MESH_ID]) { | 1362 | info->attrs[NL80211_ATTR_MESH_ID]) { |
@@ -1282,7 +1368,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1282 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1368 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1283 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); | 1369 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); |
1284 | if (err) | 1370 | if (err) |
1285 | goto unlock; | 1371 | return err; |
1286 | } | 1372 | } |
1287 | 1373 | ||
1288 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1374 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
@@ -1292,38 +1378,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1292 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 1378 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1293 | type, err ? NULL : &flags, ¶ms); | 1379 | type, err ? NULL : &flags, ¶ms); |
1294 | 1380 | ||
1295 | unlock: | ||
1296 | cfg80211_unlock_rdev(rdev); | ||
1297 | unlock_rtnl: | ||
1298 | rtnl_unlock(); | ||
1299 | return err; | 1381 | return err; |
1300 | } | 1382 | } |
1301 | 1383 | ||
1302 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1384 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1303 | { | 1385 | { |
1304 | struct cfg80211_registered_device *rdev; | 1386 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1305 | int err; | 1387 | struct net_device *dev = info->user_ptr[1]; |
1306 | struct net_device *dev; | ||
1307 | |||
1308 | rtnl_lock(); | ||
1309 | |||
1310 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1311 | if (err) | ||
1312 | goto unlock_rtnl; | ||
1313 | 1388 | ||
1314 | if (!rdev->ops->del_virtual_intf) { | 1389 | if (!rdev->ops->del_virtual_intf) |
1315 | err = -EOPNOTSUPP; | 1390 | return -EOPNOTSUPP; |
1316 | goto out; | ||
1317 | } | ||
1318 | |||
1319 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); | ||
1320 | 1391 | ||
1321 | out: | 1392 | return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); |
1322 | cfg80211_unlock_rdev(rdev); | ||
1323 | dev_put(dev); | ||
1324 | unlock_rtnl: | ||
1325 | rtnl_unlock(); | ||
1326 | return err; | ||
1327 | } | 1393 | } |
1328 | 1394 | ||
1329 | struct get_key_cookie { | 1395 | struct get_key_cookie { |
@@ -1376,9 +1442,9 @@ static void get_key_callback(void *c, struct key_params *params) | |||
1376 | 1442 | ||
1377 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | 1443 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) |
1378 | { | 1444 | { |
1379 | struct cfg80211_registered_device *rdev; | 1445 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1380 | int err; | 1446 | int err; |
1381 | struct net_device *dev; | 1447 | struct net_device *dev = info->user_ptr[1]; |
1382 | u8 key_idx = 0; | 1448 | u8 key_idx = 0; |
1383 | u8 *mac_addr = NULL; | 1449 | u8 *mac_addr = NULL; |
1384 | struct get_key_cookie cookie = { | 1450 | struct get_key_cookie cookie = { |
@@ -1396,30 +1462,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1396 | if (info->attrs[NL80211_ATTR_MAC]) | 1462 | if (info->attrs[NL80211_ATTR_MAC]) |
1397 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1463 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1398 | 1464 | ||
1399 | rtnl_lock(); | 1465 | if (!rdev->ops->get_key) |
1400 | 1466 | return -EOPNOTSUPP; | |
1401 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1402 | if (err) | ||
1403 | goto unlock_rtnl; | ||
1404 | |||
1405 | if (!rdev->ops->get_key) { | ||
1406 | err = -EOPNOTSUPP; | ||
1407 | goto out; | ||
1408 | } | ||
1409 | 1467 | ||
1410 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1468 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1411 | if (!msg) { | 1469 | if (!msg) |
1412 | err = -ENOMEM; | 1470 | return -ENOMEM; |
1413 | goto out; | ||
1414 | } | ||
1415 | 1471 | ||
1416 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 1472 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
1417 | NL80211_CMD_NEW_KEY); | 1473 | NL80211_CMD_NEW_KEY); |
1418 | 1474 | if (IS_ERR(hdr)) | |
1419 | if (IS_ERR(hdr)) { | 1475 | return PTR_ERR(hdr); |
1420 | err = PTR_ERR(hdr); | ||
1421 | goto free_msg; | ||
1422 | } | ||
1423 | 1476 | ||
1424 | cookie.msg = msg; | 1477 | cookie.msg = msg; |
1425 | cookie.idx = key_idx; | 1478 | cookie.idx = key_idx; |
@@ -1439,28 +1492,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1439 | goto nla_put_failure; | 1492 | goto nla_put_failure; |
1440 | 1493 | ||
1441 | genlmsg_end(msg, hdr); | 1494 | genlmsg_end(msg, hdr); |
1442 | err = genlmsg_reply(msg, info); | 1495 | return genlmsg_reply(msg, info); |
1443 | goto out; | ||
1444 | 1496 | ||
1445 | nla_put_failure: | 1497 | nla_put_failure: |
1446 | err = -ENOBUFS; | 1498 | err = -ENOBUFS; |
1447 | free_msg: | 1499 | free_msg: |
1448 | nlmsg_free(msg); | 1500 | nlmsg_free(msg); |
1449 | out: | ||
1450 | cfg80211_unlock_rdev(rdev); | ||
1451 | dev_put(dev); | ||
1452 | unlock_rtnl: | ||
1453 | rtnl_unlock(); | ||
1454 | |||
1455 | return err; | 1501 | return err; |
1456 | } | 1502 | } |
1457 | 1503 | ||
1458 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | 1504 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) |
1459 | { | 1505 | { |
1460 | struct cfg80211_registered_device *rdev; | 1506 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1461 | struct key_parse key; | 1507 | struct key_parse key; |
1462 | int err; | 1508 | int err; |
1463 | struct net_device *dev; | 1509 | struct net_device *dev = info->user_ptr[1]; |
1464 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | 1510 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, |
1465 | u8 key_index); | 1511 | u8 key_index); |
1466 | 1512 | ||
@@ -1475,21 +1521,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1475 | if (!key.def && !key.defmgmt) | 1521 | if (!key.def && !key.defmgmt) |
1476 | return -EINVAL; | 1522 | return -EINVAL; |
1477 | 1523 | ||
1478 | rtnl_lock(); | ||
1479 | |||
1480 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1481 | if (err) | ||
1482 | goto unlock_rtnl; | ||
1483 | |||
1484 | if (key.def) | 1524 | if (key.def) |
1485 | func = rdev->ops->set_default_key; | 1525 | func = rdev->ops->set_default_key; |
1486 | else | 1526 | else |
1487 | func = rdev->ops->set_default_mgmt_key; | 1527 | func = rdev->ops->set_default_mgmt_key; |
1488 | 1528 | ||
1489 | if (!func) { | 1529 | if (!func) |
1490 | err = -EOPNOTSUPP; | 1530 | return -EOPNOTSUPP; |
1491 | goto out; | ||
1492 | } | ||
1493 | 1531 | ||
1494 | wdev_lock(dev->ieee80211_ptr); | 1532 | wdev_lock(dev->ieee80211_ptr); |
1495 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1533 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
@@ -1506,21 +1544,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1506 | #endif | 1544 | #endif |
1507 | wdev_unlock(dev->ieee80211_ptr); | 1545 | wdev_unlock(dev->ieee80211_ptr); |
1508 | 1546 | ||
1509 | out: | ||
1510 | cfg80211_unlock_rdev(rdev); | ||
1511 | dev_put(dev); | ||
1512 | |||
1513 | unlock_rtnl: | ||
1514 | rtnl_unlock(); | ||
1515 | |||
1516 | return err; | 1547 | return err; |
1517 | } | 1548 | } |
1518 | 1549 | ||
1519 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | 1550 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) |
1520 | { | 1551 | { |
1521 | struct cfg80211_registered_device *rdev; | 1552 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1522 | int err; | 1553 | int err; |
1523 | struct net_device *dev; | 1554 | struct net_device *dev = info->user_ptr[1]; |
1524 | struct key_parse key; | 1555 | struct key_parse key; |
1525 | u8 *mac_addr = NULL; | 1556 | u8 *mac_addr = NULL; |
1526 | 1557 | ||
@@ -1534,21 +1565,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1534 | if (info->attrs[NL80211_ATTR_MAC]) | 1565 | if (info->attrs[NL80211_ATTR_MAC]) |
1535 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1566 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1536 | 1567 | ||
1537 | rtnl_lock(); | 1568 | if (!rdev->ops->add_key) |
1538 | 1569 | return -EOPNOTSUPP; | |
1539 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1540 | if (err) | ||
1541 | goto unlock_rtnl; | ||
1542 | |||
1543 | if (!rdev->ops->add_key) { | ||
1544 | err = -EOPNOTSUPP; | ||
1545 | goto out; | ||
1546 | } | ||
1547 | 1570 | ||
1548 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { | 1571 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) |
1549 | err = -EINVAL; | 1572 | return -EINVAL; |
1550 | goto out; | ||
1551 | } | ||
1552 | 1573 | ||
1553 | wdev_lock(dev->ieee80211_ptr); | 1574 | wdev_lock(dev->ieee80211_ptr); |
1554 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1575 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
@@ -1557,20 +1578,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1557 | mac_addr, &key.p); | 1578 | mac_addr, &key.p); |
1558 | wdev_unlock(dev->ieee80211_ptr); | 1579 | wdev_unlock(dev->ieee80211_ptr); |
1559 | 1580 | ||
1560 | out: | ||
1561 | cfg80211_unlock_rdev(rdev); | ||
1562 | dev_put(dev); | ||
1563 | unlock_rtnl: | ||
1564 | rtnl_unlock(); | ||
1565 | |||
1566 | return err; | 1581 | return err; |
1567 | } | 1582 | } |
1568 | 1583 | ||
1569 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | 1584 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) |
1570 | { | 1585 | { |
1571 | struct cfg80211_registered_device *rdev; | 1586 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1572 | int err; | 1587 | int err; |
1573 | struct net_device *dev; | 1588 | struct net_device *dev = info->user_ptr[1]; |
1574 | u8 *mac_addr = NULL; | 1589 | u8 *mac_addr = NULL; |
1575 | struct key_parse key; | 1590 | struct key_parse key; |
1576 | 1591 | ||
@@ -1581,16 +1596,8 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1581 | if (info->attrs[NL80211_ATTR_MAC]) | 1596 | if (info->attrs[NL80211_ATTR_MAC]) |
1582 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1597 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1583 | 1598 | ||
1584 | rtnl_lock(); | 1599 | if (!rdev->ops->del_key) |
1585 | 1600 | return -EOPNOTSUPP; | |
1586 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1587 | if (err) | ||
1588 | goto unlock_rtnl; | ||
1589 | |||
1590 | if (!rdev->ops->del_key) { | ||
1591 | err = -EOPNOTSUPP; | ||
1592 | goto out; | ||
1593 | } | ||
1594 | 1601 | ||
1595 | wdev_lock(dev->ieee80211_ptr); | 1602 | wdev_lock(dev->ieee80211_ptr); |
1596 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1603 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
@@ -1607,13 +1614,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1607 | #endif | 1614 | #endif |
1608 | wdev_unlock(dev->ieee80211_ptr); | 1615 | wdev_unlock(dev->ieee80211_ptr); |
1609 | 1616 | ||
1610 | out: | ||
1611 | cfg80211_unlock_rdev(rdev); | ||
1612 | dev_put(dev); | ||
1613 | |||
1614 | unlock_rtnl: | ||
1615 | rtnl_unlock(); | ||
1616 | |||
1617 | return err; | 1617 | return err; |
1618 | } | 1618 | } |
1619 | 1619 | ||
@@ -1621,35 +1621,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1621 | { | 1621 | { |
1622 | int (*call)(struct wiphy *wiphy, struct net_device *dev, | 1622 | int (*call)(struct wiphy *wiphy, struct net_device *dev, |
1623 | struct beacon_parameters *info); | 1623 | struct beacon_parameters *info); |
1624 | struct cfg80211_registered_device *rdev; | 1624 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1625 | int err; | 1625 | struct net_device *dev = info->user_ptr[1]; |
1626 | struct net_device *dev; | ||
1627 | struct beacon_parameters params; | 1626 | struct beacon_parameters params; |
1628 | int haveinfo = 0; | 1627 | int haveinfo = 0; |
1629 | 1628 | ||
1630 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | 1629 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) |
1631 | return -EINVAL; | 1630 | return -EINVAL; |
1632 | 1631 | ||
1633 | rtnl_lock(); | 1632 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
1634 | 1633 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | |
1635 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1634 | return -EOPNOTSUPP; |
1636 | if (err) | ||
1637 | goto unlock_rtnl; | ||
1638 | |||
1639 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | ||
1640 | err = -EOPNOTSUPP; | ||
1641 | goto out; | ||
1642 | } | ||
1643 | 1635 | ||
1644 | switch (info->genlhdr->cmd) { | 1636 | switch (info->genlhdr->cmd) { |
1645 | case NL80211_CMD_NEW_BEACON: | 1637 | case NL80211_CMD_NEW_BEACON: |
1646 | /* these are required for NEW_BEACON */ | 1638 | /* these are required for NEW_BEACON */ |
1647 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || | 1639 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || |
1648 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || | 1640 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || |
1649 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1641 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) |
1650 | err = -EINVAL; | 1642 | return -EINVAL; |
1651 | goto out; | ||
1652 | } | ||
1653 | 1643 | ||
1654 | call = rdev->ops->add_beacon; | 1644 | call = rdev->ops->add_beacon; |
1655 | break; | 1645 | break; |
@@ -1658,14 +1648,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1658 | break; | 1648 | break; |
1659 | default: | 1649 | default: |
1660 | WARN_ON(1); | 1650 | WARN_ON(1); |
1661 | err = -EOPNOTSUPP; | 1651 | return -EOPNOTSUPP; |
1662 | goto out; | ||
1663 | } | 1652 | } |
1664 | 1653 | ||
1665 | if (!call) { | 1654 | if (!call) |
1666 | err = -EOPNOTSUPP; | 1655 | return -EOPNOTSUPP; |
1667 | goto out; | ||
1668 | } | ||
1669 | 1656 | ||
1670 | memset(¶ms, 0, sizeof(params)); | 1657 | memset(¶ms, 0, sizeof(params)); |
1671 | 1658 | ||
@@ -1695,52 +1682,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1695 | haveinfo = 1; | 1682 | haveinfo = 1; |
1696 | } | 1683 | } |
1697 | 1684 | ||
1698 | if (!haveinfo) { | 1685 | if (!haveinfo) |
1699 | err = -EINVAL; | 1686 | return -EINVAL; |
1700 | goto out; | ||
1701 | } | ||
1702 | |||
1703 | err = call(&rdev->wiphy, dev, ¶ms); | ||
1704 | |||
1705 | out: | ||
1706 | cfg80211_unlock_rdev(rdev); | ||
1707 | dev_put(dev); | ||
1708 | unlock_rtnl: | ||
1709 | rtnl_unlock(); | ||
1710 | 1687 | ||
1711 | return err; | 1688 | return call(&rdev->wiphy, dev, ¶ms); |
1712 | } | 1689 | } |
1713 | 1690 | ||
1714 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 1691 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) |
1715 | { | 1692 | { |
1716 | struct cfg80211_registered_device *rdev; | 1693 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1717 | int err; | 1694 | struct net_device *dev = info->user_ptr[1]; |
1718 | struct net_device *dev; | ||
1719 | |||
1720 | rtnl_lock(); | ||
1721 | |||
1722 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1723 | if (err) | ||
1724 | goto unlock_rtnl; | ||
1725 | |||
1726 | if (!rdev->ops->del_beacon) { | ||
1727 | err = -EOPNOTSUPP; | ||
1728 | goto out; | ||
1729 | } | ||
1730 | 1695 | ||
1731 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | 1696 | if (!rdev->ops->del_beacon) |
1732 | err = -EOPNOTSUPP; | 1697 | return -EOPNOTSUPP; |
1733 | goto out; | ||
1734 | } | ||
1735 | err = rdev->ops->del_beacon(&rdev->wiphy, dev); | ||
1736 | 1698 | ||
1737 | out: | 1699 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
1738 | cfg80211_unlock_rdev(rdev); | 1700 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1739 | dev_put(dev); | 1701 | return -EOPNOTSUPP; |
1740 | unlock_rtnl: | ||
1741 | rtnl_unlock(); | ||
1742 | 1702 | ||
1743 | return err; | 1703 | return rdev->ops->del_beacon(&rdev->wiphy, dev); |
1744 | } | 1704 | } |
1745 | 1705 | ||
1746 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 1706 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -1877,28 +1837,12 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1877 | struct cfg80211_registered_device *dev; | 1837 | struct cfg80211_registered_device *dev; |
1878 | struct net_device *netdev; | 1838 | struct net_device *netdev; |
1879 | u8 mac_addr[ETH_ALEN]; | 1839 | u8 mac_addr[ETH_ALEN]; |
1880 | int ifidx = cb->args[0]; | ||
1881 | int sta_idx = cb->args[1]; | 1840 | int sta_idx = cb->args[1]; |
1882 | int err; | 1841 | int err; |
1883 | 1842 | ||
1884 | if (!ifidx) | 1843 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
1885 | ifidx = nl80211_get_ifidx(cb); | 1844 | if (err) |
1886 | if (ifidx < 0) | 1845 | return err; |
1887 | return ifidx; | ||
1888 | |||
1889 | rtnl_lock(); | ||
1890 | |||
1891 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1892 | if (!netdev) { | ||
1893 | err = -ENODEV; | ||
1894 | goto out_rtnl; | ||
1895 | } | ||
1896 | |||
1897 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
1898 | if (IS_ERR(dev)) { | ||
1899 | err = PTR_ERR(dev); | ||
1900 | goto out_rtnl; | ||
1901 | } | ||
1902 | 1846 | ||
1903 | if (!dev->ops->dump_station) { | 1847 | if (!dev->ops->dump_station) { |
1904 | err = -EOPNOTSUPP; | 1848 | err = -EOPNOTSUPP; |
@@ -1928,21 +1872,19 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1928 | cb->args[1] = sta_idx; | 1872 | cb->args[1] = sta_idx; |
1929 | err = skb->len; | 1873 | err = skb->len; |
1930 | out_err: | 1874 | out_err: |
1931 | cfg80211_unlock_rdev(dev); | 1875 | nl80211_finish_netdev_dump(dev); |
1932 | out_rtnl: | ||
1933 | rtnl_unlock(); | ||
1934 | 1876 | ||
1935 | return err; | 1877 | return err; |
1936 | } | 1878 | } |
1937 | 1879 | ||
1938 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 1880 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
1939 | { | 1881 | { |
1940 | struct cfg80211_registered_device *rdev; | 1882 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1941 | int err; | 1883 | struct net_device *dev = info->user_ptr[1]; |
1942 | struct net_device *dev; | ||
1943 | struct station_info sinfo; | 1884 | struct station_info sinfo; |
1944 | struct sk_buff *msg; | 1885 | struct sk_buff *msg; |
1945 | u8 *mac_addr = NULL; | 1886 | u8 *mac_addr = NULL; |
1887 | int err; | ||
1946 | 1888 | ||
1947 | memset(&sinfo, 0, sizeof(sinfo)); | 1889 | memset(&sinfo, 0, sizeof(sinfo)); |
1948 | 1890 | ||
@@ -1951,41 +1893,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1951 | 1893 | ||
1952 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1894 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1953 | 1895 | ||
1954 | rtnl_lock(); | 1896 | if (!rdev->ops->get_station) |
1955 | 1897 | return -EOPNOTSUPP; | |
1956 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1957 | if (err) | ||
1958 | goto out_rtnl; | ||
1959 | |||
1960 | if (!rdev->ops->get_station) { | ||
1961 | err = -EOPNOTSUPP; | ||
1962 | goto out; | ||
1963 | } | ||
1964 | 1898 | ||
1965 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); | 1899 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); |
1966 | if (err) | 1900 | if (err) |
1967 | goto out; | 1901 | return err; |
1968 | 1902 | ||
1969 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1903 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1970 | if (!msg) | 1904 | if (!msg) |
1971 | goto out; | 1905 | return -ENOMEM; |
1972 | 1906 | ||
1973 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | 1907 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, |
1974 | dev, mac_addr, &sinfo) < 0) | 1908 | dev, mac_addr, &sinfo) < 0) { |
1975 | goto out_free; | 1909 | nlmsg_free(msg); |
1976 | 1910 | return -ENOBUFS; | |
1977 | err = genlmsg_reply(msg, info); | 1911 | } |
1978 | goto out; | ||
1979 | |||
1980 | out_free: | ||
1981 | nlmsg_free(msg); | ||
1982 | out: | ||
1983 | cfg80211_unlock_rdev(rdev); | ||
1984 | dev_put(dev); | ||
1985 | out_rtnl: | ||
1986 | rtnl_unlock(); | ||
1987 | 1912 | ||
1988 | return err; | 1913 | return genlmsg_reply(msg, info); |
1989 | } | 1914 | } |
1990 | 1915 | ||
1991 | /* | 1916 | /* |
@@ -2015,9 +1940,9 @@ static int get_vlan(struct genl_info *info, | |||
2015 | 1940 | ||
2016 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 1941 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
2017 | { | 1942 | { |
2018 | struct cfg80211_registered_device *rdev; | 1943 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2019 | int err; | 1944 | int err; |
2020 | struct net_device *dev; | 1945 | struct net_device *dev = info->user_ptr[1]; |
2021 | struct station_parameters params; | 1946 | struct station_parameters params; |
2022 | u8 *mac_addr = NULL; | 1947 | u8 *mac_addr = NULL; |
2023 | 1948 | ||
@@ -2055,12 +1980,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2055 | params.plink_action = | 1980 | params.plink_action = |
2056 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 1981 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
2057 | 1982 | ||
2058 | rtnl_lock(); | ||
2059 | |||
2060 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2061 | if (err) | ||
2062 | goto out_rtnl; | ||
2063 | |||
2064 | err = get_vlan(info, rdev, ¶ms.vlan); | 1983 | err = get_vlan(info, rdev, ¶ms.vlan); |
2065 | if (err) | 1984 | if (err) |
2066 | goto out; | 1985 | goto out; |
@@ -2071,10 +1990,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2071 | switch (dev->ieee80211_ptr->iftype) { | 1990 | switch (dev->ieee80211_ptr->iftype) { |
2072 | case NL80211_IFTYPE_AP: | 1991 | case NL80211_IFTYPE_AP: |
2073 | case NL80211_IFTYPE_AP_VLAN: | 1992 | case NL80211_IFTYPE_AP_VLAN: |
1993 | case NL80211_IFTYPE_P2P_GO: | ||
2074 | /* disallow mesh-specific things */ | 1994 | /* disallow mesh-specific things */ |
2075 | if (params.plink_action) | 1995 | if (params.plink_action) |
2076 | err = -EINVAL; | 1996 | err = -EINVAL; |
2077 | break; | 1997 | break; |
1998 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2078 | case NL80211_IFTYPE_STATION: | 1999 | case NL80211_IFTYPE_STATION: |
2079 | /* disallow everything but AUTHORIZED flag */ | 2000 | /* disallow everything but AUTHORIZED flag */ |
2080 | if (params.plink_action) | 2001 | if (params.plink_action) |
@@ -2120,19 +2041,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2120 | out: | 2041 | out: |
2121 | if (params.vlan) | 2042 | if (params.vlan) |
2122 | dev_put(params.vlan); | 2043 | dev_put(params.vlan); |
2123 | cfg80211_unlock_rdev(rdev); | ||
2124 | dev_put(dev); | ||
2125 | out_rtnl: | ||
2126 | rtnl_unlock(); | ||
2127 | 2044 | ||
2128 | return err; | 2045 | return err; |
2129 | } | 2046 | } |
2130 | 2047 | ||
2131 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 2048 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
2132 | { | 2049 | { |
2133 | struct cfg80211_registered_device *rdev; | 2050 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2134 | int err; | 2051 | int err; |
2135 | struct net_device *dev; | 2052 | struct net_device *dev = info->user_ptr[1]; |
2136 | struct station_parameters params; | 2053 | struct station_parameters params; |
2137 | u8 *mac_addr = NULL; | 2054 | u8 *mac_addr = NULL; |
2138 | 2055 | ||
@@ -2169,17 +2086,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2169 | if (parse_station_flags(info, ¶ms)) | 2086 | if (parse_station_flags(info, ¶ms)) |
2170 | return -EINVAL; | 2087 | return -EINVAL; |
2171 | 2088 | ||
2172 | rtnl_lock(); | ||
2173 | |||
2174 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2175 | if (err) | ||
2176 | goto out_rtnl; | ||
2177 | |||
2178 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2089 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2179 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | 2090 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2180 | err = -EINVAL; | 2091 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2181 | goto out; | 2092 | return -EINVAL; |
2182 | } | ||
2183 | 2093 | ||
2184 | err = get_vlan(info, rdev, ¶ms.vlan); | 2094 | err = get_vlan(info, rdev, ¶ms.vlan); |
2185 | if (err) | 2095 | if (err) |
@@ -2193,61 +2103,33 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2193 | goto out; | 2103 | goto out; |
2194 | } | 2104 | } |
2195 | 2105 | ||
2196 | if (!netif_running(dev)) { | ||
2197 | err = -ENETDOWN; | ||
2198 | goto out; | ||
2199 | } | ||
2200 | |||
2201 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); | 2106 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); |
2202 | 2107 | ||
2203 | out: | 2108 | out: |
2204 | if (params.vlan) | 2109 | if (params.vlan) |
2205 | dev_put(params.vlan); | 2110 | dev_put(params.vlan); |
2206 | cfg80211_unlock_rdev(rdev); | ||
2207 | dev_put(dev); | ||
2208 | out_rtnl: | ||
2209 | rtnl_unlock(); | ||
2210 | |||
2211 | return err; | 2111 | return err; |
2212 | } | 2112 | } |
2213 | 2113 | ||
2214 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | 2114 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) |
2215 | { | 2115 | { |
2216 | struct cfg80211_registered_device *rdev; | 2116 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2217 | int err; | 2117 | struct net_device *dev = info->user_ptr[1]; |
2218 | struct net_device *dev; | ||
2219 | u8 *mac_addr = NULL; | 2118 | u8 *mac_addr = NULL; |
2220 | 2119 | ||
2221 | if (info->attrs[NL80211_ATTR_MAC]) | 2120 | if (info->attrs[NL80211_ATTR_MAC]) |
2222 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2121 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2223 | 2122 | ||
2224 | rtnl_lock(); | ||
2225 | |||
2226 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2227 | if (err) | ||
2228 | goto out_rtnl; | ||
2229 | |||
2230 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2123 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2231 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2124 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2232 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2125 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && |
2233 | err = -EINVAL; | 2126 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2234 | goto out; | 2127 | return -EINVAL; |
2235 | } | ||
2236 | |||
2237 | if (!rdev->ops->del_station) { | ||
2238 | err = -EOPNOTSUPP; | ||
2239 | goto out; | ||
2240 | } | ||
2241 | |||
2242 | err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); | ||
2243 | 2128 | ||
2244 | out: | 2129 | if (!rdev->ops->del_station) |
2245 | cfg80211_unlock_rdev(rdev); | 2130 | return -EOPNOTSUPP; |
2246 | dev_put(dev); | ||
2247 | out_rtnl: | ||
2248 | rtnl_unlock(); | ||
2249 | 2131 | ||
2250 | return err; | 2132 | return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); |
2251 | } | 2133 | } |
2252 | 2134 | ||
2253 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | 2135 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, |
@@ -2310,28 +2192,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2310 | struct net_device *netdev; | 2192 | struct net_device *netdev; |
2311 | u8 dst[ETH_ALEN]; | 2193 | u8 dst[ETH_ALEN]; |
2312 | u8 next_hop[ETH_ALEN]; | 2194 | u8 next_hop[ETH_ALEN]; |
2313 | int ifidx = cb->args[0]; | ||
2314 | int path_idx = cb->args[1]; | 2195 | int path_idx = cb->args[1]; |
2315 | int err; | 2196 | int err; |
2316 | 2197 | ||
2317 | if (!ifidx) | 2198 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
2318 | ifidx = nl80211_get_ifidx(cb); | 2199 | if (err) |
2319 | if (ifidx < 0) | 2200 | return err; |
2320 | return ifidx; | ||
2321 | |||
2322 | rtnl_lock(); | ||
2323 | |||
2324 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
2325 | if (!netdev) { | ||
2326 | err = -ENODEV; | ||
2327 | goto out_rtnl; | ||
2328 | } | ||
2329 | |||
2330 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
2331 | if (IS_ERR(dev)) { | ||
2332 | err = PTR_ERR(dev); | ||
2333 | goto out_rtnl; | ||
2334 | } | ||
2335 | 2201 | ||
2336 | if (!dev->ops->dump_mpath) { | 2202 | if (!dev->ops->dump_mpath) { |
2337 | err = -EOPNOTSUPP; | 2203 | err = -EOPNOTSUPP; |
@@ -2365,18 +2231,15 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2365 | cb->args[1] = path_idx; | 2231 | cb->args[1] = path_idx; |
2366 | err = skb->len; | 2232 | err = skb->len; |
2367 | out_err: | 2233 | out_err: |
2368 | cfg80211_unlock_rdev(dev); | 2234 | nl80211_finish_netdev_dump(dev); |
2369 | out_rtnl: | ||
2370 | rtnl_unlock(); | ||
2371 | |||
2372 | return err; | 2235 | return err; |
2373 | } | 2236 | } |
2374 | 2237 | ||
2375 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | 2238 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) |
2376 | { | 2239 | { |
2377 | struct cfg80211_registered_device *rdev; | 2240 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2378 | int err; | 2241 | int err; |
2379 | struct net_device *dev; | 2242 | struct net_device *dev = info->user_ptr[1]; |
2380 | struct mpath_info pinfo; | 2243 | struct mpath_info pinfo; |
2381 | struct sk_buff *msg; | 2244 | struct sk_buff *msg; |
2382 | u8 *dst = NULL; | 2245 | u8 *dst = NULL; |
@@ -2389,53 +2252,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2389 | 2252 | ||
2390 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2253 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2391 | 2254 | ||
2392 | rtnl_lock(); | 2255 | if (!rdev->ops->get_mpath) |
2393 | 2256 | return -EOPNOTSUPP; | |
2394 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2395 | if (err) | ||
2396 | goto out_rtnl; | ||
2397 | |||
2398 | if (!rdev->ops->get_mpath) { | ||
2399 | err = -EOPNOTSUPP; | ||
2400 | goto out; | ||
2401 | } | ||
2402 | 2257 | ||
2403 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2258 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2404 | err = -EOPNOTSUPP; | 2259 | return -EOPNOTSUPP; |
2405 | goto out; | ||
2406 | } | ||
2407 | 2260 | ||
2408 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); | 2261 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); |
2409 | if (err) | 2262 | if (err) |
2410 | goto out; | 2263 | return err; |
2411 | 2264 | ||
2412 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2265 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2413 | if (!msg) | 2266 | if (!msg) |
2414 | goto out; | 2267 | return -ENOMEM; |
2415 | 2268 | ||
2416 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, | 2269 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, |
2417 | dev, dst, next_hop, &pinfo) < 0) | 2270 | dev, dst, next_hop, &pinfo) < 0) { |
2418 | goto out_free; | 2271 | nlmsg_free(msg); |
2419 | 2272 | return -ENOBUFS; | |
2420 | err = genlmsg_reply(msg, info); | 2273 | } |
2421 | goto out; | ||
2422 | |||
2423 | out_free: | ||
2424 | nlmsg_free(msg); | ||
2425 | out: | ||
2426 | cfg80211_unlock_rdev(rdev); | ||
2427 | dev_put(dev); | ||
2428 | out_rtnl: | ||
2429 | rtnl_unlock(); | ||
2430 | 2274 | ||
2431 | return err; | 2275 | return genlmsg_reply(msg, info); |
2432 | } | 2276 | } |
2433 | 2277 | ||
2434 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | 2278 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) |
2435 | { | 2279 | { |
2436 | struct cfg80211_registered_device *rdev; | 2280 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2437 | int err; | 2281 | struct net_device *dev = info->user_ptr[1]; |
2438 | struct net_device *dev; | ||
2439 | u8 *dst = NULL; | 2282 | u8 *dst = NULL; |
2440 | u8 *next_hop = NULL; | 2283 | u8 *next_hop = NULL; |
2441 | 2284 | ||
@@ -2448,42 +2291,19 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2448 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2291 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2449 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2292 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2450 | 2293 | ||
2451 | rtnl_lock(); | 2294 | if (!rdev->ops->change_mpath) |
2452 | 2295 | return -EOPNOTSUPP; | |
2453 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2454 | if (err) | ||
2455 | goto out_rtnl; | ||
2456 | |||
2457 | if (!rdev->ops->change_mpath) { | ||
2458 | err = -EOPNOTSUPP; | ||
2459 | goto out; | ||
2460 | } | ||
2461 | |||
2462 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2463 | err = -EOPNOTSUPP; | ||
2464 | goto out; | ||
2465 | } | ||
2466 | |||
2467 | if (!netif_running(dev)) { | ||
2468 | err = -ENETDOWN; | ||
2469 | goto out; | ||
2470 | } | ||
2471 | |||
2472 | err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); | ||
2473 | 2296 | ||
2474 | out: | 2297 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2475 | cfg80211_unlock_rdev(rdev); | 2298 | return -EOPNOTSUPP; |
2476 | dev_put(dev); | ||
2477 | out_rtnl: | ||
2478 | rtnl_unlock(); | ||
2479 | 2299 | ||
2480 | return err; | 2300 | return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); |
2481 | } | 2301 | } |
2302 | |||
2482 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 2303 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) |
2483 | { | 2304 | { |
2484 | struct cfg80211_registered_device *rdev; | 2305 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2485 | int err; | 2306 | struct net_device *dev = info->user_ptr[1]; |
2486 | struct net_device *dev; | ||
2487 | u8 *dst = NULL; | 2307 | u8 *dst = NULL; |
2488 | u8 *next_hop = NULL; | 2308 | u8 *next_hop = NULL; |
2489 | 2309 | ||
@@ -2496,75 +2316,34 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2496 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2316 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2497 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2317 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2498 | 2318 | ||
2499 | rtnl_lock(); | 2319 | if (!rdev->ops->add_mpath) |
2500 | 2320 | return -EOPNOTSUPP; | |
2501 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2502 | if (err) | ||
2503 | goto out_rtnl; | ||
2504 | |||
2505 | if (!rdev->ops->add_mpath) { | ||
2506 | err = -EOPNOTSUPP; | ||
2507 | goto out; | ||
2508 | } | ||
2509 | |||
2510 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2511 | err = -EOPNOTSUPP; | ||
2512 | goto out; | ||
2513 | } | ||
2514 | |||
2515 | if (!netif_running(dev)) { | ||
2516 | err = -ENETDOWN; | ||
2517 | goto out; | ||
2518 | } | ||
2519 | |||
2520 | err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); | ||
2521 | 2321 | ||
2522 | out: | 2322 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2523 | cfg80211_unlock_rdev(rdev); | 2323 | return -EOPNOTSUPP; |
2524 | dev_put(dev); | ||
2525 | out_rtnl: | ||
2526 | rtnl_unlock(); | ||
2527 | 2324 | ||
2528 | return err; | 2325 | return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); |
2529 | } | 2326 | } |
2530 | 2327 | ||
2531 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | 2328 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) |
2532 | { | 2329 | { |
2533 | struct cfg80211_registered_device *rdev; | 2330 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2534 | int err; | 2331 | struct net_device *dev = info->user_ptr[1]; |
2535 | struct net_device *dev; | ||
2536 | u8 *dst = NULL; | 2332 | u8 *dst = NULL; |
2537 | 2333 | ||
2538 | if (info->attrs[NL80211_ATTR_MAC]) | 2334 | if (info->attrs[NL80211_ATTR_MAC]) |
2539 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2335 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2540 | 2336 | ||
2541 | rtnl_lock(); | 2337 | if (!rdev->ops->del_mpath) |
2542 | 2338 | return -EOPNOTSUPP; | |
2543 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2544 | if (err) | ||
2545 | goto out_rtnl; | ||
2546 | |||
2547 | if (!rdev->ops->del_mpath) { | ||
2548 | err = -EOPNOTSUPP; | ||
2549 | goto out; | ||
2550 | } | ||
2551 | |||
2552 | err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); | ||
2553 | |||
2554 | out: | ||
2555 | cfg80211_unlock_rdev(rdev); | ||
2556 | dev_put(dev); | ||
2557 | out_rtnl: | ||
2558 | rtnl_unlock(); | ||
2559 | 2339 | ||
2560 | return err; | 2340 | return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); |
2561 | } | 2341 | } |
2562 | 2342 | ||
2563 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | 2343 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) |
2564 | { | 2344 | { |
2565 | struct cfg80211_registered_device *rdev; | 2345 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2566 | int err; | 2346 | struct net_device *dev = info->user_ptr[1]; |
2567 | struct net_device *dev; | ||
2568 | struct bss_parameters params; | 2347 | struct bss_parameters params; |
2569 | 2348 | ||
2570 | memset(¶ms, 0, sizeof(params)); | 2349 | memset(¶ms, 0, sizeof(params)); |
@@ -2592,31 +2371,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2592 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) | 2371 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) |
2593 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); | 2372 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); |
2594 | 2373 | ||
2595 | rtnl_lock(); | 2374 | if (!rdev->ops->change_bss) |
2596 | 2375 | return -EOPNOTSUPP; | |
2597 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2598 | if (err) | ||
2599 | goto out_rtnl; | ||
2600 | |||
2601 | if (!rdev->ops->change_bss) { | ||
2602 | err = -EOPNOTSUPP; | ||
2603 | goto out; | ||
2604 | } | ||
2605 | |||
2606 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | ||
2607 | err = -EOPNOTSUPP; | ||
2608 | goto out; | ||
2609 | } | ||
2610 | |||
2611 | err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); | ||
2612 | 2376 | ||
2613 | out: | 2377 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2614 | cfg80211_unlock_rdev(rdev); | 2378 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2615 | dev_put(dev); | 2379 | return -EOPNOTSUPP; |
2616 | out_rtnl: | ||
2617 | rtnl_unlock(); | ||
2618 | 2380 | ||
2619 | return err; | 2381 | return rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); |
2620 | } | 2382 | } |
2621 | 2383 | ||
2622 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | 2384 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { |
@@ -2695,37 +2457,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2695 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2457 | static int nl80211_get_mesh_params(struct sk_buff *skb, |
2696 | struct genl_info *info) | 2458 | struct genl_info *info) |
2697 | { | 2459 | { |
2698 | struct cfg80211_registered_device *rdev; | 2460 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2699 | struct mesh_config cur_params; | 2461 | struct mesh_config cur_params; |
2700 | int err; | 2462 | int err; |
2701 | struct net_device *dev; | 2463 | struct net_device *dev = info->user_ptr[1]; |
2702 | void *hdr; | 2464 | void *hdr; |
2703 | struct nlattr *pinfoattr; | 2465 | struct nlattr *pinfoattr; |
2704 | struct sk_buff *msg; | 2466 | struct sk_buff *msg; |
2705 | 2467 | ||
2706 | rtnl_lock(); | 2468 | if (!rdev->ops->get_mesh_params) |
2707 | 2469 | return -EOPNOTSUPP; | |
2708 | /* Look up our device */ | ||
2709 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2710 | if (err) | ||
2711 | goto out_rtnl; | ||
2712 | |||
2713 | if (!rdev->ops->get_mesh_params) { | ||
2714 | err = -EOPNOTSUPP; | ||
2715 | goto out; | ||
2716 | } | ||
2717 | 2470 | ||
2718 | /* Get the mesh params */ | 2471 | /* Get the mesh params */ |
2719 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); | 2472 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); |
2720 | if (err) | 2473 | if (err) |
2721 | goto out; | 2474 | return err; |
2722 | 2475 | ||
2723 | /* Draw up a netlink message to send back */ | 2476 | /* Draw up a netlink message to send back */ |
2724 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2477 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2725 | if (!msg) { | 2478 | if (!msg) |
2726 | err = -ENOBUFS; | 2479 | return -ENOMEM; |
2727 | goto out; | ||
2728 | } | ||
2729 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 2480 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
2730 | NL80211_CMD_GET_MESH_PARAMS); | 2481 | NL80211_CMD_GET_MESH_PARAMS); |
2731 | if (!hdr) | 2482 | if (!hdr) |
@@ -2764,21 +2515,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2764 | cur_params.dot11MeshHWMPRootMode); | 2515 | cur_params.dot11MeshHWMPRootMode); |
2765 | nla_nest_end(msg, pinfoattr); | 2516 | nla_nest_end(msg, pinfoattr); |
2766 | genlmsg_end(msg, hdr); | 2517 | genlmsg_end(msg, hdr); |
2767 | err = genlmsg_reply(msg, info); | 2518 | return genlmsg_reply(msg, info); |
2768 | goto out; | ||
2769 | 2519 | ||
2770 | nla_put_failure: | 2520 | nla_put_failure: |
2771 | genlmsg_cancel(msg, hdr); | 2521 | genlmsg_cancel(msg, hdr); |
2772 | nlmsg_free(msg); | 2522 | nlmsg_free(msg); |
2773 | err = -EMSGSIZE; | 2523 | return -ENOBUFS; |
2774 | out: | ||
2775 | /* Cleanup */ | ||
2776 | cfg80211_unlock_rdev(rdev); | ||
2777 | dev_put(dev); | ||
2778 | out_rtnl: | ||
2779 | rtnl_unlock(); | ||
2780 | |||
2781 | return err; | ||
2782 | } | 2524 | } |
2783 | 2525 | ||
2784 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | 2526 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ |
@@ -2808,10 +2550,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2808 | 2550 | ||
2809 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2551 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) |
2810 | { | 2552 | { |
2811 | int err; | ||
2812 | u32 mask; | 2553 | u32 mask; |
2813 | struct cfg80211_registered_device *rdev; | 2554 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2814 | struct net_device *dev; | 2555 | struct net_device *dev = info->user_ptr[1]; |
2815 | struct mesh_config cfg; | 2556 | struct mesh_config cfg; |
2816 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; | 2557 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; |
2817 | struct nlattr *parent_attr; | 2558 | struct nlattr *parent_attr; |
@@ -2823,16 +2564,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2823 | parent_attr, nl80211_meshconf_params_policy)) | 2564 | parent_attr, nl80211_meshconf_params_policy)) |
2824 | return -EINVAL; | 2565 | return -EINVAL; |
2825 | 2566 | ||
2826 | rtnl_lock(); | 2567 | if (!rdev->ops->set_mesh_params) |
2827 | 2568 | return -EOPNOTSUPP; | |
2828 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2829 | if (err) | ||
2830 | goto out_rtnl; | ||
2831 | |||
2832 | if (!rdev->ops->set_mesh_params) { | ||
2833 | err = -EOPNOTSUPP; | ||
2834 | goto out; | ||
2835 | } | ||
2836 | 2569 | ||
2837 | /* This makes sure that there aren't more than 32 mesh config | 2570 | /* This makes sure that there aren't more than 32 mesh config |
2838 | * parameters (otherwise our bitfield scheme would not work.) */ | 2571 | * parameters (otherwise our bitfield scheme would not work.) */ |
@@ -2878,16 +2611,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2878 | nla_get_u8); | 2611 | nla_get_u8); |
2879 | 2612 | ||
2880 | /* Apply changes */ | 2613 | /* Apply changes */ |
2881 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2614 | return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); |
2882 | |||
2883 | out: | ||
2884 | /* cleanup */ | ||
2885 | cfg80211_unlock_rdev(rdev); | ||
2886 | dev_put(dev); | ||
2887 | out_rtnl: | ||
2888 | rtnl_unlock(); | ||
2889 | |||
2890 | return err; | ||
2891 | } | 2615 | } |
2892 | 2616 | ||
2893 | #undef FILL_IN_MESH_PARAM_IF_SET | 2617 | #undef FILL_IN_MESH_PARAM_IF_SET |
@@ -3070,8 +2794,8 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
3070 | 2794 | ||
3071 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2795 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
3072 | { | 2796 | { |
3073 | struct cfg80211_registered_device *rdev; | 2797 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3074 | struct net_device *dev; | 2798 | struct net_device *dev = info->user_ptr[1]; |
3075 | struct cfg80211_scan_request *request; | 2799 | struct cfg80211_scan_request *request; |
3076 | struct cfg80211_ssid *ssid; | 2800 | struct cfg80211_ssid *ssid; |
3077 | struct ieee80211_channel *channel; | 2801 | struct ieee80211_channel *channel; |
@@ -3084,36 +2808,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3084 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 2808 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3085 | return -EINVAL; | 2809 | return -EINVAL; |
3086 | 2810 | ||
3087 | rtnl_lock(); | ||
3088 | |||
3089 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3090 | if (err) | ||
3091 | goto out_rtnl; | ||
3092 | |||
3093 | wiphy = &rdev->wiphy; | 2811 | wiphy = &rdev->wiphy; |
3094 | 2812 | ||
3095 | if (!rdev->ops->scan) { | 2813 | if (!rdev->ops->scan) |
3096 | err = -EOPNOTSUPP; | 2814 | return -EOPNOTSUPP; |
3097 | goto out; | ||
3098 | } | ||
3099 | |||
3100 | if (!netif_running(dev)) { | ||
3101 | err = -ENETDOWN; | ||
3102 | goto out; | ||
3103 | } | ||
3104 | 2815 | ||
3105 | if (rdev->scan_req) { | 2816 | if (rdev->scan_req) |
3106 | err = -EBUSY; | 2817 | return -EBUSY; |
3107 | goto out; | ||
3108 | } | ||
3109 | 2818 | ||
3110 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2819 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
3111 | n_channels = validate_scan_freqs( | 2820 | n_channels = validate_scan_freqs( |
3112 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | 2821 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); |
3113 | if (!n_channels) { | 2822 | if (!n_channels) |
3114 | err = -EINVAL; | 2823 | return -EINVAL; |
3115 | goto out; | ||
3116 | } | ||
3117 | } else { | 2824 | } else { |
3118 | n_channels = 0; | 2825 | n_channels = 0; |
3119 | 2826 | ||
@@ -3126,29 +2833,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3126 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) | 2833 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) |
3127 | n_ssids++; | 2834 | n_ssids++; |
3128 | 2835 | ||
3129 | if (n_ssids > wiphy->max_scan_ssids) { | 2836 | if (n_ssids > wiphy->max_scan_ssids) |
3130 | err = -EINVAL; | 2837 | return -EINVAL; |
3131 | goto out; | ||
3132 | } | ||
3133 | 2838 | ||
3134 | if (info->attrs[NL80211_ATTR_IE]) | 2839 | if (info->attrs[NL80211_ATTR_IE]) |
3135 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2840 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3136 | else | 2841 | else |
3137 | ie_len = 0; | 2842 | ie_len = 0; |
3138 | 2843 | ||
3139 | if (ie_len > wiphy->max_scan_ie_len) { | 2844 | if (ie_len > wiphy->max_scan_ie_len) |
3140 | err = -EINVAL; | 2845 | return -EINVAL; |
3141 | goto out; | ||
3142 | } | ||
3143 | 2846 | ||
3144 | request = kzalloc(sizeof(*request) | 2847 | request = kzalloc(sizeof(*request) |
3145 | + sizeof(*ssid) * n_ssids | 2848 | + sizeof(*ssid) * n_ssids |
3146 | + sizeof(channel) * n_channels | 2849 | + sizeof(channel) * n_channels |
3147 | + ie_len, GFP_KERNEL); | 2850 | + ie_len, GFP_KERNEL); |
3148 | if (!request) { | 2851 | if (!request) |
3149 | err = -ENOMEM; | 2852 | return -ENOMEM; |
3150 | goto out; | ||
3151 | } | ||
3152 | 2853 | ||
3153 | if (n_ssids) | 2854 | if (n_ssids) |
3154 | request->ssids = (void *)&request->channels[n_channels]; | 2855 | request->ssids = (void *)&request->channels[n_channels]; |
@@ -3236,18 +2937,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3236 | if (!err) { | 2937 | if (!err) { |
3237 | nl80211_send_scan_start(rdev, dev); | 2938 | nl80211_send_scan_start(rdev, dev); |
3238 | dev_hold(dev); | 2939 | dev_hold(dev); |
3239 | } | 2940 | } else { |
3240 | |||
3241 | out_free: | 2941 | out_free: |
3242 | if (err) { | ||
3243 | rdev->scan_req = NULL; | 2942 | rdev->scan_req = NULL; |
3244 | kfree(request); | 2943 | kfree(request); |
3245 | } | 2944 | } |
3246 | out: | ||
3247 | cfg80211_unlock_rdev(rdev); | ||
3248 | dev_put(dev); | ||
3249 | out_rtnl: | ||
3250 | rtnl_unlock(); | ||
3251 | 2945 | ||
3252 | return err; | 2946 | return err; |
3253 | } | 2947 | } |
@@ -3306,6 +3000,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3306 | } | 3000 | } |
3307 | 3001 | ||
3308 | switch (wdev->iftype) { | 3002 | switch (wdev->iftype) { |
3003 | case NL80211_IFTYPE_P2P_CLIENT: | ||
3309 | case NL80211_IFTYPE_STATION: | 3004 | case NL80211_IFTYPE_STATION: |
3310 | if (intbss == wdev->current_bss) | 3005 | if (intbss == wdev->current_bss) |
3311 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, | 3006 | NLA_PUT_U32(msg, NL80211_BSS_STATUS, |
@@ -3343,25 +3038,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3343 | struct net_device *dev; | 3038 | struct net_device *dev; |
3344 | struct cfg80211_internal_bss *scan; | 3039 | struct cfg80211_internal_bss *scan; |
3345 | struct wireless_dev *wdev; | 3040 | struct wireless_dev *wdev; |
3346 | int ifidx = cb->args[0]; | ||
3347 | int start = cb->args[1], idx = 0; | 3041 | int start = cb->args[1], idx = 0; |
3348 | int err; | 3042 | int err; |
3349 | 3043 | ||
3350 | if (!ifidx) | 3044 | err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); |
3351 | ifidx = nl80211_get_ifidx(cb); | 3045 | if (err) |
3352 | if (ifidx < 0) | 3046 | return err; |
3353 | return ifidx; | ||
3354 | cb->args[0] = ifidx; | ||
3355 | |||
3356 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3357 | if (!dev) | ||
3358 | return -ENODEV; | ||
3359 | |||
3360 | rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3361 | if (IS_ERR(rdev)) { | ||
3362 | err = PTR_ERR(rdev); | ||
3363 | goto out_put_netdev; | ||
3364 | } | ||
3365 | 3047 | ||
3366 | wdev = dev->ieee80211_ptr; | 3048 | wdev = dev->ieee80211_ptr; |
3367 | 3049 | ||
@@ -3377,21 +3059,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3377 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3059 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3378 | rdev, wdev, scan) < 0) { | 3060 | rdev, wdev, scan) < 0) { |
3379 | idx--; | 3061 | idx--; |
3380 | goto out; | 3062 | break; |
3381 | } | 3063 | } |
3382 | } | 3064 | } |
3383 | 3065 | ||
3384 | out: | ||
3385 | spin_unlock_bh(&rdev->bss_lock); | 3066 | spin_unlock_bh(&rdev->bss_lock); |
3386 | wdev_unlock(wdev); | 3067 | wdev_unlock(wdev); |
3387 | 3068 | ||
3388 | cb->args[1] = idx; | 3069 | cb->args[1] = idx; |
3389 | err = skb->len; | 3070 | nl80211_finish_netdev_dump(rdev); |
3390 | cfg80211_unlock_rdev(rdev); | ||
3391 | out_put_netdev: | ||
3392 | dev_put(dev); | ||
3393 | 3071 | ||
3394 | return err; | 3072 | return skb->len; |
3395 | } | 3073 | } |
3396 | 3074 | ||
3397 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | 3075 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, |
@@ -3421,6 +3099,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | |||
3421 | if (survey->filled & SURVEY_INFO_NOISE_DBM) | 3099 | if (survey->filled & SURVEY_INFO_NOISE_DBM) |
3422 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, | 3100 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, |
3423 | survey->noise); | 3101 | survey->noise); |
3102 | if (survey->filled & SURVEY_INFO_IN_USE) | ||
3103 | NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); | ||
3424 | 3104 | ||
3425 | nla_nest_end(msg, infoattr); | 3105 | nla_nest_end(msg, infoattr); |
3426 | 3106 | ||
@@ -3437,29 +3117,12 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3437 | struct survey_info survey; | 3117 | struct survey_info survey; |
3438 | struct cfg80211_registered_device *dev; | 3118 | struct cfg80211_registered_device *dev; |
3439 | struct net_device *netdev; | 3119 | struct net_device *netdev; |
3440 | int ifidx = cb->args[0]; | ||
3441 | int survey_idx = cb->args[1]; | 3120 | int survey_idx = cb->args[1]; |
3442 | int res; | 3121 | int res; |
3443 | 3122 | ||
3444 | if (!ifidx) | 3123 | res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
3445 | ifidx = nl80211_get_ifidx(cb); | 3124 | if (res) |
3446 | if (ifidx < 0) | 3125 | return res; |
3447 | return ifidx; | ||
3448 | cb->args[0] = ifidx; | ||
3449 | |||
3450 | rtnl_lock(); | ||
3451 | |||
3452 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3453 | if (!netdev) { | ||
3454 | res = -ENODEV; | ||
3455 | goto out_rtnl; | ||
3456 | } | ||
3457 | |||
3458 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3459 | if (IS_ERR(dev)) { | ||
3460 | res = PTR_ERR(dev); | ||
3461 | goto out_rtnl; | ||
3462 | } | ||
3463 | 3126 | ||
3464 | if (!dev->ops->dump_survey) { | 3127 | if (!dev->ops->dump_survey) { |
3465 | res = -EOPNOTSUPP; | 3128 | res = -EOPNOTSUPP; |
@@ -3487,10 +3150,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3487 | cb->args[1] = survey_idx; | 3150 | cb->args[1] = survey_idx; |
3488 | res = skb->len; | 3151 | res = skb->len; |
3489 | out_err: | 3152 | out_err: |
3490 | cfg80211_unlock_rdev(dev); | 3153 | nl80211_finish_netdev_dump(dev); |
3491 | out_rtnl: | ||
3492 | rtnl_unlock(); | ||
3493 | |||
3494 | return res; | 3154 | return res; |
3495 | } | 3155 | } |
3496 | 3156 | ||
@@ -3523,8 +3183,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher) | |||
3523 | 3183 | ||
3524 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | 3184 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) |
3525 | { | 3185 | { |
3526 | struct cfg80211_registered_device *rdev; | 3186 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3527 | struct net_device *dev; | 3187 | struct net_device *dev = info->user_ptr[1]; |
3528 | struct ieee80211_channel *chan; | 3188 | struct ieee80211_channel *chan; |
3529 | const u8 *bssid, *ssid, *ie = NULL; | 3189 | const u8 *bssid, *ssid, *ie = NULL; |
3530 | int err, ssid_len, ie_len = 0; | 3190 | int err, ssid_len, ie_len = 0; |
@@ -3566,34 +3226,31 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3566 | key.p.key = NULL; | 3226 | key.p.key = NULL; |
3567 | } | 3227 | } |
3568 | 3228 | ||
3569 | rtnl_lock(); | 3229 | if (key.idx >= 0) { |
3570 | 3230 | int i; | |
3571 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3231 | bool ok = false; |
3572 | if (err) | 3232 | for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) { |
3573 | goto unlock_rtnl; | 3233 | if (key.p.cipher == rdev->wiphy.cipher_suites[i]) { |
3574 | 3234 | ok = true; | |
3575 | if (!rdev->ops->auth) { | 3235 | break; |
3576 | err = -EOPNOTSUPP; | 3236 | } |
3577 | goto out; | 3237 | } |
3238 | if (!ok) | ||
3239 | return -EINVAL; | ||
3578 | } | 3240 | } |
3579 | 3241 | ||
3580 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 3242 | if (!rdev->ops->auth) |
3581 | err = -EOPNOTSUPP; | 3243 | return -EOPNOTSUPP; |
3582 | goto out; | ||
3583 | } | ||
3584 | 3244 | ||
3585 | if (!netif_running(dev)) { | 3245 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3586 | err = -ENETDOWN; | 3246 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3587 | goto out; | 3247 | return -EOPNOTSUPP; |
3588 | } | ||
3589 | 3248 | ||
3590 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3249 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3591 | chan = ieee80211_get_channel(&rdev->wiphy, | 3250 | chan = ieee80211_get_channel(&rdev->wiphy, |
3592 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3251 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3593 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3252 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) |
3594 | err = -EINVAL; | 3253 | return -EINVAL; |
3595 | goto out; | ||
3596 | } | ||
3597 | 3254 | ||
3598 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3255 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3599 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3256 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
@@ -3604,27 +3261,19 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3604 | } | 3261 | } |
3605 | 3262 | ||
3606 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 3263 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
3607 | if (!nl80211_valid_auth_type(auth_type)) { | 3264 | if (!nl80211_valid_auth_type(auth_type)) |
3608 | err = -EINVAL; | 3265 | return -EINVAL; |
3609 | goto out; | ||
3610 | } | ||
3611 | 3266 | ||
3612 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3267 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3613 | 3268 | ||
3614 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 3269 | return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
3615 | ssid, ssid_len, ie, ie_len, | 3270 | ssid, ssid_len, ie, ie_len, |
3616 | key.p.key, key.p.key_len, key.idx, | 3271 | key.p.key, key.p.key_len, key.idx, |
3617 | local_state_change); | 3272 | local_state_change); |
3618 | |||
3619 | out: | ||
3620 | cfg80211_unlock_rdev(rdev); | ||
3621 | dev_put(dev); | ||
3622 | unlock_rtnl: | ||
3623 | rtnl_unlock(); | ||
3624 | return err; | ||
3625 | } | 3273 | } |
3626 | 3274 | ||
3627 | static int nl80211_crypto_settings(struct genl_info *info, | 3275 | static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, |
3276 | struct genl_info *info, | ||
3628 | struct cfg80211_crypto_settings *settings, | 3277 | struct cfg80211_crypto_settings *settings, |
3629 | int cipher_limit) | 3278 | int cipher_limit) |
3630 | { | 3279 | { |
@@ -3632,6 +3281,19 @@ static int nl80211_crypto_settings(struct genl_info *info, | |||
3632 | 3281 | ||
3633 | settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; | 3282 | settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; |
3634 | 3283 | ||
3284 | if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) { | ||
3285 | u16 proto; | ||
3286 | proto = nla_get_u16( | ||
3287 | info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); | ||
3288 | settings->control_port_ethertype = cpu_to_be16(proto); | ||
3289 | if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && | ||
3290 | proto != ETH_P_PAE) | ||
3291 | return -EINVAL; | ||
3292 | if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) | ||
3293 | settings->control_port_no_encrypt = true; | ||
3294 | } else | ||
3295 | settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE); | ||
3296 | |||
3635 | if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { | 3297 | if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { |
3636 | void *data; | 3298 | void *data; |
3637 | int len, i; | 3299 | int len, i; |
@@ -3691,8 +3353,8 @@ static int nl80211_crypto_settings(struct genl_info *info, | |||
3691 | 3353 | ||
3692 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | 3354 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) |
3693 | { | 3355 | { |
3694 | struct cfg80211_registered_device *rdev; | 3356 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3695 | struct net_device *dev; | 3357 | struct net_device *dev = info->user_ptr[1]; |
3696 | struct cfg80211_crypto_settings crypto; | 3358 | struct cfg80211_crypto_settings crypto; |
3697 | struct ieee80211_channel *chan; | 3359 | struct ieee80211_channel *chan; |
3698 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3360 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
@@ -3707,35 +3369,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3707 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 3369 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
3708 | return -EINVAL; | 3370 | return -EINVAL; |
3709 | 3371 | ||
3710 | rtnl_lock(); | 3372 | if (!rdev->ops->assoc) |
3711 | 3373 | return -EOPNOTSUPP; | |
3712 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3713 | if (err) | ||
3714 | goto unlock_rtnl; | ||
3715 | |||
3716 | if (!rdev->ops->assoc) { | ||
3717 | err = -EOPNOTSUPP; | ||
3718 | goto out; | ||
3719 | } | ||
3720 | |||
3721 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
3722 | err = -EOPNOTSUPP; | ||
3723 | goto out; | ||
3724 | } | ||
3725 | 3374 | ||
3726 | if (!netif_running(dev)) { | 3375 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3727 | err = -ENETDOWN; | 3376 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3728 | goto out; | 3377 | return -EOPNOTSUPP; |
3729 | } | ||
3730 | 3378 | ||
3731 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3379 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3732 | 3380 | ||
3733 | chan = ieee80211_get_channel(&rdev->wiphy, | 3381 | chan = ieee80211_get_channel(&rdev->wiphy, |
3734 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3382 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3735 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3383 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) |
3736 | err = -EINVAL; | 3384 | return -EINVAL; |
3737 | goto out; | ||
3738 | } | ||
3739 | 3385 | ||
3740 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3386 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3741 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3387 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
@@ -3750,35 +3396,28 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3750 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 3396 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
3751 | if (mfp == NL80211_MFP_REQUIRED) | 3397 | if (mfp == NL80211_MFP_REQUIRED) |
3752 | use_mfp = true; | 3398 | use_mfp = true; |
3753 | else if (mfp != NL80211_MFP_NO) { | 3399 | else if (mfp != NL80211_MFP_NO) |
3754 | err = -EINVAL; | 3400 | return -EINVAL; |
3755 | goto out; | ||
3756 | } | ||
3757 | } | 3401 | } |
3758 | 3402 | ||
3759 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 3403 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
3760 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 3404 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
3761 | 3405 | ||
3762 | err = nl80211_crypto_settings(info, &crypto, 1); | 3406 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); |
3763 | if (!err) | 3407 | if (!err) |
3764 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 3408 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
3765 | ssid, ssid_len, ie, ie_len, use_mfp, | 3409 | ssid, ssid_len, ie, ie_len, use_mfp, |
3766 | &crypto); | 3410 | &crypto); |
3767 | 3411 | ||
3768 | out: | ||
3769 | cfg80211_unlock_rdev(rdev); | ||
3770 | dev_put(dev); | ||
3771 | unlock_rtnl: | ||
3772 | rtnl_unlock(); | ||
3773 | return err; | 3412 | return err; |
3774 | } | 3413 | } |
3775 | 3414 | ||
3776 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | 3415 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) |
3777 | { | 3416 | { |
3778 | struct cfg80211_registered_device *rdev; | 3417 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3779 | struct net_device *dev; | 3418 | struct net_device *dev = info->user_ptr[1]; |
3780 | const u8 *ie = NULL, *bssid; | 3419 | const u8 *ie = NULL, *bssid; |
3781 | int err, ie_len = 0; | 3420 | int ie_len = 0; |
3782 | u16 reason_code; | 3421 | u16 reason_code; |
3783 | bool local_state_change; | 3422 | bool local_state_change; |
3784 | 3423 | ||
@@ -3791,34 +3430,19 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3791 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3430 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3792 | return -EINVAL; | 3431 | return -EINVAL; |
3793 | 3432 | ||
3794 | rtnl_lock(); | 3433 | if (!rdev->ops->deauth) |
3795 | 3434 | return -EOPNOTSUPP; | |
3796 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3797 | if (err) | ||
3798 | goto unlock_rtnl; | ||
3799 | |||
3800 | if (!rdev->ops->deauth) { | ||
3801 | err = -EOPNOTSUPP; | ||
3802 | goto out; | ||
3803 | } | ||
3804 | |||
3805 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
3806 | err = -EOPNOTSUPP; | ||
3807 | goto out; | ||
3808 | } | ||
3809 | 3435 | ||
3810 | if (!netif_running(dev)) { | 3436 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3811 | err = -ENETDOWN; | 3437 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3812 | goto out; | 3438 | return -EOPNOTSUPP; |
3813 | } | ||
3814 | 3439 | ||
3815 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3440 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3816 | 3441 | ||
3817 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3442 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3818 | if (reason_code == 0) { | 3443 | if (reason_code == 0) { |
3819 | /* Reason Code 0 is reserved */ | 3444 | /* Reason Code 0 is reserved */ |
3820 | err = -EINVAL; | 3445 | return -EINVAL; |
3821 | goto out; | ||
3822 | } | 3446 | } |
3823 | 3447 | ||
3824 | if (info->attrs[NL80211_ATTR_IE]) { | 3448 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -3828,23 +3452,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3828 | 3452 | ||
3829 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3453 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3830 | 3454 | ||
3831 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, | 3455 | return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, |
3832 | local_state_change); | 3456 | local_state_change); |
3833 | |||
3834 | out: | ||
3835 | cfg80211_unlock_rdev(rdev); | ||
3836 | dev_put(dev); | ||
3837 | unlock_rtnl: | ||
3838 | rtnl_unlock(); | ||
3839 | return err; | ||
3840 | } | 3457 | } |
3841 | 3458 | ||
3842 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | 3459 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) |
3843 | { | 3460 | { |
3844 | struct cfg80211_registered_device *rdev; | 3461 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3845 | struct net_device *dev; | 3462 | struct net_device *dev = info->user_ptr[1]; |
3846 | const u8 *ie = NULL, *bssid; | 3463 | const u8 *ie = NULL, *bssid; |
3847 | int err, ie_len = 0; | 3464 | int ie_len = 0; |
3848 | u16 reason_code; | 3465 | u16 reason_code; |
3849 | bool local_state_change; | 3466 | bool local_state_change; |
3850 | 3467 | ||
@@ -3857,34 +3474,19 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3857 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3474 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3858 | return -EINVAL; | 3475 | return -EINVAL; |
3859 | 3476 | ||
3860 | rtnl_lock(); | 3477 | if (!rdev->ops->disassoc) |
3861 | 3478 | return -EOPNOTSUPP; | |
3862 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3863 | if (err) | ||
3864 | goto unlock_rtnl; | ||
3865 | |||
3866 | if (!rdev->ops->disassoc) { | ||
3867 | err = -EOPNOTSUPP; | ||
3868 | goto out; | ||
3869 | } | ||
3870 | |||
3871 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
3872 | err = -EOPNOTSUPP; | ||
3873 | goto out; | ||
3874 | } | ||
3875 | 3479 | ||
3876 | if (!netif_running(dev)) { | 3480 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3877 | err = -ENETDOWN; | 3481 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3878 | goto out; | 3482 | return -EOPNOTSUPP; |
3879 | } | ||
3880 | 3483 | ||
3881 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3484 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3882 | 3485 | ||
3883 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3486 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3884 | if (reason_code == 0) { | 3487 | if (reason_code == 0) { |
3885 | /* Reason Code 0 is reserved */ | 3488 | /* Reason Code 0 is reserved */ |
3886 | err = -EINVAL; | 3489 | return -EINVAL; |
3887 | goto out; | ||
3888 | } | 3490 | } |
3889 | 3491 | ||
3890 | if (info->attrs[NL80211_ATTR_IE]) { | 3492 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -3894,21 +3496,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3894 | 3496 | ||
3895 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3497 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3896 | 3498 | ||
3897 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, | 3499 | return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, |
3898 | local_state_change); | 3500 | local_state_change); |
3899 | |||
3900 | out: | ||
3901 | cfg80211_unlock_rdev(rdev); | ||
3902 | dev_put(dev); | ||
3903 | unlock_rtnl: | ||
3904 | rtnl_unlock(); | ||
3905 | return err; | ||
3906 | } | 3501 | } |
3907 | 3502 | ||
3908 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | 3503 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) |
3909 | { | 3504 | { |
3910 | struct cfg80211_registered_device *rdev; | 3505 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3911 | struct net_device *dev; | 3506 | struct net_device *dev = info->user_ptr[1]; |
3912 | struct cfg80211_ibss_params ibss; | 3507 | struct cfg80211_ibss_params ibss; |
3913 | struct wiphy *wiphy; | 3508 | struct wiphy *wiphy; |
3914 | struct cfg80211_cached_keys *connkeys = NULL; | 3509 | struct cfg80211_cached_keys *connkeys = NULL; |
@@ -3933,26 +3528,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3933 | return -EINVAL; | 3528 | return -EINVAL; |
3934 | } | 3529 | } |
3935 | 3530 | ||
3936 | rtnl_lock(); | 3531 | if (!rdev->ops->join_ibss) |
3937 | 3532 | return -EOPNOTSUPP; | |
3938 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3939 | if (err) | ||
3940 | goto unlock_rtnl; | ||
3941 | |||
3942 | if (!rdev->ops->join_ibss) { | ||
3943 | err = -EOPNOTSUPP; | ||
3944 | goto out; | ||
3945 | } | ||
3946 | |||
3947 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
3948 | err = -EOPNOTSUPP; | ||
3949 | goto out; | ||
3950 | } | ||
3951 | 3533 | ||
3952 | if (!netif_running(dev)) { | 3534 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) |
3953 | err = -ENETDOWN; | 3535 | return -EOPNOTSUPP; |
3954 | goto out; | ||
3955 | } | ||
3956 | 3536 | ||
3957 | wiphy = &rdev->wiphy; | 3537 | wiphy = &rdev->wiphy; |
3958 | 3538 | ||
@@ -3970,24 +3550,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3970 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3550 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3971 | if (!ibss.channel || | 3551 | if (!ibss.channel || |
3972 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | 3552 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || |
3973 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { | 3553 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) |
3974 | err = -EINVAL; | 3554 | return -EINVAL; |
3975 | goto out; | ||
3976 | } | ||
3977 | 3555 | ||
3978 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 3556 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
3979 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 3557 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
3980 | 3558 | ||
3981 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { | ||
3982 | connkeys = nl80211_parse_connkeys(rdev, | ||
3983 | info->attrs[NL80211_ATTR_KEYS]); | ||
3984 | if (IS_ERR(connkeys)) { | ||
3985 | err = PTR_ERR(connkeys); | ||
3986 | connkeys = NULL; | ||
3987 | goto out; | ||
3988 | } | ||
3989 | } | ||
3990 | |||
3991 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | 3559 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { |
3992 | u8 *rates = | 3560 | u8 *rates = |
3993 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 3561 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
@@ -3997,10 +3565,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3997 | wiphy->bands[ibss.channel->band]; | 3565 | wiphy->bands[ibss.channel->band]; |
3998 | int i, j; | 3566 | int i, j; |
3999 | 3567 | ||
4000 | if (n_rates == 0) { | 3568 | if (n_rates == 0) |
4001 | err = -EINVAL; | 3569 | return -EINVAL; |
4002 | goto out; | ||
4003 | } | ||
4004 | 3570 | ||
4005 | for (i = 0; i < n_rates; i++) { | 3571 | for (i = 0; i < n_rates; i++) { |
4006 | int rate = (rates[i] & 0x7f) * 5; | 3572 | int rate = (rates[i] & 0x7f) * 5; |
@@ -4013,77 +3579,36 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4013 | break; | 3579 | break; |
4014 | } | 3580 | } |
4015 | } | 3581 | } |
4016 | if (!found) { | 3582 | if (!found) |
4017 | err = -EINVAL; | 3583 | return -EINVAL; |
4018 | goto out; | ||
4019 | } | ||
4020 | } | ||
4021 | } else { | ||
4022 | /* | ||
4023 | * If no rates were explicitly configured, | ||
4024 | * use the mandatory rate set for 11b or | ||
4025 | * 11a for maximum compatibility. | ||
4026 | */ | ||
4027 | struct ieee80211_supported_band *sband = | ||
4028 | wiphy->bands[ibss.channel->band]; | ||
4029 | int j; | ||
4030 | u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ? | ||
4031 | IEEE80211_RATE_MANDATORY_A : | ||
4032 | IEEE80211_RATE_MANDATORY_B; | ||
4033 | |||
4034 | for (j = 0; j < sband->n_bitrates; j++) { | ||
4035 | if (sband->bitrates[j].flags & flag) | ||
4036 | ibss.basic_rates |= BIT(j); | ||
4037 | } | 3584 | } |
4038 | } | 3585 | } |
4039 | 3586 | ||
4040 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); | 3587 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
3588 | connkeys = nl80211_parse_connkeys(rdev, | ||
3589 | info->attrs[NL80211_ATTR_KEYS]); | ||
3590 | if (IS_ERR(connkeys)) | ||
3591 | return PTR_ERR(connkeys); | ||
3592 | } | ||
4041 | 3593 | ||
4042 | out: | 3594 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); |
4043 | cfg80211_unlock_rdev(rdev); | ||
4044 | dev_put(dev); | ||
4045 | unlock_rtnl: | ||
4046 | if (err) | 3595 | if (err) |
4047 | kfree(connkeys); | 3596 | kfree(connkeys); |
4048 | rtnl_unlock(); | ||
4049 | return err; | 3597 | return err; |
4050 | } | 3598 | } |
4051 | 3599 | ||
4052 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | 3600 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) |
4053 | { | 3601 | { |
4054 | struct cfg80211_registered_device *rdev; | 3602 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4055 | struct net_device *dev; | 3603 | struct net_device *dev = info->user_ptr[1]; |
4056 | int err; | ||
4057 | |||
4058 | rtnl_lock(); | ||
4059 | |||
4060 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4061 | if (err) | ||
4062 | goto unlock_rtnl; | ||
4063 | |||
4064 | if (!rdev->ops->leave_ibss) { | ||
4065 | err = -EOPNOTSUPP; | ||
4066 | goto out; | ||
4067 | } | ||
4068 | 3604 | ||
4069 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | 3605 | if (!rdev->ops->leave_ibss) |
4070 | err = -EOPNOTSUPP; | 3606 | return -EOPNOTSUPP; |
4071 | goto out; | ||
4072 | } | ||
4073 | |||
4074 | if (!netif_running(dev)) { | ||
4075 | err = -ENETDOWN; | ||
4076 | goto out; | ||
4077 | } | ||
4078 | 3607 | ||
4079 | err = cfg80211_leave_ibss(rdev, dev, false); | 3608 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) |
3609 | return -EOPNOTSUPP; | ||
4080 | 3610 | ||
4081 | out: | 3611 | return cfg80211_leave_ibss(rdev, dev, false); |
4082 | cfg80211_unlock_rdev(rdev); | ||
4083 | dev_put(dev); | ||
4084 | unlock_rtnl: | ||
4085 | rtnl_unlock(); | ||
4086 | return err; | ||
4087 | } | 3612 | } |
4088 | 3613 | ||
4089 | #ifdef CONFIG_NL80211_TESTMODE | 3614 | #ifdef CONFIG_NL80211_TESTMODE |
@@ -4093,20 +3618,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = { | |||
4093 | 3618 | ||
4094 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | 3619 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) |
4095 | { | 3620 | { |
4096 | struct cfg80211_registered_device *rdev; | 3621 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4097 | int err; | 3622 | int err; |
4098 | 3623 | ||
4099 | if (!info->attrs[NL80211_ATTR_TESTDATA]) | 3624 | if (!info->attrs[NL80211_ATTR_TESTDATA]) |
4100 | return -EINVAL; | 3625 | return -EINVAL; |
4101 | 3626 | ||
4102 | rtnl_lock(); | ||
4103 | |||
4104 | rdev = cfg80211_get_dev_from_info(info); | ||
4105 | if (IS_ERR(rdev)) { | ||
4106 | err = PTR_ERR(rdev); | ||
4107 | goto unlock_rtnl; | ||
4108 | } | ||
4109 | |||
4110 | err = -EOPNOTSUPP; | 3627 | err = -EOPNOTSUPP; |
4111 | if (rdev->ops->testmode_cmd) { | 3628 | if (rdev->ops->testmode_cmd) { |
4112 | rdev->testmode_info = info; | 3629 | rdev->testmode_info = info; |
@@ -4116,10 +3633,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | |||
4116 | rdev->testmode_info = NULL; | 3633 | rdev->testmode_info = NULL; |
4117 | } | 3634 | } |
4118 | 3635 | ||
4119 | cfg80211_unlock_rdev(rdev); | ||
4120 | |||
4121 | unlock_rtnl: | ||
4122 | rtnl_unlock(); | ||
4123 | return err; | 3636 | return err; |
4124 | } | 3637 | } |
4125 | 3638 | ||
@@ -4210,8 +3723,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event); | |||
4210 | 3723 | ||
4211 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | 3724 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) |
4212 | { | 3725 | { |
4213 | struct cfg80211_registered_device *rdev; | 3726 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4214 | struct net_device *dev; | 3727 | struct net_device *dev = info->user_ptr[1]; |
4215 | struct cfg80211_connect_params connect; | 3728 | struct cfg80211_connect_params connect; |
4216 | struct wiphy *wiphy; | 3729 | struct wiphy *wiphy; |
4217 | struct cfg80211_cached_keys *connkeys = NULL; | 3730 | struct cfg80211_cached_keys *connkeys = NULL; |
@@ -4236,25 +3749,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4236 | 3749 | ||
4237 | connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; | 3750 | connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; |
4238 | 3751 | ||
4239 | err = nl80211_crypto_settings(info, &connect.crypto, | 3752 | err = nl80211_crypto_settings(rdev, info, &connect.crypto, |
4240 | NL80211_MAX_NR_CIPHER_SUITES); | 3753 | NL80211_MAX_NR_CIPHER_SUITES); |
4241 | if (err) | 3754 | if (err) |
4242 | return err; | 3755 | return err; |
4243 | rtnl_lock(); | ||
4244 | 3756 | ||
4245 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3757 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4246 | if (err) | 3758 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4247 | goto unlock_rtnl; | 3759 | return -EOPNOTSUPP; |
4248 | |||
4249 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
4250 | err = -EOPNOTSUPP; | ||
4251 | goto out; | ||
4252 | } | ||
4253 | |||
4254 | if (!netif_running(dev)) { | ||
4255 | err = -ENETDOWN; | ||
4256 | goto out; | ||
4257 | } | ||
4258 | 3760 | ||
4259 | wiphy = &rdev->wiphy; | 3761 | wiphy = &rdev->wiphy; |
4260 | 3762 | ||
@@ -4273,39 +3775,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4273 | ieee80211_get_channel(wiphy, | 3775 | ieee80211_get_channel(wiphy, |
4274 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3776 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
4275 | if (!connect.channel || | 3777 | if (!connect.channel || |
4276 | connect.channel->flags & IEEE80211_CHAN_DISABLED) { | 3778 | connect.channel->flags & IEEE80211_CHAN_DISABLED) |
4277 | err = -EINVAL; | 3779 | return -EINVAL; |
4278 | goto out; | ||
4279 | } | ||
4280 | } | 3780 | } |
4281 | 3781 | ||
4282 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { | 3782 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
4283 | connkeys = nl80211_parse_connkeys(rdev, | 3783 | connkeys = nl80211_parse_connkeys(rdev, |
4284 | info->attrs[NL80211_ATTR_KEYS]); | 3784 | info->attrs[NL80211_ATTR_KEYS]); |
4285 | if (IS_ERR(connkeys)) { | 3785 | if (IS_ERR(connkeys)) |
4286 | err = PTR_ERR(connkeys); | 3786 | return PTR_ERR(connkeys); |
4287 | connkeys = NULL; | ||
4288 | goto out; | ||
4289 | } | ||
4290 | } | 3787 | } |
4291 | 3788 | ||
4292 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 3789 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
4293 | |||
4294 | out: | ||
4295 | cfg80211_unlock_rdev(rdev); | ||
4296 | dev_put(dev); | ||
4297 | unlock_rtnl: | ||
4298 | if (err) | 3790 | if (err) |
4299 | kfree(connkeys); | 3791 | kfree(connkeys); |
4300 | rtnl_unlock(); | ||
4301 | return err; | 3792 | return err; |
4302 | } | 3793 | } |
4303 | 3794 | ||
4304 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | 3795 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) |
4305 | { | 3796 | { |
4306 | struct cfg80211_registered_device *rdev; | 3797 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4307 | struct net_device *dev; | 3798 | struct net_device *dev = info->user_ptr[1]; |
4308 | int err; | ||
4309 | u16 reason; | 3799 | u16 reason; |
4310 | 3800 | ||
4311 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3801 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
@@ -4316,35 +3806,16 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | |||
4316 | if (reason == 0) | 3806 | if (reason == 0) |
4317 | return -EINVAL; | 3807 | return -EINVAL; |
4318 | 3808 | ||
4319 | rtnl_lock(); | 3809 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4320 | 3810 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) | |
4321 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 3811 | return -EOPNOTSUPP; |
4322 | if (err) | ||
4323 | goto unlock_rtnl; | ||
4324 | |||
4325 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
4326 | err = -EOPNOTSUPP; | ||
4327 | goto out; | ||
4328 | } | ||
4329 | |||
4330 | if (!netif_running(dev)) { | ||
4331 | err = -ENETDOWN; | ||
4332 | goto out; | ||
4333 | } | ||
4334 | |||
4335 | err = cfg80211_disconnect(rdev, dev, reason, true); | ||
4336 | 3812 | ||
4337 | out: | 3813 | return cfg80211_disconnect(rdev, dev, reason, true); |
4338 | cfg80211_unlock_rdev(rdev); | ||
4339 | dev_put(dev); | ||
4340 | unlock_rtnl: | ||
4341 | rtnl_unlock(); | ||
4342 | return err; | ||
4343 | } | 3814 | } |
4344 | 3815 | ||
4345 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | 3816 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) |
4346 | { | 3817 | { |
4347 | struct cfg80211_registered_device *rdev; | 3818 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4348 | struct net *net; | 3819 | struct net *net; |
4349 | int err; | 3820 | int err; |
4350 | u32 pid; | 3821 | u32 pid; |
@@ -4354,43 +3825,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | |||
4354 | 3825 | ||
4355 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); | 3826 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); |
4356 | 3827 | ||
4357 | rtnl_lock(); | ||
4358 | |||
4359 | rdev = cfg80211_get_dev_from_info(info); | ||
4360 | if (IS_ERR(rdev)) { | ||
4361 | err = PTR_ERR(rdev); | ||
4362 | goto out_rtnl; | ||
4363 | } | ||
4364 | |||
4365 | net = get_net_ns_by_pid(pid); | 3828 | net = get_net_ns_by_pid(pid); |
4366 | if (IS_ERR(net)) { | 3829 | if (IS_ERR(net)) |
4367 | err = PTR_ERR(net); | 3830 | return PTR_ERR(net); |
4368 | goto out; | ||
4369 | } | ||
4370 | 3831 | ||
4371 | err = 0; | 3832 | err = 0; |
4372 | 3833 | ||
4373 | /* check if anything to do */ | 3834 | /* check if anything to do */ |
4374 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | 3835 | if (!net_eq(wiphy_net(&rdev->wiphy), net)) |
4375 | goto out_put_net; | 3836 | err = cfg80211_switch_netns(rdev, net); |
4376 | 3837 | ||
4377 | err = cfg80211_switch_netns(rdev, net); | ||
4378 | out_put_net: | ||
4379 | put_net(net); | 3838 | put_net(net); |
4380 | out: | ||
4381 | cfg80211_unlock_rdev(rdev); | ||
4382 | out_rtnl: | ||
4383 | rtnl_unlock(); | ||
4384 | return err; | 3839 | return err; |
4385 | } | 3840 | } |
4386 | 3841 | ||
4387 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | 3842 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) |
4388 | { | 3843 | { |
4389 | struct cfg80211_registered_device *rdev; | 3844 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4390 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, | 3845 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, |
4391 | struct cfg80211_pmksa *pmksa) = NULL; | 3846 | struct cfg80211_pmksa *pmksa) = NULL; |
4392 | int err; | 3847 | struct net_device *dev = info->user_ptr[1]; |
4393 | struct net_device *dev; | ||
4394 | struct cfg80211_pmksa pmksa; | 3848 | struct cfg80211_pmksa pmksa; |
4395 | 3849 | ||
4396 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); | 3850 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); |
@@ -4401,19 +3855,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4401 | if (!info->attrs[NL80211_ATTR_PMKID]) | 3855 | if (!info->attrs[NL80211_ATTR_PMKID]) |
4402 | return -EINVAL; | 3856 | return -EINVAL; |
4403 | 3857 | ||
4404 | rtnl_lock(); | ||
4405 | |||
4406 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4407 | if (err) | ||
4408 | goto out_rtnl; | ||
4409 | |||
4410 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); | 3858 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); |
4411 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3859 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4412 | 3860 | ||
4413 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 3861 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4414 | err = -EOPNOTSUPP; | 3862 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4415 | goto out; | 3863 | return -EOPNOTSUPP; |
4416 | } | ||
4417 | 3864 | ||
4418 | switch (info->genlhdr->cmd) { | 3865 | switch (info->genlhdr->cmd) { |
4419 | case NL80211_CMD_SET_PMKSA: | 3866 | case NL80211_CMD_SET_PMKSA: |
@@ -4427,61 +3874,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4427 | break; | 3874 | break; |
4428 | } | 3875 | } |
4429 | 3876 | ||
4430 | if (!rdev_ops) { | 3877 | if (!rdev_ops) |
4431 | err = -EOPNOTSUPP; | 3878 | return -EOPNOTSUPP; |
4432 | goto out; | ||
4433 | } | ||
4434 | |||
4435 | err = rdev_ops(&rdev->wiphy, dev, &pmksa); | ||
4436 | |||
4437 | out: | ||
4438 | cfg80211_unlock_rdev(rdev); | ||
4439 | dev_put(dev); | ||
4440 | out_rtnl: | ||
4441 | rtnl_unlock(); | ||
4442 | 3879 | ||
4443 | return err; | 3880 | return rdev_ops(&rdev->wiphy, dev, &pmksa); |
4444 | } | 3881 | } |
4445 | 3882 | ||
4446 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | 3883 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) |
4447 | { | 3884 | { |
4448 | struct cfg80211_registered_device *rdev; | 3885 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4449 | int err; | 3886 | struct net_device *dev = info->user_ptr[1]; |
4450 | struct net_device *dev; | ||
4451 | |||
4452 | rtnl_lock(); | ||
4453 | |||
4454 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4455 | if (err) | ||
4456 | goto out_rtnl; | ||
4457 | |||
4458 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
4459 | err = -EOPNOTSUPP; | ||
4460 | goto out; | ||
4461 | } | ||
4462 | 3887 | ||
4463 | if (!rdev->ops->flush_pmksa) { | 3888 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4464 | err = -EOPNOTSUPP; | 3889 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4465 | goto out; | 3890 | return -EOPNOTSUPP; |
4466 | } | ||
4467 | |||
4468 | err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4469 | |||
4470 | out: | ||
4471 | cfg80211_unlock_rdev(rdev); | ||
4472 | dev_put(dev); | ||
4473 | out_rtnl: | ||
4474 | rtnl_unlock(); | ||
4475 | 3891 | ||
4476 | return err; | 3892 | if (!rdev->ops->flush_pmksa) |
3893 | return -EOPNOTSUPP; | ||
4477 | 3894 | ||
3895 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4478 | } | 3896 | } |
4479 | 3897 | ||
4480 | static int nl80211_remain_on_channel(struct sk_buff *skb, | 3898 | static int nl80211_remain_on_channel(struct sk_buff *skb, |
4481 | struct genl_info *info) | 3899 | struct genl_info *info) |
4482 | { | 3900 | { |
4483 | struct cfg80211_registered_device *rdev; | 3901 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4484 | struct net_device *dev; | 3902 | struct net_device *dev = info->user_ptr[1]; |
4485 | struct ieee80211_channel *chan; | 3903 | struct ieee80211_channel *chan; |
4486 | struct sk_buff *msg; | 3904 | struct sk_buff *msg; |
4487 | void *hdr; | 3905 | void *hdr; |
@@ -4503,21 +3921,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4503 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) | 3921 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) |
4504 | return -EINVAL; | 3922 | return -EINVAL; |
4505 | 3923 | ||
4506 | rtnl_lock(); | 3924 | if (!rdev->ops->remain_on_channel) |
4507 | 3925 | return -EOPNOTSUPP; | |
4508 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4509 | if (err) | ||
4510 | goto unlock_rtnl; | ||
4511 | |||
4512 | if (!rdev->ops->remain_on_channel) { | ||
4513 | err = -EOPNOTSUPP; | ||
4514 | goto out; | ||
4515 | } | ||
4516 | |||
4517 | if (!netif_running(dev)) { | ||
4518 | err = -ENETDOWN; | ||
4519 | goto out; | ||
4520 | } | ||
4521 | 3926 | ||
4522 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 3927 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4523 | channel_type = nla_get_u32( | 3928 | channel_type = nla_get_u32( |
@@ -4525,24 +3930,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4525 | if (channel_type != NL80211_CHAN_NO_HT && | 3930 | if (channel_type != NL80211_CHAN_NO_HT && |
4526 | channel_type != NL80211_CHAN_HT20 && | 3931 | channel_type != NL80211_CHAN_HT20 && |
4527 | channel_type != NL80211_CHAN_HT40PLUS && | 3932 | channel_type != NL80211_CHAN_HT40PLUS && |
4528 | channel_type != NL80211_CHAN_HT40MINUS) { | 3933 | channel_type != NL80211_CHAN_HT40MINUS) |
4529 | err = -EINVAL; | 3934 | return -EINVAL; |
4530 | goto out; | ||
4531 | } | ||
4532 | } | 3935 | } |
4533 | 3936 | ||
4534 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 3937 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4535 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 3938 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4536 | if (chan == NULL) { | 3939 | if (chan == NULL) |
4537 | err = -EINVAL; | 3940 | return -EINVAL; |
4538 | goto out; | ||
4539 | } | ||
4540 | 3941 | ||
4541 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 3942 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4542 | if (!msg) { | 3943 | if (!msg) |
4543 | err = -ENOMEM; | 3944 | return -ENOMEM; |
4544 | goto out; | ||
4545 | } | ||
4546 | 3945 | ||
4547 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 3946 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4548 | NL80211_CMD_REMAIN_ON_CHANNEL); | 3947 | NL80211_CMD_REMAIN_ON_CHANNEL); |
@@ -4561,58 +3960,32 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4561 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 3960 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); |
4562 | 3961 | ||
4563 | genlmsg_end(msg, hdr); | 3962 | genlmsg_end(msg, hdr); |
4564 | err = genlmsg_reply(msg, info); | 3963 | |
4565 | goto out; | 3964 | return genlmsg_reply(msg, info); |
4566 | 3965 | ||
4567 | nla_put_failure: | 3966 | nla_put_failure: |
4568 | err = -ENOBUFS; | 3967 | err = -ENOBUFS; |
4569 | free_msg: | 3968 | free_msg: |
4570 | nlmsg_free(msg); | 3969 | nlmsg_free(msg); |
4571 | out: | ||
4572 | cfg80211_unlock_rdev(rdev); | ||
4573 | dev_put(dev); | ||
4574 | unlock_rtnl: | ||
4575 | rtnl_unlock(); | ||
4576 | return err; | 3970 | return err; |
4577 | } | 3971 | } |
4578 | 3972 | ||
4579 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | 3973 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, |
4580 | struct genl_info *info) | 3974 | struct genl_info *info) |
4581 | { | 3975 | { |
4582 | struct cfg80211_registered_device *rdev; | 3976 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4583 | struct net_device *dev; | 3977 | struct net_device *dev = info->user_ptr[1]; |
4584 | u64 cookie; | 3978 | u64 cookie; |
4585 | int err; | ||
4586 | 3979 | ||
4587 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 3980 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
4588 | return -EINVAL; | 3981 | return -EINVAL; |
4589 | 3982 | ||
4590 | rtnl_lock(); | 3983 | if (!rdev->ops->cancel_remain_on_channel) |
4591 | 3984 | return -EOPNOTSUPP; | |
4592 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4593 | if (err) | ||
4594 | goto unlock_rtnl; | ||
4595 | |||
4596 | if (!rdev->ops->cancel_remain_on_channel) { | ||
4597 | err = -EOPNOTSUPP; | ||
4598 | goto out; | ||
4599 | } | ||
4600 | |||
4601 | if (!netif_running(dev)) { | ||
4602 | err = -ENETDOWN; | ||
4603 | goto out; | ||
4604 | } | ||
4605 | 3985 | ||
4606 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 3986 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
4607 | 3987 | ||
4608 | err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | 3988 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); |
4609 | |||
4610 | out: | ||
4611 | cfg80211_unlock_rdev(rdev); | ||
4612 | dev_put(dev); | ||
4613 | unlock_rtnl: | ||
4614 | rtnl_unlock(); | ||
4615 | return err; | ||
4616 | } | 3989 | } |
4617 | 3990 | ||
4618 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | 3991 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, |
@@ -4648,26 +4021,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4648 | struct genl_info *info) | 4021 | struct genl_info *info) |
4649 | { | 4022 | { |
4650 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | 4023 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; |
4651 | struct cfg80211_registered_device *rdev; | 4024 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4652 | struct cfg80211_bitrate_mask mask; | 4025 | struct cfg80211_bitrate_mask mask; |
4653 | int err, rem, i; | 4026 | int rem, i; |
4654 | struct net_device *dev; | 4027 | struct net_device *dev = info->user_ptr[1]; |
4655 | struct nlattr *tx_rates; | 4028 | struct nlattr *tx_rates; |
4656 | struct ieee80211_supported_band *sband; | 4029 | struct ieee80211_supported_band *sband; |
4657 | 4030 | ||
4658 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) | 4031 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) |
4659 | return -EINVAL; | 4032 | return -EINVAL; |
4660 | 4033 | ||
4661 | rtnl_lock(); | 4034 | if (!rdev->ops->set_bitrate_mask) |
4662 | 4035 | return -EOPNOTSUPP; | |
4663 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4664 | if (err) | ||
4665 | goto unlock_rtnl; | ||
4666 | |||
4667 | if (!rdev->ops->set_bitrate_mask) { | ||
4668 | err = -EOPNOTSUPP; | ||
4669 | goto unlock; | ||
4670 | } | ||
4671 | 4036 | ||
4672 | memset(&mask, 0, sizeof(mask)); | 4037 | memset(&mask, 0, sizeof(mask)); |
4673 | /* Default to all rates enabled */ | 4038 | /* Default to all rates enabled */ |
@@ -4684,15 +4049,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4684 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | 4049 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) |
4685 | { | 4050 | { |
4686 | enum ieee80211_band band = nla_type(tx_rates); | 4051 | enum ieee80211_band band = nla_type(tx_rates); |
4687 | if (band < 0 || band >= IEEE80211_NUM_BANDS) { | 4052 | if (band < 0 || band >= IEEE80211_NUM_BANDS) |
4688 | err = -EINVAL; | 4053 | return -EINVAL; |
4689 | goto unlock; | ||
4690 | } | ||
4691 | sband = rdev->wiphy.bands[band]; | 4054 | sband = rdev->wiphy.bands[band]; |
4692 | if (sband == NULL) { | 4055 | if (sband == NULL) |
4693 | err = -EINVAL; | 4056 | return -EINVAL; |
4694 | goto unlock; | ||
4695 | } | ||
4696 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | 4057 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), |
4697 | nla_len(tx_rates), nl80211_txattr_policy); | 4058 | nla_len(tx_rates), nl80211_txattr_policy); |
4698 | if (tb[NL80211_TXRATE_LEGACY]) { | 4059 | if (tb[NL80211_TXRATE_LEGACY]) { |
@@ -4700,68 +4061,48 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4700 | sband, | 4061 | sband, |
4701 | nla_data(tb[NL80211_TXRATE_LEGACY]), | 4062 | nla_data(tb[NL80211_TXRATE_LEGACY]), |
4702 | nla_len(tb[NL80211_TXRATE_LEGACY])); | 4063 | nla_len(tb[NL80211_TXRATE_LEGACY])); |
4703 | if (mask.control[band].legacy == 0) { | 4064 | if (mask.control[band].legacy == 0) |
4704 | err = -EINVAL; | 4065 | return -EINVAL; |
4705 | goto unlock; | ||
4706 | } | ||
4707 | } | 4066 | } |
4708 | } | 4067 | } |
4709 | 4068 | ||
4710 | err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); | 4069 | return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); |
4711 | |||
4712 | unlock: | ||
4713 | dev_put(dev); | ||
4714 | cfg80211_unlock_rdev(rdev); | ||
4715 | unlock_rtnl: | ||
4716 | rtnl_unlock(); | ||
4717 | return err; | ||
4718 | } | 4070 | } |
4719 | 4071 | ||
4720 | static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | 4072 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
4721 | { | 4073 | { |
4722 | struct cfg80211_registered_device *rdev; | 4074 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4723 | struct net_device *dev; | 4075 | struct net_device *dev = info->user_ptr[1]; |
4724 | int err; | 4076 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; |
4725 | 4077 | ||
4726 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 4078 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
4727 | return -EINVAL; | 4079 | return -EINVAL; |
4728 | 4080 | ||
4729 | if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1) | 4081 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
4730 | return -EINVAL; | 4082 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
4731 | |||
4732 | rtnl_lock(); | ||
4733 | |||
4734 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4735 | if (err) | ||
4736 | goto unlock_rtnl; | ||
4737 | 4083 | ||
4738 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 4084 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4739 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | 4085 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && |
4740 | err = -EOPNOTSUPP; | 4086 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4741 | goto out; | 4087 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4742 | } | 4088 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4089 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
4090 | return -EOPNOTSUPP; | ||
4743 | 4091 | ||
4744 | /* not much point in registering if we can't reply */ | 4092 | /* not much point in registering if we can't reply */ |
4745 | if (!rdev->ops->action) { | 4093 | if (!rdev->ops->mgmt_tx) |
4746 | err = -EOPNOTSUPP; | 4094 | return -EOPNOTSUPP; |
4747 | goto out; | ||
4748 | } | ||
4749 | 4095 | ||
4750 | err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid, | 4096 | return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, |
4097 | frame_type, | ||
4751 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 4098 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
4752 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 4099 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
4753 | out: | ||
4754 | cfg80211_unlock_rdev(rdev); | ||
4755 | dev_put(dev); | ||
4756 | unlock_rtnl: | ||
4757 | rtnl_unlock(); | ||
4758 | return err; | ||
4759 | } | 4100 | } |
4760 | 4101 | ||
4761 | static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | 4102 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
4762 | { | 4103 | { |
4763 | struct cfg80211_registered_device *rdev; | 4104 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4764 | struct net_device *dev; | 4105 | struct net_device *dev = info->user_ptr[1]; |
4765 | struct ieee80211_channel *chan; | 4106 | struct ieee80211_channel *chan; |
4766 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 4107 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
4767 | bool channel_type_valid = false; | 4108 | bool channel_type_valid = false; |
@@ -4775,27 +4116,16 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4775 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 4116 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
4776 | return -EINVAL; | 4117 | return -EINVAL; |
4777 | 4118 | ||
4778 | rtnl_lock(); | 4119 | if (!rdev->ops->mgmt_tx) |
4779 | 4120 | return -EOPNOTSUPP; | |
4780 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4781 | if (err) | ||
4782 | goto unlock_rtnl; | ||
4783 | |||
4784 | if (!rdev->ops->action) { | ||
4785 | err = -EOPNOTSUPP; | ||
4786 | goto out; | ||
4787 | } | ||
4788 | 4121 | ||
4789 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 4122 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4790 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | 4123 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && |
4791 | err = -EOPNOTSUPP; | 4124 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4792 | goto out; | 4125 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4793 | } | 4126 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4794 | 4127 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | |
4795 | if (!netif_running(dev)) { | 4128 | return -EOPNOTSUPP; |
4796 | err = -ENETDOWN; | ||
4797 | goto out; | ||
4798 | } | ||
4799 | 4129 | ||
4800 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 4130 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4801 | channel_type = nla_get_u32( | 4131 | channel_type = nla_get_u32( |
@@ -4803,147 +4133,104 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4803 | if (channel_type != NL80211_CHAN_NO_HT && | 4133 | if (channel_type != NL80211_CHAN_NO_HT && |
4804 | channel_type != NL80211_CHAN_HT20 && | 4134 | channel_type != NL80211_CHAN_HT20 && |
4805 | channel_type != NL80211_CHAN_HT40PLUS && | 4135 | channel_type != NL80211_CHAN_HT40PLUS && |
4806 | channel_type != NL80211_CHAN_HT40MINUS) { | 4136 | channel_type != NL80211_CHAN_HT40MINUS) |
4807 | err = -EINVAL; | 4137 | return -EINVAL; |
4808 | goto out; | ||
4809 | } | ||
4810 | channel_type_valid = true; | 4138 | channel_type_valid = true; |
4811 | } | 4139 | } |
4812 | 4140 | ||
4813 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 4141 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4814 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 4142 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4815 | if (chan == NULL) { | 4143 | if (chan == NULL) |
4816 | err = -EINVAL; | 4144 | return -EINVAL; |
4817 | goto out; | ||
4818 | } | ||
4819 | 4145 | ||
4820 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4146 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4821 | if (!msg) { | 4147 | if (!msg) |
4822 | err = -ENOMEM; | 4148 | return -ENOMEM; |
4823 | goto out; | ||
4824 | } | ||
4825 | 4149 | ||
4826 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4150 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4827 | NL80211_CMD_ACTION); | 4151 | NL80211_CMD_FRAME); |
4828 | 4152 | ||
4829 | if (IS_ERR(hdr)) { | 4153 | if (IS_ERR(hdr)) { |
4830 | err = PTR_ERR(hdr); | 4154 | err = PTR_ERR(hdr); |
4831 | goto free_msg; | 4155 | goto free_msg; |
4832 | } | 4156 | } |
4833 | err = cfg80211_mlme_action(rdev, dev, chan, channel_type, | 4157 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type, |
4834 | channel_type_valid, | 4158 | channel_type_valid, |
4835 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 4159 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
4836 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 4160 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
4837 | &cookie); | 4161 | &cookie); |
4838 | if (err) | 4162 | if (err) |
4839 | goto free_msg; | 4163 | goto free_msg; |
4840 | 4164 | ||
4841 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 4165 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); |
4842 | 4166 | ||
4843 | genlmsg_end(msg, hdr); | 4167 | genlmsg_end(msg, hdr); |
4844 | err = genlmsg_reply(msg, info); | 4168 | return genlmsg_reply(msg, info); |
4845 | goto out; | ||
4846 | 4169 | ||
4847 | nla_put_failure: | 4170 | nla_put_failure: |
4848 | err = -ENOBUFS; | 4171 | err = -ENOBUFS; |
4849 | free_msg: | 4172 | free_msg: |
4850 | nlmsg_free(msg); | 4173 | nlmsg_free(msg); |
4851 | out: | ||
4852 | cfg80211_unlock_rdev(rdev); | ||
4853 | dev_put(dev); | ||
4854 | unlock_rtnl: | ||
4855 | rtnl_unlock(); | ||
4856 | return err; | 4174 | return err; |
4857 | } | 4175 | } |
4858 | 4176 | ||
4859 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) | 4177 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) |
4860 | { | 4178 | { |
4861 | struct cfg80211_registered_device *rdev; | 4179 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4862 | struct wireless_dev *wdev; | 4180 | struct wireless_dev *wdev; |
4863 | struct net_device *dev; | 4181 | struct net_device *dev = info->user_ptr[1]; |
4864 | u8 ps_state; | 4182 | u8 ps_state; |
4865 | bool state; | 4183 | bool state; |
4866 | int err; | 4184 | int err; |
4867 | 4185 | ||
4868 | if (!info->attrs[NL80211_ATTR_PS_STATE]) { | 4186 | if (!info->attrs[NL80211_ATTR_PS_STATE]) |
4869 | err = -EINVAL; | 4187 | return -EINVAL; |
4870 | goto out; | ||
4871 | } | ||
4872 | 4188 | ||
4873 | ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); | 4189 | ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); |
4874 | 4190 | ||
4875 | if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) { | 4191 | if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) |
4876 | err = -EINVAL; | 4192 | return -EINVAL; |
4877 | goto out; | ||
4878 | } | ||
4879 | |||
4880 | rtnl_lock(); | ||
4881 | |||
4882 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4883 | if (err) | ||
4884 | goto unlock_rdev; | ||
4885 | 4193 | ||
4886 | wdev = dev->ieee80211_ptr; | 4194 | wdev = dev->ieee80211_ptr; |
4887 | 4195 | ||
4888 | if (!rdev->ops->set_power_mgmt) { | 4196 | if (!rdev->ops->set_power_mgmt) |
4889 | err = -EOPNOTSUPP; | 4197 | return -EOPNOTSUPP; |
4890 | goto unlock_rdev; | ||
4891 | } | ||
4892 | 4198 | ||
4893 | state = (ps_state == NL80211_PS_ENABLED) ? true : false; | 4199 | state = (ps_state == NL80211_PS_ENABLED) ? true : false; |
4894 | 4200 | ||
4895 | if (state == wdev->ps) | 4201 | if (state == wdev->ps) |
4896 | goto unlock_rdev; | 4202 | return 0; |
4897 | |||
4898 | wdev->ps = state; | ||
4899 | |||
4900 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps, | ||
4901 | wdev->ps_timeout)) | ||
4902 | /* assume this means it's off */ | ||
4903 | wdev->ps = false; | ||
4904 | |||
4905 | unlock_rdev: | ||
4906 | cfg80211_unlock_rdev(rdev); | ||
4907 | dev_put(dev); | ||
4908 | rtnl_unlock(); | ||
4909 | 4203 | ||
4910 | out: | 4204 | err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state, |
4205 | wdev->ps_timeout); | ||
4206 | if (!err) | ||
4207 | wdev->ps = state; | ||
4911 | return err; | 4208 | return err; |
4912 | } | 4209 | } |
4913 | 4210 | ||
4914 | static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | 4211 | static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) |
4915 | { | 4212 | { |
4916 | struct cfg80211_registered_device *rdev; | 4213 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4917 | enum nl80211_ps_state ps_state; | 4214 | enum nl80211_ps_state ps_state; |
4918 | struct wireless_dev *wdev; | 4215 | struct wireless_dev *wdev; |
4919 | struct net_device *dev; | 4216 | struct net_device *dev = info->user_ptr[1]; |
4920 | struct sk_buff *msg; | 4217 | struct sk_buff *msg; |
4921 | void *hdr; | 4218 | void *hdr; |
4922 | int err; | 4219 | int err; |
4923 | 4220 | ||
4924 | rtnl_lock(); | ||
4925 | |||
4926 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4927 | if (err) | ||
4928 | goto unlock_rtnl; | ||
4929 | |||
4930 | wdev = dev->ieee80211_ptr; | 4221 | wdev = dev->ieee80211_ptr; |
4931 | 4222 | ||
4932 | if (!rdev->ops->set_power_mgmt) { | 4223 | if (!rdev->ops->set_power_mgmt) |
4933 | err = -EOPNOTSUPP; | 4224 | return -EOPNOTSUPP; |
4934 | goto out; | ||
4935 | } | ||
4936 | 4225 | ||
4937 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4226 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4938 | if (!msg) { | 4227 | if (!msg) |
4939 | err = -ENOMEM; | 4228 | return -ENOMEM; |
4940 | goto out; | ||
4941 | } | ||
4942 | 4229 | ||
4943 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4230 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4944 | NL80211_CMD_GET_POWER_SAVE); | 4231 | NL80211_CMD_GET_POWER_SAVE); |
4945 | if (!hdr) { | 4232 | if (!hdr) { |
4946 | err = -ENOMEM; | 4233 | err = -ENOBUFS; |
4947 | goto free_msg; | 4234 | goto free_msg; |
4948 | } | 4235 | } |
4949 | 4236 | ||
@@ -4955,22 +4242,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | |||
4955 | NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); | 4242 | NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); |
4956 | 4243 | ||
4957 | genlmsg_end(msg, hdr); | 4244 | genlmsg_end(msg, hdr); |
4958 | err = genlmsg_reply(msg, info); | 4245 | return genlmsg_reply(msg, info); |
4959 | goto out; | ||
4960 | 4246 | ||
4961 | nla_put_failure: | 4247 | nla_put_failure: |
4962 | err = -ENOBUFS; | 4248 | err = -ENOBUFS; |
4963 | 4249 | free_msg: | |
4964 | free_msg: | ||
4965 | nlmsg_free(msg); | 4250 | nlmsg_free(msg); |
4966 | |||
4967 | out: | ||
4968 | cfg80211_unlock_rdev(rdev); | ||
4969 | dev_put(dev); | ||
4970 | |||
4971 | unlock_rtnl: | ||
4972 | rtnl_unlock(); | ||
4973 | |||
4974 | return err; | 4251 | return err; |
4975 | } | 4252 | } |
4976 | 4253 | ||
@@ -4984,41 +4261,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
4984 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 4261 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
4985 | s32 threshold, u32 hysteresis) | 4262 | s32 threshold, u32 hysteresis) |
4986 | { | 4263 | { |
4987 | struct cfg80211_registered_device *rdev; | 4264 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4988 | struct wireless_dev *wdev; | 4265 | struct wireless_dev *wdev; |
4989 | struct net_device *dev; | 4266 | struct net_device *dev = info->user_ptr[1]; |
4990 | int err; | ||
4991 | 4267 | ||
4992 | if (threshold > 0) | 4268 | if (threshold > 0) |
4993 | return -EINVAL; | 4269 | return -EINVAL; |
4994 | 4270 | ||
4995 | rtnl_lock(); | ||
4996 | |||
4997 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4998 | if (err) | ||
4999 | goto unlock_rdev; | ||
5000 | |||
5001 | wdev = dev->ieee80211_ptr; | 4271 | wdev = dev->ieee80211_ptr; |
5002 | 4272 | ||
5003 | if (!rdev->ops->set_cqm_rssi_config) { | 4273 | if (!rdev->ops->set_cqm_rssi_config) |
5004 | err = -EOPNOTSUPP; | 4274 | return -EOPNOTSUPP; |
5005 | goto unlock_rdev; | ||
5006 | } | ||
5007 | |||
5008 | if (wdev->iftype != NL80211_IFTYPE_STATION) { | ||
5009 | err = -EOPNOTSUPP; | ||
5010 | goto unlock_rdev; | ||
5011 | } | ||
5012 | |||
5013 | err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, | ||
5014 | threshold, hysteresis); | ||
5015 | 4275 | ||
5016 | unlock_rdev: | 4276 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
5017 | cfg80211_unlock_rdev(rdev); | 4277 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) |
5018 | dev_put(dev); | 4278 | return -EOPNOTSUPP; |
5019 | rtnl_unlock(); | ||
5020 | 4279 | ||
5021 | return err; | 4280 | return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, |
4281 | threshold, hysteresis); | ||
5022 | } | 4282 | } |
5023 | 4283 | ||
5024 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | 4284 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) |
@@ -5052,6 +4312,63 @@ out: | |||
5052 | return err; | 4312 | return err; |
5053 | } | 4313 | } |
5054 | 4314 | ||
4315 | #define NL80211_FLAG_NEED_WIPHY 0x01 | ||
4316 | #define NL80211_FLAG_NEED_NETDEV 0x02 | ||
4317 | #define NL80211_FLAG_NEED_RTNL 0x04 | ||
4318 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 | ||
4319 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ | ||
4320 | NL80211_FLAG_CHECK_NETDEV_UP) | ||
4321 | |||
4322 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
4323 | struct genl_info *info) | ||
4324 | { | ||
4325 | struct cfg80211_registered_device *rdev; | ||
4326 | struct net_device *dev; | ||
4327 | int err; | ||
4328 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | ||
4329 | |||
4330 | if (rtnl) | ||
4331 | rtnl_lock(); | ||
4332 | |||
4333 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { | ||
4334 | rdev = cfg80211_get_dev_from_info(info); | ||
4335 | if (IS_ERR(rdev)) { | ||
4336 | if (rtnl) | ||
4337 | rtnl_unlock(); | ||
4338 | return PTR_ERR(rdev); | ||
4339 | } | ||
4340 | info->user_ptr[0] = rdev; | ||
4341 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | ||
4342 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4343 | if (err) { | ||
4344 | if (rtnl) | ||
4345 | rtnl_unlock(); | ||
4346 | return err; | ||
4347 | } | ||
4348 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | ||
4349 | !netif_running(dev)) { | ||
4350 | if (rtnl) | ||
4351 | rtnl_unlock(); | ||
4352 | return -ENETDOWN; | ||
4353 | } | ||
4354 | info->user_ptr[0] = rdev; | ||
4355 | info->user_ptr[1] = dev; | ||
4356 | } | ||
4357 | |||
4358 | return 0; | ||
4359 | } | ||
4360 | |||
4361 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
4362 | struct genl_info *info) | ||
4363 | { | ||
4364 | if (info->user_ptr[0]) | ||
4365 | cfg80211_unlock_rdev(info->user_ptr[0]); | ||
4366 | if (info->user_ptr[1]) | ||
4367 | dev_put(info->user_ptr[1]); | ||
4368 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) | ||
4369 | rtnl_unlock(); | ||
4370 | } | ||
4371 | |||
5055 | static struct genl_ops nl80211_ops[] = { | 4372 | static struct genl_ops nl80211_ops[] = { |
5056 | { | 4373 | { |
5057 | .cmd = NL80211_CMD_GET_WIPHY, | 4374 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -5059,12 +4376,14 @@ static struct genl_ops nl80211_ops[] = { | |||
5059 | .dumpit = nl80211_dump_wiphy, | 4376 | .dumpit = nl80211_dump_wiphy, |
5060 | .policy = nl80211_policy, | 4377 | .policy = nl80211_policy, |
5061 | /* can be retrieved by unprivileged users */ | 4378 | /* can be retrieved by unprivileged users */ |
4379 | .internal_flags = NL80211_FLAG_NEED_WIPHY, | ||
5062 | }, | 4380 | }, |
5063 | { | 4381 | { |
5064 | .cmd = NL80211_CMD_SET_WIPHY, | 4382 | .cmd = NL80211_CMD_SET_WIPHY, |
5065 | .doit = nl80211_set_wiphy, | 4383 | .doit = nl80211_set_wiphy, |
5066 | .policy = nl80211_policy, | 4384 | .policy = nl80211_policy, |
5067 | .flags = GENL_ADMIN_PERM, | 4385 | .flags = GENL_ADMIN_PERM, |
4386 | .internal_flags = NL80211_FLAG_NEED_RTNL, | ||
5068 | }, | 4387 | }, |
5069 | { | 4388 | { |
5070 | .cmd = NL80211_CMD_GET_INTERFACE, | 4389 | .cmd = NL80211_CMD_GET_INTERFACE, |
@@ -5072,90 +4391,119 @@ static struct genl_ops nl80211_ops[] = { | |||
5072 | .dumpit = nl80211_dump_interface, | 4391 | .dumpit = nl80211_dump_interface, |
5073 | .policy = nl80211_policy, | 4392 | .policy = nl80211_policy, |
5074 | /* can be retrieved by unprivileged users */ | 4393 | /* can be retrieved by unprivileged users */ |
4394 | .internal_flags = NL80211_FLAG_NEED_NETDEV, | ||
5075 | }, | 4395 | }, |
5076 | { | 4396 | { |
5077 | .cmd = NL80211_CMD_SET_INTERFACE, | 4397 | .cmd = NL80211_CMD_SET_INTERFACE, |
5078 | .doit = nl80211_set_interface, | 4398 | .doit = nl80211_set_interface, |
5079 | .policy = nl80211_policy, | 4399 | .policy = nl80211_policy, |
5080 | .flags = GENL_ADMIN_PERM, | 4400 | .flags = GENL_ADMIN_PERM, |
4401 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4402 | NL80211_FLAG_NEED_RTNL, | ||
5081 | }, | 4403 | }, |
5082 | { | 4404 | { |
5083 | .cmd = NL80211_CMD_NEW_INTERFACE, | 4405 | .cmd = NL80211_CMD_NEW_INTERFACE, |
5084 | .doit = nl80211_new_interface, | 4406 | .doit = nl80211_new_interface, |
5085 | .policy = nl80211_policy, | 4407 | .policy = nl80211_policy, |
5086 | .flags = GENL_ADMIN_PERM, | 4408 | .flags = GENL_ADMIN_PERM, |
4409 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4410 | NL80211_FLAG_NEED_RTNL, | ||
5087 | }, | 4411 | }, |
5088 | { | 4412 | { |
5089 | .cmd = NL80211_CMD_DEL_INTERFACE, | 4413 | .cmd = NL80211_CMD_DEL_INTERFACE, |
5090 | .doit = nl80211_del_interface, | 4414 | .doit = nl80211_del_interface, |
5091 | .policy = nl80211_policy, | 4415 | .policy = nl80211_policy, |
5092 | .flags = GENL_ADMIN_PERM, | 4416 | .flags = GENL_ADMIN_PERM, |
4417 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4418 | NL80211_FLAG_NEED_RTNL, | ||
5093 | }, | 4419 | }, |
5094 | { | 4420 | { |
5095 | .cmd = NL80211_CMD_GET_KEY, | 4421 | .cmd = NL80211_CMD_GET_KEY, |
5096 | .doit = nl80211_get_key, | 4422 | .doit = nl80211_get_key, |
5097 | .policy = nl80211_policy, | 4423 | .policy = nl80211_policy, |
5098 | .flags = GENL_ADMIN_PERM, | 4424 | .flags = GENL_ADMIN_PERM, |
4425 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4426 | NL80211_FLAG_NEED_RTNL, | ||
5099 | }, | 4427 | }, |
5100 | { | 4428 | { |
5101 | .cmd = NL80211_CMD_SET_KEY, | 4429 | .cmd = NL80211_CMD_SET_KEY, |
5102 | .doit = nl80211_set_key, | 4430 | .doit = nl80211_set_key, |
5103 | .policy = nl80211_policy, | 4431 | .policy = nl80211_policy, |
5104 | .flags = GENL_ADMIN_PERM, | 4432 | .flags = GENL_ADMIN_PERM, |
4433 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4434 | NL80211_FLAG_NEED_RTNL, | ||
5105 | }, | 4435 | }, |
5106 | { | 4436 | { |
5107 | .cmd = NL80211_CMD_NEW_KEY, | 4437 | .cmd = NL80211_CMD_NEW_KEY, |
5108 | .doit = nl80211_new_key, | 4438 | .doit = nl80211_new_key, |
5109 | .policy = nl80211_policy, | 4439 | .policy = nl80211_policy, |
5110 | .flags = GENL_ADMIN_PERM, | 4440 | .flags = GENL_ADMIN_PERM, |
4441 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4442 | NL80211_FLAG_NEED_RTNL, | ||
5111 | }, | 4443 | }, |
5112 | { | 4444 | { |
5113 | .cmd = NL80211_CMD_DEL_KEY, | 4445 | .cmd = NL80211_CMD_DEL_KEY, |
5114 | .doit = nl80211_del_key, | 4446 | .doit = nl80211_del_key, |
5115 | .policy = nl80211_policy, | 4447 | .policy = nl80211_policy, |
5116 | .flags = GENL_ADMIN_PERM, | 4448 | .flags = GENL_ADMIN_PERM, |
4449 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4450 | NL80211_FLAG_NEED_RTNL, | ||
5117 | }, | 4451 | }, |
5118 | { | 4452 | { |
5119 | .cmd = NL80211_CMD_SET_BEACON, | 4453 | .cmd = NL80211_CMD_SET_BEACON, |
5120 | .policy = nl80211_policy, | 4454 | .policy = nl80211_policy, |
5121 | .flags = GENL_ADMIN_PERM, | 4455 | .flags = GENL_ADMIN_PERM, |
5122 | .doit = nl80211_addset_beacon, | 4456 | .doit = nl80211_addset_beacon, |
4457 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4458 | NL80211_FLAG_NEED_RTNL, | ||
5123 | }, | 4459 | }, |
5124 | { | 4460 | { |
5125 | .cmd = NL80211_CMD_NEW_BEACON, | 4461 | .cmd = NL80211_CMD_NEW_BEACON, |
5126 | .policy = nl80211_policy, | 4462 | .policy = nl80211_policy, |
5127 | .flags = GENL_ADMIN_PERM, | 4463 | .flags = GENL_ADMIN_PERM, |
5128 | .doit = nl80211_addset_beacon, | 4464 | .doit = nl80211_addset_beacon, |
4465 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4466 | NL80211_FLAG_NEED_RTNL, | ||
5129 | }, | 4467 | }, |
5130 | { | 4468 | { |
5131 | .cmd = NL80211_CMD_DEL_BEACON, | 4469 | .cmd = NL80211_CMD_DEL_BEACON, |
5132 | .policy = nl80211_policy, | 4470 | .policy = nl80211_policy, |
5133 | .flags = GENL_ADMIN_PERM, | 4471 | .flags = GENL_ADMIN_PERM, |
5134 | .doit = nl80211_del_beacon, | 4472 | .doit = nl80211_del_beacon, |
4473 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4474 | NL80211_FLAG_NEED_RTNL, | ||
5135 | }, | 4475 | }, |
5136 | { | 4476 | { |
5137 | .cmd = NL80211_CMD_GET_STATION, | 4477 | .cmd = NL80211_CMD_GET_STATION, |
5138 | .doit = nl80211_get_station, | 4478 | .doit = nl80211_get_station, |
5139 | .dumpit = nl80211_dump_station, | 4479 | .dumpit = nl80211_dump_station, |
5140 | .policy = nl80211_policy, | 4480 | .policy = nl80211_policy, |
4481 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4482 | NL80211_FLAG_NEED_RTNL, | ||
5141 | }, | 4483 | }, |
5142 | { | 4484 | { |
5143 | .cmd = NL80211_CMD_SET_STATION, | 4485 | .cmd = NL80211_CMD_SET_STATION, |
5144 | .doit = nl80211_set_station, | 4486 | .doit = nl80211_set_station, |
5145 | .policy = nl80211_policy, | 4487 | .policy = nl80211_policy, |
5146 | .flags = GENL_ADMIN_PERM, | 4488 | .flags = GENL_ADMIN_PERM, |
4489 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4490 | NL80211_FLAG_NEED_RTNL, | ||
5147 | }, | 4491 | }, |
5148 | { | 4492 | { |
5149 | .cmd = NL80211_CMD_NEW_STATION, | 4493 | .cmd = NL80211_CMD_NEW_STATION, |
5150 | .doit = nl80211_new_station, | 4494 | .doit = nl80211_new_station, |
5151 | .policy = nl80211_policy, | 4495 | .policy = nl80211_policy, |
5152 | .flags = GENL_ADMIN_PERM, | 4496 | .flags = GENL_ADMIN_PERM, |
4497 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4498 | NL80211_FLAG_NEED_RTNL, | ||
5153 | }, | 4499 | }, |
5154 | { | 4500 | { |
5155 | .cmd = NL80211_CMD_DEL_STATION, | 4501 | .cmd = NL80211_CMD_DEL_STATION, |
5156 | .doit = nl80211_del_station, | 4502 | .doit = nl80211_del_station, |
5157 | .policy = nl80211_policy, | 4503 | .policy = nl80211_policy, |
5158 | .flags = GENL_ADMIN_PERM, | 4504 | .flags = GENL_ADMIN_PERM, |
4505 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4506 | NL80211_FLAG_NEED_RTNL, | ||
5159 | }, | 4507 | }, |
5160 | { | 4508 | { |
5161 | .cmd = NL80211_CMD_GET_MPATH, | 4509 | .cmd = NL80211_CMD_GET_MPATH, |
@@ -5163,30 +4511,40 @@ static struct genl_ops nl80211_ops[] = { | |||
5163 | .dumpit = nl80211_dump_mpath, | 4511 | .dumpit = nl80211_dump_mpath, |
5164 | .policy = nl80211_policy, | 4512 | .policy = nl80211_policy, |
5165 | .flags = GENL_ADMIN_PERM, | 4513 | .flags = GENL_ADMIN_PERM, |
4514 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4515 | NL80211_FLAG_NEED_RTNL, | ||
5166 | }, | 4516 | }, |
5167 | { | 4517 | { |
5168 | .cmd = NL80211_CMD_SET_MPATH, | 4518 | .cmd = NL80211_CMD_SET_MPATH, |
5169 | .doit = nl80211_set_mpath, | 4519 | .doit = nl80211_set_mpath, |
5170 | .policy = nl80211_policy, | 4520 | .policy = nl80211_policy, |
5171 | .flags = GENL_ADMIN_PERM, | 4521 | .flags = GENL_ADMIN_PERM, |
4522 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4523 | NL80211_FLAG_NEED_RTNL, | ||
5172 | }, | 4524 | }, |
5173 | { | 4525 | { |
5174 | .cmd = NL80211_CMD_NEW_MPATH, | 4526 | .cmd = NL80211_CMD_NEW_MPATH, |
5175 | .doit = nl80211_new_mpath, | 4527 | .doit = nl80211_new_mpath, |
5176 | .policy = nl80211_policy, | 4528 | .policy = nl80211_policy, |
5177 | .flags = GENL_ADMIN_PERM, | 4529 | .flags = GENL_ADMIN_PERM, |
4530 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4531 | NL80211_FLAG_NEED_RTNL, | ||
5178 | }, | 4532 | }, |
5179 | { | 4533 | { |
5180 | .cmd = NL80211_CMD_DEL_MPATH, | 4534 | .cmd = NL80211_CMD_DEL_MPATH, |
5181 | .doit = nl80211_del_mpath, | 4535 | .doit = nl80211_del_mpath, |
5182 | .policy = nl80211_policy, | 4536 | .policy = nl80211_policy, |
5183 | .flags = GENL_ADMIN_PERM, | 4537 | .flags = GENL_ADMIN_PERM, |
4538 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4539 | NL80211_FLAG_NEED_RTNL, | ||
5184 | }, | 4540 | }, |
5185 | { | 4541 | { |
5186 | .cmd = NL80211_CMD_SET_BSS, | 4542 | .cmd = NL80211_CMD_SET_BSS, |
5187 | .doit = nl80211_set_bss, | 4543 | .doit = nl80211_set_bss, |
5188 | .policy = nl80211_policy, | 4544 | .policy = nl80211_policy, |
5189 | .flags = GENL_ADMIN_PERM, | 4545 | .flags = GENL_ADMIN_PERM, |
4546 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4547 | NL80211_FLAG_NEED_RTNL, | ||
5190 | }, | 4548 | }, |
5191 | { | 4549 | { |
5192 | .cmd = NL80211_CMD_GET_REG, | 4550 | .cmd = NL80211_CMD_GET_REG, |
@@ -5211,18 +4569,24 @@ static struct genl_ops nl80211_ops[] = { | |||
5211 | .doit = nl80211_get_mesh_params, | 4569 | .doit = nl80211_get_mesh_params, |
5212 | .policy = nl80211_policy, | 4570 | .policy = nl80211_policy, |
5213 | /* can be retrieved by unprivileged users */ | 4571 | /* can be retrieved by unprivileged users */ |
4572 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4573 | NL80211_FLAG_NEED_RTNL, | ||
5214 | }, | 4574 | }, |
5215 | { | 4575 | { |
5216 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 4576 | .cmd = NL80211_CMD_SET_MESH_PARAMS, |
5217 | .doit = nl80211_set_mesh_params, | 4577 | .doit = nl80211_set_mesh_params, |
5218 | .policy = nl80211_policy, | 4578 | .policy = nl80211_policy, |
5219 | .flags = GENL_ADMIN_PERM, | 4579 | .flags = GENL_ADMIN_PERM, |
4580 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4581 | NL80211_FLAG_NEED_RTNL, | ||
5220 | }, | 4582 | }, |
5221 | { | 4583 | { |
5222 | .cmd = NL80211_CMD_TRIGGER_SCAN, | 4584 | .cmd = NL80211_CMD_TRIGGER_SCAN, |
5223 | .doit = nl80211_trigger_scan, | 4585 | .doit = nl80211_trigger_scan, |
5224 | .policy = nl80211_policy, | 4586 | .policy = nl80211_policy, |
5225 | .flags = GENL_ADMIN_PERM, | 4587 | .flags = GENL_ADMIN_PERM, |
4588 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4589 | NL80211_FLAG_NEED_RTNL, | ||
5226 | }, | 4590 | }, |
5227 | { | 4591 | { |
5228 | .cmd = NL80211_CMD_GET_SCAN, | 4592 | .cmd = NL80211_CMD_GET_SCAN, |
@@ -5234,36 +4598,48 @@ static struct genl_ops nl80211_ops[] = { | |||
5234 | .doit = nl80211_authenticate, | 4598 | .doit = nl80211_authenticate, |
5235 | .policy = nl80211_policy, | 4599 | .policy = nl80211_policy, |
5236 | .flags = GENL_ADMIN_PERM, | 4600 | .flags = GENL_ADMIN_PERM, |
4601 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4602 | NL80211_FLAG_NEED_RTNL, | ||
5237 | }, | 4603 | }, |
5238 | { | 4604 | { |
5239 | .cmd = NL80211_CMD_ASSOCIATE, | 4605 | .cmd = NL80211_CMD_ASSOCIATE, |
5240 | .doit = nl80211_associate, | 4606 | .doit = nl80211_associate, |
5241 | .policy = nl80211_policy, | 4607 | .policy = nl80211_policy, |
5242 | .flags = GENL_ADMIN_PERM, | 4608 | .flags = GENL_ADMIN_PERM, |
4609 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4610 | NL80211_FLAG_NEED_RTNL, | ||
5243 | }, | 4611 | }, |
5244 | { | 4612 | { |
5245 | .cmd = NL80211_CMD_DEAUTHENTICATE, | 4613 | .cmd = NL80211_CMD_DEAUTHENTICATE, |
5246 | .doit = nl80211_deauthenticate, | 4614 | .doit = nl80211_deauthenticate, |
5247 | .policy = nl80211_policy, | 4615 | .policy = nl80211_policy, |
5248 | .flags = GENL_ADMIN_PERM, | 4616 | .flags = GENL_ADMIN_PERM, |
4617 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4618 | NL80211_FLAG_NEED_RTNL, | ||
5249 | }, | 4619 | }, |
5250 | { | 4620 | { |
5251 | .cmd = NL80211_CMD_DISASSOCIATE, | 4621 | .cmd = NL80211_CMD_DISASSOCIATE, |
5252 | .doit = nl80211_disassociate, | 4622 | .doit = nl80211_disassociate, |
5253 | .policy = nl80211_policy, | 4623 | .policy = nl80211_policy, |
5254 | .flags = GENL_ADMIN_PERM, | 4624 | .flags = GENL_ADMIN_PERM, |
4625 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4626 | NL80211_FLAG_NEED_RTNL, | ||
5255 | }, | 4627 | }, |
5256 | { | 4628 | { |
5257 | .cmd = NL80211_CMD_JOIN_IBSS, | 4629 | .cmd = NL80211_CMD_JOIN_IBSS, |
5258 | .doit = nl80211_join_ibss, | 4630 | .doit = nl80211_join_ibss, |
5259 | .policy = nl80211_policy, | 4631 | .policy = nl80211_policy, |
5260 | .flags = GENL_ADMIN_PERM, | 4632 | .flags = GENL_ADMIN_PERM, |
4633 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4634 | NL80211_FLAG_NEED_RTNL, | ||
5261 | }, | 4635 | }, |
5262 | { | 4636 | { |
5263 | .cmd = NL80211_CMD_LEAVE_IBSS, | 4637 | .cmd = NL80211_CMD_LEAVE_IBSS, |
5264 | .doit = nl80211_leave_ibss, | 4638 | .doit = nl80211_leave_ibss, |
5265 | .policy = nl80211_policy, | 4639 | .policy = nl80211_policy, |
5266 | .flags = GENL_ADMIN_PERM, | 4640 | .flags = GENL_ADMIN_PERM, |
4641 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4642 | NL80211_FLAG_NEED_RTNL, | ||
5267 | }, | 4643 | }, |
5268 | #ifdef CONFIG_NL80211_TESTMODE | 4644 | #ifdef CONFIG_NL80211_TESTMODE |
5269 | { | 4645 | { |
@@ -5271,6 +4647,8 @@ static struct genl_ops nl80211_ops[] = { | |||
5271 | .doit = nl80211_testmode_do, | 4647 | .doit = nl80211_testmode_do, |
5272 | .policy = nl80211_policy, | 4648 | .policy = nl80211_policy, |
5273 | .flags = GENL_ADMIN_PERM, | 4649 | .flags = GENL_ADMIN_PERM, |
4650 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4651 | NL80211_FLAG_NEED_RTNL, | ||
5274 | }, | 4652 | }, |
5275 | #endif | 4653 | #endif |
5276 | { | 4654 | { |
@@ -5278,18 +4656,24 @@ static struct genl_ops nl80211_ops[] = { | |||
5278 | .doit = nl80211_connect, | 4656 | .doit = nl80211_connect, |
5279 | .policy = nl80211_policy, | 4657 | .policy = nl80211_policy, |
5280 | .flags = GENL_ADMIN_PERM, | 4658 | .flags = GENL_ADMIN_PERM, |
4659 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4660 | NL80211_FLAG_NEED_RTNL, | ||
5281 | }, | 4661 | }, |
5282 | { | 4662 | { |
5283 | .cmd = NL80211_CMD_DISCONNECT, | 4663 | .cmd = NL80211_CMD_DISCONNECT, |
5284 | .doit = nl80211_disconnect, | 4664 | .doit = nl80211_disconnect, |
5285 | .policy = nl80211_policy, | 4665 | .policy = nl80211_policy, |
5286 | .flags = GENL_ADMIN_PERM, | 4666 | .flags = GENL_ADMIN_PERM, |
4667 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4668 | NL80211_FLAG_NEED_RTNL, | ||
5287 | }, | 4669 | }, |
5288 | { | 4670 | { |
5289 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, | 4671 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, |
5290 | .doit = nl80211_wiphy_netns, | 4672 | .doit = nl80211_wiphy_netns, |
5291 | .policy = nl80211_policy, | 4673 | .policy = nl80211_policy, |
5292 | .flags = GENL_ADMIN_PERM, | 4674 | .flags = GENL_ADMIN_PERM, |
4675 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4676 | NL80211_FLAG_NEED_RTNL, | ||
5293 | }, | 4677 | }, |
5294 | { | 4678 | { |
5295 | .cmd = NL80211_CMD_GET_SURVEY, | 4679 | .cmd = NL80211_CMD_GET_SURVEY, |
@@ -5301,72 +4685,102 @@ static struct genl_ops nl80211_ops[] = { | |||
5301 | .doit = nl80211_setdel_pmksa, | 4685 | .doit = nl80211_setdel_pmksa, |
5302 | .policy = nl80211_policy, | 4686 | .policy = nl80211_policy, |
5303 | .flags = GENL_ADMIN_PERM, | 4687 | .flags = GENL_ADMIN_PERM, |
4688 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4689 | NL80211_FLAG_NEED_RTNL, | ||
5304 | }, | 4690 | }, |
5305 | { | 4691 | { |
5306 | .cmd = NL80211_CMD_DEL_PMKSA, | 4692 | .cmd = NL80211_CMD_DEL_PMKSA, |
5307 | .doit = nl80211_setdel_pmksa, | 4693 | .doit = nl80211_setdel_pmksa, |
5308 | .policy = nl80211_policy, | 4694 | .policy = nl80211_policy, |
5309 | .flags = GENL_ADMIN_PERM, | 4695 | .flags = GENL_ADMIN_PERM, |
4696 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4697 | NL80211_FLAG_NEED_RTNL, | ||
5310 | }, | 4698 | }, |
5311 | { | 4699 | { |
5312 | .cmd = NL80211_CMD_FLUSH_PMKSA, | 4700 | .cmd = NL80211_CMD_FLUSH_PMKSA, |
5313 | .doit = nl80211_flush_pmksa, | 4701 | .doit = nl80211_flush_pmksa, |
5314 | .policy = nl80211_policy, | 4702 | .policy = nl80211_policy, |
5315 | .flags = GENL_ADMIN_PERM, | 4703 | .flags = GENL_ADMIN_PERM, |
4704 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4705 | NL80211_FLAG_NEED_RTNL, | ||
5316 | }, | 4706 | }, |
5317 | { | 4707 | { |
5318 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, | 4708 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, |
5319 | .doit = nl80211_remain_on_channel, | 4709 | .doit = nl80211_remain_on_channel, |
5320 | .policy = nl80211_policy, | 4710 | .policy = nl80211_policy, |
5321 | .flags = GENL_ADMIN_PERM, | 4711 | .flags = GENL_ADMIN_PERM, |
4712 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4713 | NL80211_FLAG_NEED_RTNL, | ||
5322 | }, | 4714 | }, |
5323 | { | 4715 | { |
5324 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 4716 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
5325 | .doit = nl80211_cancel_remain_on_channel, | 4717 | .doit = nl80211_cancel_remain_on_channel, |
5326 | .policy = nl80211_policy, | 4718 | .policy = nl80211_policy, |
5327 | .flags = GENL_ADMIN_PERM, | 4719 | .flags = GENL_ADMIN_PERM, |
4720 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4721 | NL80211_FLAG_NEED_RTNL, | ||
5328 | }, | 4722 | }, |
5329 | { | 4723 | { |
5330 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, | 4724 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, |
5331 | .doit = nl80211_set_tx_bitrate_mask, | 4725 | .doit = nl80211_set_tx_bitrate_mask, |
5332 | .policy = nl80211_policy, | 4726 | .policy = nl80211_policy, |
5333 | .flags = GENL_ADMIN_PERM, | 4727 | .flags = GENL_ADMIN_PERM, |
4728 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4729 | NL80211_FLAG_NEED_RTNL, | ||
5334 | }, | 4730 | }, |
5335 | { | 4731 | { |
5336 | .cmd = NL80211_CMD_REGISTER_ACTION, | 4732 | .cmd = NL80211_CMD_REGISTER_FRAME, |
5337 | .doit = nl80211_register_action, | 4733 | .doit = nl80211_register_mgmt, |
5338 | .policy = nl80211_policy, | 4734 | .policy = nl80211_policy, |
5339 | .flags = GENL_ADMIN_PERM, | 4735 | .flags = GENL_ADMIN_PERM, |
4736 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4737 | NL80211_FLAG_NEED_RTNL, | ||
5340 | }, | 4738 | }, |
5341 | { | 4739 | { |
5342 | .cmd = NL80211_CMD_ACTION, | 4740 | .cmd = NL80211_CMD_FRAME, |
5343 | .doit = nl80211_action, | 4741 | .doit = nl80211_tx_mgmt, |
5344 | .policy = nl80211_policy, | 4742 | .policy = nl80211_policy, |
5345 | .flags = GENL_ADMIN_PERM, | 4743 | .flags = GENL_ADMIN_PERM, |
4744 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4745 | NL80211_FLAG_NEED_RTNL, | ||
5346 | }, | 4746 | }, |
5347 | { | 4747 | { |
5348 | .cmd = NL80211_CMD_SET_POWER_SAVE, | 4748 | .cmd = NL80211_CMD_SET_POWER_SAVE, |
5349 | .doit = nl80211_set_power_save, | 4749 | .doit = nl80211_set_power_save, |
5350 | .policy = nl80211_policy, | 4750 | .policy = nl80211_policy, |
5351 | .flags = GENL_ADMIN_PERM, | 4751 | .flags = GENL_ADMIN_PERM, |
4752 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4753 | NL80211_FLAG_NEED_RTNL, | ||
5352 | }, | 4754 | }, |
5353 | { | 4755 | { |
5354 | .cmd = NL80211_CMD_GET_POWER_SAVE, | 4756 | .cmd = NL80211_CMD_GET_POWER_SAVE, |
5355 | .doit = nl80211_get_power_save, | 4757 | .doit = nl80211_get_power_save, |
5356 | .policy = nl80211_policy, | 4758 | .policy = nl80211_policy, |
5357 | /* can be retrieved by unprivileged users */ | 4759 | /* can be retrieved by unprivileged users */ |
4760 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4761 | NL80211_FLAG_NEED_RTNL, | ||
5358 | }, | 4762 | }, |
5359 | { | 4763 | { |
5360 | .cmd = NL80211_CMD_SET_CQM, | 4764 | .cmd = NL80211_CMD_SET_CQM, |
5361 | .doit = nl80211_set_cqm, | 4765 | .doit = nl80211_set_cqm, |
5362 | .policy = nl80211_policy, | 4766 | .policy = nl80211_policy, |
5363 | .flags = GENL_ADMIN_PERM, | 4767 | .flags = GENL_ADMIN_PERM, |
4768 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4769 | NL80211_FLAG_NEED_RTNL, | ||
5364 | }, | 4770 | }, |
5365 | { | 4771 | { |
5366 | .cmd = NL80211_CMD_SET_CHANNEL, | 4772 | .cmd = NL80211_CMD_SET_CHANNEL, |
5367 | .doit = nl80211_set_channel, | 4773 | .doit = nl80211_set_channel, |
5368 | .policy = nl80211_policy, | 4774 | .policy = nl80211_policy, |
5369 | .flags = GENL_ADMIN_PERM, | 4775 | .flags = GENL_ADMIN_PERM, |
4776 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4777 | NL80211_FLAG_NEED_RTNL, | ||
4778 | }, | ||
4779 | { | ||
4780 | .cmd = NL80211_CMD_SET_WDS_PEER, | ||
4781 | .doit = nl80211_set_wds_peer, | ||
4782 | .policy = nl80211_policy, | ||
4783 | .flags = GENL_ADMIN_PERM, | ||
5370 | }, | 4784 | }, |
5371 | }; | 4785 | }; |
5372 | 4786 | ||
@@ -6040,9 +5454,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
6040 | nl80211_mlme_mcgrp.id, gfp); | 5454 | nl80211_mlme_mcgrp.id, gfp); |
6041 | } | 5455 | } |
6042 | 5456 | ||
6043 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 5457 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
6044 | struct net_device *netdev, u32 nlpid, | 5458 | struct net_device *netdev, u32 nlpid, |
6045 | int freq, const u8 *buf, size_t len, gfp_t gfp) | 5459 | int freq, const u8 *buf, size_t len, gfp_t gfp) |
6046 | { | 5460 | { |
6047 | struct sk_buff *msg; | 5461 | struct sk_buff *msg; |
6048 | void *hdr; | 5462 | void *hdr; |
@@ -6052,7 +5466,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, | |||
6052 | if (!msg) | 5466 | if (!msg) |
6053 | return -ENOMEM; | 5467 | return -ENOMEM; |
6054 | 5468 | ||
6055 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION); | 5469 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); |
6056 | if (!hdr) { | 5470 | if (!hdr) { |
6057 | nlmsg_free(msg); | 5471 | nlmsg_free(msg); |
6058 | return -ENOMEM; | 5472 | return -ENOMEM; |
@@ -6080,10 +5494,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, | |||
6080 | return -ENOBUFS; | 5494 | return -ENOBUFS; |
6081 | } | 5495 | } |
6082 | 5496 | ||
6083 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 5497 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
6084 | struct net_device *netdev, u64 cookie, | 5498 | struct net_device *netdev, u64 cookie, |
6085 | const u8 *buf, size_t len, bool ack, | 5499 | const u8 *buf, size_t len, bool ack, |
6086 | gfp_t gfp) | 5500 | gfp_t gfp) |
6087 | { | 5501 | { |
6088 | struct sk_buff *msg; | 5502 | struct sk_buff *msg; |
6089 | void *hdr; | 5503 | void *hdr; |
@@ -6092,7 +5506,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | |||
6092 | if (!msg) | 5506 | if (!msg) |
6093 | return; | 5507 | return; |
6094 | 5508 | ||
6095 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS); | 5509 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS); |
6096 | if (!hdr) { | 5510 | if (!hdr) { |
6097 | nlmsg_free(msg); | 5511 | nlmsg_free(msg); |
6098 | return; | 5512 | return; |
@@ -6179,7 +5593,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
6179 | 5593 | ||
6180 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) | 5594 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) |
6181 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 5595 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) |
6182 | cfg80211_mlme_unregister_actions(wdev, notify->pid); | 5596 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
6183 | 5597 | ||
6184 | rcu_read_unlock(); | 5598 | rcu_read_unlock(); |
6185 | 5599 | ||
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2ad7fbc7d9f..30d2f939150 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -74,13 +74,13 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
74 | struct net_device *dev, const u8 *mac_addr, | 74 | struct net_device *dev, const u8 *mac_addr, |
75 | struct station_info *sinfo, gfp_t gfp); | 75 | struct station_info *sinfo, gfp_t gfp); |
76 | 76 | ||
77 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 77 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
78 | struct net_device *netdev, u32 nlpid, int freq, | 78 | struct net_device *netdev, u32 nlpid, int freq, |
79 | const u8 *buf, size_t len, gfp_t gfp); | 79 | const u8 *buf, size_t len, gfp_t gfp); |
80 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 80 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
81 | struct net_device *netdev, u64 cookie, | 81 | struct net_device *netdev, u64 cookie, |
82 | const u8 *buf, size_t len, bool ack, | 82 | const u8 *buf, size_t len, bool ack, |
83 | gfp_t gfp); | 83 | gfp_t gfp); |
84 | 84 | ||
85 | void | 85 | void |
86 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | 86 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index 1332c445d1c..c774bc0f155 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * See COPYING for more details. | 14 | * See COPYING for more details. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/kernel.h> | ||
17 | #include <net/cfg80211.h> | 18 | #include <net/cfg80211.h> |
18 | #include <net/ieee80211_radiotap.h> | 19 | #include <net/ieee80211_radiotap.h> |
19 | #include <asm/unaligned.h> | 20 | #include <asm/unaligned.h> |
@@ -45,7 +46,7 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = { | |||
45 | }; | 46 | }; |
46 | 47 | ||
47 | static const struct ieee80211_radiotap_namespace radiotap_ns = { | 48 | static const struct ieee80211_radiotap_namespace radiotap_ns = { |
48 | .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), | 49 | .n_bits = ARRAY_SIZE(rtap_namespace_sizes), |
49 | .align_size = rtap_namespace_sizes, | 50 | .align_size = rtap_namespace_sizes, |
50 | }; | 51 | }; |
51 | 52 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f180db0de66..d14bbf960c1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/list.h> | 37 | #include <linux/list.h> |
38 | #include <linux/random.h> | 38 | #include <linux/random.h> |
39 | #include <linux/ctype.h> | ||
39 | #include <linux/nl80211.h> | 40 | #include <linux/nl80211.h> |
40 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
41 | #include <net/cfg80211.h> | 42 | #include <net/cfg80211.h> |
@@ -73,7 +74,11 @@ const struct ieee80211_regdomain *cfg80211_regdomain; | |||
73 | * - last_request | 74 | * - last_request |
74 | */ | 75 | */ |
75 | static DEFINE_MUTEX(reg_mutex); | 76 | static DEFINE_MUTEX(reg_mutex); |
76 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) | 77 | |
78 | static inline void assert_reg_lock(void) | ||
79 | { | ||
80 | lockdep_assert_held(®_mutex); | ||
81 | } | ||
77 | 82 | ||
78 | /* Used to queue up regulatory hints */ | 83 | /* Used to queue up regulatory hints */ |
79 | static LIST_HEAD(reg_requests_list); | 84 | static LIST_HEAD(reg_requests_list); |
@@ -181,14 +186,6 @@ static bool is_alpha2_set(const char *alpha2) | |||
181 | return false; | 186 | return false; |
182 | } | 187 | } |
183 | 188 | ||
184 | static bool is_alpha_upper(char letter) | ||
185 | { | ||
186 | /* ASCII A - Z */ | ||
187 | if (letter >= 65 && letter <= 90) | ||
188 | return true; | ||
189 | return false; | ||
190 | } | ||
191 | |||
192 | static bool is_unknown_alpha2(const char *alpha2) | 189 | static bool is_unknown_alpha2(const char *alpha2) |
193 | { | 190 | { |
194 | if (!alpha2) | 191 | if (!alpha2) |
@@ -220,7 +217,7 @@ static bool is_an_alpha2(const char *alpha2) | |||
220 | { | 217 | { |
221 | if (!alpha2) | 218 | if (!alpha2) |
222 | return false; | 219 | return false; |
223 | if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1])) | 220 | if (isalpha(alpha2[0]) && isalpha(alpha2[1])) |
224 | return true; | 221 | return true; |
225 | return false; | 222 | return false; |
226 | } | 223 | } |
@@ -1399,6 +1396,11 @@ static DECLARE_WORK(reg_work, reg_todo); | |||
1399 | 1396 | ||
1400 | static void queue_regulatory_request(struct regulatory_request *request) | 1397 | static void queue_regulatory_request(struct regulatory_request *request) |
1401 | { | 1398 | { |
1399 | if (isalpha(request->alpha2[0])) | ||
1400 | request->alpha2[0] = toupper(request->alpha2[0]); | ||
1401 | if (isalpha(request->alpha2[1])) | ||
1402 | request->alpha2[1] = toupper(request->alpha2[1]); | ||
1403 | |||
1402 | spin_lock(®_requests_lock); | 1404 | spin_lock(®_requests_lock); |
1403 | list_add_tail(&request->list, ®_requests_list); | 1405 | list_add_tail(&request->list, ®_requests_list); |
1404 | spin_unlock(®_requests_lock); | 1406 | spin_unlock(®_requests_lock); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index a8c2d6b877a..f161b984454 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -411,7 +411,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
411 | 411 | ||
412 | ASSERT_WDEV_LOCK(wdev); | 412 | ASSERT_WDEV_LOCK(wdev); |
413 | 413 | ||
414 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 414 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && |
415 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | ||
415 | return; | 416 | return; |
416 | 417 | ||
417 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 418 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
@@ -548,7 +549,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | |||
548 | 549 | ||
549 | ASSERT_WDEV_LOCK(wdev); | 550 | ASSERT_WDEV_LOCK(wdev); |
550 | 551 | ||
551 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 552 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && |
553 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | ||
552 | return; | 554 | return; |
553 | 555 | ||
554 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 556 | if (wdev->sme_state != CFG80211_SME_CONNECTED) |
@@ -644,7 +646,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
644 | 646 | ||
645 | ASSERT_WDEV_LOCK(wdev); | 647 | ASSERT_WDEV_LOCK(wdev); |
646 | 648 | ||
647 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 649 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && |
650 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | ||
648 | return; | 651 | return; |
649 | 652 | ||
650 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 653 | if (wdev->sme_state != CFG80211_SME_CONNECTED) |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 9f2cef3e0ca..74a9e3cce45 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -110,6 +110,13 @@ static int wiphy_resume(struct device *dev) | |||
110 | return ret; | 110 | return ret; |
111 | } | 111 | } |
112 | 112 | ||
113 | static const void *wiphy_namespace(struct device *d) | ||
114 | { | ||
115 | struct wiphy *wiphy = container_of(d, struct wiphy, dev); | ||
116 | |||
117 | return wiphy_net(wiphy); | ||
118 | } | ||
119 | |||
113 | struct class ieee80211_class = { | 120 | struct class ieee80211_class = { |
114 | .name = "ieee80211", | 121 | .name = "ieee80211", |
115 | .owner = THIS_MODULE, | 122 | .owner = THIS_MODULE, |
@@ -120,6 +127,8 @@ struct class ieee80211_class = { | |||
120 | #endif | 127 | #endif |
121 | .suspend = wiphy_suspend, | 128 | .suspend = wiphy_suspend, |
122 | .resume = wiphy_resume, | 129 | .resume = wiphy_resume, |
130 | .ns_type = &net_ns_type_operations, | ||
131 | .namespace = wiphy_namespace, | ||
123 | }; | 132 | }; |
124 | 133 | ||
125 | int wiphy_sysfs_init(void) | 134 | int wiphy_sysfs_init(void) |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 0c8a1e8b769..fb5448f7d55 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -183,7 +183,14 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
183 | return -EINVAL; | 183 | return -EINVAL; |
184 | break; | 184 | break; |
185 | default: | 185 | default: |
186 | return -EINVAL; | 186 | /* |
187 | * We don't know anything about this algorithm, | ||
188 | * allow using it -- but the driver must check | ||
189 | * all parameters! We still check below whether | ||
190 | * or not the driver supports this algorithm, | ||
191 | * of course. | ||
192 | */ | ||
193 | break; | ||
187 | } | 194 | } |
188 | 195 | ||
189 | if (params->seq) { | 196 | if (params->seq) { |
@@ -221,7 +228,7 @@ const unsigned char bridge_tunnel_header[] __aligned(2) = | |||
221 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | 228 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
222 | EXPORT_SYMBOL(bridge_tunnel_header); | 229 | EXPORT_SYMBOL(bridge_tunnel_header); |
223 | 230 | ||
224 | unsigned int ieee80211_hdrlen(__le16 fc) | 231 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) |
225 | { | 232 | { |
226 | unsigned int hdrlen = 24; | 233 | unsigned int hdrlen = 24; |
227 | 234 | ||
@@ -319,7 +326,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
319 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | 326 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { |
320 | case cpu_to_le16(IEEE80211_FCTL_TODS): | 327 | case cpu_to_le16(IEEE80211_FCTL_TODS): |
321 | if (unlikely(iftype != NL80211_IFTYPE_AP && | 328 | if (unlikely(iftype != NL80211_IFTYPE_AP && |
322 | iftype != NL80211_IFTYPE_AP_VLAN)) | 329 | iftype != NL80211_IFTYPE_AP_VLAN && |
330 | iftype != NL80211_IFTYPE_P2P_GO)) | ||
323 | return -1; | 331 | return -1; |
324 | break; | 332 | break; |
325 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | 333 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): |
@@ -347,7 +355,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
347 | break; | 355 | break; |
348 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 356 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
349 | if ((iftype != NL80211_IFTYPE_STATION && | 357 | if ((iftype != NL80211_IFTYPE_STATION && |
350 | iftype != NL80211_IFTYPE_MESH_POINT) || | 358 | iftype != NL80211_IFTYPE_P2P_CLIENT && |
359 | iftype != NL80211_IFTYPE_MESH_POINT) || | ||
351 | (is_multicast_ether_addr(dst) && | 360 | (is_multicast_ether_addr(dst) && |
352 | !compare_ether_addr(src, addr))) | 361 | !compare_ether_addr(src, addr))) |
353 | return -1; | 362 | return -1; |
@@ -424,6 +433,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
424 | switch (iftype) { | 433 | switch (iftype) { |
425 | case NL80211_IFTYPE_AP: | 434 | case NL80211_IFTYPE_AP: |
426 | case NL80211_IFTYPE_AP_VLAN: | 435 | case NL80211_IFTYPE_AP_VLAN: |
436 | case NL80211_IFTYPE_P2P_GO: | ||
427 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 437 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
428 | /* DA BSSID SA */ | 438 | /* DA BSSID SA */ |
429 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 439 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -432,6 +442,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
432 | hdrlen = 24; | 442 | hdrlen = 24; |
433 | break; | 443 | break; |
434 | case NL80211_IFTYPE_STATION: | 444 | case NL80211_IFTYPE_STATION: |
445 | case NL80211_IFTYPE_P2P_CLIENT: | ||
435 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 446 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
436 | /* BSSID SA DA */ | 447 | /* BSSID SA DA */ |
437 | memcpy(hdr.addr1, bssid, ETH_ALEN); | 448 | memcpy(hdr.addr1, bssid, ETH_ALEN); |
@@ -771,7 +782,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
771 | 782 | ||
772 | /* if it's part of a bridge, reject changing type to station/ibss */ | 783 | /* if it's part of a bridge, reject changing type to station/ibss */ |
773 | if ((dev->priv_flags & IFF_BRIDGE_PORT) && | 784 | if ((dev->priv_flags & IFF_BRIDGE_PORT) && |
774 | (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION)) | 785 | (ntype == NL80211_IFTYPE_ADHOC || |
786 | ntype == NL80211_IFTYPE_STATION || | ||
787 | ntype == NL80211_IFTYPE_P2P_CLIENT)) | ||
775 | return -EBUSY; | 788 | return -EBUSY; |
776 | 789 | ||
777 | if (ntype != otype) { | 790 | if (ntype != otype) { |
@@ -782,6 +795,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
782 | cfg80211_leave_ibss(rdev, dev, false); | 795 | cfg80211_leave_ibss(rdev, dev, false); |
783 | break; | 796 | break; |
784 | case NL80211_IFTYPE_STATION: | 797 | case NL80211_IFTYPE_STATION: |
798 | case NL80211_IFTYPE_P2P_CLIENT: | ||
785 | cfg80211_disconnect(rdev, dev, | 799 | cfg80211_disconnect(rdev, dev, |
786 | WLAN_REASON_DEAUTH_LEAVING, true); | 800 | WLAN_REASON_DEAUTH_LEAVING, true); |
787 | break; | 801 | break; |
@@ -810,9 +824,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
810 | if (dev->ieee80211_ptr->use_4addr) | 824 | if (dev->ieee80211_ptr->use_4addr) |
811 | break; | 825 | break; |
812 | /* fall through */ | 826 | /* fall through */ |
827 | case NL80211_IFTYPE_P2P_CLIENT: | ||
813 | case NL80211_IFTYPE_ADHOC: | 828 | case NL80211_IFTYPE_ADHOC: |
814 | dev->priv_flags |= IFF_DONT_BRIDGE; | 829 | dev->priv_flags |= IFF_DONT_BRIDGE; |
815 | break; | 830 | break; |
831 | case NL80211_IFTYPE_P2P_GO: | ||
816 | case NL80211_IFTYPE_AP: | 832 | case NL80211_IFTYPE_AP: |
817 | case NL80211_IFTYPE_AP_VLAN: | 833 | case NL80211_IFTYPE_AP_VLAN: |
818 | case NL80211_IFTYPE_WDS: | 834 | case NL80211_IFTYPE_WDS: |
@@ -823,7 +839,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
823 | /* monitor can't bridge anyway */ | 839 | /* monitor can't bridge anyway */ |
824 | break; | 840 | break; |
825 | case NL80211_IFTYPE_UNSPECIFIED: | 841 | case NL80211_IFTYPE_UNSPECIFIED: |
826 | case __NL80211_IFTYPE_AFTER_LAST: | 842 | case NUM_NL80211_IFTYPES: |
827 | /* not happening */ | 843 | /* not happening */ |
828 | break; | 844 | break; |
829 | } | 845 | } |
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 8f5116f5af1..dc675a3daa3 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c | |||
@@ -611,7 +611,7 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev) | |||
611 | #endif | 611 | #endif |
612 | 612 | ||
613 | #ifdef CONFIG_CFG80211_WEXT | 613 | #ifdef CONFIG_CFG80211_WEXT |
614 | if (dev->ieee80211_ptr && dev->ieee80211_ptr && | 614 | if (dev->ieee80211_ptr && |
615 | dev->ieee80211_ptr->wiphy && | 615 | dev->ieee80211_ptr->wiphy && |
616 | dev->ieee80211_ptr->wiphy->wext && | 616 | dev->ieee80211_ptr->wiphy->wext && |
617 | dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) | 617 | dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 9818198add8..6fffe62d7c2 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -197,6 +197,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
197 | wdev->wext.connect.ssid_len = len; | 197 | wdev->wext.connect.ssid_len = len; |
198 | 198 | ||
199 | wdev->wext.connect.crypto.control_port = false; | 199 | wdev->wext.connect.crypto.control_port = false; |
200 | wdev->wext.connect.crypto.control_port_ethertype = | ||
201 | cpu_to_be16(ETH_P_PAE); | ||
200 | 202 | ||
201 | err = cfg80211_mgd_wext_connect(rdev, wdev); | 203 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
202 | out: | 204 | out: |