diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-10-08 15:39:28 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-08 15:39:28 -0400 |
commit | e9a68707d736f4f73d7e209885d7b4c5c452b1dc (patch) | |
tree | d9f76964c77c1059483b08436ed060b702b8e25d /net | |
parent | dd53df265b1ee7a1fbbc76bb62c3bec2383bbd44 (diff) | |
parent | 15a6321d1c0f8db561932cd99e1b9897981da71f (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
Documentation/feature-removal-schedule.txt
drivers/net/wireless/ipw2x00/ipw2200.c
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/agg-rx.c | 8 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 16 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 79 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 3 | ||||
-rw-r--r-- | net/mac80211/ht.c | 17 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 65 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 20 | ||||
-rw-r--r-- | net/mac80211/iface.c | 50 | ||||
-rw-r--r-- | net/mac80211/key.c | 95 | ||||
-rw-r--r-- | net/mac80211/key.h | 3 | ||||
-rw-r--r-- | net/mac80211/main.c | 27 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 33 | ||||
-rw-r--r-- | net/mac80211/pm.c | 5 | ||||
-rw-r--r-- | net/mac80211/rx.c | 42 | ||||
-rw-r--r-- | net/mac80211/scan.c | 154 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 12 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 8 | ||||
-rw-r--r-- | net/mac80211/status.c | 6 | ||||
-rw-r--r-- | net/mac80211/tx.c | 5 | ||||
-rw-r--r-- | net/mac80211/util.c | 22 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 14 | ||||
-rw-r--r-- | net/wireless/core.c | 54 | ||||
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/ibss.c | 2 | ||||
-rw-r--r-- | net/wireless/mlme.c | 54 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 2000 | ||||
-rw-r--r-- | net/wireless/scan.c | 12 | ||||
-rw-r--r-- | net/wireless/sme.c | 2 | ||||
-rw-r--r-- | net/wireless/util.c | 12 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 38 |
30 files changed, 1228 insertions, 1632 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 58eab9e8e4ee..720b7a84af59 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -56,7 +56,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) | |||
56 | } | 56 | } |
57 | 57 | ||
58 | void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 58 | void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, |
59 | u16 initiator, u16 reason) | 59 | u16 initiator, u16 reason, bool tx) |
60 | { | 60 | { |
61 | struct ieee80211_local *local = sta->local; | 61 | struct ieee80211_local *local = sta->local; |
62 | struct tid_ampdu_rx *tid_rx; | 62 | struct tid_ampdu_rx *tid_rx; |
@@ -81,7 +81,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
81 | "aggregation for tid %d\n", tid); | 81 | "aggregation for tid %d\n", tid); |
82 | 82 | ||
83 | /* check if this is a self generated aggregation halt */ | 83 | /* check if this is a self generated aggregation halt */ |
84 | if (initiator == WLAN_BACK_RECIPIENT) | 84 | if (initiator == WLAN_BACK_RECIPIENT && tx) |
85 | ieee80211_send_delba(sta->sdata, sta->sta.addr, | 85 | ieee80211_send_delba(sta->sdata, sta->sta.addr, |
86 | tid, 0, reason); | 86 | tid, 0, reason); |
87 | 87 | ||
@@ -92,10 +92,10 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
92 | } | 92 | } |
93 | 93 | ||
94 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 94 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, |
95 | u16 initiator, u16 reason) | 95 | u16 initiator, u16 reason, bool tx) |
96 | { | 96 | { |
97 | mutex_lock(&sta->ampdu_mlme.mtx); | 97 | mutex_lock(&sta->ampdu_mlme.mtx); |
98 | ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason); | 98 | ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx); |
99 | mutex_unlock(&sta->ampdu_mlme.mtx); | 99 | mutex_unlock(&sta->ampdu_mlme.mtx); |
100 | } | 100 | } |
101 | 101 | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index c893f236acea..d4679b265ba8 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -145,7 +145,8 @@ static void kfree_tid_tx(struct rcu_head *rcu_head) | |||
145 | } | 145 | } |
146 | 146 | ||
147 | int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | 147 | int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, |
148 | enum ieee80211_back_parties initiator) | 148 | enum ieee80211_back_parties initiator, |
149 | bool tx) | ||
149 | { | 150 | { |
150 | struct ieee80211_local *local = sta->local; | 151 | struct ieee80211_local *local = sta->local; |
151 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 152 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; |
@@ -175,6 +176,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
175 | 176 | ||
176 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | 177 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); |
177 | 178 | ||
179 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
180 | |||
178 | /* | 181 | /* |
179 | * After this packets are no longer handed right through | 182 | * After this packets are no longer handed right through |
180 | * to the driver but are put onto tid_tx->pending instead, | 183 | * to the driver but are put onto tid_tx->pending instead, |
@@ -183,6 +186,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
183 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); | 186 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
184 | 187 | ||
185 | tid_tx->stop_initiator = initiator; | 188 | tid_tx->stop_initiator = initiator; |
189 | tid_tx->tx_stop = tx; | ||
186 | 190 | ||
187 | ret = drv_ampdu_action(local, sta->sdata, | 191 | ret = drv_ampdu_action(local, sta->sdata, |
188 | IEEE80211_AMPDU_TX_STOP, | 192 | IEEE80211_AMPDU_TX_STOP, |
@@ -575,13 +579,14 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, | |||
575 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | 579 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); |
576 | 580 | ||
577 | int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | 581 | int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, |
578 | enum ieee80211_back_parties initiator) | 582 | enum ieee80211_back_parties initiator, |
583 | bool tx) | ||
579 | { | 584 | { |
580 | int ret; | 585 | int ret; |
581 | 586 | ||
582 | mutex_lock(&sta->ampdu_mlme.mtx); | 587 | mutex_lock(&sta->ampdu_mlme.mtx); |
583 | 588 | ||
584 | ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator); | 589 | ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator, tx); |
585 | 590 | ||
586 | mutex_unlock(&sta->ampdu_mlme.mtx); | 591 | mutex_unlock(&sta->ampdu_mlme.mtx); |
587 | 592 | ||
@@ -670,7 +675,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
670 | goto unlock_sta; | 675 | goto unlock_sta; |
671 | } | 676 | } |
672 | 677 | ||
673 | if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR) | 678 | if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop) |
674 | ieee80211_send_delba(sta->sdata, ra, tid, | 679 | ieee80211_send_delba(sta->sdata, ra, tid, |
675 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | 680 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
676 | 681 | ||
@@ -770,7 +775,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
770 | 775 | ||
771 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 776 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
772 | } else { | 777 | } else { |
773 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); | 778 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, |
779 | true); | ||
774 | } | 780 | } |
775 | 781 | ||
776 | out: | 782 | out: |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c981604b71e6..ecf9b7166ed1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -68,14 +68,42 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
68 | params && params->use_4addr >= 0) | 68 | params && params->use_4addr >= 0) |
69 | sdata->u.mgd.use_4addr = params->use_4addr; | 69 | sdata->u.mgd.use_4addr = params->use_4addr; |
70 | 70 | ||
71 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) | 71 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) { |
72 | 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 | } | ||
73 | 101 | ||
74 | return 0; | 102 | return 0; |
75 | } | 103 | } |
76 | 104 | ||
77 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | 105 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, |
78 | u8 key_idx, const u8 *mac_addr, | 106 | u8 key_idx, bool pairwise, const u8 *mac_addr, |
79 | struct key_params *params) | 107 | struct key_params *params) |
80 | { | 108 | { |
81 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 109 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -103,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
103 | if (IS_ERR(key)) | 131 | if (IS_ERR(key)) |
104 | return PTR_ERR(key); | 132 | return PTR_ERR(key); |
105 | 133 | ||
134 | if (pairwise) | ||
135 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | ||
136 | |||
106 | mutex_lock(&sdata->local->sta_mtx); | 137 | mutex_lock(&sdata->local->sta_mtx); |
107 | 138 | ||
108 | if (mac_addr) { | 139 | if (mac_addr) { |
@@ -125,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
125 | } | 156 | } |
126 | 157 | ||
127 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 158 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
128 | u8 key_idx, const u8 *mac_addr) | 159 | u8 key_idx, bool pairwise, const u8 *mac_addr) |
129 | { | 160 | { |
130 | struct ieee80211_sub_if_data *sdata; | 161 | struct ieee80211_sub_if_data *sdata; |
131 | struct sta_info *sta; | 162 | struct sta_info *sta; |
@@ -142,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
142 | if (!sta) | 173 | if (!sta) |
143 | goto out_unlock; | 174 | goto out_unlock; |
144 | 175 | ||
145 | if (sta->key) { | 176 | if (pairwise) { |
146 | ieee80211_key_free(sdata->local, sta->key); | 177 | if (sta->ptk) { |
147 | WARN_ON(sta->key); | 178 | ieee80211_key_free(sdata->local, sta->ptk); |
148 | ret = 0; | 179 | ret = 0; |
180 | } | ||
181 | } else { | ||
182 | if (sta->gtk[key_idx]) { | ||
183 | ieee80211_key_free(sdata->local, | ||
184 | sta->gtk[key_idx]); | ||
185 | ret = 0; | ||
186 | } | ||
149 | } | 187 | } |
150 | 188 | ||
151 | goto out_unlock; | 189 | goto out_unlock; |
@@ -167,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
167 | } | 205 | } |
168 | 206 | ||
169 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | 207 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, |
170 | u8 key_idx, const u8 *mac_addr, void *cookie, | 208 | u8 key_idx, bool pairwise, const u8 *mac_addr, |
209 | void *cookie, | ||
171 | void (*callback)(void *cookie, | 210 | void (*callback)(void *cookie, |
172 | struct key_params *params)) | 211 | struct key_params *params)) |
173 | { | 212 | { |
@@ -175,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
175 | struct sta_info *sta = NULL; | 214 | struct sta_info *sta = NULL; |
176 | u8 seq[6] = {0}; | 215 | u8 seq[6] = {0}; |
177 | struct key_params params; | 216 | struct key_params params; |
178 | struct ieee80211_key *key; | 217 | struct ieee80211_key *key = NULL; |
179 | u32 iv32; | 218 | u32 iv32; |
180 | u16 iv16; | 219 | u16 iv16; |
181 | int err = -ENOENT; | 220 | int err = -ENOENT; |
@@ -189,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
189 | if (!sta) | 228 | if (!sta) |
190 | goto out; | 229 | goto out; |
191 | 230 | ||
192 | key = sta->key; | 231 | if (pairwise) |
232 | key = sta->ptk; | ||
233 | else if (key_idx < NUM_DEFAULT_KEYS) | ||
234 | key = sta->gtk[key_idx]; | ||
193 | } else | 235 | } else |
194 | key = sdata->keys[key_idx]; | 236 | key = sdata->keys[key_idx]; |
195 | 237 | ||
@@ -285,6 +327,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
285 | STATION_INFO_TX_BYTES | | 327 | STATION_INFO_TX_BYTES | |
286 | STATION_INFO_RX_PACKETS | | 328 | STATION_INFO_RX_PACKETS | |
287 | STATION_INFO_TX_PACKETS | | 329 | STATION_INFO_TX_PACKETS | |
330 | STATION_INFO_TX_RETRIES | | ||
331 | STATION_INFO_TX_FAILED | | ||
288 | STATION_INFO_TX_BITRATE; | 332 | STATION_INFO_TX_BITRATE; |
289 | 333 | ||
290 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 334 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
@@ -292,6 +336,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
292 | sinfo->tx_bytes = sta->tx_bytes; | 336 | sinfo->tx_bytes = sta->tx_bytes; |
293 | sinfo->rx_packets = sta->rx_packets; | 337 | sinfo->rx_packets = sta->rx_packets; |
294 | sinfo->tx_packets = sta->tx_packets; | 338 | sinfo->tx_packets = sta->tx_packets; |
339 | sinfo->tx_retries = sta->tx_retry_count; | ||
340 | sinfo->tx_failed = sta->tx_retry_failed; | ||
295 | 341 | ||
296 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | 342 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || |
297 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | 343 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { |
@@ -1317,7 +1363,7 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) | |||
1317 | } | 1363 | } |
1318 | 1364 | ||
1319 | static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, | 1365 | static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, |
1320 | u8 *addr) | 1366 | const u8 *addr) |
1321 | { | 1367 | { |
1322 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1368 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1323 | 1369 | ||
@@ -1366,7 +1412,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
1366 | if (!sdata->u.mgd.associated || | 1412 | if (!sdata->u.mgd.associated || |
1367 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { | 1413 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { |
1368 | mutex_lock(&sdata->local->iflist_mtx); | 1414 | mutex_lock(&sdata->local->iflist_mtx); |
1369 | ieee80211_recalc_smps(sdata->local, sdata); | 1415 | ieee80211_recalc_smps(sdata->local); |
1370 | mutex_unlock(&sdata->local->iflist_mtx); | 1416 | mutex_unlock(&sdata->local->iflist_mtx); |
1371 | return 0; | 1417 | return 0; |
1372 | } | 1418 | } |
@@ -1521,7 +1567,11 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1521 | 1567 | ||
1522 | switch (sdata->vif.type) { | 1568 | switch (sdata->vif.type) { |
1523 | case NL80211_IFTYPE_ADHOC: | 1569 | case NL80211_IFTYPE_ADHOC: |
1524 | if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) | 1570 | case NL80211_IFTYPE_AP: |
1571 | case NL80211_IFTYPE_AP_VLAN: | ||
1572 | case NL80211_IFTYPE_P2P_GO: | ||
1573 | if (!ieee80211_is_action(mgmt->frame_control) || | ||
1574 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) | ||
1525 | break; | 1575 | break; |
1526 | rcu_read_lock(); | 1576 | rcu_read_lock(); |
1527 | sta = sta_info_get(sdata, mgmt->da); | 1577 | sta = sta_info_get(sdata, mgmt->da); |
@@ -1530,6 +1580,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1530 | return -ENOLINK; | 1580 | return -ENOLINK; |
1531 | break; | 1581 | break; |
1532 | case NL80211_IFTYPE_STATION: | 1582 | case NL80211_IFTYPE_STATION: |
1583 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1533 | break; | 1584 | break; |
1534 | default: | 1585 | default: |
1535 | return -EOPNOTSUPP; | 1586 | return -EOPNOTSUPP; |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 6b7ff9fb4604..50c40ea3cb4d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -196,7 +196,8 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu | |||
196 | else | 196 | else |
197 | ret = ieee80211_stop_tx_ba_session(&sta->sta, tid); | 197 | ret = ieee80211_stop_tx_ba_session(&sta->sta, tid); |
198 | } else { | 198 | } else { |
199 | __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3); | 199 | __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, |
200 | 3, true); | ||
200 | ret = 0; | 201 | ret = 0; |
201 | } | 202 | } |
202 | 203 | ||
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 11f74f5f7b2f..4214bb6e12fc 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -101,16 +101,16 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | |||
101 | ht_cap->mcs.rx_mask[32/8] |= 1; | 101 | ht_cap->mcs.rx_mask[32/8] |= 1; |
102 | } | 102 | } |
103 | 103 | ||
104 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta) | 104 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) |
105 | { | 105 | { |
106 | int i; | 106 | int i; |
107 | 107 | ||
108 | cancel_work_sync(&sta->ampdu_mlme.work); | 108 | cancel_work_sync(&sta->ampdu_mlme.work); |
109 | 109 | ||
110 | for (i = 0; i < STA_TID_NUM; i++) { | 110 | for (i = 0; i < STA_TID_NUM; i++) { |
111 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR); | 111 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx); |
112 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, | 112 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, |
113 | WLAN_REASON_QSTA_LEAVE_QBSS); | 113 | WLAN_REASON_QSTA_LEAVE_QBSS, tx); |
114 | } | 114 | } |
115 | } | 115 | } |
116 | 116 | ||
@@ -135,7 +135,7 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
135 | if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) | 135 | if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) |
136 | ___ieee80211_stop_rx_ba_session( | 136 | ___ieee80211_stop_rx_ba_session( |
137 | sta, tid, WLAN_BACK_RECIPIENT, | 137 | sta, tid, WLAN_BACK_RECIPIENT, |
138 | WLAN_REASON_QSTA_TIMEOUT); | 138 | WLAN_REASON_QSTA_TIMEOUT, true); |
139 | 139 | ||
140 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 140 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; |
141 | if (!tid_tx) | 141 | if (!tid_tx) |
@@ -146,7 +146,8 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
146 | else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | 146 | else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, |
147 | &tid_tx->state)) | 147 | &tid_tx->state)) |
148 | ___ieee80211_stop_tx_ba_session(sta, tid, | 148 | ___ieee80211_stop_tx_ba_session(sta, tid, |
149 | WLAN_BACK_INITIATOR); | 149 | WLAN_BACK_INITIATOR, |
150 | true); | ||
150 | } | 151 | } |
151 | mutex_unlock(&sta->ampdu_mlme.mtx); | 152 | mutex_unlock(&sta->ampdu_mlme.mtx); |
152 | } | 153 | } |
@@ -214,9 +215,11 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | |||
214 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 215 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
215 | 216 | ||
216 | if (initiator == WLAN_BACK_INITIATOR) | 217 | if (initiator == WLAN_BACK_INITIATOR) |
217 | __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0); | 218 | __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0, |
219 | true); | ||
218 | else | 220 | else |
219 | __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT); | 221 | __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, |
222 | true); | ||
220 | } | 223 | } |
221 | 224 | ||
222 | int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, | 225 | int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 1a3aae54f0cf..ff60c022f51d 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; | ||
283 | 293 | ||
284 | if (sta->sta.supp_rates[band] != prev_rates) { | 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); | ||
298 | |||
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, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 945fbf29719d..f0610fa4fbe0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -369,6 +369,7 @@ struct ieee80211_if_managed { | |||
369 | 369 | ||
370 | unsigned int flags; | 370 | unsigned int flags; |
371 | 371 | ||
372 | bool beacon_crc_valid; | ||
372 | u32 beacon_crc; | 373 | u32 beacon_crc; |
373 | 374 | ||
374 | enum { | 375 | enum { |
@@ -548,8 +549,6 @@ struct ieee80211_sub_if_data { | |||
548 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 549 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
549 | unsigned int fragment_next; | 550 | unsigned int fragment_next; |
550 | 551 | ||
551 | #define NUM_DEFAULT_KEYS 4 | ||
552 | #define NUM_DEFAULT_MGMT_KEYS 2 | ||
553 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 552 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
554 | struct ieee80211_key *default_key; | 553 | struct ieee80211_key *default_key; |
555 | struct ieee80211_key *default_mgmt_key; | 554 | struct ieee80211_key *default_mgmt_key; |
@@ -1132,6 +1131,8 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); | |||
1132 | void ieee80211_remove_interfaces(struct ieee80211_local *local); | 1131 | void ieee80211_remove_interfaces(struct ieee80211_local *local); |
1133 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); | 1132 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); |
1134 | void ieee80211_recalc_idle(struct ieee80211_local *local); | 1133 | void ieee80211_recalc_idle(struct ieee80211_local *local); |
1134 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | ||
1135 | const int offset); | ||
1135 | 1136 | ||
1136 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1137 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) |
1137 | { | 1138 | { |
@@ -1172,10 +1173,10 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, | |||
1172 | void ieee80211_request_smps_work(struct work_struct *work); | 1173 | void ieee80211_request_smps_work(struct work_struct *work); |
1173 | 1174 | ||
1174 | void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 1175 | void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, |
1175 | u16 initiator, u16 reason); | 1176 | u16 initiator, u16 reason, bool stop); |
1176 | 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, |
1177 | u16 initiator, u16 reason); | 1178 | u16 initiator, u16 reason, bool stop); |
1178 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta); | 1179 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx); |
1179 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 1180 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
1180 | struct sta_info *sta, | 1181 | struct sta_info *sta, |
1181 | struct ieee80211_mgmt *mgmt, size_t len); | 1182 | struct ieee80211_mgmt *mgmt, size_t len); |
@@ -1189,9 +1190,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
1189 | size_t len); | 1190 | size_t len); |
1190 | 1191 | ||
1191 | int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | 1192 | int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, |
1192 | enum ieee80211_back_parties initiator); | 1193 | enum ieee80211_back_parties initiator, |
1194 | bool tx); | ||
1193 | int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | 1195 | int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, |
1194 | enum ieee80211_back_parties initiator); | 1196 | enum ieee80211_back_parties initiator, |
1197 | bool tx); | ||
1195 | void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); | 1198 | void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); |
1196 | 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); |
1197 | void ieee80211_ba_session_work(struct work_struct *work); | 1200 | void ieee80211_ba_session_work(struct work_struct *work); |
@@ -1294,8 +1297,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
1294 | enum ieee80211_band band); | 1297 | enum ieee80211_band band); |
1295 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | 1298 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, |
1296 | enum ieee80211_smps_mode smps_mode); | 1299 | enum ieee80211_smps_mode smps_mode); |
1297 | void ieee80211_recalc_smps(struct ieee80211_local *local, | 1300 | void ieee80211_recalc_smps(struct ieee80211_local *local); |
1298 | struct ieee80211_sub_if_data *forsdata); | ||
1299 | 1301 | ||
1300 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1302 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, |
1301 | 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 66785739dad3..e99d1b60557c 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 |
@@ -148,6 +149,26 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
148 | return 0; | 149 | return 0; |
149 | } | 150 | } |
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 | |||
151 | /* | 172 | /* |
152 | * NOTE: Be very careful when changing this function, it must NOT return | 173 | * NOTE: Be very careful when changing this function, it must NOT return |
153 | * an error on interface type changes that have been pre-checked, so most | 174 | * an error on interface type changes that have been pre-checked, so most |
@@ -240,17 +261,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
240 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 261 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
241 | } | 262 | } |
242 | 263 | ||
243 | if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) | 264 | ieee80211_adjust_monitor_flags(sdata, 1); |
244 | local->fif_fcsfail++; | ||
245 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) | ||
246 | local->fif_plcpfail++; | ||
247 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { | ||
248 | local->fif_control++; | ||
249 | local->fif_pspoll++; | ||
250 | } | ||
251 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | ||
252 | local->fif_other_bss++; | ||
253 | |||
254 | ieee80211_configure_filter(local); | 265 | ieee80211_configure_filter(local); |
255 | 266 | ||
256 | netif_carrier_on(dev); | 267 | netif_carrier_on(dev); |
@@ -301,6 +312,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
301 | /* STA has been freed */ | 312 | /* STA has been freed */ |
302 | goto err_del_interface; | 313 | goto err_del_interface; |
303 | } | 314 | } |
315 | |||
316 | rate_control_rate_init(sta); | ||
304 | } | 317 | } |
305 | 318 | ||
306 | /* | 319 | /* |
@@ -477,17 +490,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
477 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 490 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
478 | } | 491 | } |
479 | 492 | ||
480 | if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) | 493 | ieee80211_adjust_monitor_flags(sdata, -1); |
481 | local->fif_fcsfail--; | ||
482 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) | ||
483 | local->fif_plcpfail--; | ||
484 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { | ||
485 | local->fif_pspoll--; | ||
486 | local->fif_control--; | ||
487 | } | ||
488 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | ||
489 | local->fif_other_bss--; | ||
490 | |||
491 | ieee80211_configure_filter(local); | 494 | ieee80211_configure_filter(local); |
492 | break; | 495 | break; |
493 | case NL80211_IFTYPE_MESH_POINT: | 496 | case NL80211_IFTYPE_MESH_POINT: |
@@ -793,7 +796,8 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
793 | 796 | ||
794 | __ieee80211_stop_rx_ba_session( | 797 | __ieee80211_stop_rx_ba_session( |
795 | sta, tid, WLAN_BACK_RECIPIENT, | 798 | sta, tid, WLAN_BACK_RECIPIENT, |
796 | WLAN_REASON_QSTA_REQUIRE_SETUP); | 799 | WLAN_REASON_QSTA_REQUIRE_SETUP, |
800 | true); | ||
797 | } | 801 | } |
798 | mutex_unlock(&local->sta_mtx); | 802 | mutex_unlock(&local->sta_mtx); |
799 | } else switch (sdata->vif.type) { | 803 | } else switch (sdata->vif.type) { |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 6a63d1abd14d..ccd676b2f599 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -68,15 +68,21 @@ static int 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 | ret = -EOPNOTSUPP; | ||
73 | goto out_unsupported; | 72 | goto out_unsupported; |
74 | } | ||
75 | 73 | ||
76 | assert_key_lock(key->local); | 74 | assert_key_lock(key->local); |
77 | 75 | ||
78 | sta = get_sta_for_key(key); | 76 | sta = get_sta_for_key(key); |
79 | 77 | ||
78 | /* | ||
79 | * If this is a per-STA GTK, check if it | ||
80 | * is supported; if not, return. | ||
81 | */ | ||
82 | if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) && | ||
83 | !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)) | ||
84 | goto out_unsupported; | ||
85 | |||
80 | sdata = key->sdata; | 86 | sdata = key->sdata; |
81 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 87 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
82 | sdata = container_of(sdata->bss, | 88 | sdata = container_of(sdata->bss, |
@@ -85,31 +91,28 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
85 | 91 | ||
86 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); | 92 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); |
87 | 93 | ||
88 | if (!ret) | 94 | if (!ret) { |
89 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 95 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
96 | return 0; | ||
97 | } | ||
90 | 98 | ||
91 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) | 99 | if (ret != -ENOSPC && ret != -EOPNOTSUPP) |
92 | wiphy_err(key->local->hw.wiphy, | 100 | wiphy_err(key->local->hw.wiphy, |
93 | "failed to set key (%d, %pM) to hardware (%d)\n", | 101 | "failed to set key (%d, %pM) to hardware (%d)\n", |
94 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | 102 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
95 | 103 | ||
96 | out_unsupported: | 104 | out_unsupported: |
97 | if (ret) { | 105 | switch (key->conf.cipher) { |
98 | switch (key->conf.cipher) { | 106 | case WLAN_CIPHER_SUITE_WEP40: |
99 | case WLAN_CIPHER_SUITE_WEP40: | 107 | case WLAN_CIPHER_SUITE_WEP104: |
100 | case WLAN_CIPHER_SUITE_WEP104: | 108 | case WLAN_CIPHER_SUITE_TKIP: |
101 | case WLAN_CIPHER_SUITE_TKIP: | 109 | case WLAN_CIPHER_SUITE_CCMP: |
102 | case WLAN_CIPHER_SUITE_CCMP: | 110 | case WLAN_CIPHER_SUITE_AES_CMAC: |
103 | case WLAN_CIPHER_SUITE_AES_CMAC: | 111 | /* all of these we can do in software */ |
104 | /* all of these we can do in software */ | 112 | return 0; |
105 | ret = 0; | 113 | default: |
106 | break; | 114 | return -EINVAL; |
107 | default: | ||
108 | ret = -EINVAL; | ||
109 | } | ||
110 | } | 115 | } |
111 | |||
112 | return ret; | ||
113 | } | 116 | } |
114 | 117 | ||
115 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 118 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
@@ -147,6 +150,26 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
147 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 150 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
148 | } | 151 | } |
149 | 152 | ||
153 | void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) | ||
154 | { | ||
155 | struct ieee80211_key *key; | ||
156 | |||
157 | key = container_of(key_conf, struct ieee80211_key, conf); | ||
158 | |||
159 | might_sleep(); | ||
160 | assert_key_lock(key->local); | ||
161 | |||
162 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
163 | |||
164 | /* | ||
165 | * Flush TX path to avoid attempts to use this key | ||
166 | * after this function returns. Until then, drivers | ||
167 | * must be prepared to handle the key. | ||
168 | */ | ||
169 | synchronize_rcu(); | ||
170 | } | ||
171 | EXPORT_SYMBOL_GPL(ieee80211_key_removed); | ||
172 | |||
150 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | 173 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, |
151 | int idx) | 174 | int idx) |
152 | { | 175 | { |
@@ -202,6 +225,7 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | |||
202 | 225 | ||
203 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | 226 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, |
204 | struct sta_info *sta, | 227 | struct sta_info *sta, |
228 | bool pairwise, | ||
205 | struct ieee80211_key *old, | 229 | struct ieee80211_key *old, |
206 | struct ieee80211_key *new) | 230 | struct ieee80211_key *new) |
207 | { | 231 | { |
@@ -210,8 +234,14 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
210 | if (new) | 234 | if (new) |
211 | list_add(&new->list, &sdata->key_list); | 235 | list_add(&new->list, &sdata->key_list); |
212 | 236 | ||
213 | if (sta) { | 237 | if (sta && pairwise) { |
214 | rcu_assign_pointer(sta->key, new); | 238 | rcu_assign_pointer(sta->ptk, new); |
239 | } else if (sta) { | ||
240 | if (old) | ||
241 | idx = old->conf.keyidx; | ||
242 | else | ||
243 | idx = new->conf.keyidx; | ||
244 | rcu_assign_pointer(sta->gtk[idx], new); | ||
215 | } else { | 245 | } else { |
216 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | 246 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
217 | 247 | ||
@@ -355,6 +385,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
355 | { | 385 | { |
356 | struct ieee80211_key *old_key; | 386 | struct ieee80211_key *old_key; |
357 | int idx, ret; | 387 | int idx, ret; |
388 | bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; | ||
358 | 389 | ||
359 | BUG_ON(!sdata); | 390 | BUG_ON(!sdata); |
360 | BUG_ON(!key); | 391 | BUG_ON(!key); |
@@ -371,13 +402,6 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
371 | */ | 402 | */ |
372 | if (test_sta_flags(sta, WLAN_STA_WME)) | 403 | if (test_sta_flags(sta, WLAN_STA_WME)) |
373 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; | 404 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; |
374 | |||
375 | /* | ||
376 | * This key is for a specific sta interface, | ||
377 | * inform the driver that it should try to store | ||
378 | * this key as pairwise key. | ||
379 | */ | ||
380 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | ||
381 | } else { | 405 | } else { |
382 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 406 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
383 | struct sta_info *ap; | 407 | struct sta_info *ap; |
@@ -399,12 +423,14 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
399 | 423 | ||
400 | mutex_lock(&sdata->local->key_mtx); | 424 | mutex_lock(&sdata->local->key_mtx); |
401 | 425 | ||
402 | if (sta) | 426 | if (sta && pairwise) |
403 | old_key = sta->key; | 427 | old_key = sta->ptk; |
428 | else if (sta) | ||
429 | old_key = sta->gtk[idx]; | ||
404 | else | 430 | else |
405 | old_key = sdata->keys[idx]; | 431 | old_key = sdata->keys[idx]; |
406 | 432 | ||
407 | __ieee80211_key_replace(sdata, sta, old_key, key); | 433 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
408 | __ieee80211_key_destroy(old_key); | 434 | __ieee80211_key_destroy(old_key); |
409 | 435 | ||
410 | ieee80211_debugfs_key_add(key); | 436 | ieee80211_debugfs_key_add(key); |
@@ -423,7 +449,8 @@ static void __ieee80211_key_free(struct ieee80211_key *key) | |||
423 | */ | 449 | */ |
424 | if (key->sdata) | 450 | if (key->sdata) |
425 | __ieee80211_key_replace(key->sdata, key->sta, | 451 | __ieee80211_key_replace(key->sdata, key->sta, |
426 | key, NULL); | 452 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
453 | key, NULL); | ||
427 | __ieee80211_key_destroy(key); | 454 | __ieee80211_key_destroy(key); |
428 | } | 455 | } |
429 | 456 | ||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index cb9a4a65cc68..0db1c0f5f697 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -16,6 +16,9 @@ | |||
16 | #include <linux/rcupdate.h> | 16 | #include <linux/rcupdate.h> |
17 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
18 | 18 | ||
19 | #define NUM_DEFAULT_KEYS 4 | ||
20 | #define NUM_DEFAULT_MGMT_KEYS 2 | ||
21 | |||
19 | #define WEP_IV_LEN 4 | 22 | #define WEP_IV_LEN 4 |
20 | #define WEP_ICV_LEN 4 | 23 | #define WEP_ICV_LEN 4 |
21 | #define ALG_TKIP_KEY_LEN 32 | 24 | #define ALG_TKIP_KEY_LEN 32 |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index db341a99c7c7..eb0f59977676 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -201,6 +201,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
201 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 201 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
202 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 202 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
203 | 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; | ||
204 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 206 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
205 | sdata->vif.bss_conf.bssid = zero; | 207 | sdata->vif.bss_conf.bssid = zero; |
206 | } else { | 208 | } else { |
@@ -211,6 +213,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
211 | switch (sdata->vif.type) { | 213 | switch (sdata->vif.type) { |
212 | case NL80211_IFTYPE_AP: | 214 | case NL80211_IFTYPE_AP: |
213 | case NL80211_IFTYPE_ADHOC: | 215 | case NL80211_IFTYPE_ADHOC: |
216 | case NL80211_IFTYPE_WDS: | ||
214 | case NL80211_IFTYPE_MESH_POINT: | 217 | case NL80211_IFTYPE_MESH_POINT: |
215 | break; | 218 | break; |
216 | default: | 219 | default: |
@@ -295,7 +298,16 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
295 | struct ieee80211_local *local = | 298 | struct ieee80211_local *local = |
296 | container_of(work, struct ieee80211_local, restart_work); | 299 | container_of(work, struct ieee80211_local, restart_work); |
297 | 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 | |||
298 | rtnl_lock(); | 309 | rtnl_lock(); |
310 | ieee80211_scan_cancel(local); | ||
299 | ieee80211_reconfig(local); | 311 | ieee80211_reconfig(local); |
300 | rtnl_unlock(); | 312 | rtnl_unlock(); |
301 | } | 313 | } |
@@ -306,15 +318,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
306 | 318 | ||
307 | trace_api_restart_hw(local); | 319 | trace_api_restart_hw(local); |
308 | 320 | ||
309 | /* wait for scan work complete */ | ||
310 | flush_workqueue(local->workqueue); | ||
311 | |||
312 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), | ||
313 | "%s called with hardware scan in progress\n", __func__); | ||
314 | |||
315 | if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) | ||
316 | ieee80211_scan_cancel(local); | ||
317 | |||
318 | /* use this reason, ieee80211_reconfig will unblock it */ | 321 | /* use this reason, ieee80211_reconfig will unblock it */ |
319 | ieee80211_stop_queues_by_reason(hw, | 322 | ieee80211_stop_queues_by_reason(hw, |
320 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 323 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
@@ -329,7 +332,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
329 | container_of(work, struct ieee80211_local, recalc_smps); | 332 | container_of(work, struct ieee80211_local, recalc_smps); |
330 | 333 | ||
331 | mutex_lock(&local->iflist_mtx); | 334 | mutex_lock(&local->iflist_mtx); |
332 | ieee80211_recalc_smps(local, NULL); | 335 | ieee80211_recalc_smps(local); |
333 | mutex_unlock(&local->iflist_mtx); | 336 | mutex_unlock(&local->iflist_mtx); |
334 | } | 337 | } |
335 | 338 | ||
@@ -533,6 +536,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
533 | /* set up some defaults */ | 536 | /* set up some defaults */ |
534 | local->hw.queues = 1; | 537 | local->hw.queues = 1; |
535 | local->hw.max_rates = 1; | 538 | local->hw.max_rates = 1; |
539 | local->hw.max_report_rates = 0; | ||
536 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 540 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
537 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 541 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
538 | local->user_power_level = -1; | 542 | local->user_power_level = -1; |
@@ -608,6 +612,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
608 | WLAN_CIPHER_SUITE_AES_CMAC | 612 | WLAN_CIPHER_SUITE_AES_CMAC |
609 | }; | 613 | }; |
610 | 614 | ||
615 | if (hw->max_report_rates == 0) | ||
616 | hw->max_report_rates = hw->max_rates; | ||
617 | |||
611 | /* | 618 | /* |
612 | * generic code guarantees at least one band, | 619 | * generic code guarantees at least one band, |
613 | * set this very early because much code assumes | 620 | * set this very early because much code assumes |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 77913a15f537..5695c94c49aa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -913,7 +913,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
913 | 913 | ||
914 | mutex_lock(&local->iflist_mtx); | 914 | mutex_lock(&local->iflist_mtx); |
915 | ieee80211_recalc_ps(local, -1); | 915 | ieee80211_recalc_ps(local, -1); |
916 | ieee80211_recalc_smps(local, sdata); | 916 | ieee80211_recalc_smps(local); |
917 | mutex_unlock(&local->iflist_mtx); | 917 | mutex_unlock(&local->iflist_mtx); |
918 | 918 | ||
919 | netif_tx_start_all_queues(sdata->dev); | 919 | netif_tx_start_all_queues(sdata->dev); |
@@ -921,7 +921,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
921 | } | 921 | } |
922 | 922 | ||
923 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 923 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
924 | bool remove_sta) | 924 | bool remove_sta, bool tx) |
925 | { | 925 | { |
926 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 926 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
927 | struct ieee80211_local *local = sdata->local; | 927 | struct ieee80211_local *local = sdata->local; |
@@ -960,7 +960,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
960 | sta = sta_info_get(sdata, bssid); | 960 | sta = sta_info_get(sdata, bssid); |
961 | if (sta) { | 961 | if (sta) { |
962 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | 962 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); |
963 | ieee80211_sta_tear_down_BA_sessions(sta); | 963 | ieee80211_sta_tear_down_BA_sessions(sta, tx); |
964 | } | 964 | } |
965 | mutex_unlock(&local->sta_mtx); | 965 | mutex_unlock(&local->sta_mtx); |
966 | 966 | ||
@@ -1124,7 +1124,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1124 | 1124 | ||
1125 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); | 1125 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); |
1126 | 1126 | ||
1127 | ieee80211_set_disassoc(sdata, true); | 1127 | ieee80211_set_disassoc(sdata, true, true); |
1128 | mutex_unlock(&ifmgd->mtx); | 1128 | mutex_unlock(&ifmgd->mtx); |
1129 | 1129 | ||
1130 | mutex_lock(&local->mtx); | 1130 | mutex_lock(&local->mtx); |
@@ -1197,7 +1197,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1197 | printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", | 1197 | printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", |
1198 | sdata->name, bssid, reason_code); | 1198 | sdata->name, bssid, reason_code); |
1199 | 1199 | ||
1200 | ieee80211_set_disassoc(sdata, true); | 1200 | ieee80211_set_disassoc(sdata, true, false); |
1201 | mutex_lock(&sdata->local->mtx); | 1201 | mutex_lock(&sdata->local->mtx); |
1202 | ieee80211_recalc_idle(sdata->local); | 1202 | ieee80211_recalc_idle(sdata->local); |
1203 | mutex_unlock(&sdata->local->mtx); | 1203 | mutex_unlock(&sdata->local->mtx); |
@@ -1229,7 +1229,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1229 | printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", | 1229 | printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", |
1230 | sdata->name, mgmt->sa, reason_code); | 1230 | sdata->name, mgmt->sa, reason_code); |
1231 | 1231 | ||
1232 | ieee80211_set_disassoc(sdata, true); | 1232 | ieee80211_set_disassoc(sdata, true, false); |
1233 | mutex_lock(&sdata->local->mtx); | 1233 | mutex_lock(&sdata->local->mtx); |
1234 | ieee80211_recalc_idle(sdata->local); | 1234 | ieee80211_recalc_idle(sdata->local); |
1235 | mutex_unlock(&sdata->local->mtx); | 1235 | mutex_unlock(&sdata->local->mtx); |
@@ -1291,7 +1291,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1291 | 1291 | ||
1292 | rates = 0; | 1292 | rates = 0; |
1293 | basic_rates = 0; | 1293 | basic_rates = 0; |
1294 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1294 | sband = local->hw.wiphy->bands[wk->chan->band]; |
1295 | 1295 | ||
1296 | for (i = 0; i < elems.supp_rates_len; i++) { | 1296 | for (i = 0; i < elems.supp_rates_len; i++) { |
1297 | int rate = (elems.supp_rates[i] & 0x7f) * 5; | 1297 | int rate = (elems.supp_rates[i] & 0x7f) * 5; |
@@ -1327,11 +1327,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1327 | } | 1327 | } |
1328 | } | 1328 | } |
1329 | 1329 | ||
1330 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 1330 | sta->sta.supp_rates[wk->chan->band] = rates; |
1331 | sdata->vif.bss_conf.basic_rates = basic_rates; | 1331 | sdata->vif.bss_conf.basic_rates = basic_rates; |
1332 | 1332 | ||
1333 | /* cf. IEEE 802.11 9.2.12 */ | 1333 | /* cf. IEEE 802.11 9.2.12 */ |
1334 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | 1334 | if (wk->chan->band == IEEE80211_BAND_2GHZ && |
1335 | have_higher_than_11mbit) | 1335 | have_higher_than_11mbit) |
1336 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 1336 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
1337 | else | 1337 | else |
@@ -1639,7 +1639,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1639 | directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, | 1639 | directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, |
1640 | ifmgd->aid); | 1640 | ifmgd->aid); |
1641 | 1641 | ||
1642 | if (ncrc != ifmgd->beacon_crc) { | 1642 | if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) { |
1643 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, | 1643 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, |
1644 | true); | 1644 | true); |
1645 | 1645 | ||
@@ -1670,9 +1670,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1670 | } | 1670 | } |
1671 | } | 1671 | } |
1672 | 1672 | ||
1673 | if (ncrc == ifmgd->beacon_crc) | 1673 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
1674 | return; | 1674 | return; |
1675 | ifmgd->beacon_crc = ncrc; | 1675 | ifmgd->beacon_crc = ncrc; |
1676 | ifmgd->beacon_crc_valid = true; | ||
1676 | 1677 | ||
1677 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1678 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1678 | erp_valid = true; | 1679 | erp_valid = true; |
@@ -1879,7 +1880,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1879 | printk(KERN_DEBUG "No probe response from AP %pM" | 1880 | printk(KERN_DEBUG "No probe response from AP %pM" |
1880 | " after %dms, disconnecting.\n", | 1881 | " after %dms, disconnecting.\n", |
1881 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 1882 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
1882 | ieee80211_set_disassoc(sdata, true); | 1883 | ieee80211_set_disassoc(sdata, true, true); |
1883 | mutex_unlock(&ifmgd->mtx); | 1884 | mutex_unlock(&ifmgd->mtx); |
1884 | mutex_lock(&local->mtx); | 1885 | mutex_lock(&local->mtx); |
1885 | ieee80211_recalc_idle(local); | 1886 | ieee80211_recalc_idle(local); |
@@ -2203,7 +2204,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2203 | } | 2204 | } |
2204 | 2205 | ||
2205 | /* Trying to reassociate - clear previous association state */ | 2206 | /* Trying to reassociate - clear previous association state */ |
2206 | ieee80211_set_disassoc(sdata, true); | 2207 | ieee80211_set_disassoc(sdata, true, false); |
2207 | } | 2208 | } |
2208 | mutex_unlock(&ifmgd->mtx); | 2209 | mutex_unlock(&ifmgd->mtx); |
2209 | 2210 | ||
@@ -2214,6 +2215,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2214 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 2215 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
2215 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 2216 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; |
2216 | 2217 | ||
2218 | ifmgd->beacon_crc_valid = false; | ||
2219 | |||
2217 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) | 2220 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) |
2218 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | 2221 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || |
2219 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | 2222 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || |
@@ -2315,7 +2318,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2315 | 2318 | ||
2316 | memcpy(bssid, req->bss->bssid, ETH_ALEN); | 2319 | memcpy(bssid, req->bss->bssid, ETH_ALEN); |
2317 | if (ifmgd->associated == req->bss) { | 2320 | if (ifmgd->associated == req->bss) { |
2318 | ieee80211_set_disassoc(sdata, false); | 2321 | ieee80211_set_disassoc(sdata, false, true); |
2319 | mutex_unlock(&ifmgd->mtx); | 2322 | mutex_unlock(&ifmgd->mtx); |
2320 | assoc_bss = true; | 2323 | assoc_bss = true; |
2321 | } else { | 2324 | } else { |
@@ -2398,7 +2401,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2398 | sdata->name, req->bss->bssid, req->reason_code); | 2401 | sdata->name, req->bss->bssid, req->reason_code); |
2399 | 2402 | ||
2400 | memcpy(bssid, req->bss->bssid, ETH_ALEN); | 2403 | memcpy(bssid, req->bss->bssid, ETH_ALEN); |
2401 | ieee80211_set_disassoc(sdata, false); | 2404 | ieee80211_set_disassoc(sdata, false, true); |
2402 | 2405 | ||
2403 | mutex_unlock(&ifmgd->mtx); | 2406 | mutex_unlock(&ifmgd->mtx); |
2404 | 2407 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index ce671dfd238c..e37355193ed1 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -12,8 +12,7 @@ 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 | if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) | 15 | ieee80211_scan_cancel(local); |
16 | ieee80211_scan_cancel(local); | ||
17 | 16 | ||
18 | ieee80211_stop_queues_by_reason(hw, | 17 | ieee80211_stop_queues_by_reason(hw, |
19 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 18 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
@@ -46,7 +45,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
46 | list_for_each_entry(sta, &local->sta_list, list) { | 45 | list_for_each_entry(sta, &local->sta_list, list) { |
47 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | 46 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { |
48 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | 47 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); |
49 | ieee80211_sta_tear_down_BA_sessions(sta); | 48 | ieee80211_sta_tear_down_BA_sessions(sta, true); |
50 | } | 49 | } |
51 | 50 | ||
52 | if (sta->uploaded) { | 51 | if (sta->uploaded) { |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0b0e83ebe3d5..b67221def584 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -819,6 +819,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
819 | if (unlikely((ieee80211_is_data(hdr->frame_control) || | 819 | if (unlikely((ieee80211_is_data(hdr->frame_control) || |
820 | ieee80211_is_pspoll(hdr->frame_control)) && | 820 | ieee80211_is_pspoll(hdr->frame_control)) && |
821 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 821 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
822 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && | ||
822 | (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { | 823 | (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { |
823 | if ((!ieee80211_has_fromds(hdr->frame_control) && | 824 | if ((!ieee80211_has_fromds(hdr->frame_control) && |
824 | !ieee80211_has_tods(hdr->frame_control) && | 825 | !ieee80211_has_tods(hdr->frame_control) && |
@@ -845,7 +846,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
845 | int keyidx; | 846 | int keyidx; |
846 | int hdrlen; | 847 | int hdrlen; |
847 | ieee80211_rx_result result = RX_DROP_UNUSABLE; | 848 | ieee80211_rx_result result = RX_DROP_UNUSABLE; |
848 | struct ieee80211_key *stakey = NULL; | 849 | struct ieee80211_key *sta_ptk = NULL; |
849 | int mmie_keyidx = -1; | 850 | int mmie_keyidx = -1; |
850 | __le16 fc; | 851 | __le16 fc; |
851 | 852 | ||
@@ -887,15 +888,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
887 | rx->key = NULL; | 888 | rx->key = NULL; |
888 | 889 | ||
889 | if (rx->sta) | 890 | if (rx->sta) |
890 | stakey = rcu_dereference(rx->sta->key); | 891 | sta_ptk = rcu_dereference(rx->sta->ptk); |
891 | 892 | ||
892 | fc = hdr->frame_control; | 893 | fc = hdr->frame_control; |
893 | 894 | ||
894 | if (!ieee80211_has_protected(fc)) | 895 | if (!ieee80211_has_protected(fc)) |
895 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | 896 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); |
896 | 897 | ||
897 | if (!is_multicast_ether_addr(hdr->addr1) && stakey) { | 898 | if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { |
898 | rx->key = stakey; | 899 | rx->key = sta_ptk; |
899 | if ((status->flag & RX_FLAG_DECRYPTED) && | 900 | if ((status->flag & RX_FLAG_DECRYPTED) && |
900 | (status->flag & RX_FLAG_IV_STRIPPED)) | 901 | (status->flag & RX_FLAG_IV_STRIPPED)) |
901 | return RX_CONTINUE; | 902 | return RX_CONTINUE; |
@@ -911,7 +912,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
911 | if (mmie_keyidx < NUM_DEFAULT_KEYS || | 912 | if (mmie_keyidx < NUM_DEFAULT_KEYS || |
912 | mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | 913 | mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) |
913 | return RX_DROP_MONITOR; /* unexpected BIP keyidx */ | 914 | return RX_DROP_MONITOR; /* unexpected BIP keyidx */ |
914 | rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); | 915 | if (rx->sta) |
916 | rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]); | ||
917 | if (!rx->key) | ||
918 | rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); | ||
915 | } else if (!ieee80211_has_protected(fc)) { | 919 | } else if (!ieee80211_has_protected(fc)) { |
916 | /* | 920 | /* |
917 | * The frame was not protected, so skip decryption. However, we | 921 | * The frame was not protected, so skip decryption. However, we |
@@ -954,17 +958,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
954 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | 958 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); |
955 | keyidx = keyid >> 6; | 959 | keyidx = keyid >> 6; |
956 | 960 | ||
957 | rx->key = rcu_dereference(rx->sdata->keys[keyidx]); | 961 | /* check per-station GTK first, if multicast packet */ |
962 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) | ||
963 | rx->key = rcu_dereference(rx->sta->gtk[keyidx]); | ||
958 | 964 | ||
959 | /* | 965 | /* if not found, try default key */ |
960 | * RSNA-protected unicast frames should always be sent with | 966 | if (!rx->key) { |
961 | * pairwise or station-to-station keys, but for WEP we allow | 967 | rx->key = rcu_dereference(rx->sdata->keys[keyidx]); |
962 | * using a key index as well. | 968 | |
963 | */ | 969 | /* |
964 | if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && | 970 | * RSNA-protected unicast frames should always be |
965 | rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && | 971 | * sent with pairwise or station-to-station keys, |
966 | !is_multicast_ether_addr(hdr->addr1)) | 972 | * but for WEP we allow using a key index as well. |
967 | rx->key = NULL; | 973 | */ |
974 | if (rx->key && | ||
975 | rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
976 | rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && | ||
977 | !is_multicast_ether_addr(hdr->addr1)) | ||
978 | rx->key = NULL; | ||
979 | } | ||
968 | } | 980 | } |
969 | 981 | ||
970 | if (rx->key) { | 982 | if (rx->key) { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5171a9581631..fb274db77e3c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -249,12 +249,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
249 | return true; | 249 | return true; |
250 | } | 250 | } |
251 | 251 | ||
252 | static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 252 | static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, |
253 | bool was_hw_scan) | ||
253 | { | 254 | { |
254 | struct ieee80211_local *local = hw_to_local(hw); | 255 | struct ieee80211_local *local = hw_to_local(hw); |
255 | bool was_hw_scan; | ||
256 | 256 | ||
257 | mutex_lock(&local->mtx); | 257 | lockdep_assert_held(&local->mtx); |
258 | 258 | ||
259 | /* | 259 | /* |
260 | * It's ok to abort a not-yet-running scan (that | 260 | * It's ok to abort a not-yet-running scan (that |
@@ -265,17 +265,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
265 | if (WARN_ON(!local->scanning && !aborted)) | 265 | if (WARN_ON(!local->scanning && !aborted)) |
266 | aborted = true; | 266 | aborted = true; |
267 | 267 | ||
268 | if (WARN_ON(!local->scan_req)) { | 268 | if (WARN_ON(!local->scan_req)) |
269 | mutex_unlock(&local->mtx); | 269 | return false; |
270 | return; | ||
271 | } | ||
272 | 270 | ||
273 | was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); | ||
274 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { | 271 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { |
275 | ieee80211_queue_delayed_work(&local->hw, | 272 | int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); |
276 | &local->scan_work, 0); | 273 | if (rc == 0) |
277 | mutex_unlock(&local->mtx); | 274 | return false; |
278 | return; | ||
279 | } | 275 | } |
280 | 276 | ||
281 | kfree(local->hw_scan_req); | 277 | kfree(local->hw_scan_req); |
@@ -289,23 +285,25 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
289 | local->scanning = 0; | 285 | local->scanning = 0; |
290 | local->scan_channel = NULL; | 286 | local->scan_channel = NULL; |
291 | 287 | ||
292 | /* we only have to protect scan_req and hw/sw scan */ | 288 | return true; |
293 | mutex_unlock(&local->mtx); | 289 | } |
294 | |||
295 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
296 | if (was_hw_scan) | ||
297 | goto done; | ||
298 | |||
299 | ieee80211_configure_filter(local); | ||
300 | 290 | ||
301 | drv_sw_scan_complete(local); | 291 | static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw, |
292 | bool was_hw_scan) | ||
293 | { | ||
294 | struct ieee80211_local *local = hw_to_local(hw); | ||
302 | 295 | ||
303 | ieee80211_offchannel_return(local, true); | 296 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
297 | if (!was_hw_scan) { | ||
298 | ieee80211_configure_filter(local); | ||
299 | drv_sw_scan_complete(local); | ||
300 | ieee80211_offchannel_return(local, true); | ||
301 | } | ||
304 | 302 | ||
305 | done: | ||
306 | mutex_lock(&local->mtx); | 303 | mutex_lock(&local->mtx); |
307 | ieee80211_recalc_idle(local); | 304 | ieee80211_recalc_idle(local); |
308 | mutex_unlock(&local->mtx); | 305 | mutex_unlock(&local->mtx); |
306 | |||
309 | ieee80211_mlme_notify_scan_completed(local); | 307 | ieee80211_mlme_notify_scan_completed(local); |
310 | ieee80211_ibss_notify_scan_completed(local); | 308 | ieee80211_ibss_notify_scan_completed(local); |
311 | ieee80211_mesh_notify_scan_completed(local); | 309 | ieee80211_mesh_notify_scan_completed(local); |
@@ -366,6 +364,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
366 | struct ieee80211_local *local = sdata->local; | 364 | struct ieee80211_local *local = sdata->local; |
367 | int rc; | 365 | int rc; |
368 | 366 | ||
367 | lockdep_assert_held(&local->mtx); | ||
368 | |||
369 | if (local->scan_req) | 369 | if (local->scan_req) |
370 | return -EBUSY; | 370 | return -EBUSY; |
371 | 371 | ||
@@ -447,8 +447,8 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) | |||
447 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; | 447 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; |
448 | } | 448 | } |
449 | 449 | ||
450 | static int ieee80211_scan_state_decision(struct ieee80211_local *local, | 450 | static void ieee80211_scan_state_decision(struct ieee80211_local *local, |
451 | unsigned long *next_delay) | 451 | unsigned long *next_delay) |
452 | { | 452 | { |
453 | bool associated = false; | 453 | bool associated = false; |
454 | bool tx_empty = true; | 454 | bool tx_empty = true; |
@@ -458,12 +458,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
458 | struct ieee80211_sub_if_data *sdata; | 458 | struct ieee80211_sub_if_data *sdata; |
459 | struct ieee80211_channel *next_chan; | 459 | struct ieee80211_channel *next_chan; |
460 | 460 | ||
461 | /* if no more bands/channels left, complete scan and advance to the idle state */ | ||
462 | if (local->scan_channel_idx >= local->scan_req->n_channels) { | ||
463 | __ieee80211_scan_completed(&local->hw, false); | ||
464 | return 1; | ||
465 | } | ||
466 | |||
467 | /* | 461 | /* |
468 | * check if at least one STA interface is associated, | 462 | * check if at least one STA interface is associated, |
469 | * check if at least one STA interface has pending tx frames | 463 | * check if at least one STA interface has pending tx frames |
@@ -535,7 +529,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
535 | } | 529 | } |
536 | 530 | ||
537 | *next_delay = 0; | 531 | *next_delay = 0; |
538 | return 0; | ||
539 | } | 532 | } |
540 | 533 | ||
541 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, | 534 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, |
@@ -651,28 +644,17 @@ void ieee80211_scan_work(struct work_struct *work) | |||
651 | container_of(work, struct ieee80211_local, scan_work.work); | 644 | container_of(work, struct ieee80211_local, scan_work.work); |
652 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 645 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
653 | unsigned long next_delay = 0; | 646 | unsigned long next_delay = 0; |
647 | bool aborted, hw_scan, finish; | ||
654 | 648 | ||
655 | if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { | 649 | mutex_lock(&local->mtx); |
656 | bool aborted; | ||
657 | 650 | ||
651 | if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { | ||
658 | aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); | 652 | aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); |
659 | __ieee80211_scan_completed(&local->hw, aborted); | 653 | goto out_complete; |
660 | return; | ||
661 | } | ||
662 | |||
663 | mutex_lock(&local->mtx); | ||
664 | if (!sdata || !local->scan_req) { | ||
665 | mutex_unlock(&local->mtx); | ||
666 | return; | ||
667 | } | 654 | } |
668 | 655 | ||
669 | if (local->hw_scan_req) { | 656 | if (!sdata || !local->scan_req) |
670 | int rc = drv_hw_scan(local, sdata, local->hw_scan_req); | 657 | goto out; |
671 | mutex_unlock(&local->mtx); | ||
672 | if (rc) | ||
673 | __ieee80211_scan_completed(&local->hw, true); | ||
674 | return; | ||
675 | } | ||
676 | 658 | ||
677 | if (local->scan_req && !local->scanning) { | 659 | if (local->scan_req && !local->scanning) { |
678 | struct cfg80211_scan_request *req = local->scan_req; | 660 | struct cfg80211_scan_request *req = local->scan_req; |
@@ -682,21 +664,21 @@ void ieee80211_scan_work(struct work_struct *work) | |||
682 | local->scan_sdata = NULL; | 664 | local->scan_sdata = NULL; |
683 | 665 | ||
684 | rc = __ieee80211_start_scan(sdata, req); | 666 | rc = __ieee80211_start_scan(sdata, req); |
685 | mutex_unlock(&local->mtx); | 667 | if (rc) { |
686 | 668 | /* need to complete scan in cfg80211 */ | |
687 | if (rc) | 669 | local->scan_req = req; |
688 | __ieee80211_scan_completed(&local->hw, true); | 670 | aborted = true; |
689 | return; | 671 | goto out_complete; |
672 | } else | ||
673 | goto out; | ||
690 | } | 674 | } |
691 | 675 | ||
692 | mutex_unlock(&local->mtx); | ||
693 | |||
694 | /* | 676 | /* |
695 | * Avoid re-scheduling when the sdata is going away. | 677 | * Avoid re-scheduling when the sdata is going away. |
696 | */ | 678 | */ |
697 | if (!ieee80211_sdata_running(sdata)) { | 679 | if (!ieee80211_sdata_running(sdata)) { |
698 | __ieee80211_scan_completed(&local->hw, true); | 680 | aborted = true; |
699 | return; | 681 | goto out_complete; |
700 | } | 682 | } |
701 | 683 | ||
702 | /* | 684 | /* |
@@ -706,8 +688,12 @@ void ieee80211_scan_work(struct work_struct *work) | |||
706 | do { | 688 | do { |
707 | switch (local->next_scan_state) { | 689 | switch (local->next_scan_state) { |
708 | case SCAN_DECISION: | 690 | case SCAN_DECISION: |
709 | if (ieee80211_scan_state_decision(local, &next_delay)) | 691 | /* if no more bands/channels left, complete scan */ |
710 | return; | 692 | if (local->scan_channel_idx >= local->scan_req->n_channels) { |
693 | aborted = false; | ||
694 | goto out_complete; | ||
695 | } | ||
696 | ieee80211_scan_state_decision(local, &next_delay); | ||
711 | break; | 697 | break; |
712 | case SCAN_SET_CHANNEL: | 698 | case SCAN_SET_CHANNEL: |
713 | ieee80211_scan_state_set_channel(local, &next_delay); | 699 | ieee80211_scan_state_set_channel(local, &next_delay); |
@@ -725,6 +711,19 @@ void ieee80211_scan_work(struct work_struct *work) | |||
725 | } while (next_delay == 0); | 711 | } while (next_delay == 0); |
726 | 712 | ||
727 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); | 713 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); |
714 | mutex_unlock(&local->mtx); | ||
715 | return; | ||
716 | |||
717 | out_complete: | ||
718 | hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); | ||
719 | finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan); | ||
720 | mutex_unlock(&local->mtx); | ||
721 | if (finish) | ||
722 | __ieee80211_scan_completed_finish(&local->hw, hw_scan); | ||
723 | return; | ||
724 | |||
725 | out: | ||
726 | mutex_unlock(&local->mtx); | ||
728 | } | 727 | } |
729 | 728 | ||
730 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 729 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
@@ -786,21 +785,40 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
786 | return ret; | 785 | return ret; |
787 | } | 786 | } |
788 | 787 | ||
788 | /* | ||
789 | * Only call this function when a scan can't be queued -- under RTNL. | ||
790 | */ | ||
789 | void ieee80211_scan_cancel(struct ieee80211_local *local) | 791 | void ieee80211_scan_cancel(struct ieee80211_local *local) |
790 | { | 792 | { |
791 | bool abortscan; | 793 | bool abortscan; |
792 | 794 | bool finish = false; | |
793 | cancel_delayed_work_sync(&local->scan_work); | ||
794 | 795 | ||
795 | /* | 796 | /* |
796 | * Only call this function when a scan can't be | 797 | * We are only canceling software scan, or deferred scan that was not |
797 | * queued -- mostly at suspend under RTNL. | 798 | * yet really started (see __ieee80211_start_scan ). |
799 | * | ||
800 | * Regarding hardware scan: | ||
801 | * - we can not call __ieee80211_scan_completed() as when | ||
802 | * SCAN_HW_SCANNING bit is set this function change | ||
803 | * local->hw_scan_req to operate on 5G band, what race with | ||
804 | * driver which can use local->hw_scan_req | ||
805 | * | ||
806 | * - we can not cancel scan_work since driver can schedule it | ||
807 | * by ieee80211_scan_completed(..., true) to finish scan | ||
808 | * | ||
809 | * Hence low lever driver is responsible for canceling HW scan. | ||
798 | */ | 810 | */ |
811 | |||
799 | mutex_lock(&local->mtx); | 812 | mutex_lock(&local->mtx); |
800 | abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || | 813 | abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning); |
801 | (!local->scanning && local->scan_req); | 814 | if (abortscan) |
815 | finish = __ieee80211_scan_completed(&local->hw, true, false); | ||
802 | mutex_unlock(&local->mtx); | 816 | mutex_unlock(&local->mtx); |
803 | 817 | ||
804 | if (abortscan) | 818 | if (abortscan) { |
805 | __ieee80211_scan_completed(&local->hw, true); | 819 | /* The scan is canceled, but stop work from being pending */ |
820 | cancel_delayed_work_sync(&local->scan_work); | ||
821 | } | ||
822 | if (finish) | ||
823 | __ieee80211_scan_completed_finish(&local->hw, false); | ||
806 | } | 824 | } |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ca2cba9cea87..6d8f897d8763 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -616,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
616 | struct ieee80211_sub_if_data *sdata; | 616 | struct ieee80211_sub_if_data *sdata; |
617 | struct sk_buff *skb; | 617 | struct sk_buff *skb; |
618 | unsigned long flags; | 618 | unsigned long flags; |
619 | int ret; | 619 | int ret, i; |
620 | 620 | ||
621 | might_sleep(); | 621 | might_sleep(); |
622 | 622 | ||
@@ -633,7 +633,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
633 | * will be sufficient. | 633 | * will be sufficient. |
634 | */ | 634 | */ |
635 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | 635 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); |
636 | ieee80211_sta_tear_down_BA_sessions(sta); | 636 | ieee80211_sta_tear_down_BA_sessions(sta, true); |
637 | 637 | ||
638 | spin_lock_irqsave(&local->sta_lock, flags); | 638 | spin_lock_irqsave(&local->sta_lock, flags); |
639 | ret = sta_info_hash_del(local, sta); | 639 | ret = sta_info_hash_del(local, sta); |
@@ -644,10 +644,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
644 | if (ret) | 644 | if (ret) |
645 | return ret; | 645 | return ret; |
646 | 646 | ||
647 | if (sta->key) { | 647 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
648 | ieee80211_key_free(local, sta->key); | 648 | ieee80211_key_free(local, sta->gtk[i]); |
649 | WARN_ON(sta->key); | 649 | if (sta->ptk) |
650 | } | 650 | ieee80211_key_free(local, sta->ptk); |
651 | 651 | ||
652 | sta->dead = true; | 652 | sta->dead = true; |
653 | 653 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 810c5ce98316..9265acadef32 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -79,6 +79,7 @@ enum ieee80211_sta_info_flags { | |||
79 | * @dialog_token: dialog token for aggregation session | 79 | * @dialog_token: dialog token for aggregation session |
80 | * @state: session state (see above) | 80 | * @state: session state (see above) |
81 | * @stop_initiator: initiator of a session stop | 81 | * @stop_initiator: initiator of a session stop |
82 | * @tx_stop: TX DelBA frame when stopping | ||
82 | * | 83 | * |
83 | * This structure is protected by RCU and the per-station | 84 | * This structure is protected by RCU and the per-station |
84 | * spinlock. Assignments to the array holding it must hold | 85 | * spinlock. Assignments to the array holding it must hold |
@@ -95,6 +96,7 @@ struct tid_ampdu_tx { | |||
95 | unsigned long state; | 96 | unsigned long state; |
96 | u8 dialog_token; | 97 | u8 dialog_token; |
97 | u8 stop_initiator; | 98 | u8 stop_initiator; |
99 | bool tx_stop; | ||
98 | }; | 100 | }; |
99 | 101 | ||
100 | /** | 102 | /** |
@@ -197,7 +199,8 @@ enum plink_state { | |||
197 | * @hnext: hash table linked list pointer | 199 | * @hnext: hash table linked list pointer |
198 | * @local: pointer to the global information | 200 | * @local: pointer to the global information |
199 | * @sdata: virtual interface this station belongs to | 201 | * @sdata: virtual interface this station belongs to |
200 | * @key: peer key negotiated with this station, if any | 202 | * @ptk: peer key negotiated with this station, if any |
203 | * @gtk: group keys negotiated with this station, if any | ||
201 | * @rate_ctrl: rate control algorithm reference | 204 | * @rate_ctrl: rate control algorithm reference |
202 | * @rate_ctrl_priv: rate control private per-STA pointer | 205 | * @rate_ctrl_priv: rate control private per-STA pointer |
203 | * @last_tx_rate: rate used for last transmit, to report to userspace as | 206 | * @last_tx_rate: rate used for last transmit, to report to userspace as |
@@ -252,7 +255,8 @@ struct sta_info { | |||
252 | struct sta_info *hnext; | 255 | struct sta_info *hnext; |
253 | struct ieee80211_local *local; | 256 | struct ieee80211_local *local; |
254 | struct ieee80211_sub_if_data *sdata; | 257 | struct ieee80211_sub_if_data *sdata; |
255 | struct ieee80211_key *key; | 258 | struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
259 | struct ieee80211_key *ptk; | ||
256 | struct rate_control_ref *rate_ctrl; | 260 | struct rate_control_ref *rate_ctrl; |
257 | void *rate_ctrl_priv; | 261 | void *rate_ctrl_priv; |
258 | spinlock_t lock; | 262 | spinlock_t lock; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index dd85006c4fe8..3153c19893b8 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -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) { |
@@ -377,7 +377,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
377 | skb2 = skb_clone(skb, GFP_ATOMIC); | 377 | skb2 = skb_clone(skb, GFP_ATOMIC); |
378 | if (skb2) { | 378 | if (skb2) { |
379 | skb2->dev = prev_dev; | 379 | skb2->dev = prev_dev; |
380 | netif_receive_skb(skb2); | 380 | netif_rx(skb2); |
381 | } | 381 | } |
382 | } | 382 | } |
383 | 383 | ||
@@ -386,7 +386,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
386 | } | 386 | } |
387 | if (prev_dev) { | 387 | if (prev_dev) { |
388 | skb->dev = prev_dev; | 388 | skb->dev = prev_dev; |
389 | netif_receive_skb(skb); | 389 | netif_rx(skb); |
390 | skb = NULL; | 390 | skb = NULL; |
391 | } | 391 | } |
392 | rcu_read_unlock(); | 392 | rcu_read_unlock(); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e1733dcb58a7..96c594309506 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 | ||
@@ -529,7 +532,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
529 | 532 | ||
530 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) | 533 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) |
531 | tx->key = NULL; | 534 | tx->key = NULL; |
532 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) | 535 | else if (tx->sta && (key = rcu_dereference(tx->sta->ptk))) |
533 | tx->key = key; | 536 | tx->key = key; |
534 | else if (ieee80211_is_mgmt(hdr->frame_control) && | 537 | else if (ieee80211_is_mgmt(hdr->frame_control) && |
535 | is_multicast_ether_addr(hdr->addr1) && | 538 | is_multicast_ether_addr(hdr->addr1) && |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aba025d748e9..0b6fc92bc0d7 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1221,7 +1221,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1221 | mutex_lock(&local->sta_mtx); | 1221 | mutex_lock(&local->sta_mtx); |
1222 | 1222 | ||
1223 | list_for_each_entry(sta, &local->sta_list, list) { | 1223 | list_for_each_entry(sta, &local->sta_list, list) { |
1224 | ieee80211_sta_tear_down_BA_sessions(sta); | 1224 | ieee80211_sta_tear_down_BA_sessions(sta, true); |
1225 | clear_sta_flags(sta, WLAN_STA_BLOCK_BA); | 1225 | clear_sta_flags(sta, WLAN_STA_BLOCK_BA); |
1226 | } | 1226 | } |
1227 | 1227 | ||
@@ -1297,16 +1297,12 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | |||
1297 | } | 1297 | } |
1298 | 1298 | ||
1299 | /* must hold iflist_mtx */ | 1299 | /* must hold iflist_mtx */ |
1300 | void ieee80211_recalc_smps(struct ieee80211_local *local, | 1300 | void ieee80211_recalc_smps(struct ieee80211_local *local) |
1301 | struct ieee80211_sub_if_data *forsdata) | ||
1302 | { | 1301 | { |
1303 | struct ieee80211_sub_if_data *sdata; | 1302 | struct ieee80211_sub_if_data *sdata; |
1304 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | 1303 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; |
1305 | int count = 0; | 1304 | int count = 0; |
1306 | 1305 | ||
1307 | if (forsdata) | ||
1308 | lockdep_assert_held(&forsdata->u.mgd.mtx); | ||
1309 | |||
1310 | lockdep_assert_held(&local->iflist_mtx); | 1306 | lockdep_assert_held(&local->iflist_mtx); |
1311 | 1307 | ||
1312 | /* | 1308 | /* |
@@ -1324,18 +1320,8 @@ void ieee80211_recalc_smps(struct ieee80211_local *local, | |||
1324 | continue; | 1320 | continue; |
1325 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1321 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
1326 | goto set; | 1322 | goto set; |
1327 | if (sdata != forsdata) { | 1323 | |
1328 | /* | 1324 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); |
1329 | * This nested is ok -- we are holding the iflist_mtx | ||
1330 | * so can't get here twice or so. But it's required | ||
1331 | * since normally we acquire it first and then the | ||
1332 | * iflist_mtx. | ||
1333 | */ | ||
1334 | mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); | ||
1335 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1336 | mutex_unlock(&sdata->u.mgd.mtx); | ||
1337 | } else | ||
1338 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1339 | 1325 | ||
1340 | if (count > 1) { | 1326 | if (count > 1) { |
1341 | smps_mode = IEEE80211_SMPS_OFF; | 1327 | smps_mode = IEEE80211_SMPS_OFF; |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 26ed3e8587c2..1781d99145e2 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 9c21ebf9780e..1684ad91763c 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) |
@@ -320,9 +304,11 @@ static void cfg80211_event_work(struct work_struct *work) | |||
320 | 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) |
321 | { | 305 | { |
322 | static int wiphy_counter; | 306 | static int wiphy_counter; |
323 | 307 | int i; | |
324 | struct cfg80211_registered_device *rdev; | 308 | struct cfg80211_registered_device *rdev, *rdev2; |
325 | int alloc_size; | 309 | int alloc_size; |
310 | char nname[IFNAMSIZ + 1]; | ||
311 | bool found = false; | ||
326 | 312 | ||
327 | 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)); |
328 | WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); | 314 | WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); |
@@ -346,16 +332,36 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
346 | 332 | ||
347 | if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { | 333 | if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { |
348 | 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: | ||
349 | mutex_unlock(&cfg80211_mutex); | 355 | mutex_unlock(&cfg80211_mutex); |
350 | /* ugh, wrapped! */ | 356 | /* ugh, too many devices already! */ |
351 | kfree(rdev); | 357 | kfree(rdev); |
352 | return NULL; | 358 | return NULL; |
353 | } | 359 | } |
354 | 360 | ||
355 | mutex_unlock(&cfg80211_mutex); | ||
356 | |||
357 | /* give it a proper name */ | 361 | /* give it a proper name */ |
358 | 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); | ||
359 | 365 | ||
360 | mutex_init(&rdev->mtx); | 366 | mutex_init(&rdev->mtx); |
361 | mutex_init(&rdev->devlist_mtx); | 367 | mutex_init(&rdev->devlist_mtx); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 5d89310b3587..6583cca0e2ee 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -375,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | |||
375 | /* internal helpers */ | 375 | /* internal helpers */ |
376 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 376 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
377 | struct key_params *params, int key_idx, | 377 | struct key_params *params, int key_idx, |
378 | const u8 *mac_addr); | 378 | bool pairwise, const u8 *mac_addr); |
379 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | 379 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
380 | size_t ie_len, u16 reason, bool from_ap); | 380 | size_t ie_len, u16 reason, bool from_ap); |
381 | void cfg80211_sme_scan_done(struct net_device *dev); | 381 | void cfg80211_sme_scan_done(struct net_device *dev); |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 8cb6e08373b9..f33fbb79437c 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -160,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
160 | */ | 160 | */ |
161 | if (rdev->ops->del_key) | 161 | if (rdev->ops->del_key) |
162 | for (i = 0; i < 6; i++) | 162 | for (i = 0; i < 6; i++) |
163 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | 163 | rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); |
164 | 164 | ||
165 | if (wdev->current_bss) { | 165 | if (wdev->current_bss) { |
166 | cfg80211_unhold_bss(wdev->current_bss); | 166 | cfg80211_unhold_bss(wdev->current_bss); |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 46f371160896..caf11a427507 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -876,21 +876,53 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
876 | 876 | ||
877 | if (ieee80211_is_action(mgmt->frame_control) && | 877 | if (ieee80211_is_action(mgmt->frame_control) && |
878 | mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | 878 | mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { |
879 | /* Verify that we are associated with the destination AP */ | 879 | int err = 0; |
880 | |||
880 | wdev_lock(wdev); | 881 | wdev_lock(wdev); |
881 | 882 | ||
882 | if (!wdev->current_bss || | 883 | switch (wdev->iftype) { |
883 | memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, | 884 | case NL80211_IFTYPE_ADHOC: |
884 | ETH_ALEN) != 0 || | 885 | case NL80211_IFTYPE_STATION: |
885 | ((wdev->iftype == NL80211_IFTYPE_STATION || | 886 | case NL80211_IFTYPE_P2P_CLIENT: |
886 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && | 887 | if (!wdev->current_bss) { |
887 | memcmp(wdev->current_bss->pub.bssid, mgmt->da, | 888 | err = -ENOTCONN; |
888 | ETH_ALEN) != 0)) { | 889 | break; |
889 | wdev_unlock(wdev); | 890 | } |
890 | return -ENOTCONN; | 891 | |
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; | ||
892 | 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 | } | ||
893 | wdev_unlock(wdev); | 922 | wdev_unlock(wdev); |
923 | |||
924 | if (err) | ||
925 | return err; | ||
894 | } | 926 | } |
895 | 927 | ||
896 | if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) | 928 | if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9c84825803ce..882dc921103b 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 */ |
@@ -86,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
86 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 93 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
87 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 94 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
88 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 95 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
96 | [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, | ||
89 | 97 | ||
90 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 98 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
91 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | 99 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, |
@@ -161,7 +169,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
161 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, | 169 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, |
162 | }; | 170 | }; |
163 | 171 | ||
164 | /* policy for the attributes */ | 172 | /* policy for the key attributes */ |
165 | static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | 173 | static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { |
166 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, | 174 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, |
167 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, | 175 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, |
@@ -169,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | |||
169 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 177 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
170 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | 178 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, |
171 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 179 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
180 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, | ||
172 | }; | 181 | }; |
173 | 182 | ||
174 | /* ifidx get helper */ | 183 | /* ifidx get helper */ |
@@ -191,6 +200,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb) | |||
191 | return res; | 200 | return res; |
192 | } | 201 | } |
193 | 202 | ||
203 | static int nl80211_prepare_netdev_dump(struct sk_buff *skb, | ||
204 | struct netlink_callback *cb, | ||
205 | struct cfg80211_registered_device **rdev, | ||
206 | struct net_device **dev) | ||
207 | { | ||
208 | int ifidx = cb->args[0]; | ||
209 | int err; | ||
210 | |||
211 | if (!ifidx) | ||
212 | ifidx = nl80211_get_ifidx(cb); | ||
213 | if (ifidx < 0) | ||
214 | return ifidx; | ||
215 | |||
216 | cb->args[0] = ifidx; | ||
217 | |||
218 | rtnl_lock(); | ||
219 | |||
220 | *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
221 | if (!*dev) { | ||
222 | err = -ENODEV; | ||
223 | goto out_rtnl; | ||
224 | } | ||
225 | |||
226 | *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
227 | if (IS_ERR(dev)) { | ||
228 | err = PTR_ERR(dev); | ||
229 | goto out_rtnl; | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | out_rtnl: | ||
234 | rtnl_unlock(); | ||
235 | return err; | ||
236 | } | ||
237 | |||
238 | static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) | ||
239 | { | ||
240 | cfg80211_unlock_rdev(rdev); | ||
241 | rtnl_unlock(); | ||
242 | } | ||
243 | |||
194 | /* IE validation */ | 244 | /* IE validation */ |
195 | static bool is_valid_ie_attr(const struct nlattr *attr) | 245 | static bool is_valid_ie_attr(const struct nlattr *attr) |
196 | { | 246 | { |
@@ -258,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
258 | struct key_parse { | 308 | struct key_parse { |
259 | struct key_params p; | 309 | struct key_params p; |
260 | int idx; | 310 | int idx; |
311 | int type; | ||
261 | bool def, defmgmt; | 312 | bool def, defmgmt; |
262 | }; | 313 | }; |
263 | 314 | ||
@@ -288,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | |||
288 | if (tb[NL80211_KEY_CIPHER]) | 339 | if (tb[NL80211_KEY_CIPHER]) |
289 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); | 340 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); |
290 | 341 | ||
342 | if (tb[NL80211_KEY_TYPE]) { | ||
343 | k->type = nla_get_u32(tb[NL80211_KEY_TYPE]); | ||
344 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
291 | return 0; | 348 | return 0; |
292 | } | 349 | } |
293 | 350 | ||
@@ -312,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) | |||
312 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; | 369 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; |
313 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; | 370 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; |
314 | 371 | ||
372 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | ||
373 | k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); | ||
374 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | |||
315 | return 0; | 378 | return 0; |
316 | } | 379 | } |
317 | 380 | ||
@@ -321,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) | |||
321 | 384 | ||
322 | memset(k, 0, sizeof(*k)); | 385 | memset(k, 0, sizeof(*k)); |
323 | k->idx = -1; | 386 | k->idx = -1; |
387 | k->type = -1; | ||
324 | 388 | ||
325 | if (info->attrs[NL80211_ATTR_KEY]) | 389 | if (info->attrs[NL80211_ATTR_KEY]) |
326 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); | 390 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); |
@@ -385,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
385 | } else if (parse.defmgmt) | 449 | } else if (parse.defmgmt) |
386 | goto error; | 450 | goto error; |
387 | err = cfg80211_validate_key_settings(rdev, &parse.p, | 451 | err = cfg80211_validate_key_settings(rdev, &parse.p, |
388 | parse.idx, NULL); | 452 | parse.idx, false, NULL); |
389 | if (err) | 453 | if (err) |
390 | goto error; | 454 | goto error; |
391 | result->params[parse.idx].cipher = parse.p.cipher; | 455 | result->params[parse.idx].cipher = parse.p.cipher; |
@@ -404,9 +468,6 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
404 | { | 468 | { |
405 | ASSERT_WDEV_LOCK(wdev); | 469 | ASSERT_WDEV_LOCK(wdev); |
406 | 470 | ||
407 | if (!netif_running(wdev->netdev)) | ||
408 | return -ENETDOWN; | ||
409 | |||
410 | switch (wdev->iftype) { | 471 | switch (wdev->iftype) { |
411 | case NL80211_IFTYPE_AP: | 472 | case NL80211_IFTYPE_AP: |
412 | case NL80211_IFTYPE_AP_VLAN: | 473 | case NL80211_IFTYPE_AP_VLAN: |
@@ -471,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
471 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 532 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
472 | dev->wiphy.max_scan_ie_len); | 533 | dev->wiphy.max_scan_ie_len); |
473 | 534 | ||
535 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) | ||
536 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); | ||
537 | |||
474 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | 538 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, |
475 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 539 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
476 | dev->wiphy.cipher_suites); | 540 | dev->wiphy.cipher_suites); |
@@ -603,6 +667,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
603 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 667 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
604 | } | 668 | } |
605 | CMD(set_channel, SET_CHANNEL); | 669 | CMD(set_channel, SET_CHANNEL); |
670 | CMD(set_wds_peer, SET_WDS_PEER); | ||
606 | 671 | ||
607 | #undef CMD | 672 | #undef CMD |
608 | 673 | ||
@@ -703,28 +768,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
703 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 768 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
704 | { | 769 | { |
705 | struct sk_buff *msg; | 770 | struct sk_buff *msg; |
706 | struct cfg80211_registered_device *dev; | 771 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
707 | |||
708 | dev = cfg80211_get_dev_from_info(info); | ||
709 | if (IS_ERR(dev)) | ||
710 | return PTR_ERR(dev); | ||
711 | 772 | ||
712 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 773 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
713 | if (!msg) | 774 | if (!msg) |
714 | goto out_err; | 775 | return -ENOMEM; |
715 | |||
716 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) | ||
717 | goto out_free; | ||
718 | 776 | ||
719 | cfg80211_unlock_rdev(dev); | 777 | if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) { |
778 | nlmsg_free(msg); | ||
779 | return -ENOBUFS; | ||
780 | } | ||
720 | 781 | ||
721 | return genlmsg_reply(msg, info); | 782 | return genlmsg_reply(msg, info); |
722 | |||
723 | out_free: | ||
724 | nlmsg_free(msg); | ||
725 | out_err: | ||
726 | cfg80211_unlock_rdev(dev); | ||
727 | return -ENOBUFS; | ||
728 | } | 783 | } |
729 | 784 | ||
730 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { | 785 | static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { |
@@ -813,24 +868,36 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
813 | 868 | ||
814 | static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) | 869 | static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) |
815 | { | 870 | { |
816 | struct cfg80211_registered_device *rdev; | 871 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
817 | struct net_device *netdev; | 872 | struct net_device *netdev = info->user_ptr[1]; |
818 | int result; | ||
819 | 873 | ||
820 | rtnl_lock(); | 874 | return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); |
875 | } | ||
821 | 876 | ||
822 | result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); | 877 | static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) |
823 | if (result) | 878 | { |
824 | goto unlock; | 879 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
880 | struct net_device *dev = info->user_ptr[1]; | ||
881 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
882 | const u8 *bssid; | ||
825 | 883 | ||
826 | result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); | 884 | if (!info->attrs[NL80211_ATTR_MAC]) |
885 | return -EINVAL; | ||
827 | 886 | ||
828 | unlock: | 887 | if (netif_running(dev)) |
829 | rtnl_unlock(); | 888 | return -EBUSY; |
830 | 889 | ||
831 | return result; | 890 | if (!rdev->ops->set_wds_peer) |
891 | return -EOPNOTSUPP; | ||
892 | |||
893 | if (wdev->iftype != NL80211_IFTYPE_WDS) | ||
894 | return -EOPNOTSUPP; | ||
895 | |||
896 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
897 | return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); | ||
832 | } | 898 | } |
833 | 899 | ||
900 | |||
834 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | 901 | static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) |
835 | { | 902 | { |
836 | struct cfg80211_registered_device *rdev; | 903 | struct cfg80211_registered_device *rdev; |
@@ -843,8 +910,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
843 | u32 frag_threshold = 0, rts_threshold = 0; | 910 | u32 frag_threshold = 0, rts_threshold = 0; |
844 | u8 coverage_class = 0; | 911 | u8 coverage_class = 0; |
845 | 912 | ||
846 | rtnl_lock(); | ||
847 | |||
848 | /* | 913 | /* |
849 | * Try to find the wiphy and netdev. Normally this | 914 | * Try to find the wiphy and netdev. Normally this |
850 | * function shouldn't need the netdev, but this is | 915 | * function shouldn't need the netdev, but this is |
@@ -871,8 +936,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
871 | rdev = __cfg80211_rdev_from_info(info); | 936 | rdev = __cfg80211_rdev_from_info(info); |
872 | if (IS_ERR(rdev)) { | 937 | if (IS_ERR(rdev)) { |
873 | mutex_unlock(&cfg80211_mutex); | 938 | mutex_unlock(&cfg80211_mutex); |
874 | result = PTR_ERR(rdev); | 939 | return PTR_ERR(rdev); |
875 | goto unlock; | ||
876 | } | 940 | } |
877 | wdev = NULL; | 941 | wdev = NULL; |
878 | netdev = NULL; | 942 | netdev = NULL; |
@@ -1054,8 +1118,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1054 | mutex_unlock(&rdev->mtx); | 1118 | mutex_unlock(&rdev->mtx); |
1055 | if (netdev) | 1119 | if (netdev) |
1056 | dev_put(netdev); | 1120 | dev_put(netdev); |
1057 | unlock: | ||
1058 | rtnl_unlock(); | ||
1059 | return result; | 1121 | return result; |
1060 | } | 1122 | } |
1061 | 1123 | ||
@@ -1135,33 +1197,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1135 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | 1197 | static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) |
1136 | { | 1198 | { |
1137 | struct sk_buff *msg; | 1199 | struct sk_buff *msg; |
1138 | struct cfg80211_registered_device *dev; | 1200 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1139 | struct net_device *netdev; | 1201 | struct net_device *netdev = info->user_ptr[1]; |
1140 | int err; | ||
1141 | |||
1142 | err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); | ||
1143 | if (err) | ||
1144 | return err; | ||
1145 | 1202 | ||
1146 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1203 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1147 | if (!msg) | 1204 | if (!msg) |
1148 | goto out_err; | 1205 | return -ENOMEM; |
1149 | 1206 | ||
1150 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, | 1207 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
1151 | dev, netdev) < 0) | 1208 | dev, netdev) < 0) { |
1152 | goto out_free; | 1209 | nlmsg_free(msg); |
1153 | 1210 | return -ENOBUFS; | |
1154 | dev_put(netdev); | 1211 | } |
1155 | cfg80211_unlock_rdev(dev); | ||
1156 | 1212 | ||
1157 | return genlmsg_reply(msg, info); | 1213 | return genlmsg_reply(msg, info); |
1158 | |||
1159 | out_free: | ||
1160 | nlmsg_free(msg); | ||
1161 | out_err: | ||
1162 | dev_put(netdev); | ||
1163 | cfg80211_unlock_rdev(dev); | ||
1164 | return -ENOBUFS; | ||
1165 | } | 1214 | } |
1166 | 1215 | ||
1167 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { | 1216 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { |
@@ -1221,39 +1270,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, | |||
1221 | 1270 | ||
1222 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 1271 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
1223 | { | 1272 | { |
1224 | struct cfg80211_registered_device *rdev; | 1273 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1225 | struct vif_params params; | 1274 | struct vif_params params; |
1226 | int err; | 1275 | int err; |
1227 | enum nl80211_iftype otype, ntype; | 1276 | enum nl80211_iftype otype, ntype; |
1228 | struct net_device *dev; | 1277 | struct net_device *dev = info->user_ptr[1]; |
1229 | u32 _flags, *flags = NULL; | 1278 | u32 _flags, *flags = NULL; |
1230 | bool change = false; | 1279 | bool change = false; |
1231 | 1280 | ||
1232 | memset(¶ms, 0, sizeof(params)); | 1281 | memset(¶ms, 0, sizeof(params)); |
1233 | 1282 | ||
1234 | rtnl_lock(); | ||
1235 | |||
1236 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1237 | if (err) | ||
1238 | goto unlock_rtnl; | ||
1239 | |||
1240 | otype = ntype = dev->ieee80211_ptr->iftype; | 1283 | otype = ntype = dev->ieee80211_ptr->iftype; |
1241 | 1284 | ||
1242 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 1285 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
1243 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 1286 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
1244 | if (otype != ntype) | 1287 | if (otype != ntype) |
1245 | change = true; | 1288 | change = true; |
1246 | if (ntype > NL80211_IFTYPE_MAX) { | 1289 | if (ntype > NL80211_IFTYPE_MAX) |
1247 | err = -EINVAL; | 1290 | return -EINVAL; |
1248 | goto unlock; | ||
1249 | } | ||
1250 | } | 1291 | } |
1251 | 1292 | ||
1252 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 1293 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
1253 | if (ntype != NL80211_IFTYPE_MESH_POINT) { | 1294 | if (ntype != NL80211_IFTYPE_MESH_POINT) |
1254 | err = -EINVAL; | 1295 | return -EINVAL; |
1255 | goto unlock; | ||
1256 | } | ||
1257 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1296 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
1258 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1297 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
1259 | change = true; | 1298 | change = true; |
@@ -1264,20 +1303,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1264 | change = true; | 1303 | change = true; |
1265 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); | 1304 | err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); |
1266 | if (err) | 1305 | if (err) |
1267 | goto unlock; | 1306 | return err; |
1268 | } else { | 1307 | } else { |
1269 | params.use_4addr = -1; | 1308 | params.use_4addr = -1; |
1270 | } | 1309 | } |
1271 | 1310 | ||
1272 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 1311 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
1273 | if (ntype != NL80211_IFTYPE_MONITOR) { | 1312 | if (ntype != NL80211_IFTYPE_MONITOR) |
1274 | err = -EINVAL; | 1313 | return -EINVAL; |
1275 | goto unlock; | ||
1276 | } | ||
1277 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | 1314 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], |
1278 | &_flags); | 1315 | &_flags); |
1279 | if (err) | 1316 | if (err) |
1280 | goto unlock; | 1317 | return err; |
1281 | 1318 | ||
1282 | flags = &_flags; | 1319 | flags = &_flags; |
1283 | change = true; | 1320 | change = true; |
@@ -1291,17 +1328,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1291 | if (!err && params.use_4addr != -1) | 1328 | if (!err && params.use_4addr != -1) |
1292 | dev->ieee80211_ptr->use_4addr = params.use_4addr; | 1329 | dev->ieee80211_ptr->use_4addr = params.use_4addr; |
1293 | 1330 | ||
1294 | unlock: | ||
1295 | dev_put(dev); | ||
1296 | cfg80211_unlock_rdev(rdev); | ||
1297 | unlock_rtnl: | ||
1298 | rtnl_unlock(); | ||
1299 | return err; | 1331 | return err; |
1300 | } | 1332 | } |
1301 | 1333 | ||
1302 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | 1334 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) |
1303 | { | 1335 | { |
1304 | struct cfg80211_registered_device *rdev; | 1336 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1305 | struct vif_params params; | 1337 | struct vif_params params; |
1306 | int err; | 1338 | int err; |
1307 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1339 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
@@ -1318,19 +1350,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1318 | return -EINVAL; | 1350 | return -EINVAL; |
1319 | } | 1351 | } |
1320 | 1352 | ||
1321 | rtnl_lock(); | ||
1322 | |||
1323 | rdev = cfg80211_get_dev_from_info(info); | ||
1324 | if (IS_ERR(rdev)) { | ||
1325 | err = PTR_ERR(rdev); | ||
1326 | goto unlock_rtnl; | ||
1327 | } | ||
1328 | |||
1329 | if (!rdev->ops->add_virtual_intf || | 1353 | if (!rdev->ops->add_virtual_intf || |
1330 | !(rdev->wiphy.interface_modes & (1 << type))) { | 1354 | !(rdev->wiphy.interface_modes & (1 << type))) |
1331 | err = -EOPNOTSUPP; | 1355 | return -EOPNOTSUPP; |
1332 | goto unlock; | ||
1333 | } | ||
1334 | 1356 | ||
1335 | if (type == NL80211_IFTYPE_MESH_POINT && | 1357 | if (type == NL80211_IFTYPE_MESH_POINT && |
1336 | info->attrs[NL80211_ATTR_MESH_ID]) { | 1358 | info->attrs[NL80211_ATTR_MESH_ID]) { |
@@ -1342,7 +1364,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1342 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1364 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1343 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); | 1365 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); |
1344 | if (err) | 1366 | if (err) |
1345 | goto unlock; | 1367 | return err; |
1346 | } | 1368 | } |
1347 | 1369 | ||
1348 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1370 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
@@ -1352,38 +1374,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1352 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 1374 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1353 | type, err ? NULL : &flags, ¶ms); | 1375 | type, err ? NULL : &flags, ¶ms); |
1354 | 1376 | ||
1355 | unlock: | ||
1356 | cfg80211_unlock_rdev(rdev); | ||
1357 | unlock_rtnl: | ||
1358 | rtnl_unlock(); | ||
1359 | return err; | 1377 | return err; |
1360 | } | 1378 | } |
1361 | 1379 | ||
1362 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1380 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1363 | { | 1381 | { |
1364 | struct cfg80211_registered_device *rdev; | 1382 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1365 | int err; | 1383 | struct net_device *dev = info->user_ptr[1]; |
1366 | struct net_device *dev; | ||
1367 | |||
1368 | rtnl_lock(); | ||
1369 | |||
1370 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1371 | if (err) | ||
1372 | goto unlock_rtnl; | ||
1373 | 1384 | ||
1374 | if (!rdev->ops->del_virtual_intf) { | 1385 | if (!rdev->ops->del_virtual_intf) |
1375 | err = -EOPNOTSUPP; | 1386 | return -EOPNOTSUPP; |
1376 | goto out; | ||
1377 | } | ||
1378 | |||
1379 | err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); | ||
1380 | 1387 | ||
1381 | out: | 1388 | return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); |
1382 | cfg80211_unlock_rdev(rdev); | ||
1383 | dev_put(dev); | ||
1384 | unlock_rtnl: | ||
1385 | rtnl_unlock(); | ||
1386 | return err; | ||
1387 | } | 1389 | } |
1388 | 1390 | ||
1389 | struct get_key_cookie { | 1391 | struct get_key_cookie { |
@@ -1436,11 +1438,12 @@ static void get_key_callback(void *c, struct key_params *params) | |||
1436 | 1438 | ||
1437 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | 1439 | static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) |
1438 | { | 1440 | { |
1439 | struct cfg80211_registered_device *rdev; | 1441 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1440 | int err; | 1442 | int err; |
1441 | struct net_device *dev; | 1443 | struct net_device *dev = info->user_ptr[1]; |
1442 | u8 key_idx = 0; | 1444 | u8 key_idx = 0; |
1443 | u8 *mac_addr = NULL; | 1445 | const u8 *mac_addr = NULL; |
1446 | bool pairwise; | ||
1444 | struct get_key_cookie cookie = { | 1447 | struct get_key_cookie cookie = { |
1445 | .error = 0, | 1448 | .error = 0, |
1446 | }; | 1449 | }; |
@@ -1456,30 +1459,28 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1456 | if (info->attrs[NL80211_ATTR_MAC]) | 1459 | if (info->attrs[NL80211_ATTR_MAC]) |
1457 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1460 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1458 | 1461 | ||
1459 | rtnl_lock(); | 1462 | pairwise = !!mac_addr; |
1460 | 1463 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | |
1461 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1464 | u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); |
1462 | if (err) | 1465 | if (kt >= NUM_NL80211_KEYTYPES) |
1463 | goto unlock_rtnl; | 1466 | return -EINVAL; |
1464 | 1467 | if (kt != NL80211_KEYTYPE_GROUP && | |
1465 | if (!rdev->ops->get_key) { | 1468 | kt != NL80211_KEYTYPE_PAIRWISE) |
1466 | err = -EOPNOTSUPP; | 1469 | return -EINVAL; |
1467 | goto out; | 1470 | pairwise = kt == NL80211_KEYTYPE_PAIRWISE; |
1468 | } | 1471 | } |
1469 | 1472 | ||
1473 | if (!rdev->ops->get_key) | ||
1474 | return -EOPNOTSUPP; | ||
1475 | |||
1470 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1476 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1471 | if (!msg) { | 1477 | if (!msg) |
1472 | err = -ENOMEM; | 1478 | return -ENOMEM; |
1473 | goto out; | ||
1474 | } | ||
1475 | 1479 | ||
1476 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 1480 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
1477 | NL80211_CMD_NEW_KEY); | 1481 | NL80211_CMD_NEW_KEY); |
1478 | 1482 | if (IS_ERR(hdr)) | |
1479 | if (IS_ERR(hdr)) { | 1483 | return PTR_ERR(hdr); |
1480 | err = PTR_ERR(hdr); | ||
1481 | goto free_msg; | ||
1482 | } | ||
1483 | 1484 | ||
1484 | cookie.msg = msg; | 1485 | cookie.msg = msg; |
1485 | cookie.idx = key_idx; | 1486 | cookie.idx = key_idx; |
@@ -1489,8 +1490,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1489 | if (mac_addr) | 1490 | if (mac_addr) |
1490 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1491 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1491 | 1492 | ||
1492 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, | 1493 | if (pairwise && mac_addr && |
1493 | &cookie, get_key_callback); | 1494 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) |
1495 | return -ENOENT; | ||
1496 | |||
1497 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise, | ||
1498 | mac_addr, &cookie, get_key_callback); | ||
1494 | 1499 | ||
1495 | if (err) | 1500 | if (err) |
1496 | goto free_msg; | 1501 | goto free_msg; |
@@ -1499,28 +1504,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1499 | goto nla_put_failure; | 1504 | goto nla_put_failure; |
1500 | 1505 | ||
1501 | genlmsg_end(msg, hdr); | 1506 | genlmsg_end(msg, hdr); |
1502 | err = genlmsg_reply(msg, info); | 1507 | return genlmsg_reply(msg, info); |
1503 | goto out; | ||
1504 | 1508 | ||
1505 | nla_put_failure: | 1509 | nla_put_failure: |
1506 | err = -ENOBUFS; | 1510 | err = -ENOBUFS; |
1507 | free_msg: | 1511 | free_msg: |
1508 | nlmsg_free(msg); | 1512 | nlmsg_free(msg); |
1509 | out: | ||
1510 | cfg80211_unlock_rdev(rdev); | ||
1511 | dev_put(dev); | ||
1512 | unlock_rtnl: | ||
1513 | rtnl_unlock(); | ||
1514 | |||
1515 | return err; | 1513 | return err; |
1516 | } | 1514 | } |
1517 | 1515 | ||
1518 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | 1516 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) |
1519 | { | 1517 | { |
1520 | struct cfg80211_registered_device *rdev; | 1518 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1521 | struct key_parse key; | 1519 | struct key_parse key; |
1522 | int err; | 1520 | int err; |
1523 | struct net_device *dev; | 1521 | struct net_device *dev = info->user_ptr[1]; |
1524 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | 1522 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, |
1525 | u8 key_index); | 1523 | u8 key_index); |
1526 | 1524 | ||
@@ -1535,21 +1533,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1535 | if (!key.def && !key.defmgmt) | 1533 | if (!key.def && !key.defmgmt) |
1536 | return -EINVAL; | 1534 | return -EINVAL; |
1537 | 1535 | ||
1538 | rtnl_lock(); | ||
1539 | |||
1540 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1541 | if (err) | ||
1542 | goto unlock_rtnl; | ||
1543 | |||
1544 | if (key.def) | 1536 | if (key.def) |
1545 | func = rdev->ops->set_default_key; | 1537 | func = rdev->ops->set_default_key; |
1546 | else | 1538 | else |
1547 | func = rdev->ops->set_default_mgmt_key; | 1539 | func = rdev->ops->set_default_mgmt_key; |
1548 | 1540 | ||
1549 | if (!func) { | 1541 | if (!func) |
1550 | err = -EOPNOTSUPP; | 1542 | return -EOPNOTSUPP; |
1551 | goto out; | ||
1552 | } | ||
1553 | 1543 | ||
1554 | wdev_lock(dev->ieee80211_ptr); | 1544 | wdev_lock(dev->ieee80211_ptr); |
1555 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1545 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
@@ -1566,23 +1556,16 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1566 | #endif | 1556 | #endif |
1567 | wdev_unlock(dev->ieee80211_ptr); | 1557 | wdev_unlock(dev->ieee80211_ptr); |
1568 | 1558 | ||
1569 | out: | ||
1570 | cfg80211_unlock_rdev(rdev); | ||
1571 | dev_put(dev); | ||
1572 | |||
1573 | unlock_rtnl: | ||
1574 | rtnl_unlock(); | ||
1575 | |||
1576 | return err; | 1559 | return err; |
1577 | } | 1560 | } |
1578 | 1561 | ||
1579 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | 1562 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) |
1580 | { | 1563 | { |
1581 | struct cfg80211_registered_device *rdev; | 1564 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1582 | int err; | 1565 | int err; |
1583 | struct net_device *dev; | 1566 | struct net_device *dev = info->user_ptr[1]; |
1584 | struct key_parse key; | 1567 | struct key_parse key; |
1585 | u8 *mac_addr = NULL; | 1568 | const u8 *mac_addr = NULL; |
1586 | 1569 | ||
1587 | err = nl80211_parse_key(info, &key); | 1570 | err = nl80211_parse_key(info, &key); |
1588 | if (err) | 1571 | if (err) |
@@ -1594,43 +1577,42 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1594 | if (info->attrs[NL80211_ATTR_MAC]) | 1577 | if (info->attrs[NL80211_ATTR_MAC]) |
1595 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1578 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1596 | 1579 | ||
1597 | rtnl_lock(); | 1580 | if (key.type == -1) { |
1581 | if (mac_addr) | ||
1582 | key.type = NL80211_KEYTYPE_PAIRWISE; | ||
1583 | else | ||
1584 | key.type = NL80211_KEYTYPE_GROUP; | ||
1585 | } | ||
1598 | 1586 | ||
1599 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1587 | /* for now */ |
1600 | if (err) | 1588 | if (key.type != NL80211_KEYTYPE_PAIRWISE && |
1601 | goto unlock_rtnl; | 1589 | key.type != NL80211_KEYTYPE_GROUP) |
1590 | return -EINVAL; | ||
1602 | 1591 | ||
1603 | if (!rdev->ops->add_key) { | 1592 | if (!rdev->ops->add_key) |
1604 | err = -EOPNOTSUPP; | 1593 | return -EOPNOTSUPP; |
1605 | goto out; | ||
1606 | } | ||
1607 | 1594 | ||
1608 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { | 1595 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, |
1609 | err = -EINVAL; | 1596 | key.type == NL80211_KEYTYPE_PAIRWISE, |
1610 | goto out; | 1597 | mac_addr)) |
1611 | } | 1598 | return -EINVAL; |
1612 | 1599 | ||
1613 | wdev_lock(dev->ieee80211_ptr); | 1600 | wdev_lock(dev->ieee80211_ptr); |
1614 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1601 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1615 | if (!err) | 1602 | if (!err) |
1616 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, | 1603 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, |
1604 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1617 | mac_addr, &key.p); | 1605 | mac_addr, &key.p); |
1618 | wdev_unlock(dev->ieee80211_ptr); | 1606 | wdev_unlock(dev->ieee80211_ptr); |
1619 | 1607 | ||
1620 | out: | ||
1621 | cfg80211_unlock_rdev(rdev); | ||
1622 | dev_put(dev); | ||
1623 | unlock_rtnl: | ||
1624 | rtnl_unlock(); | ||
1625 | |||
1626 | return err; | 1608 | return err; |
1627 | } | 1609 | } |
1628 | 1610 | ||
1629 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | 1611 | static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) |
1630 | { | 1612 | { |
1631 | struct cfg80211_registered_device *rdev; | 1613 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1632 | int err; | 1614 | int err; |
1633 | struct net_device *dev; | 1615 | struct net_device *dev = info->user_ptr[1]; |
1634 | u8 *mac_addr = NULL; | 1616 | u8 *mac_addr = NULL; |
1635 | struct key_parse key; | 1617 | struct key_parse key; |
1636 | 1618 | ||
@@ -1641,21 +1623,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1641 | if (info->attrs[NL80211_ATTR_MAC]) | 1623 | if (info->attrs[NL80211_ATTR_MAC]) |
1642 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1624 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1643 | 1625 | ||
1644 | rtnl_lock(); | 1626 | if (key.type == -1) { |
1627 | if (mac_addr) | ||
1628 | key.type = NL80211_KEYTYPE_PAIRWISE; | ||
1629 | else | ||
1630 | key.type = NL80211_KEYTYPE_GROUP; | ||
1631 | } | ||
1645 | 1632 | ||
1646 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 1633 | /* for now */ |
1647 | if (err) | 1634 | if (key.type != NL80211_KEYTYPE_PAIRWISE && |
1648 | goto unlock_rtnl; | 1635 | key.type != NL80211_KEYTYPE_GROUP) |
1636 | return -EINVAL; | ||
1649 | 1637 | ||
1650 | if (!rdev->ops->del_key) { | 1638 | if (!rdev->ops->del_key) |
1651 | err = -EOPNOTSUPP; | 1639 | return -EOPNOTSUPP; |
1652 | goto out; | ||
1653 | } | ||
1654 | 1640 | ||
1655 | wdev_lock(dev->ieee80211_ptr); | 1641 | wdev_lock(dev->ieee80211_ptr); |
1656 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1642 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1643 | |||
1644 | if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && | ||
1645 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
1646 | err = -ENOENT; | ||
1647 | |||
1657 | if (!err) | 1648 | if (!err) |
1658 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); | 1649 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, |
1650 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1651 | mac_addr); | ||
1659 | 1652 | ||
1660 | #ifdef CONFIG_CFG80211_WEXT | 1653 | #ifdef CONFIG_CFG80211_WEXT |
1661 | if (!err) { | 1654 | if (!err) { |
@@ -1667,13 +1660,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1667 | #endif | 1660 | #endif |
1668 | wdev_unlock(dev->ieee80211_ptr); | 1661 | wdev_unlock(dev->ieee80211_ptr); |
1669 | 1662 | ||
1670 | out: | ||
1671 | cfg80211_unlock_rdev(rdev); | ||
1672 | dev_put(dev); | ||
1673 | |||
1674 | unlock_rtnl: | ||
1675 | rtnl_unlock(); | ||
1676 | |||
1677 | return err; | 1663 | return err; |
1678 | } | 1664 | } |
1679 | 1665 | ||
@@ -1681,36 +1667,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1681 | { | 1667 | { |
1682 | int (*call)(struct wiphy *wiphy, struct net_device *dev, | 1668 | int (*call)(struct wiphy *wiphy, struct net_device *dev, |
1683 | struct beacon_parameters *info); | 1669 | struct beacon_parameters *info); |
1684 | struct cfg80211_registered_device *rdev; | 1670 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1685 | int err; | 1671 | struct net_device *dev = info->user_ptr[1]; |
1686 | struct net_device *dev; | ||
1687 | struct beacon_parameters params; | 1672 | struct beacon_parameters params; |
1688 | int haveinfo = 0; | 1673 | int haveinfo = 0; |
1689 | 1674 | ||
1690 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | 1675 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) |
1691 | return -EINVAL; | 1676 | return -EINVAL; |
1692 | 1677 | ||
1693 | rtnl_lock(); | ||
1694 | |||
1695 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1696 | if (err) | ||
1697 | goto unlock_rtnl; | ||
1698 | |||
1699 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 1678 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
1700 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 1679 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1701 | err = -EOPNOTSUPP; | 1680 | return -EOPNOTSUPP; |
1702 | goto out; | ||
1703 | } | ||
1704 | 1681 | ||
1705 | switch (info->genlhdr->cmd) { | 1682 | switch (info->genlhdr->cmd) { |
1706 | case NL80211_CMD_NEW_BEACON: | 1683 | case NL80211_CMD_NEW_BEACON: |
1707 | /* these are required for NEW_BEACON */ | 1684 | /* these are required for NEW_BEACON */ |
1708 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || | 1685 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || |
1709 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || | 1686 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || |
1710 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1687 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) |
1711 | err = -EINVAL; | 1688 | return -EINVAL; |
1712 | goto out; | ||
1713 | } | ||
1714 | 1689 | ||
1715 | call = rdev->ops->add_beacon; | 1690 | call = rdev->ops->add_beacon; |
1716 | break; | 1691 | break; |
@@ -1719,14 +1694,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1719 | break; | 1694 | break; |
1720 | default: | 1695 | default: |
1721 | WARN_ON(1); | 1696 | WARN_ON(1); |
1722 | err = -EOPNOTSUPP; | 1697 | return -EOPNOTSUPP; |
1723 | goto out; | ||
1724 | } | 1698 | } |
1725 | 1699 | ||
1726 | if (!call) { | 1700 | if (!call) |
1727 | err = -EOPNOTSUPP; | 1701 | return -EOPNOTSUPP; |
1728 | goto out; | ||
1729 | } | ||
1730 | 1702 | ||
1731 | memset(¶ms, 0, sizeof(params)); | 1703 | memset(¶ms, 0, sizeof(params)); |
1732 | 1704 | ||
@@ -1756,53 +1728,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1756 | haveinfo = 1; | 1728 | haveinfo = 1; |
1757 | } | 1729 | } |
1758 | 1730 | ||
1759 | if (!haveinfo) { | 1731 | if (!haveinfo) |
1760 | err = -EINVAL; | 1732 | return -EINVAL; |
1761 | goto out; | ||
1762 | } | ||
1763 | |||
1764 | err = call(&rdev->wiphy, dev, ¶ms); | ||
1765 | |||
1766 | out: | ||
1767 | cfg80211_unlock_rdev(rdev); | ||
1768 | dev_put(dev); | ||
1769 | unlock_rtnl: | ||
1770 | rtnl_unlock(); | ||
1771 | 1733 | ||
1772 | return err; | 1734 | return call(&rdev->wiphy, dev, ¶ms); |
1773 | } | 1735 | } |
1774 | 1736 | ||
1775 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 1737 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) |
1776 | { | 1738 | { |
1777 | struct cfg80211_registered_device *rdev; | 1739 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1778 | int err; | 1740 | struct net_device *dev = info->user_ptr[1]; |
1779 | struct net_device *dev; | ||
1780 | 1741 | ||
1781 | rtnl_lock(); | 1742 | if (!rdev->ops->del_beacon) |
1782 | 1743 | return -EOPNOTSUPP; | |
1783 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
1784 | if (err) | ||
1785 | goto unlock_rtnl; | ||
1786 | |||
1787 | if (!rdev->ops->del_beacon) { | ||
1788 | err = -EOPNOTSUPP; | ||
1789 | goto out; | ||
1790 | } | ||
1791 | 1744 | ||
1792 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 1745 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
1793 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 1746 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1794 | err = -EOPNOTSUPP; | 1747 | return -EOPNOTSUPP; |
1795 | goto out; | ||
1796 | } | ||
1797 | err = rdev->ops->del_beacon(&rdev->wiphy, dev); | ||
1798 | |||
1799 | out: | ||
1800 | cfg80211_unlock_rdev(rdev); | ||
1801 | dev_put(dev); | ||
1802 | unlock_rtnl: | ||
1803 | rtnl_unlock(); | ||
1804 | 1748 | ||
1805 | return err; | 1749 | return rdev->ops->del_beacon(&rdev->wiphy, dev); |
1806 | } | 1750 | } |
1807 | 1751 | ||
1808 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 1752 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -1923,6 +1867,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1923 | if (sinfo->filled & STATION_INFO_TX_PACKETS) | 1867 | if (sinfo->filled & STATION_INFO_TX_PACKETS) |
1924 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, | 1868 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, |
1925 | sinfo->tx_packets); | 1869 | sinfo->tx_packets); |
1870 | if (sinfo->filled & STATION_INFO_TX_RETRIES) | ||
1871 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES, | ||
1872 | sinfo->tx_retries); | ||
1873 | if (sinfo->filled & STATION_INFO_TX_FAILED) | ||
1874 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, | ||
1875 | sinfo->tx_failed); | ||
1926 | nla_nest_end(msg, sinfoattr); | 1876 | nla_nest_end(msg, sinfoattr); |
1927 | 1877 | ||
1928 | return genlmsg_end(msg, hdr); | 1878 | return genlmsg_end(msg, hdr); |
@@ -1939,28 +1889,12 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1939 | struct cfg80211_registered_device *dev; | 1889 | struct cfg80211_registered_device *dev; |
1940 | struct net_device *netdev; | 1890 | struct net_device *netdev; |
1941 | u8 mac_addr[ETH_ALEN]; | 1891 | u8 mac_addr[ETH_ALEN]; |
1942 | int ifidx = cb->args[0]; | ||
1943 | int sta_idx = cb->args[1]; | 1892 | int sta_idx = cb->args[1]; |
1944 | int err; | 1893 | int err; |
1945 | 1894 | ||
1946 | if (!ifidx) | 1895 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
1947 | ifidx = nl80211_get_ifidx(cb); | 1896 | if (err) |
1948 | if (ifidx < 0) | 1897 | return err; |
1949 | return ifidx; | ||
1950 | |||
1951 | rtnl_lock(); | ||
1952 | |||
1953 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1954 | if (!netdev) { | ||
1955 | err = -ENODEV; | ||
1956 | goto out_rtnl; | ||
1957 | } | ||
1958 | |||
1959 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
1960 | if (IS_ERR(dev)) { | ||
1961 | err = PTR_ERR(dev); | ||
1962 | goto out_rtnl; | ||
1963 | } | ||
1964 | 1898 | ||
1965 | if (!dev->ops->dump_station) { | 1899 | if (!dev->ops->dump_station) { |
1966 | err = -EOPNOTSUPP; | 1900 | err = -EOPNOTSUPP; |
@@ -1990,21 +1924,19 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1990 | cb->args[1] = sta_idx; | 1924 | cb->args[1] = sta_idx; |
1991 | err = skb->len; | 1925 | err = skb->len; |
1992 | out_err: | 1926 | out_err: |
1993 | cfg80211_unlock_rdev(dev); | 1927 | nl80211_finish_netdev_dump(dev); |
1994 | out_rtnl: | ||
1995 | rtnl_unlock(); | ||
1996 | 1928 | ||
1997 | return err; | 1929 | return err; |
1998 | } | 1930 | } |
1999 | 1931 | ||
2000 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 1932 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
2001 | { | 1933 | { |
2002 | struct cfg80211_registered_device *rdev; | 1934 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2003 | int err; | 1935 | struct net_device *dev = info->user_ptr[1]; |
2004 | struct net_device *dev; | ||
2005 | struct station_info sinfo; | 1936 | struct station_info sinfo; |
2006 | struct sk_buff *msg; | 1937 | struct sk_buff *msg; |
2007 | u8 *mac_addr = NULL; | 1938 | u8 *mac_addr = NULL; |
1939 | int err; | ||
2008 | 1940 | ||
2009 | memset(&sinfo, 0, sizeof(sinfo)); | 1941 | memset(&sinfo, 0, sizeof(sinfo)); |
2010 | 1942 | ||
@@ -2013,41 +1945,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
2013 | 1945 | ||
2014 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1946 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2015 | 1947 | ||
2016 | rtnl_lock(); | 1948 | if (!rdev->ops->get_station) |
2017 | 1949 | return -EOPNOTSUPP; | |
2018 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2019 | if (err) | ||
2020 | goto out_rtnl; | ||
2021 | |||
2022 | if (!rdev->ops->get_station) { | ||
2023 | err = -EOPNOTSUPP; | ||
2024 | goto out; | ||
2025 | } | ||
2026 | 1950 | ||
2027 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); | 1951 | err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); |
2028 | if (err) | 1952 | if (err) |
2029 | goto out; | 1953 | return err; |
2030 | 1954 | ||
2031 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1955 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2032 | if (!msg) | 1956 | if (!msg) |
2033 | goto out; | 1957 | return -ENOMEM; |
2034 | 1958 | ||
2035 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | 1959 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, |
2036 | dev, mac_addr, &sinfo) < 0) | 1960 | dev, mac_addr, &sinfo) < 0) { |
2037 | goto out_free; | 1961 | nlmsg_free(msg); |
2038 | 1962 | return -ENOBUFS; | |
2039 | err = genlmsg_reply(msg, info); | 1963 | } |
2040 | goto out; | ||
2041 | |||
2042 | out_free: | ||
2043 | nlmsg_free(msg); | ||
2044 | out: | ||
2045 | cfg80211_unlock_rdev(rdev); | ||
2046 | dev_put(dev); | ||
2047 | out_rtnl: | ||
2048 | rtnl_unlock(); | ||
2049 | 1964 | ||
2050 | return err; | 1965 | return genlmsg_reply(msg, info); |
2051 | } | 1966 | } |
2052 | 1967 | ||
2053 | /* | 1968 | /* |
@@ -2077,9 +1992,9 @@ static int get_vlan(struct genl_info *info, | |||
2077 | 1992 | ||
2078 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 1993 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
2079 | { | 1994 | { |
2080 | struct cfg80211_registered_device *rdev; | 1995 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2081 | int err; | 1996 | int err; |
2082 | struct net_device *dev; | 1997 | struct net_device *dev = info->user_ptr[1]; |
2083 | struct station_parameters params; | 1998 | struct station_parameters params; |
2084 | u8 *mac_addr = NULL; | 1999 | u8 *mac_addr = NULL; |
2085 | 2000 | ||
@@ -2117,12 +2032,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2117 | params.plink_action = | 2032 | params.plink_action = |
2118 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 2033 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
2119 | 2034 | ||
2120 | rtnl_lock(); | ||
2121 | |||
2122 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2123 | if (err) | ||
2124 | goto out_rtnl; | ||
2125 | |||
2126 | err = get_vlan(info, rdev, ¶ms.vlan); | 2035 | err = get_vlan(info, rdev, ¶ms.vlan); |
2127 | if (err) | 2036 | if (err) |
2128 | goto out; | 2037 | goto out; |
@@ -2184,19 +2093,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2184 | out: | 2093 | out: |
2185 | if (params.vlan) | 2094 | if (params.vlan) |
2186 | dev_put(params.vlan); | 2095 | dev_put(params.vlan); |
2187 | cfg80211_unlock_rdev(rdev); | ||
2188 | dev_put(dev); | ||
2189 | out_rtnl: | ||
2190 | rtnl_unlock(); | ||
2191 | 2096 | ||
2192 | return err; | 2097 | return err; |
2193 | } | 2098 | } |
2194 | 2099 | ||
2195 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 2100 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
2196 | { | 2101 | { |
2197 | struct cfg80211_registered_device *rdev; | 2102 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2198 | int err; | 2103 | int err; |
2199 | struct net_device *dev; | 2104 | struct net_device *dev = info->user_ptr[1]; |
2200 | struct station_parameters params; | 2105 | struct station_parameters params; |
2201 | u8 *mac_addr = NULL; | 2106 | u8 *mac_addr = NULL; |
2202 | 2107 | ||
@@ -2233,18 +2138,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2233 | if (parse_station_flags(info, ¶ms)) | 2138 | if (parse_station_flags(info, ¶ms)) |
2234 | return -EINVAL; | 2139 | return -EINVAL; |
2235 | 2140 | ||
2236 | rtnl_lock(); | ||
2237 | |||
2238 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2239 | if (err) | ||
2240 | goto out_rtnl; | ||
2241 | |||
2242 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2141 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2243 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2142 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2244 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 2143 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2245 | err = -EINVAL; | 2144 | return -EINVAL; |
2246 | goto out; | ||
2247 | } | ||
2248 | 2145 | ||
2249 | err = get_vlan(info, rdev, ¶ms.vlan); | 2146 | err = get_vlan(info, rdev, ¶ms.vlan); |
2250 | if (err) | 2147 | if (err) |
@@ -2258,62 +2155,33 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2258 | goto out; | 2155 | goto out; |
2259 | } | 2156 | } |
2260 | 2157 | ||
2261 | if (!netif_running(dev)) { | ||
2262 | err = -ENETDOWN; | ||
2263 | goto out; | ||
2264 | } | ||
2265 | |||
2266 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); | 2158 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); |
2267 | 2159 | ||
2268 | out: | 2160 | out: |
2269 | if (params.vlan) | 2161 | if (params.vlan) |
2270 | dev_put(params.vlan); | 2162 | dev_put(params.vlan); |
2271 | cfg80211_unlock_rdev(rdev); | ||
2272 | dev_put(dev); | ||
2273 | out_rtnl: | ||
2274 | rtnl_unlock(); | ||
2275 | |||
2276 | return err; | 2163 | return err; |
2277 | } | 2164 | } |
2278 | 2165 | ||
2279 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | 2166 | static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) |
2280 | { | 2167 | { |
2281 | struct cfg80211_registered_device *rdev; | 2168 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2282 | int err; | 2169 | struct net_device *dev = info->user_ptr[1]; |
2283 | struct net_device *dev; | ||
2284 | u8 *mac_addr = NULL; | 2170 | u8 *mac_addr = NULL; |
2285 | 2171 | ||
2286 | if (info->attrs[NL80211_ATTR_MAC]) | 2172 | if (info->attrs[NL80211_ATTR_MAC]) |
2287 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2173 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2288 | 2174 | ||
2289 | rtnl_lock(); | ||
2290 | |||
2291 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2292 | if (err) | ||
2293 | goto out_rtnl; | ||
2294 | |||
2295 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2175 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2296 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2176 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2297 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 2177 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && |
2298 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 2178 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2299 | err = -EINVAL; | 2179 | return -EINVAL; |
2300 | goto out; | ||
2301 | } | ||
2302 | |||
2303 | if (!rdev->ops->del_station) { | ||
2304 | err = -EOPNOTSUPP; | ||
2305 | goto out; | ||
2306 | } | ||
2307 | |||
2308 | err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); | ||
2309 | 2180 | ||
2310 | out: | 2181 | if (!rdev->ops->del_station) |
2311 | cfg80211_unlock_rdev(rdev); | 2182 | return -EOPNOTSUPP; |
2312 | dev_put(dev); | ||
2313 | out_rtnl: | ||
2314 | rtnl_unlock(); | ||
2315 | 2183 | ||
2316 | return err; | 2184 | return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); |
2317 | } | 2185 | } |
2318 | 2186 | ||
2319 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | 2187 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, |
@@ -2376,28 +2244,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2376 | struct net_device *netdev; | 2244 | struct net_device *netdev; |
2377 | u8 dst[ETH_ALEN]; | 2245 | u8 dst[ETH_ALEN]; |
2378 | u8 next_hop[ETH_ALEN]; | 2246 | u8 next_hop[ETH_ALEN]; |
2379 | int ifidx = cb->args[0]; | ||
2380 | int path_idx = cb->args[1]; | 2247 | int path_idx = cb->args[1]; |
2381 | int err; | 2248 | int err; |
2382 | 2249 | ||
2383 | if (!ifidx) | 2250 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
2384 | ifidx = nl80211_get_ifidx(cb); | 2251 | if (err) |
2385 | if (ifidx < 0) | 2252 | return err; |
2386 | return ifidx; | ||
2387 | |||
2388 | rtnl_lock(); | ||
2389 | |||
2390 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
2391 | if (!netdev) { | ||
2392 | err = -ENODEV; | ||
2393 | goto out_rtnl; | ||
2394 | } | ||
2395 | |||
2396 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
2397 | if (IS_ERR(dev)) { | ||
2398 | err = PTR_ERR(dev); | ||
2399 | goto out_rtnl; | ||
2400 | } | ||
2401 | 2253 | ||
2402 | if (!dev->ops->dump_mpath) { | 2254 | if (!dev->ops->dump_mpath) { |
2403 | err = -EOPNOTSUPP; | 2255 | err = -EOPNOTSUPP; |
@@ -2431,18 +2283,15 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2431 | cb->args[1] = path_idx; | 2283 | cb->args[1] = path_idx; |
2432 | err = skb->len; | 2284 | err = skb->len; |
2433 | out_err: | 2285 | out_err: |
2434 | cfg80211_unlock_rdev(dev); | 2286 | nl80211_finish_netdev_dump(dev); |
2435 | out_rtnl: | ||
2436 | rtnl_unlock(); | ||
2437 | |||
2438 | return err; | 2287 | return err; |
2439 | } | 2288 | } |
2440 | 2289 | ||
2441 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | 2290 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) |
2442 | { | 2291 | { |
2443 | struct cfg80211_registered_device *rdev; | 2292 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2444 | int err; | 2293 | int err; |
2445 | struct net_device *dev; | 2294 | struct net_device *dev = info->user_ptr[1]; |
2446 | struct mpath_info pinfo; | 2295 | struct mpath_info pinfo; |
2447 | struct sk_buff *msg; | 2296 | struct sk_buff *msg; |
2448 | u8 *dst = NULL; | 2297 | u8 *dst = NULL; |
@@ -2455,53 +2304,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2455 | 2304 | ||
2456 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2305 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2457 | 2306 | ||
2458 | rtnl_lock(); | 2307 | if (!rdev->ops->get_mpath) |
2459 | 2308 | return -EOPNOTSUPP; | |
2460 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2461 | if (err) | ||
2462 | goto out_rtnl; | ||
2463 | |||
2464 | if (!rdev->ops->get_mpath) { | ||
2465 | err = -EOPNOTSUPP; | ||
2466 | goto out; | ||
2467 | } | ||
2468 | 2309 | ||
2469 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 2310 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2470 | err = -EOPNOTSUPP; | 2311 | return -EOPNOTSUPP; |
2471 | goto out; | ||
2472 | } | ||
2473 | 2312 | ||
2474 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); | 2313 | err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); |
2475 | if (err) | 2314 | if (err) |
2476 | goto out; | 2315 | return err; |
2477 | 2316 | ||
2478 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2317 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2479 | if (!msg) | 2318 | if (!msg) |
2480 | goto out; | 2319 | return -ENOMEM; |
2481 | 2320 | ||
2482 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, | 2321 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, |
2483 | dev, dst, next_hop, &pinfo) < 0) | 2322 | dev, dst, next_hop, &pinfo) < 0) { |
2484 | goto out_free; | 2323 | nlmsg_free(msg); |
2485 | 2324 | return -ENOBUFS; | |
2486 | err = genlmsg_reply(msg, info); | 2325 | } |
2487 | goto out; | ||
2488 | |||
2489 | out_free: | ||
2490 | nlmsg_free(msg); | ||
2491 | out: | ||
2492 | cfg80211_unlock_rdev(rdev); | ||
2493 | dev_put(dev); | ||
2494 | out_rtnl: | ||
2495 | rtnl_unlock(); | ||
2496 | 2326 | ||
2497 | return err; | 2327 | return genlmsg_reply(msg, info); |
2498 | } | 2328 | } |
2499 | 2329 | ||
2500 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | 2330 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) |
2501 | { | 2331 | { |
2502 | struct cfg80211_registered_device *rdev; | 2332 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2503 | int err; | 2333 | struct net_device *dev = info->user_ptr[1]; |
2504 | struct net_device *dev; | ||
2505 | u8 *dst = NULL; | 2334 | u8 *dst = NULL; |
2506 | u8 *next_hop = NULL; | 2335 | u8 *next_hop = NULL; |
2507 | 2336 | ||
@@ -2514,42 +2343,19 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2514 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2343 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2515 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2344 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2516 | 2345 | ||
2517 | rtnl_lock(); | 2346 | if (!rdev->ops->change_mpath) |
2518 | 2347 | return -EOPNOTSUPP; | |
2519 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2520 | if (err) | ||
2521 | goto out_rtnl; | ||
2522 | |||
2523 | if (!rdev->ops->change_mpath) { | ||
2524 | err = -EOPNOTSUPP; | ||
2525 | goto out; | ||
2526 | } | ||
2527 | |||
2528 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2529 | err = -EOPNOTSUPP; | ||
2530 | goto out; | ||
2531 | } | ||
2532 | |||
2533 | if (!netif_running(dev)) { | ||
2534 | err = -ENETDOWN; | ||
2535 | goto out; | ||
2536 | } | ||
2537 | |||
2538 | err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); | ||
2539 | 2348 | ||
2540 | out: | 2349 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2541 | cfg80211_unlock_rdev(rdev); | 2350 | return -EOPNOTSUPP; |
2542 | dev_put(dev); | ||
2543 | out_rtnl: | ||
2544 | rtnl_unlock(); | ||
2545 | 2351 | ||
2546 | return err; | 2352 | return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); |
2547 | } | 2353 | } |
2354 | |||
2548 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 2355 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) |
2549 | { | 2356 | { |
2550 | struct cfg80211_registered_device *rdev; | 2357 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2551 | int err; | 2358 | struct net_device *dev = info->user_ptr[1]; |
2552 | struct net_device *dev; | ||
2553 | u8 *dst = NULL; | 2359 | u8 *dst = NULL; |
2554 | u8 *next_hop = NULL; | 2360 | u8 *next_hop = NULL; |
2555 | 2361 | ||
@@ -2562,75 +2368,34 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
2562 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2368 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2563 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 2369 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
2564 | 2370 | ||
2565 | rtnl_lock(); | 2371 | if (!rdev->ops->add_mpath) |
2566 | 2372 | return -EOPNOTSUPP; | |
2567 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2568 | if (err) | ||
2569 | goto out_rtnl; | ||
2570 | |||
2571 | if (!rdev->ops->add_mpath) { | ||
2572 | err = -EOPNOTSUPP; | ||
2573 | goto out; | ||
2574 | } | ||
2575 | |||
2576 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
2577 | err = -EOPNOTSUPP; | ||
2578 | goto out; | ||
2579 | } | ||
2580 | |||
2581 | if (!netif_running(dev)) { | ||
2582 | err = -ENETDOWN; | ||
2583 | goto out; | ||
2584 | } | ||
2585 | |||
2586 | err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); | ||
2587 | 2373 | ||
2588 | out: | 2374 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) |
2589 | cfg80211_unlock_rdev(rdev); | 2375 | return -EOPNOTSUPP; |
2590 | dev_put(dev); | ||
2591 | out_rtnl: | ||
2592 | rtnl_unlock(); | ||
2593 | 2376 | ||
2594 | return err; | 2377 | return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); |
2595 | } | 2378 | } |
2596 | 2379 | ||
2597 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | 2380 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) |
2598 | { | 2381 | { |
2599 | struct cfg80211_registered_device *rdev; | 2382 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2600 | int err; | 2383 | struct net_device *dev = info->user_ptr[1]; |
2601 | struct net_device *dev; | ||
2602 | u8 *dst = NULL; | 2384 | u8 *dst = NULL; |
2603 | 2385 | ||
2604 | if (info->attrs[NL80211_ATTR_MAC]) | 2386 | if (info->attrs[NL80211_ATTR_MAC]) |
2605 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 2387 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2606 | 2388 | ||
2607 | rtnl_lock(); | 2389 | if (!rdev->ops->del_mpath) |
2608 | 2390 | return -EOPNOTSUPP; | |
2609 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2610 | if (err) | ||
2611 | goto out_rtnl; | ||
2612 | |||
2613 | if (!rdev->ops->del_mpath) { | ||
2614 | err = -EOPNOTSUPP; | ||
2615 | goto out; | ||
2616 | } | ||
2617 | |||
2618 | err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); | ||
2619 | |||
2620 | out: | ||
2621 | cfg80211_unlock_rdev(rdev); | ||
2622 | dev_put(dev); | ||
2623 | out_rtnl: | ||
2624 | rtnl_unlock(); | ||
2625 | 2391 | ||
2626 | return err; | 2392 | return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); |
2627 | } | 2393 | } |
2628 | 2394 | ||
2629 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | 2395 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) |
2630 | { | 2396 | { |
2631 | struct cfg80211_registered_device *rdev; | 2397 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2632 | int err; | 2398 | struct net_device *dev = info->user_ptr[1]; |
2633 | struct net_device *dev; | ||
2634 | struct bss_parameters params; | 2399 | struct bss_parameters params; |
2635 | 2400 | ||
2636 | memset(¶ms, 0, sizeof(params)); | 2401 | memset(¶ms, 0, sizeof(params)); |
@@ -2658,32 +2423,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2658 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) | 2423 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) |
2659 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); | 2424 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); |
2660 | 2425 | ||
2661 | rtnl_lock(); | 2426 | if (!rdev->ops->change_bss) |
2662 | 2427 | return -EOPNOTSUPP; | |
2663 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2664 | if (err) | ||
2665 | goto out_rtnl; | ||
2666 | |||
2667 | if (!rdev->ops->change_bss) { | ||
2668 | err = -EOPNOTSUPP; | ||
2669 | goto out; | ||
2670 | } | ||
2671 | 2428 | ||
2672 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2429 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2673 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | 2430 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2674 | err = -EOPNOTSUPP; | 2431 | return -EOPNOTSUPP; |
2675 | goto out; | ||
2676 | } | ||
2677 | |||
2678 | err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); | ||
2679 | |||
2680 | out: | ||
2681 | cfg80211_unlock_rdev(rdev); | ||
2682 | dev_put(dev); | ||
2683 | out_rtnl: | ||
2684 | rtnl_unlock(); | ||
2685 | 2432 | ||
2686 | return err; | 2433 | return rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); |
2687 | } | 2434 | } |
2688 | 2435 | ||
2689 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | 2436 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { |
@@ -2762,37 +2509,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2762 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2509 | static int nl80211_get_mesh_params(struct sk_buff *skb, |
2763 | struct genl_info *info) | 2510 | struct genl_info *info) |
2764 | { | 2511 | { |
2765 | struct cfg80211_registered_device *rdev; | 2512 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2766 | struct mesh_config cur_params; | 2513 | struct mesh_config cur_params; |
2767 | int err; | 2514 | int err; |
2768 | struct net_device *dev; | 2515 | struct net_device *dev = info->user_ptr[1]; |
2769 | void *hdr; | 2516 | void *hdr; |
2770 | struct nlattr *pinfoattr; | 2517 | struct nlattr *pinfoattr; |
2771 | struct sk_buff *msg; | 2518 | struct sk_buff *msg; |
2772 | 2519 | ||
2773 | rtnl_lock(); | 2520 | if (!rdev->ops->get_mesh_params) |
2774 | 2521 | return -EOPNOTSUPP; | |
2775 | /* Look up our device */ | ||
2776 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2777 | if (err) | ||
2778 | goto out_rtnl; | ||
2779 | |||
2780 | if (!rdev->ops->get_mesh_params) { | ||
2781 | err = -EOPNOTSUPP; | ||
2782 | goto out; | ||
2783 | } | ||
2784 | 2522 | ||
2785 | /* Get the mesh params */ | 2523 | /* Get the mesh params */ |
2786 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); | 2524 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); |
2787 | if (err) | 2525 | if (err) |
2788 | goto out; | 2526 | return err; |
2789 | 2527 | ||
2790 | /* Draw up a netlink message to send back */ | 2528 | /* Draw up a netlink message to send back */ |
2791 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 2529 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2792 | if (!msg) { | 2530 | if (!msg) |
2793 | err = -ENOBUFS; | 2531 | return -ENOMEM; |
2794 | goto out; | ||
2795 | } | ||
2796 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 2532 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
2797 | NL80211_CMD_GET_MESH_PARAMS); | 2533 | NL80211_CMD_GET_MESH_PARAMS); |
2798 | if (!hdr) | 2534 | if (!hdr) |
@@ -2831,21 +2567,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2831 | cur_params.dot11MeshHWMPRootMode); | 2567 | cur_params.dot11MeshHWMPRootMode); |
2832 | nla_nest_end(msg, pinfoattr); | 2568 | nla_nest_end(msg, pinfoattr); |
2833 | genlmsg_end(msg, hdr); | 2569 | genlmsg_end(msg, hdr); |
2834 | err = genlmsg_reply(msg, info); | 2570 | return genlmsg_reply(msg, info); |
2835 | goto out; | ||
2836 | 2571 | ||
2837 | nla_put_failure: | 2572 | nla_put_failure: |
2838 | genlmsg_cancel(msg, hdr); | 2573 | genlmsg_cancel(msg, hdr); |
2839 | nlmsg_free(msg); | 2574 | nlmsg_free(msg); |
2840 | err = -EMSGSIZE; | 2575 | return -ENOBUFS; |
2841 | out: | ||
2842 | /* Cleanup */ | ||
2843 | cfg80211_unlock_rdev(rdev); | ||
2844 | dev_put(dev); | ||
2845 | out_rtnl: | ||
2846 | rtnl_unlock(); | ||
2847 | |||
2848 | return err; | ||
2849 | } | 2576 | } |
2850 | 2577 | ||
2851 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | 2578 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ |
@@ -2875,10 +2602,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2875 | 2602 | ||
2876 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2603 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) |
2877 | { | 2604 | { |
2878 | int err; | ||
2879 | u32 mask; | 2605 | u32 mask; |
2880 | struct cfg80211_registered_device *rdev; | 2606 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2881 | struct net_device *dev; | 2607 | struct net_device *dev = info->user_ptr[1]; |
2882 | struct mesh_config cfg; | 2608 | struct mesh_config cfg; |
2883 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; | 2609 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; |
2884 | struct nlattr *parent_attr; | 2610 | struct nlattr *parent_attr; |
@@ -2890,16 +2616,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2890 | parent_attr, nl80211_meshconf_params_policy)) | 2616 | parent_attr, nl80211_meshconf_params_policy)) |
2891 | return -EINVAL; | 2617 | return -EINVAL; |
2892 | 2618 | ||
2893 | rtnl_lock(); | 2619 | if (!rdev->ops->set_mesh_params) |
2894 | 2620 | return -EOPNOTSUPP; | |
2895 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
2896 | if (err) | ||
2897 | goto out_rtnl; | ||
2898 | |||
2899 | if (!rdev->ops->set_mesh_params) { | ||
2900 | err = -EOPNOTSUPP; | ||
2901 | goto out; | ||
2902 | } | ||
2903 | 2621 | ||
2904 | /* This makes sure that there aren't more than 32 mesh config | 2622 | /* This makes sure that there aren't more than 32 mesh config |
2905 | * parameters (otherwise our bitfield scheme would not work.) */ | 2623 | * parameters (otherwise our bitfield scheme would not work.) */ |
@@ -2945,16 +2663,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2945 | nla_get_u8); | 2663 | nla_get_u8); |
2946 | 2664 | ||
2947 | /* Apply changes */ | 2665 | /* Apply changes */ |
2948 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2666 | return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); |
2949 | |||
2950 | out: | ||
2951 | /* cleanup */ | ||
2952 | cfg80211_unlock_rdev(rdev); | ||
2953 | dev_put(dev); | ||
2954 | out_rtnl: | ||
2955 | rtnl_unlock(); | ||
2956 | |||
2957 | return err; | ||
2958 | } | 2667 | } |
2959 | 2668 | ||
2960 | #undef FILL_IN_MESH_PARAM_IF_SET | 2669 | #undef FILL_IN_MESH_PARAM_IF_SET |
@@ -3137,8 +2846,8 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
3137 | 2846 | ||
3138 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2847 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
3139 | { | 2848 | { |
3140 | struct cfg80211_registered_device *rdev; | 2849 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3141 | struct net_device *dev; | 2850 | struct net_device *dev = info->user_ptr[1]; |
3142 | struct cfg80211_scan_request *request; | 2851 | struct cfg80211_scan_request *request; |
3143 | struct cfg80211_ssid *ssid; | 2852 | struct cfg80211_ssid *ssid; |
3144 | struct ieee80211_channel *channel; | 2853 | struct ieee80211_channel *channel; |
@@ -3151,36 +2860,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3151 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 2860 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3152 | return -EINVAL; | 2861 | return -EINVAL; |
3153 | 2862 | ||
3154 | rtnl_lock(); | ||
3155 | |||
3156 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3157 | if (err) | ||
3158 | goto out_rtnl; | ||
3159 | |||
3160 | wiphy = &rdev->wiphy; | 2863 | wiphy = &rdev->wiphy; |
3161 | 2864 | ||
3162 | if (!rdev->ops->scan) { | 2865 | if (!rdev->ops->scan) |
3163 | err = -EOPNOTSUPP; | 2866 | return -EOPNOTSUPP; |
3164 | goto out; | ||
3165 | } | ||
3166 | |||
3167 | if (!netif_running(dev)) { | ||
3168 | err = -ENETDOWN; | ||
3169 | goto out; | ||
3170 | } | ||
3171 | 2867 | ||
3172 | if (rdev->scan_req) { | 2868 | if (rdev->scan_req) |
3173 | err = -EBUSY; | 2869 | return -EBUSY; |
3174 | goto out; | ||
3175 | } | ||
3176 | 2870 | ||
3177 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2871 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
3178 | n_channels = validate_scan_freqs( | 2872 | n_channels = validate_scan_freqs( |
3179 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | 2873 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); |
3180 | if (!n_channels) { | 2874 | if (!n_channels) |
3181 | err = -EINVAL; | 2875 | return -EINVAL; |
3182 | goto out; | ||
3183 | } | ||
3184 | } else { | 2876 | } else { |
3185 | n_channels = 0; | 2877 | n_channels = 0; |
3186 | 2878 | ||
@@ -3193,29 +2885,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3193 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) | 2885 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) |
3194 | n_ssids++; | 2886 | n_ssids++; |
3195 | 2887 | ||
3196 | if (n_ssids > wiphy->max_scan_ssids) { | 2888 | if (n_ssids > wiphy->max_scan_ssids) |
3197 | err = -EINVAL; | 2889 | return -EINVAL; |
3198 | goto out; | ||
3199 | } | ||
3200 | 2890 | ||
3201 | if (info->attrs[NL80211_ATTR_IE]) | 2891 | if (info->attrs[NL80211_ATTR_IE]) |
3202 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2892 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3203 | else | 2893 | else |
3204 | ie_len = 0; | 2894 | ie_len = 0; |
3205 | 2895 | ||
3206 | if (ie_len > wiphy->max_scan_ie_len) { | 2896 | if (ie_len > wiphy->max_scan_ie_len) |
3207 | err = -EINVAL; | 2897 | return -EINVAL; |
3208 | goto out; | ||
3209 | } | ||
3210 | 2898 | ||
3211 | request = kzalloc(sizeof(*request) | 2899 | request = kzalloc(sizeof(*request) |
3212 | + sizeof(*ssid) * n_ssids | 2900 | + sizeof(*ssid) * n_ssids |
3213 | + sizeof(channel) * n_channels | 2901 | + sizeof(channel) * n_channels |
3214 | + ie_len, GFP_KERNEL); | 2902 | + ie_len, GFP_KERNEL); |
3215 | if (!request) { | 2903 | if (!request) |
3216 | err = -ENOMEM; | 2904 | return -ENOMEM; |
3217 | goto out; | ||
3218 | } | ||
3219 | 2905 | ||
3220 | if (n_ssids) | 2906 | if (n_ssids) |
3221 | request->ssids = (void *)&request->channels[n_channels]; | 2907 | request->ssids = (void *)&request->channels[n_channels]; |
@@ -3303,18 +2989,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3303 | if (!err) { | 2989 | if (!err) { |
3304 | nl80211_send_scan_start(rdev, dev); | 2990 | nl80211_send_scan_start(rdev, dev); |
3305 | dev_hold(dev); | 2991 | dev_hold(dev); |
3306 | } | 2992 | } else { |
3307 | |||
3308 | out_free: | 2993 | out_free: |
3309 | if (err) { | ||
3310 | rdev->scan_req = NULL; | 2994 | rdev->scan_req = NULL; |
3311 | kfree(request); | 2995 | kfree(request); |
3312 | } | 2996 | } |
3313 | out: | ||
3314 | cfg80211_unlock_rdev(rdev); | ||
3315 | dev_put(dev); | ||
3316 | out_rtnl: | ||
3317 | rtnl_unlock(); | ||
3318 | 2997 | ||
3319 | return err; | 2998 | return err; |
3320 | } | 2999 | } |
@@ -3411,25 +3090,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3411 | struct net_device *dev; | 3090 | struct net_device *dev; |
3412 | struct cfg80211_internal_bss *scan; | 3091 | struct cfg80211_internal_bss *scan; |
3413 | struct wireless_dev *wdev; | 3092 | struct wireless_dev *wdev; |
3414 | int ifidx = cb->args[0]; | ||
3415 | int start = cb->args[1], idx = 0; | 3093 | int start = cb->args[1], idx = 0; |
3416 | int err; | 3094 | int err; |
3417 | 3095 | ||
3418 | if (!ifidx) | 3096 | err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); |
3419 | ifidx = nl80211_get_ifidx(cb); | 3097 | if (err) |
3420 | if (ifidx < 0) | 3098 | return err; |
3421 | return ifidx; | ||
3422 | cb->args[0] = ifidx; | ||
3423 | |||
3424 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3425 | if (!dev) | ||
3426 | return -ENODEV; | ||
3427 | |||
3428 | rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3429 | if (IS_ERR(rdev)) { | ||
3430 | err = PTR_ERR(rdev); | ||
3431 | goto out_put_netdev; | ||
3432 | } | ||
3433 | 3099 | ||
3434 | wdev = dev->ieee80211_ptr; | 3100 | wdev = dev->ieee80211_ptr; |
3435 | 3101 | ||
@@ -3445,21 +3111,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3445 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3111 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3446 | rdev, wdev, scan) < 0) { | 3112 | rdev, wdev, scan) < 0) { |
3447 | idx--; | 3113 | idx--; |
3448 | goto out; | 3114 | break; |
3449 | } | 3115 | } |
3450 | } | 3116 | } |
3451 | 3117 | ||
3452 | out: | ||
3453 | spin_unlock_bh(&rdev->bss_lock); | 3118 | spin_unlock_bh(&rdev->bss_lock); |
3454 | wdev_unlock(wdev); | 3119 | wdev_unlock(wdev); |
3455 | 3120 | ||
3456 | cb->args[1] = idx; | 3121 | cb->args[1] = idx; |
3457 | err = skb->len; | 3122 | nl80211_finish_netdev_dump(rdev); |
3458 | cfg80211_unlock_rdev(rdev); | ||
3459 | out_put_netdev: | ||
3460 | dev_put(dev); | ||
3461 | 3123 | ||
3462 | return err; | 3124 | return skb->len; |
3463 | } | 3125 | } |
3464 | 3126 | ||
3465 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | 3127 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, |
@@ -3489,6 +3151,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | |||
3489 | if (survey->filled & SURVEY_INFO_NOISE_DBM) | 3151 | if (survey->filled & SURVEY_INFO_NOISE_DBM) |
3490 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, | 3152 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, |
3491 | survey->noise); | 3153 | survey->noise); |
3154 | if (survey->filled & SURVEY_INFO_IN_USE) | ||
3155 | NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); | ||
3492 | 3156 | ||
3493 | nla_nest_end(msg, infoattr); | 3157 | nla_nest_end(msg, infoattr); |
3494 | 3158 | ||
@@ -3505,29 +3169,12 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3505 | struct survey_info survey; | 3169 | struct survey_info survey; |
3506 | struct cfg80211_registered_device *dev; | 3170 | struct cfg80211_registered_device *dev; |
3507 | struct net_device *netdev; | 3171 | struct net_device *netdev; |
3508 | int ifidx = cb->args[0]; | ||
3509 | int survey_idx = cb->args[1]; | 3172 | int survey_idx = cb->args[1]; |
3510 | int res; | 3173 | int res; |
3511 | 3174 | ||
3512 | if (!ifidx) | 3175 | res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); |
3513 | ifidx = nl80211_get_ifidx(cb); | 3176 | if (res) |
3514 | if (ifidx < 0) | 3177 | return res; |
3515 | return ifidx; | ||
3516 | cb->args[0] = ifidx; | ||
3517 | |||
3518 | rtnl_lock(); | ||
3519 | |||
3520 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3521 | if (!netdev) { | ||
3522 | res = -ENODEV; | ||
3523 | goto out_rtnl; | ||
3524 | } | ||
3525 | |||
3526 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3527 | if (IS_ERR(dev)) { | ||
3528 | res = PTR_ERR(dev); | ||
3529 | goto out_rtnl; | ||
3530 | } | ||
3531 | 3178 | ||
3532 | if (!dev->ops->dump_survey) { | 3179 | if (!dev->ops->dump_survey) { |
3533 | res = -EOPNOTSUPP; | 3180 | res = -EOPNOTSUPP; |
@@ -3555,10 +3202,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3555 | cb->args[1] = survey_idx; | 3202 | cb->args[1] = survey_idx; |
3556 | res = skb->len; | 3203 | res = skb->len; |
3557 | out_err: | 3204 | out_err: |
3558 | cfg80211_unlock_rdev(dev); | 3205 | nl80211_finish_netdev_dump(dev); |
3559 | out_rtnl: | ||
3560 | rtnl_unlock(); | ||
3561 | |||
3562 | return res; | 3206 | return res; |
3563 | } | 3207 | } |
3564 | 3208 | ||
@@ -3591,8 +3235,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher) | |||
3591 | 3235 | ||
3592 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | 3236 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) |
3593 | { | 3237 | { |
3594 | struct cfg80211_registered_device *rdev; | 3238 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3595 | struct net_device *dev; | 3239 | struct net_device *dev = info->user_ptr[1]; |
3596 | struct ieee80211_channel *chan; | 3240 | struct ieee80211_channel *chan; |
3597 | const u8 *bssid, *ssid, *ie = NULL; | 3241 | const u8 *bssid, *ssid, *ie = NULL; |
3598 | int err, ssid_len, ie_len = 0; | 3242 | int err, ssid_len, ie_len = 0; |
@@ -3620,6 +3264,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3620 | return err; | 3264 | return err; |
3621 | 3265 | ||
3622 | if (key.idx >= 0) { | 3266 | if (key.idx >= 0) { |
3267 | if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP) | ||
3268 | return -EINVAL; | ||
3623 | if (!key.p.key || !key.p.key_len) | 3269 | if (!key.p.key || !key.p.key_len) |
3624 | return -EINVAL; | 3270 | return -EINVAL; |
3625 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || | 3271 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || |
@@ -3634,12 +3280,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3634 | key.p.key = NULL; | 3280 | key.p.key = NULL; |
3635 | } | 3281 | } |
3636 | 3282 | ||
3637 | rtnl_lock(); | ||
3638 | |||
3639 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3640 | if (err) | ||
3641 | goto unlock_rtnl; | ||
3642 | |||
3643 | if (key.idx >= 0) { | 3283 | if (key.idx >= 0) { |
3644 | int i; | 3284 | int i; |
3645 | bool ok = false; | 3285 | bool ok = false; |
@@ -3649,35 +3289,22 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3649 | break; | 3289 | break; |
3650 | } | 3290 | } |
3651 | } | 3291 | } |
3652 | if (!ok) { | 3292 | if (!ok) |
3653 | err = -EINVAL; | 3293 | return -EINVAL; |
3654 | goto out; | ||
3655 | } | ||
3656 | } | 3294 | } |
3657 | 3295 | ||
3658 | if (!rdev->ops->auth) { | 3296 | if (!rdev->ops->auth) |
3659 | err = -EOPNOTSUPP; | 3297 | return -EOPNOTSUPP; |
3660 | goto out; | ||
3661 | } | ||
3662 | 3298 | ||
3663 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3299 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3664 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3300 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3665 | err = -EOPNOTSUPP; | 3301 | return -EOPNOTSUPP; |
3666 | goto out; | ||
3667 | } | ||
3668 | |||
3669 | if (!netif_running(dev)) { | ||
3670 | err = -ENETDOWN; | ||
3671 | goto out; | ||
3672 | } | ||
3673 | 3302 | ||
3674 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3303 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3675 | chan = ieee80211_get_channel(&rdev->wiphy, | 3304 | chan = ieee80211_get_channel(&rdev->wiphy, |
3676 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3305 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3677 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3306 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) |
3678 | err = -EINVAL; | 3307 | return -EINVAL; |
3679 | goto out; | ||
3680 | } | ||
3681 | 3308 | ||
3682 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3309 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3683 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3310 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
@@ -3688,24 +3315,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3688 | } | 3315 | } |
3689 | 3316 | ||
3690 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 3317 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
3691 | if (!nl80211_valid_auth_type(auth_type)) { | 3318 | if (!nl80211_valid_auth_type(auth_type)) |
3692 | err = -EINVAL; | 3319 | return -EINVAL; |
3693 | goto out; | ||
3694 | } | ||
3695 | 3320 | ||
3696 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3321 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3697 | 3322 | ||
3698 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 3323 | return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
3699 | ssid, ssid_len, ie, ie_len, | 3324 | ssid, ssid_len, ie, ie_len, |
3700 | key.p.key, key.p.key_len, key.idx, | 3325 | key.p.key, key.p.key_len, key.idx, |
3701 | local_state_change); | 3326 | local_state_change); |
3702 | |||
3703 | out: | ||
3704 | cfg80211_unlock_rdev(rdev); | ||
3705 | dev_put(dev); | ||
3706 | unlock_rtnl: | ||
3707 | rtnl_unlock(); | ||
3708 | return err; | ||
3709 | } | 3327 | } |
3710 | 3328 | ||
3711 | static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, | 3329 | static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, |
@@ -3789,8 +3407,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, | |||
3789 | 3407 | ||
3790 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | 3408 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) |
3791 | { | 3409 | { |
3792 | struct cfg80211_registered_device *rdev; | 3410 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3793 | struct net_device *dev; | 3411 | struct net_device *dev = info->user_ptr[1]; |
3794 | struct cfg80211_crypto_settings crypto; | 3412 | struct cfg80211_crypto_settings crypto; |
3795 | struct ieee80211_channel *chan; | 3413 | struct ieee80211_channel *chan; |
3796 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3414 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
@@ -3805,36 +3423,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3805 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 3423 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
3806 | return -EINVAL; | 3424 | return -EINVAL; |
3807 | 3425 | ||
3808 | rtnl_lock(); | 3426 | if (!rdev->ops->assoc) |
3809 | 3427 | return -EOPNOTSUPP; | |
3810 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3811 | if (err) | ||
3812 | goto unlock_rtnl; | ||
3813 | |||
3814 | if (!rdev->ops->assoc) { | ||
3815 | err = -EOPNOTSUPP; | ||
3816 | goto out; | ||
3817 | } | ||
3818 | 3428 | ||
3819 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3429 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3820 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3430 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3821 | err = -EOPNOTSUPP; | 3431 | return -EOPNOTSUPP; |
3822 | goto out; | ||
3823 | } | ||
3824 | |||
3825 | if (!netif_running(dev)) { | ||
3826 | err = -ENETDOWN; | ||
3827 | goto out; | ||
3828 | } | ||
3829 | 3432 | ||
3830 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3433 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3831 | 3434 | ||
3832 | chan = ieee80211_get_channel(&rdev->wiphy, | 3435 | chan = ieee80211_get_channel(&rdev->wiphy, |
3833 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3436 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3834 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { | 3437 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) |
3835 | err = -EINVAL; | 3438 | return -EINVAL; |
3836 | goto out; | ||
3837 | } | ||
3838 | 3439 | ||
3839 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3440 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3840 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3441 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
@@ -3849,10 +3450,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3849 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 3450 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
3850 | if (mfp == NL80211_MFP_REQUIRED) | 3451 | if (mfp == NL80211_MFP_REQUIRED) |
3851 | use_mfp = true; | 3452 | use_mfp = true; |
3852 | else if (mfp != NL80211_MFP_NO) { | 3453 | else if (mfp != NL80211_MFP_NO) |
3853 | err = -EINVAL; | 3454 | return -EINVAL; |
3854 | goto out; | ||
3855 | } | ||
3856 | } | 3455 | } |
3857 | 3456 | ||
3858 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 3457 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
@@ -3864,20 +3463,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3864 | ssid, ssid_len, ie, ie_len, use_mfp, | 3463 | ssid, ssid_len, ie, ie_len, use_mfp, |
3865 | &crypto); | 3464 | &crypto); |
3866 | 3465 | ||
3867 | out: | ||
3868 | cfg80211_unlock_rdev(rdev); | ||
3869 | dev_put(dev); | ||
3870 | unlock_rtnl: | ||
3871 | rtnl_unlock(); | ||
3872 | return err; | 3466 | return err; |
3873 | } | 3467 | } |
3874 | 3468 | ||
3875 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | 3469 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) |
3876 | { | 3470 | { |
3877 | struct cfg80211_registered_device *rdev; | 3471 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3878 | struct net_device *dev; | 3472 | struct net_device *dev = info->user_ptr[1]; |
3879 | const u8 *ie = NULL, *bssid; | 3473 | const u8 *ie = NULL, *bssid; |
3880 | int err, ie_len = 0; | 3474 | int ie_len = 0; |
3881 | u16 reason_code; | 3475 | u16 reason_code; |
3882 | bool local_state_change; | 3476 | bool local_state_change; |
3883 | 3477 | ||
@@ -3890,35 +3484,19 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3890 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3484 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3891 | return -EINVAL; | 3485 | return -EINVAL; |
3892 | 3486 | ||
3893 | rtnl_lock(); | 3487 | if (!rdev->ops->deauth) |
3894 | 3488 | return -EOPNOTSUPP; | |
3895 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3896 | if (err) | ||
3897 | goto unlock_rtnl; | ||
3898 | |||
3899 | if (!rdev->ops->deauth) { | ||
3900 | err = -EOPNOTSUPP; | ||
3901 | goto out; | ||
3902 | } | ||
3903 | 3489 | ||
3904 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3490 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3905 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3491 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3906 | err = -EOPNOTSUPP; | 3492 | return -EOPNOTSUPP; |
3907 | goto out; | ||
3908 | } | ||
3909 | |||
3910 | if (!netif_running(dev)) { | ||
3911 | err = -ENETDOWN; | ||
3912 | goto out; | ||
3913 | } | ||
3914 | 3493 | ||
3915 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3494 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3916 | 3495 | ||
3917 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3496 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3918 | if (reason_code == 0) { | 3497 | if (reason_code == 0) { |
3919 | /* Reason Code 0 is reserved */ | 3498 | /* Reason Code 0 is reserved */ |
3920 | err = -EINVAL; | 3499 | return -EINVAL; |
3921 | goto out; | ||
3922 | } | 3500 | } |
3923 | 3501 | ||
3924 | if (info->attrs[NL80211_ATTR_IE]) { | 3502 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -3928,23 +3506,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3928 | 3506 | ||
3929 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3507 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3930 | 3508 | ||
3931 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, | 3509 | return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, |
3932 | local_state_change); | 3510 | local_state_change); |
3933 | |||
3934 | out: | ||
3935 | cfg80211_unlock_rdev(rdev); | ||
3936 | dev_put(dev); | ||
3937 | unlock_rtnl: | ||
3938 | rtnl_unlock(); | ||
3939 | return err; | ||
3940 | } | 3511 | } |
3941 | 3512 | ||
3942 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | 3513 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) |
3943 | { | 3514 | { |
3944 | struct cfg80211_registered_device *rdev; | 3515 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3945 | struct net_device *dev; | 3516 | struct net_device *dev = info->user_ptr[1]; |
3946 | const u8 *ie = NULL, *bssid; | 3517 | const u8 *ie = NULL, *bssid; |
3947 | int err, ie_len = 0; | 3518 | int ie_len = 0; |
3948 | u16 reason_code; | 3519 | u16 reason_code; |
3949 | bool local_state_change; | 3520 | bool local_state_change; |
3950 | 3521 | ||
@@ -3957,35 +3528,19 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3957 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3528 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
3958 | return -EINVAL; | 3529 | return -EINVAL; |
3959 | 3530 | ||
3960 | rtnl_lock(); | 3531 | if (!rdev->ops->disassoc) |
3961 | 3532 | return -EOPNOTSUPP; | |
3962 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
3963 | if (err) | ||
3964 | goto unlock_rtnl; | ||
3965 | |||
3966 | if (!rdev->ops->disassoc) { | ||
3967 | err = -EOPNOTSUPP; | ||
3968 | goto out; | ||
3969 | } | ||
3970 | 3533 | ||
3971 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3534 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
3972 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3535 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
3973 | err = -EOPNOTSUPP; | 3536 | return -EOPNOTSUPP; |
3974 | goto out; | ||
3975 | } | ||
3976 | |||
3977 | if (!netif_running(dev)) { | ||
3978 | err = -ENETDOWN; | ||
3979 | goto out; | ||
3980 | } | ||
3981 | 3537 | ||
3982 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3538 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3983 | 3539 | ||
3984 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3540 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3985 | if (reason_code == 0) { | 3541 | if (reason_code == 0) { |
3986 | /* Reason Code 0 is reserved */ | 3542 | /* Reason Code 0 is reserved */ |
3987 | err = -EINVAL; | 3543 | return -EINVAL; |
3988 | goto out; | ||
3989 | } | 3544 | } |
3990 | 3545 | ||
3991 | if (info->attrs[NL80211_ATTR_IE]) { | 3546 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -3995,21 +3550,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3995 | 3550 | ||
3996 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 3551 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
3997 | 3552 | ||
3998 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, | 3553 | return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, |
3999 | local_state_change); | 3554 | local_state_change); |
4000 | |||
4001 | out: | ||
4002 | cfg80211_unlock_rdev(rdev); | ||
4003 | dev_put(dev); | ||
4004 | unlock_rtnl: | ||
4005 | rtnl_unlock(); | ||
4006 | return err; | ||
4007 | } | 3555 | } |
4008 | 3556 | ||
4009 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | 3557 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) |
4010 | { | 3558 | { |
4011 | struct cfg80211_registered_device *rdev; | 3559 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4012 | struct net_device *dev; | 3560 | struct net_device *dev = info->user_ptr[1]; |
4013 | struct cfg80211_ibss_params ibss; | 3561 | struct cfg80211_ibss_params ibss; |
4014 | struct wiphy *wiphy; | 3562 | struct wiphy *wiphy; |
4015 | struct cfg80211_cached_keys *connkeys = NULL; | 3563 | struct cfg80211_cached_keys *connkeys = NULL; |
@@ -4034,26 +3582,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4034 | return -EINVAL; | 3582 | return -EINVAL; |
4035 | } | 3583 | } |
4036 | 3584 | ||
4037 | rtnl_lock(); | 3585 | if (!rdev->ops->join_ibss) |
4038 | 3586 | return -EOPNOTSUPP; | |
4039 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4040 | if (err) | ||
4041 | goto unlock_rtnl; | ||
4042 | |||
4043 | if (!rdev->ops->join_ibss) { | ||
4044 | err = -EOPNOTSUPP; | ||
4045 | goto out; | ||
4046 | } | ||
4047 | |||
4048 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
4049 | err = -EOPNOTSUPP; | ||
4050 | goto out; | ||
4051 | } | ||
4052 | 3587 | ||
4053 | if (!netif_running(dev)) { | 3588 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) |
4054 | err = -ENETDOWN; | 3589 | return -EOPNOTSUPP; |
4055 | goto out; | ||
4056 | } | ||
4057 | 3590 | ||
4058 | wiphy = &rdev->wiphy; | 3591 | wiphy = &rdev->wiphy; |
4059 | 3592 | ||
@@ -4071,24 +3604,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4071 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3604 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
4072 | if (!ibss.channel || | 3605 | if (!ibss.channel || |
4073 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | 3606 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || |
4074 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { | 3607 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) |
4075 | err = -EINVAL; | 3608 | return -EINVAL; |
4076 | goto out; | ||
4077 | } | ||
4078 | 3609 | ||
4079 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 3610 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
4080 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 3611 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
4081 | 3612 | ||
4082 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { | ||
4083 | connkeys = nl80211_parse_connkeys(rdev, | ||
4084 | info->attrs[NL80211_ATTR_KEYS]); | ||
4085 | if (IS_ERR(connkeys)) { | ||
4086 | err = PTR_ERR(connkeys); | ||
4087 | connkeys = NULL; | ||
4088 | goto out; | ||
4089 | } | ||
4090 | } | ||
4091 | |||
4092 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | 3613 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { |
4093 | u8 *rates = | 3614 | u8 *rates = |
4094 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 3615 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
@@ -4098,10 +3619,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4098 | wiphy->bands[ibss.channel->band]; | 3619 | wiphy->bands[ibss.channel->band]; |
4099 | int i, j; | 3620 | int i, j; |
4100 | 3621 | ||
4101 | if (n_rates == 0) { | 3622 | if (n_rates == 0) |
4102 | err = -EINVAL; | 3623 | return -EINVAL; |
4103 | goto out; | ||
4104 | } | ||
4105 | 3624 | ||
4106 | for (i = 0; i < n_rates; i++) { | 3625 | for (i = 0; i < n_rates; i++) { |
4107 | int rate = (rates[i] & 0x7f) * 5; | 3626 | int rate = (rates[i] & 0x7f) * 5; |
@@ -4114,60 +3633,36 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4114 | break; | 3633 | break; |
4115 | } | 3634 | } |
4116 | } | 3635 | } |
4117 | if (!found) { | 3636 | if (!found) |
4118 | err = -EINVAL; | 3637 | return -EINVAL; |
4119 | goto out; | ||
4120 | } | ||
4121 | } | 3638 | } |
4122 | } | 3639 | } |
4123 | 3640 | ||
4124 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); | 3641 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
3642 | connkeys = nl80211_parse_connkeys(rdev, | ||
3643 | info->attrs[NL80211_ATTR_KEYS]); | ||
3644 | if (IS_ERR(connkeys)) | ||
3645 | return PTR_ERR(connkeys); | ||
3646 | } | ||
4125 | 3647 | ||
4126 | out: | 3648 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); |
4127 | cfg80211_unlock_rdev(rdev); | ||
4128 | dev_put(dev); | ||
4129 | unlock_rtnl: | ||
4130 | if (err) | 3649 | if (err) |
4131 | kfree(connkeys); | 3650 | kfree(connkeys); |
4132 | rtnl_unlock(); | ||
4133 | return err; | 3651 | return err; |
4134 | } | 3652 | } |
4135 | 3653 | ||
4136 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | 3654 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) |
4137 | { | 3655 | { |
4138 | struct cfg80211_registered_device *rdev; | 3656 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4139 | struct net_device *dev; | 3657 | struct net_device *dev = info->user_ptr[1]; |
4140 | int err; | ||
4141 | 3658 | ||
4142 | rtnl_lock(); | 3659 | if (!rdev->ops->leave_ibss) |
4143 | 3660 | return -EOPNOTSUPP; | |
4144 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4145 | if (err) | ||
4146 | goto unlock_rtnl; | ||
4147 | |||
4148 | if (!rdev->ops->leave_ibss) { | ||
4149 | err = -EOPNOTSUPP; | ||
4150 | goto out; | ||
4151 | } | ||
4152 | |||
4153 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
4154 | err = -EOPNOTSUPP; | ||
4155 | goto out; | ||
4156 | } | ||
4157 | |||
4158 | if (!netif_running(dev)) { | ||
4159 | err = -ENETDOWN; | ||
4160 | goto out; | ||
4161 | } | ||
4162 | 3661 | ||
4163 | err = cfg80211_leave_ibss(rdev, dev, false); | 3662 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) |
3663 | return -EOPNOTSUPP; | ||
4164 | 3664 | ||
4165 | out: | 3665 | return cfg80211_leave_ibss(rdev, dev, false); |
4166 | cfg80211_unlock_rdev(rdev); | ||
4167 | dev_put(dev); | ||
4168 | unlock_rtnl: | ||
4169 | rtnl_unlock(); | ||
4170 | return err; | ||
4171 | } | 3666 | } |
4172 | 3667 | ||
4173 | #ifdef CONFIG_NL80211_TESTMODE | 3668 | #ifdef CONFIG_NL80211_TESTMODE |
@@ -4177,20 +3672,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = { | |||
4177 | 3672 | ||
4178 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | 3673 | static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) |
4179 | { | 3674 | { |
4180 | struct cfg80211_registered_device *rdev; | 3675 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4181 | int err; | 3676 | int err; |
4182 | 3677 | ||
4183 | if (!info->attrs[NL80211_ATTR_TESTDATA]) | 3678 | if (!info->attrs[NL80211_ATTR_TESTDATA]) |
4184 | return -EINVAL; | 3679 | return -EINVAL; |
4185 | 3680 | ||
4186 | rtnl_lock(); | ||
4187 | |||
4188 | rdev = cfg80211_get_dev_from_info(info); | ||
4189 | if (IS_ERR(rdev)) { | ||
4190 | err = PTR_ERR(rdev); | ||
4191 | goto unlock_rtnl; | ||
4192 | } | ||
4193 | |||
4194 | err = -EOPNOTSUPP; | 3681 | err = -EOPNOTSUPP; |
4195 | if (rdev->ops->testmode_cmd) { | 3682 | if (rdev->ops->testmode_cmd) { |
4196 | rdev->testmode_info = info; | 3683 | rdev->testmode_info = info; |
@@ -4200,10 +3687,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | |||
4200 | rdev->testmode_info = NULL; | 3687 | rdev->testmode_info = NULL; |
4201 | } | 3688 | } |
4202 | 3689 | ||
4203 | cfg80211_unlock_rdev(rdev); | ||
4204 | |||
4205 | unlock_rtnl: | ||
4206 | rtnl_unlock(); | ||
4207 | return err; | 3690 | return err; |
4208 | } | 3691 | } |
4209 | 3692 | ||
@@ -4294,8 +3777,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event); | |||
4294 | 3777 | ||
4295 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | 3778 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) |
4296 | { | 3779 | { |
4297 | struct cfg80211_registered_device *rdev; | 3780 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4298 | struct net_device *dev; | 3781 | struct net_device *dev = info->user_ptr[1]; |
4299 | struct cfg80211_connect_params connect; | 3782 | struct cfg80211_connect_params connect; |
4300 | struct wiphy *wiphy; | 3783 | struct wiphy *wiphy; |
4301 | struct cfg80211_cached_keys *connkeys = NULL; | 3784 | struct cfg80211_cached_keys *connkeys = NULL; |
@@ -4324,22 +3807,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4324 | NL80211_MAX_NR_CIPHER_SUITES); | 3807 | NL80211_MAX_NR_CIPHER_SUITES); |
4325 | if (err) | 3808 | if (err) |
4326 | return err; | 3809 | return err; |
4327 | rtnl_lock(); | ||
4328 | |||
4329 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4330 | if (err) | ||
4331 | goto unlock_rtnl; | ||
4332 | 3810 | ||
4333 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3811 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4334 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3812 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4335 | err = -EOPNOTSUPP; | 3813 | return -EOPNOTSUPP; |
4336 | goto out; | ||
4337 | } | ||
4338 | |||
4339 | if (!netif_running(dev)) { | ||
4340 | err = -ENETDOWN; | ||
4341 | goto out; | ||
4342 | } | ||
4343 | 3814 | ||
4344 | wiphy = &rdev->wiphy; | 3815 | wiphy = &rdev->wiphy; |
4345 | 3816 | ||
@@ -4358,39 +3829,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4358 | ieee80211_get_channel(wiphy, | 3829 | ieee80211_get_channel(wiphy, |
4359 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3830 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
4360 | if (!connect.channel || | 3831 | if (!connect.channel || |
4361 | connect.channel->flags & IEEE80211_CHAN_DISABLED) { | 3832 | connect.channel->flags & IEEE80211_CHAN_DISABLED) |
4362 | err = -EINVAL; | 3833 | return -EINVAL; |
4363 | goto out; | ||
4364 | } | ||
4365 | } | 3834 | } |
4366 | 3835 | ||
4367 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { | 3836 | if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
4368 | connkeys = nl80211_parse_connkeys(rdev, | 3837 | connkeys = nl80211_parse_connkeys(rdev, |
4369 | info->attrs[NL80211_ATTR_KEYS]); | 3838 | info->attrs[NL80211_ATTR_KEYS]); |
4370 | if (IS_ERR(connkeys)) { | 3839 | if (IS_ERR(connkeys)) |
4371 | err = PTR_ERR(connkeys); | 3840 | return PTR_ERR(connkeys); |
4372 | connkeys = NULL; | ||
4373 | goto out; | ||
4374 | } | ||
4375 | } | 3841 | } |
4376 | 3842 | ||
4377 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 3843 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
4378 | |||
4379 | out: | ||
4380 | cfg80211_unlock_rdev(rdev); | ||
4381 | dev_put(dev); | ||
4382 | unlock_rtnl: | ||
4383 | if (err) | 3844 | if (err) |
4384 | kfree(connkeys); | 3845 | kfree(connkeys); |
4385 | rtnl_unlock(); | ||
4386 | return err; | 3846 | return err; |
4387 | } | 3847 | } |
4388 | 3848 | ||
4389 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | 3849 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) |
4390 | { | 3850 | { |
4391 | struct cfg80211_registered_device *rdev; | 3851 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4392 | struct net_device *dev; | 3852 | struct net_device *dev = info->user_ptr[1]; |
4393 | int err; | ||
4394 | u16 reason; | 3853 | u16 reason; |
4395 | 3854 | ||
4396 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 3855 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
@@ -4401,36 +3860,16 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | |||
4401 | if (reason == 0) | 3860 | if (reason == 0) |
4402 | return -EINVAL; | 3861 | return -EINVAL; |
4403 | 3862 | ||
4404 | rtnl_lock(); | ||
4405 | |||
4406 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4407 | if (err) | ||
4408 | goto unlock_rtnl; | ||
4409 | |||
4410 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3863 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4411 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3864 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4412 | err = -EOPNOTSUPP; | 3865 | return -EOPNOTSUPP; |
4413 | goto out; | ||
4414 | } | ||
4415 | |||
4416 | if (!netif_running(dev)) { | ||
4417 | err = -ENETDOWN; | ||
4418 | goto out; | ||
4419 | } | ||
4420 | |||
4421 | err = cfg80211_disconnect(rdev, dev, reason, true); | ||
4422 | 3866 | ||
4423 | out: | 3867 | return cfg80211_disconnect(rdev, dev, reason, true); |
4424 | cfg80211_unlock_rdev(rdev); | ||
4425 | dev_put(dev); | ||
4426 | unlock_rtnl: | ||
4427 | rtnl_unlock(); | ||
4428 | return err; | ||
4429 | } | 3868 | } |
4430 | 3869 | ||
4431 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | 3870 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) |
4432 | { | 3871 | { |
4433 | struct cfg80211_registered_device *rdev; | 3872 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4434 | struct net *net; | 3873 | struct net *net; |
4435 | int err; | 3874 | int err; |
4436 | u32 pid; | 3875 | u32 pid; |
@@ -4440,43 +3879,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | |||
4440 | 3879 | ||
4441 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); | 3880 | pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); |
4442 | 3881 | ||
4443 | rtnl_lock(); | ||
4444 | |||
4445 | rdev = cfg80211_get_dev_from_info(info); | ||
4446 | if (IS_ERR(rdev)) { | ||
4447 | err = PTR_ERR(rdev); | ||
4448 | goto out_rtnl; | ||
4449 | } | ||
4450 | |||
4451 | net = get_net_ns_by_pid(pid); | 3882 | net = get_net_ns_by_pid(pid); |
4452 | if (IS_ERR(net)) { | 3883 | if (IS_ERR(net)) |
4453 | err = PTR_ERR(net); | 3884 | return PTR_ERR(net); |
4454 | goto out; | ||
4455 | } | ||
4456 | 3885 | ||
4457 | err = 0; | 3886 | err = 0; |
4458 | 3887 | ||
4459 | /* check if anything to do */ | 3888 | /* check if anything to do */ |
4460 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | 3889 | if (!net_eq(wiphy_net(&rdev->wiphy), net)) |
4461 | goto out_put_net; | 3890 | err = cfg80211_switch_netns(rdev, net); |
4462 | 3891 | ||
4463 | err = cfg80211_switch_netns(rdev, net); | ||
4464 | out_put_net: | ||
4465 | put_net(net); | 3892 | put_net(net); |
4466 | out: | ||
4467 | cfg80211_unlock_rdev(rdev); | ||
4468 | out_rtnl: | ||
4469 | rtnl_unlock(); | ||
4470 | return err; | 3893 | return err; |
4471 | } | 3894 | } |
4472 | 3895 | ||
4473 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | 3896 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) |
4474 | { | 3897 | { |
4475 | struct cfg80211_registered_device *rdev; | 3898 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4476 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, | 3899 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, |
4477 | struct cfg80211_pmksa *pmksa) = NULL; | 3900 | struct cfg80211_pmksa *pmksa) = NULL; |
4478 | int err; | 3901 | struct net_device *dev = info->user_ptr[1]; |
4479 | struct net_device *dev; | ||
4480 | struct cfg80211_pmksa pmksa; | 3902 | struct cfg80211_pmksa pmksa; |
4481 | 3903 | ||
4482 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); | 3904 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); |
@@ -4487,20 +3909,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4487 | if (!info->attrs[NL80211_ATTR_PMKID]) | 3909 | if (!info->attrs[NL80211_ATTR_PMKID]) |
4488 | return -EINVAL; | 3910 | return -EINVAL; |
4489 | 3911 | ||
4490 | rtnl_lock(); | ||
4491 | |||
4492 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4493 | if (err) | ||
4494 | goto out_rtnl; | ||
4495 | |||
4496 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); | 3912 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); |
4497 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3913 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4498 | 3914 | ||
4499 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3915 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4500 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3916 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4501 | err = -EOPNOTSUPP; | 3917 | return -EOPNOTSUPP; |
4502 | goto out; | ||
4503 | } | ||
4504 | 3918 | ||
4505 | switch (info->genlhdr->cmd) { | 3919 | switch (info->genlhdr->cmd) { |
4506 | case NL80211_CMD_SET_PMKSA: | 3920 | case NL80211_CMD_SET_PMKSA: |
@@ -4514,62 +3928,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4514 | break; | 3928 | break; |
4515 | } | 3929 | } |
4516 | 3930 | ||
4517 | if (!rdev_ops) { | 3931 | if (!rdev_ops) |
4518 | err = -EOPNOTSUPP; | 3932 | return -EOPNOTSUPP; |
4519 | goto out; | ||
4520 | } | ||
4521 | |||
4522 | err = rdev_ops(&rdev->wiphy, dev, &pmksa); | ||
4523 | |||
4524 | out: | ||
4525 | cfg80211_unlock_rdev(rdev); | ||
4526 | dev_put(dev); | ||
4527 | out_rtnl: | ||
4528 | rtnl_unlock(); | ||
4529 | 3933 | ||
4530 | return err; | 3934 | return rdev_ops(&rdev->wiphy, dev, &pmksa); |
4531 | } | 3935 | } |
4532 | 3936 | ||
4533 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | 3937 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) |
4534 | { | 3938 | { |
4535 | struct cfg80211_registered_device *rdev; | 3939 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4536 | int err; | 3940 | struct net_device *dev = info->user_ptr[1]; |
4537 | struct net_device *dev; | ||
4538 | |||
4539 | rtnl_lock(); | ||
4540 | |||
4541 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4542 | if (err) | ||
4543 | goto out_rtnl; | ||
4544 | 3941 | ||
4545 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 3942 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4546 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 3943 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
4547 | err = -EOPNOTSUPP; | 3944 | return -EOPNOTSUPP; |
4548 | goto out; | ||
4549 | } | ||
4550 | |||
4551 | if (!rdev->ops->flush_pmksa) { | ||
4552 | err = -EOPNOTSUPP; | ||
4553 | goto out; | ||
4554 | } | ||
4555 | |||
4556 | err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4557 | |||
4558 | out: | ||
4559 | cfg80211_unlock_rdev(rdev); | ||
4560 | dev_put(dev); | ||
4561 | out_rtnl: | ||
4562 | rtnl_unlock(); | ||
4563 | 3945 | ||
4564 | return err; | 3946 | if (!rdev->ops->flush_pmksa) |
3947 | return -EOPNOTSUPP; | ||
4565 | 3948 | ||
3949 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4566 | } | 3950 | } |
4567 | 3951 | ||
4568 | static int nl80211_remain_on_channel(struct sk_buff *skb, | 3952 | static int nl80211_remain_on_channel(struct sk_buff *skb, |
4569 | struct genl_info *info) | 3953 | struct genl_info *info) |
4570 | { | 3954 | { |
4571 | struct cfg80211_registered_device *rdev; | 3955 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4572 | struct net_device *dev; | 3956 | struct net_device *dev = info->user_ptr[1]; |
4573 | struct ieee80211_channel *chan; | 3957 | struct ieee80211_channel *chan; |
4574 | struct sk_buff *msg; | 3958 | struct sk_buff *msg; |
4575 | void *hdr; | 3959 | void *hdr; |
@@ -4591,21 +3975,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4591 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) | 3975 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) |
4592 | return -EINVAL; | 3976 | return -EINVAL; |
4593 | 3977 | ||
4594 | rtnl_lock(); | 3978 | if (!rdev->ops->remain_on_channel) |
4595 | 3979 | return -EOPNOTSUPP; | |
4596 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4597 | if (err) | ||
4598 | goto unlock_rtnl; | ||
4599 | |||
4600 | if (!rdev->ops->remain_on_channel) { | ||
4601 | err = -EOPNOTSUPP; | ||
4602 | goto out; | ||
4603 | } | ||
4604 | |||
4605 | if (!netif_running(dev)) { | ||
4606 | err = -ENETDOWN; | ||
4607 | goto out; | ||
4608 | } | ||
4609 | 3980 | ||
4610 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 3981 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4611 | channel_type = nla_get_u32( | 3982 | channel_type = nla_get_u32( |
@@ -4613,24 +3984,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4613 | if (channel_type != NL80211_CHAN_NO_HT && | 3984 | if (channel_type != NL80211_CHAN_NO_HT && |
4614 | channel_type != NL80211_CHAN_HT20 && | 3985 | channel_type != NL80211_CHAN_HT20 && |
4615 | channel_type != NL80211_CHAN_HT40PLUS && | 3986 | channel_type != NL80211_CHAN_HT40PLUS && |
4616 | channel_type != NL80211_CHAN_HT40MINUS) { | 3987 | channel_type != NL80211_CHAN_HT40MINUS) |
4617 | err = -EINVAL; | 3988 | return -EINVAL; |
4618 | goto out; | ||
4619 | } | ||
4620 | } | 3989 | } |
4621 | 3990 | ||
4622 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 3991 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4623 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 3992 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4624 | if (chan == NULL) { | 3993 | if (chan == NULL) |
4625 | err = -EINVAL; | 3994 | return -EINVAL; |
4626 | goto out; | ||
4627 | } | ||
4628 | 3995 | ||
4629 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 3996 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4630 | if (!msg) { | 3997 | if (!msg) |
4631 | err = -ENOMEM; | 3998 | return -ENOMEM; |
4632 | goto out; | ||
4633 | } | ||
4634 | 3999 | ||
4635 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4000 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4636 | NL80211_CMD_REMAIN_ON_CHANNEL); | 4001 | NL80211_CMD_REMAIN_ON_CHANNEL); |
@@ -4649,58 +4014,32 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4649 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 4014 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); |
4650 | 4015 | ||
4651 | genlmsg_end(msg, hdr); | 4016 | genlmsg_end(msg, hdr); |
4652 | err = genlmsg_reply(msg, info); | 4017 | |
4653 | goto out; | 4018 | return genlmsg_reply(msg, info); |
4654 | 4019 | ||
4655 | nla_put_failure: | 4020 | nla_put_failure: |
4656 | err = -ENOBUFS; | 4021 | err = -ENOBUFS; |
4657 | free_msg: | 4022 | free_msg: |
4658 | nlmsg_free(msg); | 4023 | nlmsg_free(msg); |
4659 | out: | ||
4660 | cfg80211_unlock_rdev(rdev); | ||
4661 | dev_put(dev); | ||
4662 | unlock_rtnl: | ||
4663 | rtnl_unlock(); | ||
4664 | return err; | 4024 | return err; |
4665 | } | 4025 | } |
4666 | 4026 | ||
4667 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | 4027 | static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, |
4668 | struct genl_info *info) | 4028 | struct genl_info *info) |
4669 | { | 4029 | { |
4670 | struct cfg80211_registered_device *rdev; | 4030 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4671 | struct net_device *dev; | 4031 | struct net_device *dev = info->user_ptr[1]; |
4672 | u64 cookie; | 4032 | u64 cookie; |
4673 | int err; | ||
4674 | 4033 | ||
4675 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 4034 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
4676 | return -EINVAL; | 4035 | return -EINVAL; |
4677 | 4036 | ||
4678 | rtnl_lock(); | 4037 | if (!rdev->ops->cancel_remain_on_channel) |
4679 | 4038 | return -EOPNOTSUPP; | |
4680 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4681 | if (err) | ||
4682 | goto unlock_rtnl; | ||
4683 | |||
4684 | if (!rdev->ops->cancel_remain_on_channel) { | ||
4685 | err = -EOPNOTSUPP; | ||
4686 | goto out; | ||
4687 | } | ||
4688 | |||
4689 | if (!netif_running(dev)) { | ||
4690 | err = -ENETDOWN; | ||
4691 | goto out; | ||
4692 | } | ||
4693 | 4039 | ||
4694 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 4040 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
4695 | 4041 | ||
4696 | err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | 4042 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); |
4697 | |||
4698 | out: | ||
4699 | cfg80211_unlock_rdev(rdev); | ||
4700 | dev_put(dev); | ||
4701 | unlock_rtnl: | ||
4702 | rtnl_unlock(); | ||
4703 | return err; | ||
4704 | } | 4043 | } |
4705 | 4044 | ||
4706 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | 4045 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, |
@@ -4736,26 +4075,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4736 | struct genl_info *info) | 4075 | struct genl_info *info) |
4737 | { | 4076 | { |
4738 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | 4077 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; |
4739 | struct cfg80211_registered_device *rdev; | 4078 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4740 | struct cfg80211_bitrate_mask mask; | 4079 | struct cfg80211_bitrate_mask mask; |
4741 | int err, rem, i; | 4080 | int rem, i; |
4742 | struct net_device *dev; | 4081 | struct net_device *dev = info->user_ptr[1]; |
4743 | struct nlattr *tx_rates; | 4082 | struct nlattr *tx_rates; |
4744 | struct ieee80211_supported_band *sband; | 4083 | struct ieee80211_supported_band *sband; |
4745 | 4084 | ||
4746 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) | 4085 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) |
4747 | return -EINVAL; | 4086 | return -EINVAL; |
4748 | 4087 | ||
4749 | rtnl_lock(); | 4088 | if (!rdev->ops->set_bitrate_mask) |
4750 | 4089 | return -EOPNOTSUPP; | |
4751 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4752 | if (err) | ||
4753 | goto unlock_rtnl; | ||
4754 | |||
4755 | if (!rdev->ops->set_bitrate_mask) { | ||
4756 | err = -EOPNOTSUPP; | ||
4757 | goto unlock; | ||
4758 | } | ||
4759 | 4090 | ||
4760 | memset(&mask, 0, sizeof(mask)); | 4091 | memset(&mask, 0, sizeof(mask)); |
4761 | /* Default to all rates enabled */ | 4092 | /* Default to all rates enabled */ |
@@ -4772,15 +4103,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4772 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | 4103 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) |
4773 | { | 4104 | { |
4774 | enum ieee80211_band band = nla_type(tx_rates); | 4105 | enum ieee80211_band band = nla_type(tx_rates); |
4775 | if (band < 0 || band >= IEEE80211_NUM_BANDS) { | 4106 | if (band < 0 || band >= IEEE80211_NUM_BANDS) |
4776 | err = -EINVAL; | 4107 | return -EINVAL; |
4777 | goto unlock; | ||
4778 | } | ||
4779 | sband = rdev->wiphy.bands[band]; | 4108 | sband = rdev->wiphy.bands[band]; |
4780 | if (sband == NULL) { | 4109 | if (sband == NULL) |
4781 | err = -EINVAL; | 4110 | return -EINVAL; |
4782 | goto unlock; | ||
4783 | } | ||
4784 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | 4111 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), |
4785 | nla_len(tx_rates), nl80211_txattr_policy); | 4112 | nla_len(tx_rates), nl80211_txattr_policy); |
4786 | if (tb[NL80211_TXRATE_LEGACY]) { | 4113 | if (tb[NL80211_TXRATE_LEGACY]) { |
@@ -4788,29 +4115,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4788 | sband, | 4115 | sband, |
4789 | nla_data(tb[NL80211_TXRATE_LEGACY]), | 4116 | nla_data(tb[NL80211_TXRATE_LEGACY]), |
4790 | nla_len(tb[NL80211_TXRATE_LEGACY])); | 4117 | nla_len(tb[NL80211_TXRATE_LEGACY])); |
4791 | if (mask.control[band].legacy == 0) { | 4118 | if (mask.control[band].legacy == 0) |
4792 | err = -EINVAL; | 4119 | return -EINVAL; |
4793 | goto unlock; | ||
4794 | } | ||
4795 | } | 4120 | } |
4796 | } | 4121 | } |
4797 | 4122 | ||
4798 | err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); | 4123 | return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); |
4799 | |||
4800 | unlock: | ||
4801 | dev_put(dev); | ||
4802 | cfg80211_unlock_rdev(rdev); | ||
4803 | unlock_rtnl: | ||
4804 | rtnl_unlock(); | ||
4805 | return err; | ||
4806 | } | 4124 | } |
4807 | 4125 | ||
4808 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | 4126 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
4809 | { | 4127 | { |
4810 | struct cfg80211_registered_device *rdev; | 4128 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4811 | struct net_device *dev; | 4129 | struct net_device *dev = info->user_ptr[1]; |
4812 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; | 4130 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; |
4813 | int err; | ||
4814 | 4131 | ||
4815 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 4132 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
4816 | return -EINVAL; | 4133 | return -EINVAL; |
@@ -4818,41 +4135,28 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4818 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) | 4135 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
4819 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); | 4136 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
4820 | 4137 | ||
4821 | rtnl_lock(); | ||
4822 | |||
4823 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4824 | if (err) | ||
4825 | goto unlock_rtnl; | ||
4826 | |||
4827 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 4138 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4828 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 4139 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && |
4829 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 4140 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4830 | err = -EOPNOTSUPP; | 4141 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4831 | goto out; | 4142 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4832 | } | 4143 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4144 | return -EOPNOTSUPP; | ||
4833 | 4145 | ||
4834 | /* not much point in registering if we can't reply */ | 4146 | /* not much point in registering if we can't reply */ |
4835 | if (!rdev->ops->mgmt_tx) { | 4147 | if (!rdev->ops->mgmt_tx) |
4836 | err = -EOPNOTSUPP; | 4148 | return -EOPNOTSUPP; |
4837 | goto out; | ||
4838 | } | ||
4839 | 4149 | ||
4840 | err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, | 4150 | return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, |
4841 | frame_type, | 4151 | frame_type, |
4842 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 4152 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
4843 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 4153 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
4844 | out: | ||
4845 | cfg80211_unlock_rdev(rdev); | ||
4846 | dev_put(dev); | ||
4847 | unlock_rtnl: | ||
4848 | rtnl_unlock(); | ||
4849 | return err; | ||
4850 | } | 4154 | } |
4851 | 4155 | ||
4852 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | 4156 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
4853 | { | 4157 | { |
4854 | struct cfg80211_registered_device *rdev; | 4158 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4855 | struct net_device *dev; | 4159 | struct net_device *dev = info->user_ptr[1]; |
4856 | struct ieee80211_channel *chan; | 4160 | struct ieee80211_channel *chan; |
4857 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 4161 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
4858 | bool channel_type_valid = false; | 4162 | bool channel_type_valid = false; |
@@ -4866,28 +4170,16 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4866 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 4170 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
4867 | return -EINVAL; | 4171 | return -EINVAL; |
4868 | 4172 | ||
4869 | rtnl_lock(); | 4173 | if (!rdev->ops->mgmt_tx) |
4870 | 4174 | return -EOPNOTSUPP; | |
4871 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4872 | if (err) | ||
4873 | goto unlock_rtnl; | ||
4874 | |||
4875 | if (!rdev->ops->mgmt_tx) { | ||
4876 | err = -EOPNOTSUPP; | ||
4877 | goto out; | ||
4878 | } | ||
4879 | 4175 | ||
4880 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 4176 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
4881 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 4177 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && |
4882 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 4178 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4883 | err = -EOPNOTSUPP; | 4179 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4884 | goto out; | 4180 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4885 | } | 4181 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4886 | 4182 | return -EOPNOTSUPP; | |
4887 | if (!netif_running(dev)) { | ||
4888 | err = -ENETDOWN; | ||
4889 | goto out; | ||
4890 | } | ||
4891 | 4183 | ||
4892 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 4184 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4893 | channel_type = nla_get_u32( | 4185 | channel_type = nla_get_u32( |
@@ -4895,25 +4187,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4895 | if (channel_type != NL80211_CHAN_NO_HT && | 4187 | if (channel_type != NL80211_CHAN_NO_HT && |
4896 | channel_type != NL80211_CHAN_HT20 && | 4188 | channel_type != NL80211_CHAN_HT20 && |
4897 | channel_type != NL80211_CHAN_HT40PLUS && | 4189 | channel_type != NL80211_CHAN_HT40PLUS && |
4898 | channel_type != NL80211_CHAN_HT40MINUS) { | 4190 | channel_type != NL80211_CHAN_HT40MINUS) |
4899 | err = -EINVAL; | 4191 | return -EINVAL; |
4900 | goto out; | ||
4901 | } | ||
4902 | channel_type_valid = true; | 4192 | channel_type_valid = true; |
4903 | } | 4193 | } |
4904 | 4194 | ||
4905 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 4195 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4906 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 4196 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4907 | if (chan == NULL) { | 4197 | if (chan == NULL) |
4908 | err = -EINVAL; | 4198 | return -EINVAL; |
4909 | goto out; | ||
4910 | } | ||
4911 | 4199 | ||
4912 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4200 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4913 | if (!msg) { | 4201 | if (!msg) |
4914 | err = -ENOMEM; | 4202 | return -ENOMEM; |
4915 | goto out; | ||
4916 | } | ||
4917 | 4203 | ||
4918 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4204 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4919 | NL80211_CMD_FRAME); | 4205 | NL80211_CMD_FRAME); |
@@ -4933,110 +4219,72 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4933 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | 4219 | NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); |
4934 | 4220 | ||
4935 | genlmsg_end(msg, hdr); | 4221 | genlmsg_end(msg, hdr); |
4936 | err = genlmsg_reply(msg, info); | 4222 | return genlmsg_reply(msg, info); |
4937 | goto out; | ||
4938 | 4223 | ||
4939 | nla_put_failure: | 4224 | nla_put_failure: |
4940 | err = -ENOBUFS; | 4225 | err = -ENOBUFS; |
4941 | free_msg: | 4226 | free_msg: |
4942 | nlmsg_free(msg); | 4227 | nlmsg_free(msg); |
4943 | out: | ||
4944 | cfg80211_unlock_rdev(rdev); | ||
4945 | dev_put(dev); | ||
4946 | unlock_rtnl: | ||
4947 | rtnl_unlock(); | ||
4948 | return err; | 4228 | return err; |
4949 | } | 4229 | } |
4950 | 4230 | ||
4951 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) | 4231 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) |
4952 | { | 4232 | { |
4953 | struct cfg80211_registered_device *rdev; | 4233 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4954 | struct wireless_dev *wdev; | 4234 | struct wireless_dev *wdev; |
4955 | struct net_device *dev; | 4235 | struct net_device *dev = info->user_ptr[1]; |
4956 | u8 ps_state; | 4236 | u8 ps_state; |
4957 | bool state; | 4237 | bool state; |
4958 | int err; | 4238 | int err; |
4959 | 4239 | ||
4960 | if (!info->attrs[NL80211_ATTR_PS_STATE]) { | 4240 | if (!info->attrs[NL80211_ATTR_PS_STATE]) |
4961 | err = -EINVAL; | 4241 | return -EINVAL; |
4962 | goto out; | ||
4963 | } | ||
4964 | 4242 | ||
4965 | ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); | 4243 | ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); |
4966 | 4244 | ||
4967 | if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) { | 4245 | if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) |
4968 | err = -EINVAL; | 4246 | return -EINVAL; |
4969 | goto out; | ||
4970 | } | ||
4971 | |||
4972 | rtnl_lock(); | ||
4973 | |||
4974 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4975 | if (err) | ||
4976 | goto unlock_rtnl; | ||
4977 | 4247 | ||
4978 | wdev = dev->ieee80211_ptr; | 4248 | wdev = dev->ieee80211_ptr; |
4979 | 4249 | ||
4980 | if (!rdev->ops->set_power_mgmt) { | 4250 | if (!rdev->ops->set_power_mgmt) |
4981 | err = -EOPNOTSUPP; | 4251 | return -EOPNOTSUPP; |
4982 | goto unlock_rdev; | ||
4983 | } | ||
4984 | 4252 | ||
4985 | state = (ps_state == NL80211_PS_ENABLED) ? true : false; | 4253 | state = (ps_state == NL80211_PS_ENABLED) ? true : false; |
4986 | 4254 | ||
4987 | if (state == wdev->ps) | 4255 | if (state == wdev->ps) |
4988 | goto unlock_rdev; | 4256 | return 0; |
4989 | |||
4990 | wdev->ps = state; | ||
4991 | |||
4992 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps, | ||
4993 | wdev->ps_timeout)) | ||
4994 | /* assume this means it's off */ | ||
4995 | wdev->ps = false; | ||
4996 | |||
4997 | unlock_rdev: | ||
4998 | cfg80211_unlock_rdev(rdev); | ||
4999 | dev_put(dev); | ||
5000 | unlock_rtnl: | ||
5001 | rtnl_unlock(); | ||
5002 | 4257 | ||
5003 | out: | 4258 | err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state, |
4259 | wdev->ps_timeout); | ||
4260 | if (!err) | ||
4261 | wdev->ps = state; | ||
5004 | return err; | 4262 | return err; |
5005 | } | 4263 | } |
5006 | 4264 | ||
5007 | static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | 4265 | static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) |
5008 | { | 4266 | { |
5009 | struct cfg80211_registered_device *rdev; | 4267 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5010 | enum nl80211_ps_state ps_state; | 4268 | enum nl80211_ps_state ps_state; |
5011 | struct wireless_dev *wdev; | 4269 | struct wireless_dev *wdev; |
5012 | struct net_device *dev; | 4270 | struct net_device *dev = info->user_ptr[1]; |
5013 | struct sk_buff *msg; | 4271 | struct sk_buff *msg; |
5014 | void *hdr; | 4272 | void *hdr; |
5015 | int err; | 4273 | int err; |
5016 | 4274 | ||
5017 | rtnl_lock(); | ||
5018 | |||
5019 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
5020 | if (err) | ||
5021 | goto unlock_rtnl; | ||
5022 | |||
5023 | wdev = dev->ieee80211_ptr; | 4275 | wdev = dev->ieee80211_ptr; |
5024 | 4276 | ||
5025 | if (!rdev->ops->set_power_mgmt) { | 4277 | if (!rdev->ops->set_power_mgmt) |
5026 | err = -EOPNOTSUPP; | 4278 | return -EOPNOTSUPP; |
5027 | goto out; | ||
5028 | } | ||
5029 | 4279 | ||
5030 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4280 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
5031 | if (!msg) { | 4281 | if (!msg) |
5032 | err = -ENOMEM; | 4282 | return -ENOMEM; |
5033 | goto out; | ||
5034 | } | ||
5035 | 4283 | ||
5036 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4284 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
5037 | NL80211_CMD_GET_POWER_SAVE); | 4285 | NL80211_CMD_GET_POWER_SAVE); |
5038 | if (!hdr) { | 4286 | if (!hdr) { |
5039 | err = -ENOMEM; | 4287 | err = -ENOBUFS; |
5040 | goto free_msg; | 4288 | goto free_msg; |
5041 | } | 4289 | } |
5042 | 4290 | ||
@@ -5048,22 +4296,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | |||
5048 | NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); | 4296 | NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); |
5049 | 4297 | ||
5050 | genlmsg_end(msg, hdr); | 4298 | genlmsg_end(msg, hdr); |
5051 | err = genlmsg_reply(msg, info); | 4299 | return genlmsg_reply(msg, info); |
5052 | goto out; | ||
5053 | 4300 | ||
5054 | nla_put_failure: | 4301 | nla_put_failure: |
5055 | err = -ENOBUFS; | 4302 | err = -ENOBUFS; |
5056 | 4303 | free_msg: | |
5057 | free_msg: | ||
5058 | nlmsg_free(msg); | 4304 | nlmsg_free(msg); |
5059 | |||
5060 | out: | ||
5061 | cfg80211_unlock_rdev(rdev); | ||
5062 | dev_put(dev); | ||
5063 | |||
5064 | unlock_rtnl: | ||
5065 | rtnl_unlock(); | ||
5066 | |||
5067 | return err; | 4305 | return err; |
5068 | } | 4306 | } |
5069 | 4307 | ||
@@ -5077,42 +4315,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
5077 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 4315 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
5078 | s32 threshold, u32 hysteresis) | 4316 | s32 threshold, u32 hysteresis) |
5079 | { | 4317 | { |
5080 | struct cfg80211_registered_device *rdev; | 4318 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5081 | struct wireless_dev *wdev; | 4319 | struct wireless_dev *wdev; |
5082 | struct net_device *dev; | 4320 | struct net_device *dev = info->user_ptr[1]; |
5083 | int err; | ||
5084 | 4321 | ||
5085 | if (threshold > 0) | 4322 | if (threshold > 0) |
5086 | return -EINVAL; | 4323 | return -EINVAL; |
5087 | 4324 | ||
5088 | rtnl_lock(); | ||
5089 | |||
5090 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
5091 | if (err) | ||
5092 | goto unlock_rdev; | ||
5093 | |||
5094 | wdev = dev->ieee80211_ptr; | 4325 | wdev = dev->ieee80211_ptr; |
5095 | 4326 | ||
5096 | if (!rdev->ops->set_cqm_rssi_config) { | 4327 | if (!rdev->ops->set_cqm_rssi_config) |
5097 | err = -EOPNOTSUPP; | 4328 | return -EOPNOTSUPP; |
5098 | goto unlock_rdev; | ||
5099 | } | ||
5100 | 4329 | ||
5101 | if (wdev->iftype != NL80211_IFTYPE_STATION && | 4330 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
5102 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { | 4331 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) |
5103 | err = -EOPNOTSUPP; | 4332 | return -EOPNOTSUPP; |
5104 | goto unlock_rdev; | ||
5105 | } | ||
5106 | |||
5107 | err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, | ||
5108 | threshold, hysteresis); | ||
5109 | |||
5110 | unlock_rdev: | ||
5111 | cfg80211_unlock_rdev(rdev); | ||
5112 | dev_put(dev); | ||
5113 | rtnl_unlock(); | ||
5114 | 4333 | ||
5115 | return err; | 4334 | return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, |
4335 | threshold, hysteresis); | ||
5116 | } | 4336 | } |
5117 | 4337 | ||
5118 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | 4338 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) |
@@ -5146,6 +4366,65 @@ out: | |||
5146 | return err; | 4366 | return err; |
5147 | } | 4367 | } |
5148 | 4368 | ||
4369 | #define NL80211_FLAG_NEED_WIPHY 0x01 | ||
4370 | #define NL80211_FLAG_NEED_NETDEV 0x02 | ||
4371 | #define NL80211_FLAG_NEED_RTNL 0x04 | ||
4372 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 | ||
4373 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ | ||
4374 | NL80211_FLAG_CHECK_NETDEV_UP) | ||
4375 | |||
4376 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
4377 | struct genl_info *info) | ||
4378 | { | ||
4379 | struct cfg80211_registered_device *rdev; | ||
4380 | struct net_device *dev; | ||
4381 | int err; | ||
4382 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | ||
4383 | |||
4384 | if (rtnl) | ||
4385 | rtnl_lock(); | ||
4386 | |||
4387 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { | ||
4388 | rdev = cfg80211_get_dev_from_info(info); | ||
4389 | if (IS_ERR(rdev)) { | ||
4390 | if (rtnl) | ||
4391 | rtnl_unlock(); | ||
4392 | return PTR_ERR(rdev); | ||
4393 | } | ||
4394 | info->user_ptr[0] = rdev; | ||
4395 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | ||
4396 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4397 | if (err) { | ||
4398 | if (rtnl) | ||
4399 | rtnl_unlock(); | ||
4400 | return err; | ||
4401 | } | ||
4402 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | ||
4403 | !netif_running(dev)) { | ||
4404 | cfg80211_unlock_rdev(rdev); | ||
4405 | dev_put(dev); | ||
4406 | if (rtnl) | ||
4407 | rtnl_unlock(); | ||
4408 | return -ENETDOWN; | ||
4409 | } | ||
4410 | info->user_ptr[0] = rdev; | ||
4411 | info->user_ptr[1] = dev; | ||
4412 | } | ||
4413 | |||
4414 | return 0; | ||
4415 | } | ||
4416 | |||
4417 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | ||
4418 | struct genl_info *info) | ||
4419 | { | ||
4420 | if (info->user_ptr[0]) | ||
4421 | cfg80211_unlock_rdev(info->user_ptr[0]); | ||
4422 | if (info->user_ptr[1]) | ||
4423 | dev_put(info->user_ptr[1]); | ||
4424 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) | ||
4425 | rtnl_unlock(); | ||
4426 | } | ||
4427 | |||
5149 | static struct genl_ops nl80211_ops[] = { | 4428 | static struct genl_ops nl80211_ops[] = { |
5150 | { | 4429 | { |
5151 | .cmd = NL80211_CMD_GET_WIPHY, | 4430 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -5153,12 +4432,14 @@ static struct genl_ops nl80211_ops[] = { | |||
5153 | .dumpit = nl80211_dump_wiphy, | 4432 | .dumpit = nl80211_dump_wiphy, |
5154 | .policy = nl80211_policy, | 4433 | .policy = nl80211_policy, |
5155 | /* can be retrieved by unprivileged users */ | 4434 | /* can be retrieved by unprivileged users */ |
4435 | .internal_flags = NL80211_FLAG_NEED_WIPHY, | ||
5156 | }, | 4436 | }, |
5157 | { | 4437 | { |
5158 | .cmd = NL80211_CMD_SET_WIPHY, | 4438 | .cmd = NL80211_CMD_SET_WIPHY, |
5159 | .doit = nl80211_set_wiphy, | 4439 | .doit = nl80211_set_wiphy, |
5160 | .policy = nl80211_policy, | 4440 | .policy = nl80211_policy, |
5161 | .flags = GENL_ADMIN_PERM, | 4441 | .flags = GENL_ADMIN_PERM, |
4442 | .internal_flags = NL80211_FLAG_NEED_RTNL, | ||
5162 | }, | 4443 | }, |
5163 | { | 4444 | { |
5164 | .cmd = NL80211_CMD_GET_INTERFACE, | 4445 | .cmd = NL80211_CMD_GET_INTERFACE, |
@@ -5166,90 +4447,119 @@ static struct genl_ops nl80211_ops[] = { | |||
5166 | .dumpit = nl80211_dump_interface, | 4447 | .dumpit = nl80211_dump_interface, |
5167 | .policy = nl80211_policy, | 4448 | .policy = nl80211_policy, |
5168 | /* can be retrieved by unprivileged users */ | 4449 | /* can be retrieved by unprivileged users */ |
4450 | .internal_flags = NL80211_FLAG_NEED_NETDEV, | ||
5169 | }, | 4451 | }, |
5170 | { | 4452 | { |
5171 | .cmd = NL80211_CMD_SET_INTERFACE, | 4453 | .cmd = NL80211_CMD_SET_INTERFACE, |
5172 | .doit = nl80211_set_interface, | 4454 | .doit = nl80211_set_interface, |
5173 | .policy = nl80211_policy, | 4455 | .policy = nl80211_policy, |
5174 | .flags = GENL_ADMIN_PERM, | 4456 | .flags = GENL_ADMIN_PERM, |
4457 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4458 | NL80211_FLAG_NEED_RTNL, | ||
5175 | }, | 4459 | }, |
5176 | { | 4460 | { |
5177 | .cmd = NL80211_CMD_NEW_INTERFACE, | 4461 | .cmd = NL80211_CMD_NEW_INTERFACE, |
5178 | .doit = nl80211_new_interface, | 4462 | .doit = nl80211_new_interface, |
5179 | .policy = nl80211_policy, | 4463 | .policy = nl80211_policy, |
5180 | .flags = GENL_ADMIN_PERM, | 4464 | .flags = GENL_ADMIN_PERM, |
4465 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4466 | NL80211_FLAG_NEED_RTNL, | ||
5181 | }, | 4467 | }, |
5182 | { | 4468 | { |
5183 | .cmd = NL80211_CMD_DEL_INTERFACE, | 4469 | .cmd = NL80211_CMD_DEL_INTERFACE, |
5184 | .doit = nl80211_del_interface, | 4470 | .doit = nl80211_del_interface, |
5185 | .policy = nl80211_policy, | 4471 | .policy = nl80211_policy, |
5186 | .flags = GENL_ADMIN_PERM, | 4472 | .flags = GENL_ADMIN_PERM, |
4473 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4474 | NL80211_FLAG_NEED_RTNL, | ||
5187 | }, | 4475 | }, |
5188 | { | 4476 | { |
5189 | .cmd = NL80211_CMD_GET_KEY, | 4477 | .cmd = NL80211_CMD_GET_KEY, |
5190 | .doit = nl80211_get_key, | 4478 | .doit = nl80211_get_key, |
5191 | .policy = nl80211_policy, | 4479 | .policy = nl80211_policy, |
5192 | .flags = GENL_ADMIN_PERM, | 4480 | .flags = GENL_ADMIN_PERM, |
4481 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4482 | NL80211_FLAG_NEED_RTNL, | ||
5193 | }, | 4483 | }, |
5194 | { | 4484 | { |
5195 | .cmd = NL80211_CMD_SET_KEY, | 4485 | .cmd = NL80211_CMD_SET_KEY, |
5196 | .doit = nl80211_set_key, | 4486 | .doit = nl80211_set_key, |
5197 | .policy = nl80211_policy, | 4487 | .policy = nl80211_policy, |
5198 | .flags = GENL_ADMIN_PERM, | 4488 | .flags = GENL_ADMIN_PERM, |
4489 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4490 | NL80211_FLAG_NEED_RTNL, | ||
5199 | }, | 4491 | }, |
5200 | { | 4492 | { |
5201 | .cmd = NL80211_CMD_NEW_KEY, | 4493 | .cmd = NL80211_CMD_NEW_KEY, |
5202 | .doit = nl80211_new_key, | 4494 | .doit = nl80211_new_key, |
5203 | .policy = nl80211_policy, | 4495 | .policy = nl80211_policy, |
5204 | .flags = GENL_ADMIN_PERM, | 4496 | .flags = GENL_ADMIN_PERM, |
4497 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4498 | NL80211_FLAG_NEED_RTNL, | ||
5205 | }, | 4499 | }, |
5206 | { | 4500 | { |
5207 | .cmd = NL80211_CMD_DEL_KEY, | 4501 | .cmd = NL80211_CMD_DEL_KEY, |
5208 | .doit = nl80211_del_key, | 4502 | .doit = nl80211_del_key, |
5209 | .policy = nl80211_policy, | 4503 | .policy = nl80211_policy, |
5210 | .flags = GENL_ADMIN_PERM, | 4504 | .flags = GENL_ADMIN_PERM, |
4505 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4506 | NL80211_FLAG_NEED_RTNL, | ||
5211 | }, | 4507 | }, |
5212 | { | 4508 | { |
5213 | .cmd = NL80211_CMD_SET_BEACON, | 4509 | .cmd = NL80211_CMD_SET_BEACON, |
5214 | .policy = nl80211_policy, | 4510 | .policy = nl80211_policy, |
5215 | .flags = GENL_ADMIN_PERM, | 4511 | .flags = GENL_ADMIN_PERM, |
5216 | .doit = nl80211_addset_beacon, | 4512 | .doit = nl80211_addset_beacon, |
4513 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4514 | NL80211_FLAG_NEED_RTNL, | ||
5217 | }, | 4515 | }, |
5218 | { | 4516 | { |
5219 | .cmd = NL80211_CMD_NEW_BEACON, | 4517 | .cmd = NL80211_CMD_NEW_BEACON, |
5220 | .policy = nl80211_policy, | 4518 | .policy = nl80211_policy, |
5221 | .flags = GENL_ADMIN_PERM, | 4519 | .flags = GENL_ADMIN_PERM, |
5222 | .doit = nl80211_addset_beacon, | 4520 | .doit = nl80211_addset_beacon, |
4521 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4522 | NL80211_FLAG_NEED_RTNL, | ||
5223 | }, | 4523 | }, |
5224 | { | 4524 | { |
5225 | .cmd = NL80211_CMD_DEL_BEACON, | 4525 | .cmd = NL80211_CMD_DEL_BEACON, |
5226 | .policy = nl80211_policy, | 4526 | .policy = nl80211_policy, |
5227 | .flags = GENL_ADMIN_PERM, | 4527 | .flags = GENL_ADMIN_PERM, |
5228 | .doit = nl80211_del_beacon, | 4528 | .doit = nl80211_del_beacon, |
4529 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4530 | NL80211_FLAG_NEED_RTNL, | ||
5229 | }, | 4531 | }, |
5230 | { | 4532 | { |
5231 | .cmd = NL80211_CMD_GET_STATION, | 4533 | .cmd = NL80211_CMD_GET_STATION, |
5232 | .doit = nl80211_get_station, | 4534 | .doit = nl80211_get_station, |
5233 | .dumpit = nl80211_dump_station, | 4535 | .dumpit = nl80211_dump_station, |
5234 | .policy = nl80211_policy, | 4536 | .policy = nl80211_policy, |
4537 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4538 | NL80211_FLAG_NEED_RTNL, | ||
5235 | }, | 4539 | }, |
5236 | { | 4540 | { |
5237 | .cmd = NL80211_CMD_SET_STATION, | 4541 | .cmd = NL80211_CMD_SET_STATION, |
5238 | .doit = nl80211_set_station, | 4542 | .doit = nl80211_set_station, |
5239 | .policy = nl80211_policy, | 4543 | .policy = nl80211_policy, |
5240 | .flags = GENL_ADMIN_PERM, | 4544 | .flags = GENL_ADMIN_PERM, |
4545 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4546 | NL80211_FLAG_NEED_RTNL, | ||
5241 | }, | 4547 | }, |
5242 | { | 4548 | { |
5243 | .cmd = NL80211_CMD_NEW_STATION, | 4549 | .cmd = NL80211_CMD_NEW_STATION, |
5244 | .doit = nl80211_new_station, | 4550 | .doit = nl80211_new_station, |
5245 | .policy = nl80211_policy, | 4551 | .policy = nl80211_policy, |
5246 | .flags = GENL_ADMIN_PERM, | 4552 | .flags = GENL_ADMIN_PERM, |
4553 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4554 | NL80211_FLAG_NEED_RTNL, | ||
5247 | }, | 4555 | }, |
5248 | { | 4556 | { |
5249 | .cmd = NL80211_CMD_DEL_STATION, | 4557 | .cmd = NL80211_CMD_DEL_STATION, |
5250 | .doit = nl80211_del_station, | 4558 | .doit = nl80211_del_station, |
5251 | .policy = nl80211_policy, | 4559 | .policy = nl80211_policy, |
5252 | .flags = GENL_ADMIN_PERM, | 4560 | .flags = GENL_ADMIN_PERM, |
4561 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4562 | NL80211_FLAG_NEED_RTNL, | ||
5253 | }, | 4563 | }, |
5254 | { | 4564 | { |
5255 | .cmd = NL80211_CMD_GET_MPATH, | 4565 | .cmd = NL80211_CMD_GET_MPATH, |
@@ -5257,30 +4567,40 @@ static struct genl_ops nl80211_ops[] = { | |||
5257 | .dumpit = nl80211_dump_mpath, | 4567 | .dumpit = nl80211_dump_mpath, |
5258 | .policy = nl80211_policy, | 4568 | .policy = nl80211_policy, |
5259 | .flags = GENL_ADMIN_PERM, | 4569 | .flags = GENL_ADMIN_PERM, |
4570 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4571 | NL80211_FLAG_NEED_RTNL, | ||
5260 | }, | 4572 | }, |
5261 | { | 4573 | { |
5262 | .cmd = NL80211_CMD_SET_MPATH, | 4574 | .cmd = NL80211_CMD_SET_MPATH, |
5263 | .doit = nl80211_set_mpath, | 4575 | .doit = nl80211_set_mpath, |
5264 | .policy = nl80211_policy, | 4576 | .policy = nl80211_policy, |
5265 | .flags = GENL_ADMIN_PERM, | 4577 | .flags = GENL_ADMIN_PERM, |
4578 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4579 | NL80211_FLAG_NEED_RTNL, | ||
5266 | }, | 4580 | }, |
5267 | { | 4581 | { |
5268 | .cmd = NL80211_CMD_NEW_MPATH, | 4582 | .cmd = NL80211_CMD_NEW_MPATH, |
5269 | .doit = nl80211_new_mpath, | 4583 | .doit = nl80211_new_mpath, |
5270 | .policy = nl80211_policy, | 4584 | .policy = nl80211_policy, |
5271 | .flags = GENL_ADMIN_PERM, | 4585 | .flags = GENL_ADMIN_PERM, |
4586 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4587 | NL80211_FLAG_NEED_RTNL, | ||
5272 | }, | 4588 | }, |
5273 | { | 4589 | { |
5274 | .cmd = NL80211_CMD_DEL_MPATH, | 4590 | .cmd = NL80211_CMD_DEL_MPATH, |
5275 | .doit = nl80211_del_mpath, | 4591 | .doit = nl80211_del_mpath, |
5276 | .policy = nl80211_policy, | 4592 | .policy = nl80211_policy, |
5277 | .flags = GENL_ADMIN_PERM, | 4593 | .flags = GENL_ADMIN_PERM, |
4594 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4595 | NL80211_FLAG_NEED_RTNL, | ||
5278 | }, | 4596 | }, |
5279 | { | 4597 | { |
5280 | .cmd = NL80211_CMD_SET_BSS, | 4598 | .cmd = NL80211_CMD_SET_BSS, |
5281 | .doit = nl80211_set_bss, | 4599 | .doit = nl80211_set_bss, |
5282 | .policy = nl80211_policy, | 4600 | .policy = nl80211_policy, |
5283 | .flags = GENL_ADMIN_PERM, | 4601 | .flags = GENL_ADMIN_PERM, |
4602 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4603 | NL80211_FLAG_NEED_RTNL, | ||
5284 | }, | 4604 | }, |
5285 | { | 4605 | { |
5286 | .cmd = NL80211_CMD_GET_REG, | 4606 | .cmd = NL80211_CMD_GET_REG, |
@@ -5305,18 +4625,24 @@ static struct genl_ops nl80211_ops[] = { | |||
5305 | .doit = nl80211_get_mesh_params, | 4625 | .doit = nl80211_get_mesh_params, |
5306 | .policy = nl80211_policy, | 4626 | .policy = nl80211_policy, |
5307 | /* can be retrieved by unprivileged users */ | 4627 | /* can be retrieved by unprivileged users */ |
4628 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4629 | NL80211_FLAG_NEED_RTNL, | ||
5308 | }, | 4630 | }, |
5309 | { | 4631 | { |
5310 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 4632 | .cmd = NL80211_CMD_SET_MESH_PARAMS, |
5311 | .doit = nl80211_set_mesh_params, | 4633 | .doit = nl80211_set_mesh_params, |
5312 | .policy = nl80211_policy, | 4634 | .policy = nl80211_policy, |
5313 | .flags = GENL_ADMIN_PERM, | 4635 | .flags = GENL_ADMIN_PERM, |
4636 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4637 | NL80211_FLAG_NEED_RTNL, | ||
5314 | }, | 4638 | }, |
5315 | { | 4639 | { |
5316 | .cmd = NL80211_CMD_TRIGGER_SCAN, | 4640 | .cmd = NL80211_CMD_TRIGGER_SCAN, |
5317 | .doit = nl80211_trigger_scan, | 4641 | .doit = nl80211_trigger_scan, |
5318 | .policy = nl80211_policy, | 4642 | .policy = nl80211_policy, |
5319 | .flags = GENL_ADMIN_PERM, | 4643 | .flags = GENL_ADMIN_PERM, |
4644 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4645 | NL80211_FLAG_NEED_RTNL, | ||
5320 | }, | 4646 | }, |
5321 | { | 4647 | { |
5322 | .cmd = NL80211_CMD_GET_SCAN, | 4648 | .cmd = NL80211_CMD_GET_SCAN, |
@@ -5328,36 +4654,48 @@ static struct genl_ops nl80211_ops[] = { | |||
5328 | .doit = nl80211_authenticate, | 4654 | .doit = nl80211_authenticate, |
5329 | .policy = nl80211_policy, | 4655 | .policy = nl80211_policy, |
5330 | .flags = GENL_ADMIN_PERM, | 4656 | .flags = GENL_ADMIN_PERM, |
4657 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4658 | NL80211_FLAG_NEED_RTNL, | ||
5331 | }, | 4659 | }, |
5332 | { | 4660 | { |
5333 | .cmd = NL80211_CMD_ASSOCIATE, | 4661 | .cmd = NL80211_CMD_ASSOCIATE, |
5334 | .doit = nl80211_associate, | 4662 | .doit = nl80211_associate, |
5335 | .policy = nl80211_policy, | 4663 | .policy = nl80211_policy, |
5336 | .flags = GENL_ADMIN_PERM, | 4664 | .flags = GENL_ADMIN_PERM, |
4665 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4666 | NL80211_FLAG_NEED_RTNL, | ||
5337 | }, | 4667 | }, |
5338 | { | 4668 | { |
5339 | .cmd = NL80211_CMD_DEAUTHENTICATE, | 4669 | .cmd = NL80211_CMD_DEAUTHENTICATE, |
5340 | .doit = nl80211_deauthenticate, | 4670 | .doit = nl80211_deauthenticate, |
5341 | .policy = nl80211_policy, | 4671 | .policy = nl80211_policy, |
5342 | .flags = GENL_ADMIN_PERM, | 4672 | .flags = GENL_ADMIN_PERM, |
4673 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4674 | NL80211_FLAG_NEED_RTNL, | ||
5343 | }, | 4675 | }, |
5344 | { | 4676 | { |
5345 | .cmd = NL80211_CMD_DISASSOCIATE, | 4677 | .cmd = NL80211_CMD_DISASSOCIATE, |
5346 | .doit = nl80211_disassociate, | 4678 | .doit = nl80211_disassociate, |
5347 | .policy = nl80211_policy, | 4679 | .policy = nl80211_policy, |
5348 | .flags = GENL_ADMIN_PERM, | 4680 | .flags = GENL_ADMIN_PERM, |
4681 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4682 | NL80211_FLAG_NEED_RTNL, | ||
5349 | }, | 4683 | }, |
5350 | { | 4684 | { |
5351 | .cmd = NL80211_CMD_JOIN_IBSS, | 4685 | .cmd = NL80211_CMD_JOIN_IBSS, |
5352 | .doit = nl80211_join_ibss, | 4686 | .doit = nl80211_join_ibss, |
5353 | .policy = nl80211_policy, | 4687 | .policy = nl80211_policy, |
5354 | .flags = GENL_ADMIN_PERM, | 4688 | .flags = GENL_ADMIN_PERM, |
4689 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4690 | NL80211_FLAG_NEED_RTNL, | ||
5355 | }, | 4691 | }, |
5356 | { | 4692 | { |
5357 | .cmd = NL80211_CMD_LEAVE_IBSS, | 4693 | .cmd = NL80211_CMD_LEAVE_IBSS, |
5358 | .doit = nl80211_leave_ibss, | 4694 | .doit = nl80211_leave_ibss, |
5359 | .policy = nl80211_policy, | 4695 | .policy = nl80211_policy, |
5360 | .flags = GENL_ADMIN_PERM, | 4696 | .flags = GENL_ADMIN_PERM, |
4697 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4698 | NL80211_FLAG_NEED_RTNL, | ||
5361 | }, | 4699 | }, |
5362 | #ifdef CONFIG_NL80211_TESTMODE | 4700 | #ifdef CONFIG_NL80211_TESTMODE |
5363 | { | 4701 | { |
@@ -5365,6 +4703,8 @@ static struct genl_ops nl80211_ops[] = { | |||
5365 | .doit = nl80211_testmode_do, | 4703 | .doit = nl80211_testmode_do, |
5366 | .policy = nl80211_policy, | 4704 | .policy = nl80211_policy, |
5367 | .flags = GENL_ADMIN_PERM, | 4705 | .flags = GENL_ADMIN_PERM, |
4706 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4707 | NL80211_FLAG_NEED_RTNL, | ||
5368 | }, | 4708 | }, |
5369 | #endif | 4709 | #endif |
5370 | { | 4710 | { |
@@ -5372,18 +4712,24 @@ static struct genl_ops nl80211_ops[] = { | |||
5372 | .doit = nl80211_connect, | 4712 | .doit = nl80211_connect, |
5373 | .policy = nl80211_policy, | 4713 | .policy = nl80211_policy, |
5374 | .flags = GENL_ADMIN_PERM, | 4714 | .flags = GENL_ADMIN_PERM, |
4715 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4716 | NL80211_FLAG_NEED_RTNL, | ||
5375 | }, | 4717 | }, |
5376 | { | 4718 | { |
5377 | .cmd = NL80211_CMD_DISCONNECT, | 4719 | .cmd = NL80211_CMD_DISCONNECT, |
5378 | .doit = nl80211_disconnect, | 4720 | .doit = nl80211_disconnect, |
5379 | .policy = nl80211_policy, | 4721 | .policy = nl80211_policy, |
5380 | .flags = GENL_ADMIN_PERM, | 4722 | .flags = GENL_ADMIN_PERM, |
4723 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4724 | NL80211_FLAG_NEED_RTNL, | ||
5381 | }, | 4725 | }, |
5382 | { | 4726 | { |
5383 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, | 4727 | .cmd = NL80211_CMD_SET_WIPHY_NETNS, |
5384 | .doit = nl80211_wiphy_netns, | 4728 | .doit = nl80211_wiphy_netns, |
5385 | .policy = nl80211_policy, | 4729 | .policy = nl80211_policy, |
5386 | .flags = GENL_ADMIN_PERM, | 4730 | .flags = GENL_ADMIN_PERM, |
4731 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
4732 | NL80211_FLAG_NEED_RTNL, | ||
5387 | }, | 4733 | }, |
5388 | { | 4734 | { |
5389 | .cmd = NL80211_CMD_GET_SURVEY, | 4735 | .cmd = NL80211_CMD_GET_SURVEY, |
@@ -5395,72 +4741,104 @@ static struct genl_ops nl80211_ops[] = { | |||
5395 | .doit = nl80211_setdel_pmksa, | 4741 | .doit = nl80211_setdel_pmksa, |
5396 | .policy = nl80211_policy, | 4742 | .policy = nl80211_policy, |
5397 | .flags = GENL_ADMIN_PERM, | 4743 | .flags = GENL_ADMIN_PERM, |
4744 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4745 | NL80211_FLAG_NEED_RTNL, | ||
5398 | }, | 4746 | }, |
5399 | { | 4747 | { |
5400 | .cmd = NL80211_CMD_DEL_PMKSA, | 4748 | .cmd = NL80211_CMD_DEL_PMKSA, |
5401 | .doit = nl80211_setdel_pmksa, | 4749 | .doit = nl80211_setdel_pmksa, |
5402 | .policy = nl80211_policy, | 4750 | .policy = nl80211_policy, |
5403 | .flags = GENL_ADMIN_PERM, | 4751 | .flags = GENL_ADMIN_PERM, |
4752 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4753 | NL80211_FLAG_NEED_RTNL, | ||
5404 | }, | 4754 | }, |
5405 | { | 4755 | { |
5406 | .cmd = NL80211_CMD_FLUSH_PMKSA, | 4756 | .cmd = NL80211_CMD_FLUSH_PMKSA, |
5407 | .doit = nl80211_flush_pmksa, | 4757 | .doit = nl80211_flush_pmksa, |
5408 | .policy = nl80211_policy, | 4758 | .policy = nl80211_policy, |
5409 | .flags = GENL_ADMIN_PERM, | 4759 | .flags = GENL_ADMIN_PERM, |
4760 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4761 | NL80211_FLAG_NEED_RTNL, | ||
5410 | }, | 4762 | }, |
5411 | { | 4763 | { |
5412 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, | 4764 | .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, |
5413 | .doit = nl80211_remain_on_channel, | 4765 | .doit = nl80211_remain_on_channel, |
5414 | .policy = nl80211_policy, | 4766 | .policy = nl80211_policy, |
5415 | .flags = GENL_ADMIN_PERM, | 4767 | .flags = GENL_ADMIN_PERM, |
4768 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4769 | NL80211_FLAG_NEED_RTNL, | ||
5416 | }, | 4770 | }, |
5417 | { | 4771 | { |
5418 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 4772 | .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
5419 | .doit = nl80211_cancel_remain_on_channel, | 4773 | .doit = nl80211_cancel_remain_on_channel, |
5420 | .policy = nl80211_policy, | 4774 | .policy = nl80211_policy, |
5421 | .flags = GENL_ADMIN_PERM, | 4775 | .flags = GENL_ADMIN_PERM, |
4776 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4777 | NL80211_FLAG_NEED_RTNL, | ||
5422 | }, | 4778 | }, |
5423 | { | 4779 | { |
5424 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, | 4780 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, |
5425 | .doit = nl80211_set_tx_bitrate_mask, | 4781 | .doit = nl80211_set_tx_bitrate_mask, |
5426 | .policy = nl80211_policy, | 4782 | .policy = nl80211_policy, |
5427 | .flags = GENL_ADMIN_PERM, | 4783 | .flags = GENL_ADMIN_PERM, |
4784 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4785 | NL80211_FLAG_NEED_RTNL, | ||
5428 | }, | 4786 | }, |
5429 | { | 4787 | { |
5430 | .cmd = NL80211_CMD_REGISTER_FRAME, | 4788 | .cmd = NL80211_CMD_REGISTER_FRAME, |
5431 | .doit = nl80211_register_mgmt, | 4789 | .doit = nl80211_register_mgmt, |
5432 | .policy = nl80211_policy, | 4790 | .policy = nl80211_policy, |
5433 | .flags = GENL_ADMIN_PERM, | 4791 | .flags = GENL_ADMIN_PERM, |
4792 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4793 | NL80211_FLAG_NEED_RTNL, | ||
5434 | }, | 4794 | }, |
5435 | { | 4795 | { |
5436 | .cmd = NL80211_CMD_FRAME, | 4796 | .cmd = NL80211_CMD_FRAME, |
5437 | .doit = nl80211_tx_mgmt, | 4797 | .doit = nl80211_tx_mgmt, |
5438 | .policy = nl80211_policy, | 4798 | .policy = nl80211_policy, |
5439 | .flags = GENL_ADMIN_PERM, | 4799 | .flags = GENL_ADMIN_PERM, |
4800 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
4801 | NL80211_FLAG_NEED_RTNL, | ||
5440 | }, | 4802 | }, |
5441 | { | 4803 | { |
5442 | .cmd = NL80211_CMD_SET_POWER_SAVE, | 4804 | .cmd = NL80211_CMD_SET_POWER_SAVE, |
5443 | .doit = nl80211_set_power_save, | 4805 | .doit = nl80211_set_power_save, |
5444 | .policy = nl80211_policy, | 4806 | .policy = nl80211_policy, |
5445 | .flags = GENL_ADMIN_PERM, | 4807 | .flags = GENL_ADMIN_PERM, |
4808 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4809 | NL80211_FLAG_NEED_RTNL, | ||
5446 | }, | 4810 | }, |
5447 | { | 4811 | { |
5448 | .cmd = NL80211_CMD_GET_POWER_SAVE, | 4812 | .cmd = NL80211_CMD_GET_POWER_SAVE, |
5449 | .doit = nl80211_get_power_save, | 4813 | .doit = nl80211_get_power_save, |
5450 | .policy = nl80211_policy, | 4814 | .policy = nl80211_policy, |
5451 | /* can be retrieved by unprivileged users */ | 4815 | /* can be retrieved by unprivileged users */ |
4816 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4817 | NL80211_FLAG_NEED_RTNL, | ||
5452 | }, | 4818 | }, |
5453 | { | 4819 | { |
5454 | .cmd = NL80211_CMD_SET_CQM, | 4820 | .cmd = NL80211_CMD_SET_CQM, |
5455 | .doit = nl80211_set_cqm, | 4821 | .doit = nl80211_set_cqm, |
5456 | .policy = nl80211_policy, | 4822 | .policy = nl80211_policy, |
5457 | .flags = GENL_ADMIN_PERM, | 4823 | .flags = GENL_ADMIN_PERM, |
4824 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4825 | NL80211_FLAG_NEED_RTNL, | ||
5458 | }, | 4826 | }, |
5459 | { | 4827 | { |
5460 | .cmd = NL80211_CMD_SET_CHANNEL, | 4828 | .cmd = NL80211_CMD_SET_CHANNEL, |
5461 | .doit = nl80211_set_channel, | 4829 | .doit = nl80211_set_channel, |
5462 | .policy = nl80211_policy, | 4830 | .policy = nl80211_policy, |
5463 | .flags = GENL_ADMIN_PERM, | 4831 | .flags = GENL_ADMIN_PERM, |
4832 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4833 | NL80211_FLAG_NEED_RTNL, | ||
4834 | }, | ||
4835 | { | ||
4836 | .cmd = NL80211_CMD_SET_WDS_PEER, | ||
4837 | .doit = nl80211_set_wds_peer, | ||
4838 | .policy = nl80211_policy, | ||
4839 | .flags = GENL_ADMIN_PERM, | ||
4840 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
4841 | NL80211_FLAG_NEED_RTNL, | ||
5464 | }, | 4842 | }, |
5465 | }; | 4843 | }; |
5466 | 4844 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 5ca8c7180141..503ebb86ba18 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
650 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | 650 | bss = container_of(pub, struct cfg80211_internal_bss, pub); |
651 | 651 | ||
652 | spin_lock_bh(&dev->bss_lock); | 652 | spin_lock_bh(&dev->bss_lock); |
653 | if (!list_empty(&bss->list)) { | ||
654 | list_del_init(&bss->list); | ||
655 | dev->bss_generation++; | ||
656 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
653 | 657 | ||
654 | list_del(&bss->list); | 658 | kref_put(&bss->ref, bss_release); |
655 | dev->bss_generation++; | 659 | } |
656 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
657 | |||
658 | spin_unlock_bh(&dev->bss_lock); | 660 | spin_unlock_bh(&dev->bss_lock); |
659 | |||
660 | kref_put(&bss->ref, bss_release); | ||
661 | } | 661 | } |
662 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 662 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
663 | 663 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f161b9844542..e17b0bee6bdc 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -698,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
698 | */ | 698 | */ |
699 | if (rdev->ops->del_key) | 699 | if (rdev->ops->del_key) |
700 | for (i = 0; i < 6; i++) | 700 | for (i = 0; i < 6; i++) |
701 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | 701 | rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); |
702 | 702 | ||
703 | #ifdef CONFIG_CFG80211_WEXT | 703 | #ifdef CONFIG_CFG80211_WEXT |
704 | memset(&wrqu, 0, sizeof(wrqu)); | 704 | memset(&wrqu, 0, sizeof(wrqu)); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index fb5448f7d55a..76120aeda57d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
144 | 144 | ||
145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
146 | struct key_params *params, int key_idx, | 146 | struct key_params *params, int key_idx, |
147 | const u8 *mac_addr) | 147 | bool pairwise, const u8 *mac_addr) |
148 | { | 148 | { |
149 | int i; | 149 | int i; |
150 | 150 | ||
151 | if (key_idx > 5) | 151 | if (key_idx > 5) |
152 | return -EINVAL; | 152 | return -EINVAL; |
153 | 153 | ||
154 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
155 | return -EINVAL; | ||
156 | |||
157 | if (pairwise && !mac_addr) | ||
158 | return -EINVAL; | ||
159 | |||
154 | /* | 160 | /* |
155 | * Disallow pairwise keys with non-zero index unless it's WEP | 161 | * Disallow pairwise keys with non-zero index unless it's WEP |
156 | * (because current deployments use pairwise WEP keys with | 162 | * (because current deployments use pairwise WEP keys with |
157 | * non-zero indizes but 802.11i clearly specifies to use zero) | 163 | * non-zero indizes but 802.11i clearly specifies to use zero) |
158 | */ | 164 | */ |
159 | if (mac_addr && key_idx && | 165 | if (pairwise && key_idx && |
160 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && | 166 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && |
161 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | 167 | params->cipher != WLAN_CIPHER_SUITE_WEP104) |
162 | return -EINVAL; | 168 | return -EINVAL; |
@@ -677,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
677 | for (i = 0; i < 6; i++) { | 683 | for (i = 0; i < 6; i++) { |
678 | if (!wdev->connect_keys->params[i].cipher) | 684 | if (!wdev->connect_keys->params[i].cipher) |
679 | continue; | 685 | continue; |
680 | if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, | 686 | if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, |
681 | &wdev->connect_keys->params[i])) { | 687 | &wdev->connect_keys->params[i])) { |
682 | printk(KERN_ERR "%s: failed to set key %d\n", | 688 | printk(KERN_ERR "%s: failed to set key %d\n", |
683 | dev->name, i); | 689 | dev->name, i); |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7e5c3a45f811..6002265289c6 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
433 | 433 | ||
434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
435 | struct net_device *dev, const u8 *addr, | 435 | struct net_device *dev, bool pairwise, |
436 | bool remove, bool tx_key, int idx, | 436 | const u8 *addr, bool remove, bool tx_key, |
437 | struct key_params *params) | 437 | int idx, struct key_params *params) |
438 | { | 438 | { |
439 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 439 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
440 | int err, i; | 440 | int err, i; |
441 | bool rejoin = false; | 441 | bool rejoin = false; |
442 | 442 | ||
443 | if (pairwise && !addr) | ||
444 | return -EINVAL; | ||
445 | |||
443 | if (!wdev->wext.keys) { | 446 | if (!wdev->wext.keys) { |
444 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | 447 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
445 | GFP_KERNEL); | 448 | GFP_KERNEL); |
@@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
478 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | 481 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
479 | rejoin = true; | 482 | rejoin = true; |
480 | } | 483 | } |
481 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | 484 | |
485 | if (!pairwise && addr && | ||
486 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
487 | err = -ENOENT; | ||
488 | else | ||
489 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, | ||
490 | pairwise, addr); | ||
482 | } | 491 | } |
483 | wdev->wext.connect.privacy = false; | 492 | wdev->wext.connect.privacy = false; |
484 | /* | 493 | /* |
@@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
507 | if (addr) | 516 | if (addr) |
508 | tx_key = false; | 517 | tx_key = false; |
509 | 518 | ||
510 | if (cfg80211_validate_key_settings(rdev, params, idx, addr)) | 519 | if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr)) |
511 | return -EINVAL; | 520 | return -EINVAL; |
512 | 521 | ||
513 | err = 0; | 522 | err = 0; |
514 | if (wdev->current_bss) | 523 | if (wdev->current_bss) |
515 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); | 524 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, |
525 | pairwise, addr, params); | ||
516 | if (err) | 526 | if (err) |
517 | return err; | 527 | return err; |
518 | 528 | ||
@@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
563 | } | 573 | } |
564 | 574 | ||
565 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 575 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
566 | struct net_device *dev, const u8 *addr, | 576 | struct net_device *dev, bool pairwise, |
567 | bool remove, bool tx_key, int idx, | 577 | const u8 *addr, bool remove, bool tx_key, |
568 | struct key_params *params) | 578 | int idx, struct key_params *params) |
569 | { | 579 | { |
570 | int err; | 580 | int err; |
571 | 581 | ||
572 | /* devlist mutex needed for possible IBSS re-join */ | 582 | /* devlist mutex needed for possible IBSS re-join */ |
573 | mutex_lock(&rdev->devlist_mtx); | 583 | mutex_lock(&rdev->devlist_mtx); |
574 | wdev_lock(dev->ieee80211_ptr); | 584 | wdev_lock(dev->ieee80211_ptr); |
575 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, | 585 | err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, |
576 | tx_key, idx, params); | 586 | remove, tx_key, idx, params); |
577 | wdev_unlock(dev->ieee80211_ptr); | 587 | wdev_unlock(dev->ieee80211_ptr); |
578 | mutex_unlock(&rdev->devlist_mtx); | 588 | mutex_unlock(&rdev->devlist_mtx); |
579 | 589 | ||
@@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev, | |||
635 | else if (!remove) | 645 | else if (!remove) |
636 | return -EINVAL; | 646 | return -EINVAL; |
637 | 647 | ||
638 | return cfg80211_set_encryption(rdev, dev, NULL, remove, | 648 | return cfg80211_set_encryption(rdev, dev, false, NULL, remove, |
639 | wdev->wext.default_key == -1, | 649 | wdev->wext.default_key == -1, |
640 | idx, ¶ms); | 650 | idx, ¶ms); |
641 | } | 651 | } |
@@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, | |||
725 | } | 735 | } |
726 | 736 | ||
727 | return cfg80211_set_encryption( | 737 | return cfg80211_set_encryption( |
728 | rdev, dev, addr, remove, | 738 | rdev, dev, |
739 | !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), | ||
740 | addr, remove, | ||
729 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | 741 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, |
730 | idx, ¶ms); | 742 | idx, ¶ms); |
731 | } | 743 | } |