diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/wext.c | 279 | ||||
-rw-r--r-- | net/wireless/core.c | 6 | ||||
-rw-r--r-- | net/wireless/core.h | 6 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 57 | ||||
-rw-r--r-- | net/wireless/util.c | 45 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 257 |
6 files changed, 333 insertions, 317 deletions
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 6b4eb8d43a4e..d84502644686 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -27,100 +27,6 @@ | |||
27 | #include "aes_ccm.h" | 27 | #include "aes_ccm.h" |
28 | 28 | ||
29 | 29 | ||
30 | static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta_addr, | ||
31 | int idx, int alg, int remove, | ||
32 | int set_tx_key, const u8 *_key, | ||
33 | size_t key_len) | ||
34 | { | ||
35 | struct ieee80211_local *local = sdata->local; | ||
36 | struct sta_info *sta; | ||
37 | struct ieee80211_key *key; | ||
38 | int err; | ||
39 | |||
40 | if (alg == ALG_AES_CMAC) { | ||
41 | if (idx < NUM_DEFAULT_KEYS || | ||
42 | idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { | ||
43 | printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d " | ||
44 | "(BIP)\n", sdata->dev->name, idx); | ||
45 | return -EINVAL; | ||
46 | } | ||
47 | } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { | ||
48 | printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", | ||
49 | sdata->dev->name, idx); | ||
50 | return -EINVAL; | ||
51 | } | ||
52 | |||
53 | if (remove) { | ||
54 | rcu_read_lock(); | ||
55 | |||
56 | err = 0; | ||
57 | |||
58 | if (is_broadcast_ether_addr(sta_addr)) { | ||
59 | key = sdata->keys[idx]; | ||
60 | } else { | ||
61 | sta = sta_info_get(local, sta_addr); | ||
62 | if (!sta) { | ||
63 | err = -ENOENT; | ||
64 | goto out_unlock; | ||
65 | } | ||
66 | key = sta->key; | ||
67 | } | ||
68 | |||
69 | ieee80211_key_free(key); | ||
70 | } else { | ||
71 | key = ieee80211_key_alloc(alg, idx, key_len, _key); | ||
72 | if (!key) | ||
73 | return -ENOMEM; | ||
74 | |||
75 | sta = NULL; | ||
76 | err = 0; | ||
77 | |||
78 | rcu_read_lock(); | ||
79 | |||
80 | if (!is_broadcast_ether_addr(sta_addr)) { | ||
81 | set_tx_key = 0; | ||
82 | /* | ||
83 | * According to the standard, the key index of a | ||
84 | * pairwise key must be zero. However, some AP are | ||
85 | * broken when it comes to WEP key indices, so we | ||
86 | * work around this. | ||
87 | */ | ||
88 | if (idx != 0 && alg != ALG_WEP) { | ||
89 | ieee80211_key_free(key); | ||
90 | err = -EINVAL; | ||
91 | goto out_unlock; | ||
92 | } | ||
93 | |||
94 | sta = sta_info_get(local, sta_addr); | ||
95 | if (!sta) { | ||
96 | ieee80211_key_free(key); | ||
97 | err = -ENOENT; | ||
98 | goto out_unlock; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | if (alg == ALG_WEP && | ||
103 | key_len != LEN_WEP40 && key_len != LEN_WEP104) { | ||
104 | ieee80211_key_free(key); | ||
105 | err = -EINVAL; | ||
106 | goto out_unlock; | ||
107 | } | ||
108 | |||
109 | ieee80211_key_link(key, sdata, sta); | ||
110 | |||
111 | if (set_tx_key || (!sta && !sdata->default_key && key)) | ||
112 | ieee80211_set_default_key(sdata, idx); | ||
113 | if (alg == ALG_AES_CMAC && | ||
114 | (set_tx_key || (!sta && !sdata->default_mgmt_key && key))) | ||
115 | ieee80211_set_default_mgmt_key(sdata, idx); | ||
116 | } | ||
117 | |||
118 | out_unlock: | ||
119 | rcu_read_unlock(); | ||
120 | |||
121 | return err; | ||
122 | } | ||
123 | |||
124 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, | 30 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, |
125 | struct iw_request_info *info, | 31 | struct iw_request_info *info, |
126 | struct iw_point *data, char *extra) | 32 | struct iw_point *data, char *extra) |
@@ -472,109 +378,6 @@ static int ieee80211_ioctl_giwtxpower(struct net_device *dev, | |||
472 | return 0; | 378 | return 0; |
473 | } | 379 | } |
474 | 380 | ||
475 | static int ieee80211_ioctl_siwencode(struct net_device *dev, | ||
476 | struct iw_request_info *info, | ||
477 | struct iw_point *erq, char *keybuf) | ||
478 | { | ||
479 | struct ieee80211_sub_if_data *sdata; | ||
480 | int idx, i, alg = ALG_WEP; | ||
481 | u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
482 | int remove = 0, ret; | ||
483 | |||
484 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
485 | |||
486 | idx = erq->flags & IW_ENCODE_INDEX; | ||
487 | if (idx == 0) { | ||
488 | if (sdata->default_key) | ||
489 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
490 | if (sdata->default_key == sdata->keys[i]) { | ||
491 | idx = i; | ||
492 | break; | ||
493 | } | ||
494 | } | ||
495 | } else if (idx < 1 || idx > 4) | ||
496 | return -EINVAL; | ||
497 | else | ||
498 | idx--; | ||
499 | |||
500 | if (erq->flags & IW_ENCODE_DISABLED) | ||
501 | remove = 1; | ||
502 | else if (erq->length == 0) { | ||
503 | /* No key data - just set the default TX key index */ | ||
504 | ieee80211_set_default_key(sdata, idx); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | ret = ieee80211_set_encryption( | ||
509 | sdata, bcaddr, | ||
510 | idx, alg, remove, | ||
511 | !sdata->default_key, | ||
512 | keybuf, erq->length); | ||
513 | |||
514 | if (!ret && sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
515 | if (remove) | ||
516 | sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; | ||
517 | else | ||
518 | sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; | ||
519 | } | ||
520 | |||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | |||
525 | static int ieee80211_ioctl_giwencode(struct net_device *dev, | ||
526 | struct iw_request_info *info, | ||
527 | struct iw_point *erq, char *key) | ||
528 | { | ||
529 | struct ieee80211_sub_if_data *sdata; | ||
530 | int idx, i; | ||
531 | |||
532 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
533 | |||
534 | idx = erq->flags & IW_ENCODE_INDEX; | ||
535 | if (idx < 1 || idx > 4) { | ||
536 | idx = -1; | ||
537 | if (!sdata->default_key) | ||
538 | idx = 0; | ||
539 | else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
540 | if (sdata->default_key == sdata->keys[i]) { | ||
541 | idx = i; | ||
542 | break; | ||
543 | } | ||
544 | } | ||
545 | if (idx < 0) | ||
546 | return -EINVAL; | ||
547 | } else | ||
548 | idx--; | ||
549 | |||
550 | erq->flags = idx + 1; | ||
551 | |||
552 | if (!sdata->keys[idx]) { | ||
553 | erq->length = 0; | ||
554 | erq->flags |= IW_ENCODE_DISABLED; | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | memcpy(key, sdata->keys[idx]->conf.key, | ||
559 | min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); | ||
560 | erq->length = sdata->keys[idx]->conf.keylen; | ||
561 | erq->flags |= IW_ENCODE_ENABLED; | ||
562 | |||
563 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
564 | switch (sdata->u.mgd.auth_alg) { | ||
565 | case WLAN_AUTH_OPEN: | ||
566 | case WLAN_AUTH_LEAP: | ||
567 | erq->flags |= IW_ENCODE_OPEN; | ||
568 | break; | ||
569 | case WLAN_AUTH_SHARED_KEY: | ||
570 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
571 | break; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static int ieee80211_ioctl_siwpower(struct net_device *dev, | 381 | static int ieee80211_ioctl_siwpower(struct net_device *dev, |
579 | struct iw_request_info *info, | 382 | struct iw_request_info *info, |
580 | struct iw_param *wrq, | 383 | struct iw_param *wrq, |
@@ -809,82 +612,6 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev, | |||
809 | } | 612 | } |
810 | 613 | ||
811 | 614 | ||
812 | static int ieee80211_ioctl_siwencodeext(struct net_device *dev, | ||
813 | struct iw_request_info *info, | ||
814 | struct iw_point *erq, char *extra) | ||
815 | { | ||
816 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
817 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
818 | int uninitialized_var(alg), idx, i, remove = 0; | ||
819 | |||
820 | switch (ext->alg) { | ||
821 | case IW_ENCODE_ALG_NONE: | ||
822 | remove = 1; | ||
823 | break; | ||
824 | case IW_ENCODE_ALG_WEP: | ||
825 | alg = ALG_WEP; | ||
826 | break; | ||
827 | case IW_ENCODE_ALG_TKIP: | ||
828 | alg = ALG_TKIP; | ||
829 | break; | ||
830 | case IW_ENCODE_ALG_CCMP: | ||
831 | alg = ALG_CCMP; | ||
832 | break; | ||
833 | case IW_ENCODE_ALG_AES_CMAC: | ||
834 | alg = ALG_AES_CMAC; | ||
835 | break; | ||
836 | default: | ||
837 | return -EOPNOTSUPP; | ||
838 | } | ||
839 | |||
840 | if (erq->flags & IW_ENCODE_DISABLED) | ||
841 | remove = 1; | ||
842 | |||
843 | idx = erq->flags & IW_ENCODE_INDEX; | ||
844 | if (alg == ALG_AES_CMAC) { | ||
845 | if (idx < NUM_DEFAULT_KEYS + 1 || | ||
846 | idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { | ||
847 | idx = -1; | ||
848 | if (!sdata->default_mgmt_key) | ||
849 | idx = 0; | ||
850 | else for (i = NUM_DEFAULT_KEYS; | ||
851 | i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS; | ||
852 | i++) { | ||
853 | if (sdata->default_mgmt_key == sdata->keys[i]) | ||
854 | { | ||
855 | idx = i; | ||
856 | break; | ||
857 | } | ||
858 | } | ||
859 | if (idx < 0) | ||
860 | return -EINVAL; | ||
861 | } else | ||
862 | idx--; | ||
863 | } else { | ||
864 | if (idx < 1 || idx > 4) { | ||
865 | idx = -1; | ||
866 | if (!sdata->default_key) | ||
867 | idx = 0; | ||
868 | else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
869 | if (sdata->default_key == sdata->keys[i]) { | ||
870 | idx = i; | ||
871 | break; | ||
872 | } | ||
873 | } | ||
874 | if (idx < 0) | ||
875 | return -EINVAL; | ||
876 | } else | ||
877 | idx--; | ||
878 | } | ||
879 | |||
880 | return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg, | ||
881 | remove, | ||
882 | ext->ext_flags & | ||
883 | IW_ENCODE_EXT_SET_TX_KEY, | ||
884 | ext->key, ext->key_len); | ||
885 | } | ||
886 | |||
887 | |||
888 | /* Structures to export the Wireless Handlers */ | 615 | /* Structures to export the Wireless Handlers */ |
889 | 616 | ||
890 | static const iw_handler ieee80211_handler[] = | 617 | static const iw_handler ieee80211_handler[] = |
@@ -931,8 +658,8 @@ static const iw_handler ieee80211_handler[] = | |||
931 | (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ | 658 | (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ |
932 | (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ | 659 | (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ |
933 | (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ | 660 | (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ |
934 | (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ | 661 | (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ |
935 | (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ | 662 | (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ |
936 | (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ | 663 | (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ |
937 | (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ | 664 | (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ |
938 | (iw_handler) NULL, /* -- hole -- */ | 665 | (iw_handler) NULL, /* -- hole -- */ |
@@ -941,7 +668,7 @@ static const iw_handler ieee80211_handler[] = | |||
941 | (iw_handler) NULL, /* SIOCGIWGENIE */ | 668 | (iw_handler) NULL, /* SIOCGIWGENIE */ |
942 | (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ | 669 | (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ |
943 | (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ | 670 | (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ |
944 | (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ | 671 | (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ |
945 | (iw_handler) NULL, /* SIOCGIWENCODEEXT */ | 672 | (iw_handler) NULL, /* SIOCGIWENCODEEXT */ |
946 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | 673 | (iw_handler) NULL, /* SIOCSIWPMKSA */ |
947 | (iw_handler) NULL, /* -- hole -- */ | 674 | (iw_handler) NULL, /* -- hole -- */ |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 15b2a1794805..47c20eb0c04d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * This is the linux wireless configuration interface. | 2 | * This is the linux wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
@@ -457,6 +457,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
457 | "symlink to netdev!\n"); | 457 | "symlink to netdev!\n"); |
458 | } | 458 | } |
459 | dev->ieee80211_ptr->netdev = dev; | 459 | dev->ieee80211_ptr->netdev = dev; |
460 | #ifdef CONFIG_WIRELESS_EXT | ||
461 | dev->ieee80211_ptr->wext.default_key = -1; | ||
462 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; | ||
463 | #endif | ||
460 | mutex_unlock(&rdev->devlist_mtx); | 464 | mutex_unlock(&rdev->devlist_mtx); |
461 | break; | 465 | break; |
462 | case NETDEV_GOING_DOWN: | 466 | case NETDEV_GOING_DOWN: |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 3e49d3399311..f14b6c5f4221 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Wireless configuration interface internals. | 2 | * Wireless configuration interface internals. |
3 | * | 3 | * |
4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | #ifndef __NET_WIRELESS_CORE_H | 6 | #ifndef __NET_WIRELESS_CORE_H |
7 | #define __NET_WIRELESS_CORE_H | 7 | #define __NET_WIRELESS_CORE_H |
@@ -151,4 +151,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext); | |||
151 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 151 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
152 | struct net_device *dev, bool nowext); | 152 | struct net_device *dev, bool nowext); |
153 | 153 | ||
154 | /* internal helpers */ | ||
155 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | ||
156 | const u8 *mac_addr); | ||
157 | |||
154 | #endif /* __NET_WIRELESS_CORE_H */ | 158 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a39e4644778b..f88dbbec7521 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * This is the new netlink-based wireless configuration interface. | 2 | * This is the new netlink-based wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
@@ -1073,6 +1073,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1073 | } | 1073 | } |
1074 | 1074 | ||
1075 | err = func(&drv->wiphy, dev, key_idx); | 1075 | err = func(&drv->wiphy, dev, key_idx); |
1076 | #ifdef CONFIG_WIRELESS_EXT | ||
1077 | if (!err) { | ||
1078 | if (func == drv->ops->set_default_key) | ||
1079 | dev->ieee80211_ptr->wext.default_key = key_idx; | ||
1080 | else | ||
1081 | dev->ieee80211_ptr->wext.default_mgmt_key = key_idx; | ||
1082 | } | ||
1083 | #endif | ||
1076 | 1084 | ||
1077 | out: | 1085 | out: |
1078 | cfg80211_put_dev(drv); | 1086 | cfg80211_put_dev(drv); |
@@ -1111,45 +1119,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1111 | if (info->attrs[NL80211_ATTR_MAC]) | 1119 | if (info->attrs[NL80211_ATTR_MAC]) |
1112 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1120 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1113 | 1121 | ||
1114 | if (key_idx > 5) | 1122 | if (cfg80211_validate_key_settings(¶ms, key_idx, mac_addr)) |
1115 | return -EINVAL; | 1123 | return -EINVAL; |
1116 | 1124 | ||
1117 | /* | ||
1118 | * Disallow pairwise keys with non-zero index unless it's WEP | ||
1119 | * (because current deployments use pairwise WEP keys with | ||
1120 | * non-zero indizes but 802.11i clearly specifies to use zero) | ||
1121 | */ | ||
1122 | if (mac_addr && key_idx && | ||
1123 | params.cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
1124 | params.cipher != WLAN_CIPHER_SUITE_WEP104) | ||
1125 | return -EINVAL; | ||
1126 | |||
1127 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ | ||
1128 | switch (params.cipher) { | ||
1129 | case WLAN_CIPHER_SUITE_WEP40: | ||
1130 | if (params.key_len != 5) | ||
1131 | return -EINVAL; | ||
1132 | break; | ||
1133 | case WLAN_CIPHER_SUITE_TKIP: | ||
1134 | if (params.key_len != 32) | ||
1135 | return -EINVAL; | ||
1136 | break; | ||
1137 | case WLAN_CIPHER_SUITE_CCMP: | ||
1138 | if (params.key_len != 16) | ||
1139 | return -EINVAL; | ||
1140 | break; | ||
1141 | case WLAN_CIPHER_SUITE_WEP104: | ||
1142 | if (params.key_len != 13) | ||
1143 | return -EINVAL; | ||
1144 | break; | ||
1145 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
1146 | if (params.key_len != 16) | ||
1147 | return -EINVAL; | ||
1148 | break; | ||
1149 | default: | ||
1150 | return -EINVAL; | ||
1151 | } | ||
1152 | |||
1153 | rtnl_lock(); | 1125 | rtnl_lock(); |
1154 | 1126 | ||
1155 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1127 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -1210,6 +1182,15 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1210 | 1182 | ||
1211 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); | 1183 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); |
1212 | 1184 | ||
1185 | #ifdef CONFIG_WIRELESS_EXT | ||
1186 | if (!err) { | ||
1187 | if (key_idx == dev->ieee80211_ptr->wext.default_key) | ||
1188 | dev->ieee80211_ptr->wext.default_key = -1; | ||
1189 | else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key) | ||
1190 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; | ||
1191 | } | ||
1192 | #endif | ||
1193 | |||
1213 | out: | 1194 | out: |
1214 | cfg80211_put_dev(drv); | 1195 | cfg80211_put_dev(drv); |
1215 | dev_put(dev); | 1196 | dev_put(dev); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 5f7e997195c7..beb226e78cd7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -138,3 +138,48 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
138 | if (wiphy->bands[band]) | 138 | if (wiphy->bands[band]) |
139 | set_mandatory_flags_band(wiphy->bands[band], band); | 139 | set_mandatory_flags_band(wiphy->bands[band], band); |
140 | } | 140 | } |
141 | |||
142 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | ||
143 | const u8 *mac_addr) | ||
144 | { | ||
145 | if (key_idx > 5) | ||
146 | return -EINVAL; | ||
147 | |||
148 | /* | ||
149 | * Disallow pairwise keys with non-zero index unless it's WEP | ||
150 | * (because current deployments use pairwise WEP keys with | ||
151 | * non-zero indizes but 802.11i clearly specifies to use zero) | ||
152 | */ | ||
153 | if (mac_addr && key_idx && | ||
154 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
155 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | ||
156 | return -EINVAL; | ||
157 | |||
158 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ | ||
159 | switch (params->cipher) { | ||
160 | case WLAN_CIPHER_SUITE_WEP40: | ||
161 | if (params->key_len != 5) | ||
162 | return -EINVAL; | ||
163 | break; | ||
164 | case WLAN_CIPHER_SUITE_TKIP: | ||
165 | if (params->key_len != 32) | ||
166 | return -EINVAL; | ||
167 | break; | ||
168 | case WLAN_CIPHER_SUITE_CCMP: | ||
169 | if (params->key_len != 16) | ||
170 | return -EINVAL; | ||
171 | break; | ||
172 | case WLAN_CIPHER_SUITE_WEP104: | ||
173 | if (params->key_len != 13) | ||
174 | return -EINVAL; | ||
175 | break; | ||
176 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
177 | if (params->key_len != 16) | ||
178 | return -EINVAL; | ||
179 | break; | ||
180 | default: | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | return 0; | ||
185 | } | ||
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index abf6b0a047d8..ffc98a8d6e5c 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -5,12 +5,13 @@ | |||
5 | * into cfg80211, when that happens all the exports here go away and | 5 | * into cfg80211, when that happens all the exports here go away and |
6 | * we directly assign the wireless handlers of wireless interfaces. | 6 | * we directly assign the wireless handlers of wireless interfaces. |
7 | * | 7 | * |
8 | * Copyright 2008 Johannes Berg <johannes@sipsolutions.net> | 8 | * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/wireless.h> | 11 | #include <linux/wireless.h> |
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 <net/iw_handler.h> | 15 | #include <net/iw_handler.h> |
15 | #include <net/cfg80211.h> | 16 | #include <net/cfg80211.h> |
16 | #include "core.h" | 17 | #include "core.h" |
@@ -477,3 +478,257 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
477 | return 0; | 478 | return 0; |
478 | } | 479 | } |
479 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 480 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
481 | |||
482 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | ||
483 | struct net_device *dev, const u8 *addr, | ||
484 | bool remove, bool tx_key, int idx, | ||
485 | struct key_params *params) | ||
486 | { | ||
487 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
488 | int err; | ||
489 | |||
490 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { | ||
491 | if (!rdev->ops->set_default_mgmt_key) | ||
492 | return -EOPNOTSUPP; | ||
493 | |||
494 | if (idx < 4 || idx > 5) | ||
495 | return -EINVAL; | ||
496 | } else if (idx < 0 || idx > 3) | ||
497 | return -EINVAL; | ||
498 | |||
499 | if (remove) { | ||
500 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | ||
501 | if (!err) { | ||
502 | if (idx == wdev->wext.default_key) | ||
503 | wdev->wext.default_key = -1; | ||
504 | else if (idx == wdev->wext.default_mgmt_key) | ||
505 | wdev->wext.default_mgmt_key = -1; | ||
506 | } | ||
507 | return err; | ||
508 | } else { | ||
509 | if (addr) | ||
510 | tx_key = false; | ||
511 | |||
512 | if (cfg80211_validate_key_settings(params, idx, addr)) | ||
513 | return -EINVAL; | ||
514 | |||
515 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); | ||
516 | if (err) | ||
517 | return err; | ||
518 | |||
519 | if (tx_key || (!addr && wdev->wext.default_key == -1)) { | ||
520 | err = rdev->ops->set_default_key(&rdev->wiphy, | ||
521 | dev, idx); | ||
522 | if (!err) | ||
523 | wdev->wext.default_key = idx; | ||
524 | return err; | ||
525 | } | ||
526 | |||
527 | if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && | ||
528 | (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { | ||
529 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, | ||
530 | dev, idx); | ||
531 | if (!err) | ||
532 | wdev->wext.default_mgmt_key = idx; | ||
533 | return err; | ||
534 | } | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | int cfg80211_wext_siwencode(struct net_device *dev, | ||
541 | struct iw_request_info *info, | ||
542 | struct iw_point *erq, char *keybuf) | ||
543 | { | ||
544 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
545 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
546 | int idx, err; | ||
547 | bool remove = false; | ||
548 | struct key_params params; | ||
549 | |||
550 | /* no use -- only MFP (set_default_mgmt_key) is optional */ | ||
551 | if (!rdev->ops->del_key || | ||
552 | !rdev->ops->add_key || | ||
553 | !rdev->ops->set_default_key) | ||
554 | return -EOPNOTSUPP; | ||
555 | |||
556 | idx = erq->flags & IW_ENCODE_INDEX; | ||
557 | if (idx == 0) { | ||
558 | idx = wdev->wext.default_key; | ||
559 | if (idx < 0) | ||
560 | idx = 0; | ||
561 | } else if (idx < 1 || idx > 4) | ||
562 | return -EINVAL; | ||
563 | else | ||
564 | idx--; | ||
565 | |||
566 | if (erq->flags & IW_ENCODE_DISABLED) | ||
567 | remove = true; | ||
568 | else if (erq->length == 0) { | ||
569 | /* No key data - just set the default TX key index */ | ||
570 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); | ||
571 | if (!err) | ||
572 | wdev->wext.default_key = idx; | ||
573 | return err; | ||
574 | } | ||
575 | |||
576 | memset(¶ms, 0, sizeof(params)); | ||
577 | params.key = keybuf; | ||
578 | params.key_len = erq->length; | ||
579 | if (erq->length == 5) | ||
580 | params.cipher = WLAN_CIPHER_SUITE_WEP40; | ||
581 | else if (erq->length == 13) | ||
582 | params.cipher = WLAN_CIPHER_SUITE_WEP104; | ||
583 | else if (!remove) | ||
584 | return -EINVAL; | ||
585 | |||
586 | return cfg80211_set_encryption(rdev, dev, NULL, remove, | ||
587 | wdev->wext.default_key == -1, | ||
588 | idx, ¶ms); | ||
589 | } | ||
590 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode); | ||
591 | |||
592 | int cfg80211_wext_siwencodeext(struct net_device *dev, | ||
593 | struct iw_request_info *info, | ||
594 | struct iw_point *erq, char *extra) | ||
595 | { | ||
596 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
597 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
598 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
599 | const u8 *addr; | ||
600 | int idx; | ||
601 | bool remove = false; | ||
602 | struct key_params params; | ||
603 | u32 cipher; | ||
604 | |||
605 | /* no use -- only MFP (set_default_mgmt_key) is optional */ | ||
606 | if (!rdev->ops->del_key || | ||
607 | !rdev->ops->add_key || | ||
608 | !rdev->ops->set_default_key) | ||
609 | return -EOPNOTSUPP; | ||
610 | |||
611 | switch (ext->alg) { | ||
612 | case IW_ENCODE_ALG_NONE: | ||
613 | remove = true; | ||
614 | cipher = 0; | ||
615 | break; | ||
616 | case IW_ENCODE_ALG_WEP: | ||
617 | if (ext->key_len == 5) | ||
618 | cipher = WLAN_CIPHER_SUITE_WEP40; | ||
619 | else if (ext->key_len == 13) | ||
620 | cipher = WLAN_CIPHER_SUITE_WEP104; | ||
621 | else | ||
622 | return -EINVAL; | ||
623 | break; | ||
624 | case IW_ENCODE_ALG_TKIP: | ||
625 | cipher = WLAN_CIPHER_SUITE_TKIP; | ||
626 | break; | ||
627 | case IW_ENCODE_ALG_CCMP: | ||
628 | cipher = WLAN_CIPHER_SUITE_CCMP; | ||
629 | break; | ||
630 | case IW_ENCODE_ALG_AES_CMAC: | ||
631 | cipher = WLAN_CIPHER_SUITE_AES_CMAC; | ||
632 | break; | ||
633 | default: | ||
634 | return -EOPNOTSUPP; | ||
635 | } | ||
636 | |||
637 | if (erq->flags & IW_ENCODE_DISABLED) | ||
638 | remove = true; | ||
639 | |||
640 | idx = erq->flags & IW_ENCODE_INDEX; | ||
641 | if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) { | ||
642 | if (idx < 4 || idx > 5) { | ||
643 | idx = wdev->wext.default_mgmt_key; | ||
644 | if (idx < 0) | ||
645 | return -EINVAL; | ||
646 | } else | ||
647 | idx--; | ||
648 | } else { | ||
649 | if (idx < 1 || idx > 4) { | ||
650 | idx = wdev->wext.default_key; | ||
651 | if (idx < 0) | ||
652 | return -EINVAL; | ||
653 | } else | ||
654 | idx--; | ||
655 | } | ||
656 | |||
657 | addr = ext->addr.sa_data; | ||
658 | if (is_broadcast_ether_addr(addr)) | ||
659 | addr = NULL; | ||
660 | |||
661 | memset(¶ms, 0, sizeof(params)); | ||
662 | params.key = ext->key; | ||
663 | params.key_len = ext->key_len; | ||
664 | params.cipher = cipher; | ||
665 | |||
666 | return cfg80211_set_encryption( | ||
667 | rdev, dev, addr, remove, | ||
668 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | ||
669 | idx, ¶ms); | ||
670 | } | ||
671 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); | ||
672 | |||
673 | struct giwencode_cookie { | ||
674 | size_t buflen; | ||
675 | char *keybuf; | ||
676 | }; | ||
677 | |||
678 | static void giwencode_get_key_cb(void *cookie, struct key_params *params) | ||
679 | { | ||
680 | struct giwencode_cookie *data = cookie; | ||
681 | |||
682 | if (!params->key) { | ||
683 | data->buflen = 0; | ||
684 | return; | ||
685 | } | ||
686 | |||
687 | data->buflen = min_t(size_t, data->buflen, params->key_len); | ||
688 | memcpy(data->keybuf, params->key, data->buflen); | ||
689 | } | ||
690 | |||
691 | int cfg80211_wext_giwencode(struct net_device *dev, | ||
692 | struct iw_request_info *info, | ||
693 | struct iw_point *erq, char *keybuf) | ||
694 | { | ||
695 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
696 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
697 | int idx, err; | ||
698 | struct giwencode_cookie data = { | ||
699 | .keybuf = keybuf, | ||
700 | .buflen = erq->length, | ||
701 | }; | ||
702 | |||
703 | if (!rdev->ops->get_key) | ||
704 | return -EOPNOTSUPP; | ||
705 | |||
706 | idx = erq->flags & IW_ENCODE_INDEX; | ||
707 | if (idx == 0) { | ||
708 | idx = wdev->wext.default_key; | ||
709 | if (idx < 0) | ||
710 | idx = 0; | ||
711 | } else if (idx < 1 || idx > 4) | ||
712 | return -EINVAL; | ||
713 | else | ||
714 | idx--; | ||
715 | |||
716 | erq->flags = idx + 1; | ||
717 | |||
718 | err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data, | ||
719 | giwencode_get_key_cb); | ||
720 | if (!err) { | ||
721 | erq->length = data.buflen; | ||
722 | erq->flags |= IW_ENCODE_ENABLED; | ||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | if (err == -ENOENT) { | ||
727 | erq->flags |= IW_ENCODE_DISABLED; | ||
728 | erq->length = 0; | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | return err; | ||
733 | } | ||
734 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | ||