diff options
Diffstat (limited to 'net/wireless/wext-compat.c')
-rw-r--r-- | net/wireless/wext-compat.c | 148 |
1 files changed, 122 insertions, 26 deletions
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 561a45cf2a6a..a60a2773b497 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/nl80211.h> | 12 | #include <linux/nl80211.h> |
13 | #include <linux/if_arp.h> | 13 | #include <linux/if_arp.h> |
14 | #include <linux/etherdevice.h> | 14 | #include <linux/etherdevice.h> |
15 | #include <linux/slab.h> | ||
15 | #include <net/iw_handler.h> | 16 | #include <net/iw_handler.h> |
16 | #include <net/cfg80211.h> | 17 | #include <net/cfg80211.h> |
17 | #include "wext-compat.h" | 18 | #include "wext-compat.h" |
@@ -437,6 +438,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
437 | { | 438 | { |
438 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 439 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
439 | int err, i; | 440 | int err, i; |
441 | bool rejoin = false; | ||
440 | 442 | ||
441 | if (!wdev->wext.keys) { | 443 | if (!wdev->wext.keys) { |
442 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | 444 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
@@ -466,8 +468,25 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
466 | 468 | ||
467 | if (remove) { | 469 | if (remove) { |
468 | err = 0; | 470 | err = 0; |
469 | if (wdev->current_bss) | 471 | if (wdev->current_bss) { |
472 | /* | ||
473 | * If removing the current TX key, we will need to | ||
474 | * join a new IBSS without the privacy bit clear. | ||
475 | */ | ||
476 | if (idx == wdev->wext.default_key && | ||
477 | wdev->iftype == NL80211_IFTYPE_ADHOC) { | ||
478 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | ||
479 | rejoin = true; | ||
480 | } | ||
470 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | 481 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); |
482 | } | ||
483 | wdev->wext.connect.privacy = false; | ||
484 | /* | ||
485 | * Applications using wireless extensions expect to be | ||
486 | * able to delete keys that don't exist, so allow that. | ||
487 | */ | ||
488 | if (err == -ENOENT) | ||
489 | err = 0; | ||
471 | if (!err) { | 490 | if (!err) { |
472 | if (!addr) { | 491 | if (!addr) { |
473 | wdev->wext.keys->params[idx].key_len = 0; | 492 | wdev->wext.keys->params[idx].key_len = 0; |
@@ -478,12 +497,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
478 | else if (idx == wdev->wext.default_mgmt_key) | 497 | else if (idx == wdev->wext.default_mgmt_key) |
479 | wdev->wext.default_mgmt_key = -1; | 498 | wdev->wext.default_mgmt_key = -1; |
480 | } | 499 | } |
481 | /* | 500 | |
482 | * Applications using wireless extensions expect to be | 501 | if (!err && rejoin) |
483 | * able to delete keys that don't exist, so allow that. | 502 | err = cfg80211_ibss_wext_join(rdev, wdev); |
484 | */ | ||
485 | if (err == -ENOENT) | ||
486 | return 0; | ||
487 | 503 | ||
488 | return err; | 504 | return err; |
489 | } | 505 | } |
@@ -511,11 +527,25 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
511 | if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || | 527 | if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || |
512 | params->cipher == WLAN_CIPHER_SUITE_WEP104) && | 528 | params->cipher == WLAN_CIPHER_SUITE_WEP104) && |
513 | (tx_key || (!addr && wdev->wext.default_key == -1))) { | 529 | (tx_key || (!addr && wdev->wext.default_key == -1))) { |
514 | if (wdev->current_bss) | 530 | if (wdev->current_bss) { |
531 | /* | ||
532 | * If we are getting a new TX key from not having | ||
533 | * had one before we need to join a new IBSS with | ||
534 | * the privacy bit set. | ||
535 | */ | ||
536 | if (wdev->iftype == NL80211_IFTYPE_ADHOC && | ||
537 | wdev->wext.default_key == -1) { | ||
538 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | ||
539 | rejoin = true; | ||
540 | } | ||
515 | err = rdev->ops->set_default_key(&rdev->wiphy, | 541 | err = rdev->ops->set_default_key(&rdev->wiphy, |
516 | dev, idx); | 542 | dev, idx); |
517 | if (!err) | 543 | } |
544 | if (!err) { | ||
518 | wdev->wext.default_key = idx; | 545 | wdev->wext.default_key = idx; |
546 | if (rejoin) | ||
547 | err = cfg80211_ibss_wext_join(rdev, wdev); | ||
548 | } | ||
519 | return err; | 549 | return err; |
520 | } | 550 | } |
521 | 551 | ||
@@ -539,10 +569,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
539 | { | 569 | { |
540 | int err; | 570 | int err; |
541 | 571 | ||
572 | /* devlist mutex needed for possible IBSS re-join */ | ||
573 | mutex_lock(&rdev->devlist_mtx); | ||
542 | wdev_lock(dev->ieee80211_ptr); | 574 | wdev_lock(dev->ieee80211_ptr); |
543 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, | 575 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, |
544 | tx_key, idx, params); | 576 | tx_key, idx, params); |
545 | wdev_unlock(dev->ieee80211_ptr); | 577 | wdev_unlock(dev->ieee80211_ptr); |
578 | mutex_unlock(&rdev->devlist_mtx); | ||
546 | 579 | ||
547 | return err; | 580 | return err; |
548 | } | 581 | } |
@@ -904,8 +937,6 @@ static int cfg80211_set_auth_alg(struct wireless_dev *wdev, | |||
904 | 937 | ||
905 | static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) | 938 | static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) |
906 | { | 939 | { |
907 | wdev->wext.connect.crypto.wpa_versions = 0; | ||
908 | |||
909 | if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | | 940 | if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | |
910 | IW_AUTH_WPA_VERSION_WPA2| | 941 | IW_AUTH_WPA_VERSION_WPA2| |
911 | IW_AUTH_WPA_VERSION_DISABLED)) | 942 | IW_AUTH_WPA_VERSION_DISABLED)) |
@@ -933,8 +964,6 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) | |||
933 | 964 | ||
934 | static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) | 965 | static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) |
935 | { | 966 | { |
936 | wdev->wext.connect.crypto.cipher_group = 0; | ||
937 | |||
938 | if (cipher & IW_AUTH_CIPHER_WEP40) | 967 | if (cipher & IW_AUTH_CIPHER_WEP40) |
939 | wdev->wext.connect.crypto.cipher_group = | 968 | wdev->wext.connect.crypto.cipher_group = |
940 | WLAN_CIPHER_SUITE_WEP40; | 969 | WLAN_CIPHER_SUITE_WEP40; |
@@ -950,6 +979,8 @@ static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) | |||
950 | else if (cipher & IW_AUTH_CIPHER_AES_CMAC) | 979 | else if (cipher & IW_AUTH_CIPHER_AES_CMAC) |
951 | wdev->wext.connect.crypto.cipher_group = | 980 | wdev->wext.connect.crypto.cipher_group = |
952 | WLAN_CIPHER_SUITE_AES_CMAC; | 981 | WLAN_CIPHER_SUITE_AES_CMAC; |
982 | else if (cipher & IW_AUTH_CIPHER_NONE) | ||
983 | wdev->wext.connect.crypto.cipher_group = 0; | ||
953 | else | 984 | else |
954 | return -EINVAL; | 985 | return -EINVAL; |
955 | 986 | ||
@@ -1069,8 +1100,8 @@ int cfg80211_wext_siwpower(struct net_device *dev, | |||
1069 | { | 1100 | { |
1070 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1101 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1071 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1102 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1072 | bool ps = wdev->wext.ps; | 1103 | bool ps = wdev->ps; |
1073 | int timeout = wdev->wext.ps_timeout; | 1104 | int timeout = wdev->ps_timeout; |
1074 | int err; | 1105 | int err; |
1075 | 1106 | ||
1076 | if (wdev->iftype != NL80211_IFTYPE_STATION) | 1107 | if (wdev->iftype != NL80211_IFTYPE_STATION) |
@@ -1103,8 +1134,8 @@ int cfg80211_wext_siwpower(struct net_device *dev, | |||
1103 | if (err) | 1134 | if (err) |
1104 | return err; | 1135 | return err; |
1105 | 1136 | ||
1106 | wdev->wext.ps = ps; | 1137 | wdev->ps = ps; |
1107 | wdev->wext.ps_timeout = timeout; | 1138 | wdev->ps_timeout = timeout; |
1108 | 1139 | ||
1109 | return 0; | 1140 | return 0; |
1110 | 1141 | ||
@@ -1117,7 +1148,7 @@ int cfg80211_wext_giwpower(struct net_device *dev, | |||
1117 | { | 1148 | { |
1118 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1149 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1119 | 1150 | ||
1120 | wrq->disabled = !wdev->wext.ps; | 1151 | wrq->disabled = !wdev->ps; |
1121 | 1152 | ||
1122 | return 0; | 1153 | return 0; |
1123 | } | 1154 | } |
@@ -1174,21 +1205,47 @@ int cfg80211_wext_siwrate(struct net_device *dev, | |||
1174 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1205 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1175 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1206 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1176 | struct cfg80211_bitrate_mask mask; | 1207 | struct cfg80211_bitrate_mask mask; |
1208 | u32 fixed, maxrate; | ||
1209 | struct ieee80211_supported_band *sband; | ||
1210 | int band, ridx; | ||
1211 | bool match = false; | ||
1177 | 1212 | ||
1178 | if (!rdev->ops->set_bitrate_mask) | 1213 | if (!rdev->ops->set_bitrate_mask) |
1179 | return -EOPNOTSUPP; | 1214 | return -EOPNOTSUPP; |
1180 | 1215 | ||
1181 | mask.fixed = 0; | 1216 | memset(&mask, 0, sizeof(mask)); |
1182 | mask.maxrate = 0; | 1217 | fixed = 0; |
1218 | maxrate = (u32)-1; | ||
1183 | 1219 | ||
1184 | if (rate->value < 0) { | 1220 | if (rate->value < 0) { |
1185 | /* nothing */ | 1221 | /* nothing */ |
1186 | } else if (rate->fixed) { | 1222 | } else if (rate->fixed) { |
1187 | mask.fixed = rate->value / 1000; /* kbps */ | 1223 | fixed = rate->value / 100000; |
1188 | } else { | 1224 | } else { |
1189 | mask.maxrate = rate->value / 1000; /* kbps */ | 1225 | maxrate = rate->value / 100000; |
1190 | } | 1226 | } |
1191 | 1227 | ||
1228 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
1229 | sband = wdev->wiphy->bands[band]; | ||
1230 | if (sband == NULL) | ||
1231 | continue; | ||
1232 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
1233 | struct ieee80211_rate *srate = &sband->bitrates[ridx]; | ||
1234 | if (fixed == srate->bitrate) { | ||
1235 | mask.control[band].legacy = 1 << ridx; | ||
1236 | match = true; | ||
1237 | break; | ||
1238 | } | ||
1239 | if (srate->bitrate <= maxrate) { | ||
1240 | mask.control[band].legacy |= 1 << ridx; | ||
1241 | match = true; | ||
1242 | } | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | if (!match) | ||
1247 | return -EINVAL; | ||
1248 | |||
1192 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); | 1249 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); |
1193 | } | 1250 | } |
1194 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); | 1251 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); |
@@ -1227,10 +1284,7 @@ int cfg80211_wext_giwrate(struct net_device *dev, | |||
1227 | if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) | 1284 | if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) |
1228 | return -EOPNOTSUPP; | 1285 | return -EOPNOTSUPP; |
1229 | 1286 | ||
1230 | rate->value = 0; | 1287 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); |
1231 | |||
1232 | if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS)) | ||
1233 | rate->value = 100000 * sinfo.txrate.legacy; | ||
1234 | 1288 | ||
1235 | return 0; | 1289 | return 0; |
1236 | } | 1290 | } |
@@ -1372,6 +1426,47 @@ int cfg80211_wext_giwessid(struct net_device *dev, | |||
1372 | } | 1426 | } |
1373 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); | 1427 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); |
1374 | 1428 | ||
1429 | int cfg80211_wext_siwpmksa(struct net_device *dev, | ||
1430 | struct iw_request_info *info, | ||
1431 | struct iw_point *data, char *extra) | ||
1432 | { | ||
1433 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1434 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
1435 | struct cfg80211_pmksa cfg_pmksa; | ||
1436 | struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; | ||
1437 | |||
1438 | memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa)); | ||
1439 | |||
1440 | if (wdev->iftype != NL80211_IFTYPE_STATION) | ||
1441 | return -EINVAL; | ||
1442 | |||
1443 | cfg_pmksa.bssid = pmksa->bssid.sa_data; | ||
1444 | cfg_pmksa.pmkid = pmksa->pmkid; | ||
1445 | |||
1446 | switch (pmksa->cmd) { | ||
1447 | case IW_PMKSA_ADD: | ||
1448 | if (!rdev->ops->set_pmksa) | ||
1449 | return -EOPNOTSUPP; | ||
1450 | |||
1451 | return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa); | ||
1452 | |||
1453 | case IW_PMKSA_REMOVE: | ||
1454 | if (!rdev->ops->del_pmksa) | ||
1455 | return -EOPNOTSUPP; | ||
1456 | |||
1457 | return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa); | ||
1458 | |||
1459 | case IW_PMKSA_FLUSH: | ||
1460 | if (!rdev->ops->flush_pmksa) | ||
1461 | return -EOPNOTSUPP; | ||
1462 | |||
1463 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
1464 | |||
1465 | default: | ||
1466 | return -EOPNOTSUPP; | ||
1467 | } | ||
1468 | } | ||
1469 | |||
1375 | static const iw_handler cfg80211_handlers[] = { | 1470 | static const iw_handler cfg80211_handlers[] = { |
1376 | [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, | 1471 | [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, |
1377 | [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, | 1472 | [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, |
@@ -1404,6 +1499,7 @@ static const iw_handler cfg80211_handlers[] = { | |||
1404 | [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, | 1499 | [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, |
1405 | [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, | 1500 | [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, |
1406 | [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, | 1501 | [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, |
1502 | [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa, | ||
1407 | }; | 1503 | }; |
1408 | 1504 | ||
1409 | const struct iw_handler_def cfg80211_wext_handler = { | 1505 | const struct iw_handler_def cfg80211_wext_handler = { |