diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-05-11 07:54:58 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-13 15:44:32 -0400 |
commit | 08645126dd24872c2e27014f93968f7312e29176 (patch) | |
tree | 2011cb3cb2f70d35278ef3b39ea696a058fb7b29 /net/mac80211/wext.c | |
parent | 7be69c0b9aa93ef655db4d46e5654996489d62f5 (diff) |
cfg80211: implement wext key handling
Move key handling wireless extension ioctls from mac80211 to cfg80211
so that all drivers that implement the cfg80211 operations get wext
compatibility.
Note that this drops the SIOCGIWENCODE ioctl support for getting
IW_ENCODE_RESTRICTED/IW_ENCODE_OPEN. This means that iwconfig will
no longer report "Security mode:open" or "Security mode:restricted"
for mac80211. However, what we displayed there (the authentication
algo used) was actually wrong -- linux/wireless.h states that this
setting is meant to differentiate between "Refuse non-encoded packets"
and "Accept non-encoded packets".
(Combined with "cfg80211: fix a couple of bugs with key ioctls". -- JWL)
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/wext.c')
-rw-r--r-- | net/mac80211/wext.c | 279 |
1 files changed, 3 insertions, 276 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 -- */ |