diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 213 |
1 files changed, 157 insertions, 56 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e677b751d468..3f47276caeb8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/rcupdate.h> | 13 | #include <linux/rcupdate.h> |
14 | #include <net/cfg80211.h> | 14 | #include <net/cfg80211.h> |
15 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
16 | #include "driver-ops.h" | ||
16 | #include "cfg.h" | 17 | #include "cfg.h" |
17 | #include "rate.h" | 18 | #include "rate.h" |
18 | #include "mesh.h" | 19 | #include "mesh.h" |
@@ -111,7 +112,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | |||
111 | } | 112 | } |
112 | 113 | ||
113 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | 114 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, |
114 | u8 key_idx, u8 *mac_addr, | 115 | u8 key_idx, const u8 *mac_addr, |
115 | struct key_params *params) | 116 | struct key_params *params) |
116 | { | 117 | { |
117 | struct ieee80211_sub_if_data *sdata; | 118 | struct ieee80211_sub_if_data *sdata; |
@@ -140,7 +141,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
140 | return -EINVAL; | 141 | return -EINVAL; |
141 | } | 142 | } |
142 | 143 | ||
143 | key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); | 144 | key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key, |
145 | params->seq_len, params->seq); | ||
144 | if (!key) | 146 | if (!key) |
145 | return -ENOMEM; | 147 | return -ENOMEM; |
146 | 148 | ||
@@ -165,7 +167,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
165 | } | 167 | } |
166 | 168 | ||
167 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 169 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
168 | u8 key_idx, u8 *mac_addr) | 170 | u8 key_idx, const u8 *mac_addr) |
169 | { | 171 | { |
170 | struct ieee80211_sub_if_data *sdata; | 172 | struct ieee80211_sub_if_data *sdata; |
171 | struct sta_info *sta; | 173 | struct sta_info *sta; |
@@ -207,7 +209,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
207 | } | 209 | } |
208 | 210 | ||
209 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | 211 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, |
210 | u8 key_idx, u8 *mac_addr, void *cookie, | 212 | u8 key_idx, const u8 *mac_addr, void *cookie, |
211 | void (*callback)(void *cookie, | 213 | void (*callback)(void *cookie, |
212 | struct key_params *params)) | 214 | struct key_params *params)) |
213 | { | 215 | { |
@@ -245,12 +247,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
245 | iv32 = key->u.tkip.tx.iv32; | 247 | iv32 = key->u.tkip.tx.iv32; |
246 | iv16 = key->u.tkip.tx.iv16; | 248 | iv16 = key->u.tkip.tx.iv16; |
247 | 249 | ||
248 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && | 250 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) |
249 | sdata->local->ops->get_tkip_seq) | 251 | drv_get_tkip_seq(sdata->local, |
250 | sdata->local->ops->get_tkip_seq( | 252 | key->conf.hw_key_idx, |
251 | local_to_hw(sdata->local), | 253 | &iv32, &iv16); |
252 | key->conf.hw_key_idx, | ||
253 | &iv32, &iv16); | ||
254 | 254 | ||
255 | seq[0] = iv16 & 0xff; | 255 | seq[0] = iv16 & 0xff; |
256 | seq[1] = (iv16 >> 8) & 0xff; | 256 | seq[1] = (iv16 >> 8) & 0xff; |
@@ -451,18 +451,11 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
451 | * This is a kludge. beacon interval should really be part | 451 | * This is a kludge. beacon interval should really be part |
452 | * of the beacon information. | 452 | * of the beacon information. |
453 | */ | 453 | */ |
454 | if (params->interval && (sdata->local->hw.conf.beacon_int != | 454 | if (params->interval && |
455 | params->interval)) { | 455 | (sdata->vif.bss_conf.beacon_int != params->interval)) { |
456 | sdata->local->hw.conf.beacon_int = params->interval; | 456 | sdata->vif.bss_conf.beacon_int = params->interval; |
457 | err = ieee80211_hw_config(sdata->local, | 457 | ieee80211_bss_info_change_notify(sdata, |
458 | IEEE80211_CONF_CHANGE_BEACON_INTERVAL); | 458 | BSS_CHANGED_BEACON_INT); |
459 | if (err < 0) | ||
460 | return err; | ||
461 | /* | ||
462 | * We updated some parameter so if below bails out | ||
463 | * it's not an error. | ||
464 | */ | ||
465 | err = 0; | ||
466 | } | 459 | } |
467 | 460 | ||
468 | /* Need to have a beacon head if we don't have one yet */ | 461 | /* Need to have a beacon head if we don't have one yet */ |
@@ -528,8 +521,9 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
528 | 521 | ||
529 | kfree(old); | 522 | kfree(old); |
530 | 523 | ||
531 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | | 524 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
532 | IEEE80211_IFCC_BEACON_ENABLED); | 525 | BSS_CHANGED_BEACON); |
526 | return 0; | ||
533 | } | 527 | } |
534 | 528 | ||
535 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | 529 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, |
@@ -580,7 +574,8 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
580 | synchronize_rcu(); | 574 | synchronize_rcu(); |
581 | kfree(old); | 575 | kfree(old); |
582 | 576 | ||
583 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); | 577 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
578 | return 0; | ||
584 | } | 579 | } |
585 | 580 | ||
586 | /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ | 581 | /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ |
@@ -635,34 +630,45 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
635 | int i, j; | 630 | int i, j; |
636 | struct ieee80211_supported_band *sband; | 631 | struct ieee80211_supported_band *sband; |
637 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 632 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
633 | u32 mask, set; | ||
638 | 634 | ||
639 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 635 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
640 | 636 | ||
641 | /* | 637 | spin_lock_bh(&sta->lock); |
642 | * FIXME: updating the flags is racy when this function is | 638 | mask = params->sta_flags_mask; |
643 | * called from ieee80211_change_station(), this will | 639 | set = params->sta_flags_set; |
644 | * be resolved in a future patch. | ||
645 | */ | ||
646 | 640 | ||
647 | if (params->station_flags & STATION_FLAG_CHANGED) { | 641 | if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { |
648 | spin_lock_bh(&sta->lock); | ||
649 | sta->flags &= ~WLAN_STA_AUTHORIZED; | 642 | sta->flags &= ~WLAN_STA_AUTHORIZED; |
650 | if (params->station_flags & STATION_FLAG_AUTHORIZED) | 643 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) |
651 | sta->flags |= WLAN_STA_AUTHORIZED; | 644 | sta->flags |= WLAN_STA_AUTHORIZED; |
645 | } | ||
652 | 646 | ||
647 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { | ||
653 | sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; | 648 | sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; |
654 | if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) | 649 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) |
655 | sta->flags |= WLAN_STA_SHORT_PREAMBLE; | 650 | sta->flags |= WLAN_STA_SHORT_PREAMBLE; |
651 | } | ||
656 | 652 | ||
653 | if (mask & BIT(NL80211_STA_FLAG_WME)) { | ||
657 | sta->flags &= ~WLAN_STA_WME; | 654 | sta->flags &= ~WLAN_STA_WME; |
658 | if (params->station_flags & STATION_FLAG_WME) | 655 | if (set & BIT(NL80211_STA_FLAG_WME)) |
659 | sta->flags |= WLAN_STA_WME; | 656 | sta->flags |= WLAN_STA_WME; |
657 | } | ||
660 | 658 | ||
659 | if (mask & BIT(NL80211_STA_FLAG_MFP)) { | ||
661 | sta->flags &= ~WLAN_STA_MFP; | 660 | sta->flags &= ~WLAN_STA_MFP; |
662 | if (params->station_flags & STATION_FLAG_MFP) | 661 | if (set & BIT(NL80211_STA_FLAG_MFP)) |
663 | sta->flags |= WLAN_STA_MFP; | 662 | sta->flags |= WLAN_STA_MFP; |
664 | spin_unlock_bh(&sta->lock); | ||
665 | } | 663 | } |
664 | spin_unlock_bh(&sta->lock); | ||
665 | |||
666 | /* | ||
667 | * cfg80211 validates this (1-2007) and allows setting the AID | ||
668 | * only when creating a new station entry | ||
669 | */ | ||
670 | if (params->aid) | ||
671 | sta->sta.aid = params->aid; | ||
666 | 672 | ||
667 | /* | 673 | /* |
668 | * FIXME: updating the following information is racy when this | 674 | * FIXME: updating the following information is racy when this |
@@ -671,12 +677,6 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
671 | * maybe we should just reject attemps to change it. | 677 | * maybe we should just reject attemps to change it. |
672 | */ | 678 | */ |
673 | 679 | ||
674 | if (params->aid) { | ||
675 | sta->sta.aid = params->aid; | ||
676 | if (sta->sta.aid > IEEE80211_MAX_AID) | ||
677 | sta->sta.aid = 0; /* XXX: should this be an error? */ | ||
678 | } | ||
679 | |||
680 | if (params->listen_interval >= 0) | 680 | if (params->listen_interval >= 0) |
681 | sta->listen_interval = params->listen_interval; | 681 | sta->listen_interval = params->listen_interval; |
682 | 682 | ||
@@ -1120,10 +1120,10 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1120 | p.cw_max = params->cwmax; | 1120 | p.cw_max = params->cwmax; |
1121 | p.cw_min = params->cwmin; | 1121 | p.cw_min = params->cwmin; |
1122 | p.txop = params->txop; | 1122 | p.txop = params->txop; |
1123 | if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { | 1123 | if (drv_conf_tx(local, params->queue, &p)) { |
1124 | printk(KERN_DEBUG "%s: failed to set TX queue " | 1124 | printk(KERN_DEBUG "%s: failed to set TX queue " |
1125 | "parameters for queue %d\n", local->mdev->name, | 1125 | "parameters for queue %d\n", |
1126 | params->queue); | 1126 | wiphy_name(local->hw.wiphy), params->queue); |
1127 | return -EINVAL; | 1127 | return -EINVAL; |
1128 | } | 1128 | } |
1129 | 1129 | ||
@@ -1167,7 +1167,8 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1167 | 1167 | ||
1168 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 1168 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
1169 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1169 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
1170 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 1170 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && |
1171 | (sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon)) | ||
1171 | return -EOPNOTSUPP; | 1172 | return -EOPNOTSUPP; |
1172 | 1173 | ||
1173 | return ieee80211_request_scan(sdata, req); | 1174 | return ieee80211_request_scan(sdata, req); |
@@ -1255,9 +1256,22 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | |||
1255 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; | 1256 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; |
1256 | 1257 | ||
1257 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); | 1258 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); |
1258 | if (ret) | 1259 | if (ret && ret != -EALREADY) |
1259 | return ret; | 1260 | return ret; |
1260 | 1261 | ||
1262 | if (req->use_mfp) { | ||
1263 | sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; | ||
1264 | sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; | ||
1265 | } else { | ||
1266 | sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; | ||
1267 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; | ||
1268 | } | ||
1269 | |||
1270 | if (req->control_port) | ||
1271 | sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; | ||
1272 | else | ||
1273 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; | ||
1274 | |||
1261 | sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; | 1275 | sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; |
1262 | sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; | 1276 | sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; |
1263 | ieee80211_sta_req_auth(sdata); | 1277 | ieee80211_sta_req_auth(sdata); |
@@ -1267,25 +1281,106 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | |||
1267 | static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, | 1281 | static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, |
1268 | struct cfg80211_deauth_request *req) | 1282 | struct cfg80211_deauth_request *req) |
1269 | { | 1283 | { |
1270 | struct ieee80211_sub_if_data *sdata; | 1284 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1271 | |||
1272 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1273 | 1285 | ||
1274 | /* TODO: req->ie */ | 1286 | /* TODO: req->ie, req->peer_addr */ |
1275 | return ieee80211_sta_deauthenticate(sdata, req->reason_code); | 1287 | return ieee80211_sta_deauthenticate(sdata, req->reason_code); |
1276 | } | 1288 | } |
1277 | 1289 | ||
1278 | static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, | 1290 | static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, |
1279 | struct cfg80211_disassoc_request *req) | 1291 | struct cfg80211_disassoc_request *req) |
1280 | { | 1292 | { |
1281 | struct ieee80211_sub_if_data *sdata; | 1293 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1282 | |||
1283 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1284 | 1294 | ||
1285 | /* TODO: req->ie */ | 1295 | /* TODO: req->ie, req->peer_addr */ |
1286 | return ieee80211_sta_disassociate(sdata, req->reason_code); | 1296 | return ieee80211_sta_disassociate(sdata, req->reason_code); |
1287 | } | 1297 | } |
1288 | 1298 | ||
1299 | static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
1300 | struct cfg80211_ibss_params *params) | ||
1301 | { | ||
1302 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1303 | |||
1304 | return ieee80211_ibss_join(sdata, params); | ||
1305 | } | ||
1306 | |||
1307 | static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | ||
1308 | { | ||
1309 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1310 | |||
1311 | return ieee80211_ibss_leave(sdata); | ||
1312 | } | ||
1313 | |||
1314 | static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | ||
1315 | { | ||
1316 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1317 | int err; | ||
1318 | |||
1319 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | ||
1320 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); | ||
1321 | |||
1322 | if (err) | ||
1323 | return err; | ||
1324 | } | ||
1325 | |||
1326 | if (changed & WIPHY_PARAM_RETRY_SHORT) | ||
1327 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | ||
1328 | if (changed & WIPHY_PARAM_RETRY_LONG) | ||
1329 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | ||
1330 | if (changed & | ||
1331 | (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) | ||
1332 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); | ||
1333 | |||
1334 | return 0; | ||
1335 | } | ||
1336 | |||
1337 | static int ieee80211_set_tx_power(struct wiphy *wiphy, | ||
1338 | enum tx_power_setting type, int dbm) | ||
1339 | { | ||
1340 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1341 | struct ieee80211_channel *chan = local->hw.conf.channel; | ||
1342 | u32 changes = 0; | ||
1343 | |||
1344 | switch (type) { | ||
1345 | case TX_POWER_AUTOMATIC: | ||
1346 | local->user_power_level = -1; | ||
1347 | break; | ||
1348 | case TX_POWER_LIMITED: | ||
1349 | if (dbm < 0) | ||
1350 | return -EINVAL; | ||
1351 | local->user_power_level = dbm; | ||
1352 | break; | ||
1353 | case TX_POWER_FIXED: | ||
1354 | if (dbm < 0) | ||
1355 | return -EINVAL; | ||
1356 | /* TODO: move to cfg80211 when it knows the channel */ | ||
1357 | if (dbm > chan->max_power) | ||
1358 | return -EINVAL; | ||
1359 | local->user_power_level = dbm; | ||
1360 | break; | ||
1361 | } | ||
1362 | |||
1363 | ieee80211_hw_config(local, changes); | ||
1364 | |||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1368 | static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) | ||
1369 | { | ||
1370 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1371 | |||
1372 | *dbm = local->hw.conf.power_level; | ||
1373 | |||
1374 | return 0; | ||
1375 | } | ||
1376 | |||
1377 | static void ieee80211_rfkill_poll(struct wiphy *wiphy) | ||
1378 | { | ||
1379 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1380 | |||
1381 | drv_rfkill_poll(local); | ||
1382 | } | ||
1383 | |||
1289 | struct cfg80211_ops mac80211_config_ops = { | 1384 | struct cfg80211_ops mac80211_config_ops = { |
1290 | .add_virtual_intf = ieee80211_add_iface, | 1385 | .add_virtual_intf = ieee80211_add_iface, |
1291 | .del_virtual_intf = ieee80211_del_iface, | 1386 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1322,4 +1417,10 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1322 | .assoc = ieee80211_assoc, | 1417 | .assoc = ieee80211_assoc, |
1323 | .deauth = ieee80211_deauth, | 1418 | .deauth = ieee80211_deauth, |
1324 | .disassoc = ieee80211_disassoc, | 1419 | .disassoc = ieee80211_disassoc, |
1420 | .join_ibss = ieee80211_join_ibss, | ||
1421 | .leave_ibss = ieee80211_leave_ibss, | ||
1422 | .set_wiphy_params = ieee80211_set_wiphy_params, | ||
1423 | .set_tx_power = ieee80211_set_tx_power, | ||
1424 | .get_tx_power = ieee80211_get_tx_power, | ||
1425 | .rfkill_poll = ieee80211_rfkill_poll, | ||
1325 | }; | 1426 | }; |