diff options
Diffstat (limited to 'drivers/net/wireless/orinoco/wext.c')
-rw-r--r-- | drivers/net/wireless/orinoco/wext.c | 173 |
1 files changed, 101 insertions, 72 deletions
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index b6ff3dbb7dd6..3e56f7643df5 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c | |||
@@ -22,6 +22,67 @@ | |||
22 | 22 | ||
23 | #define MAX_RID_LEN 1024 | 23 | #define MAX_RID_LEN 1024 |
24 | 24 | ||
25 | /* Helper routine to record keys | ||
26 | * Do not call from interrupt context */ | ||
27 | static int orinoco_set_key(struct orinoco_private *priv, int index, | ||
28 | enum orinoco_alg alg, const u8 *key, int key_len, | ||
29 | const u8 *seq, int seq_len) | ||
30 | { | ||
31 | kzfree(priv->keys[index].key); | ||
32 | kzfree(priv->keys[index].seq); | ||
33 | |||
34 | if (key_len) { | ||
35 | priv->keys[index].key = kzalloc(key_len, GFP_KERNEL); | ||
36 | if (!priv->keys[index].key) | ||
37 | goto nomem; | ||
38 | } else | ||
39 | priv->keys[index].key = NULL; | ||
40 | |||
41 | if (seq_len) { | ||
42 | priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL); | ||
43 | if (!priv->keys[index].seq) | ||
44 | goto free_key; | ||
45 | } else | ||
46 | priv->keys[index].seq = NULL; | ||
47 | |||
48 | priv->keys[index].key_len = key_len; | ||
49 | priv->keys[index].seq_len = seq_len; | ||
50 | |||
51 | if (key_len) | ||
52 | memcpy(priv->keys[index].key, key, key_len); | ||
53 | if (seq_len) | ||
54 | memcpy(priv->keys[index].seq, seq, seq_len); | ||
55 | |||
56 | switch (alg) { | ||
57 | case ORINOCO_ALG_TKIP: | ||
58 | priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP; | ||
59 | break; | ||
60 | |||
61 | case ORINOCO_ALG_WEP: | ||
62 | priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ? | ||
63 | WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40; | ||
64 | break; | ||
65 | |||
66 | case ORINOCO_ALG_NONE: | ||
67 | default: | ||
68 | priv->keys[index].cipher = 0; | ||
69 | break; | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | |||
74 | free_key: | ||
75 | kfree(priv->keys[index].key); | ||
76 | priv->keys[index].key = NULL; | ||
77 | |||
78 | nomem: | ||
79 | priv->keys[index].key_len = 0; | ||
80 | priv->keys[index].seq_len = 0; | ||
81 | priv->keys[index].cipher = 0; | ||
82 | |||
83 | return -ENOMEM; | ||
84 | } | ||
85 | |||
25 | static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) | 86 | static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) |
26 | { | 87 | { |
27 | struct orinoco_private *priv = ndev_priv(dev); | 88 | struct orinoco_private *priv = ndev_priv(dev); |
@@ -156,7 +217,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev, | |||
156 | { | 217 | { |
157 | struct orinoco_private *priv = ndev_priv(dev); | 218 | struct orinoco_private *priv = ndev_priv(dev); |
158 | 219 | ||
159 | hermes_t *hw = &priv->hw; | ||
160 | int err = 0; | 220 | int err = 0; |
161 | unsigned long flags; | 221 | unsigned long flags; |
162 | 222 | ||
@@ -164,8 +224,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev, | |||
164 | return -EBUSY; | 224 | return -EBUSY; |
165 | 225 | ||
166 | ap_addr->sa_family = ARPHRD_ETHER; | 226 | ap_addr->sa_family = ARPHRD_ETHER; |
167 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, | 227 | err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data); |
168 | ETH_ALEN, NULL, ap_addr->sa_data); | ||
169 | 228 | ||
170 | orinoco_unlock(priv, &flags); | 229 | orinoco_unlock(priv, &flags); |
171 | 230 | ||
@@ -180,9 +239,8 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, | |||
180 | struct orinoco_private *priv = ndev_priv(dev); | 239 | struct orinoco_private *priv = ndev_priv(dev); |
181 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | 240 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; |
182 | int setindex = priv->tx_key; | 241 | int setindex = priv->tx_key; |
183 | int encode_alg = priv->encode_alg; | 242 | enum orinoco_alg encode_alg = priv->encode_alg; |
184 | int restricted = priv->wep_restrict; | 243 | int restricted = priv->wep_restrict; |
185 | u16 xlen = 0; | ||
186 | int err = -EINPROGRESS; /* Call commit handler */ | 244 | int err = -EINPROGRESS; /* Call commit handler */ |
187 | unsigned long flags; | 245 | unsigned long flags; |
188 | 246 | ||
@@ -202,25 +260,17 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, | |||
202 | return -EBUSY; | 260 | return -EBUSY; |
203 | 261 | ||
204 | /* Clear any TKIP key we have */ | 262 | /* Clear any TKIP key we have */ |
205 | if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) | 263 | if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP)) |
206 | (void) orinoco_clear_tkip_key(priv, setindex); | 264 | (void) orinoco_clear_tkip_key(priv, setindex); |
207 | 265 | ||
208 | if (erq->length > 0) { | 266 | if (erq->length > 0) { |
209 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) | 267 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) |
210 | index = priv->tx_key; | 268 | index = priv->tx_key; |
211 | 269 | ||
212 | /* Adjust key length to a supported value */ | ||
213 | if (erq->length > SMALL_KEY_SIZE) | ||
214 | xlen = LARGE_KEY_SIZE; | ||
215 | else if (erq->length > 0) | ||
216 | xlen = SMALL_KEY_SIZE; | ||
217 | else | ||
218 | xlen = 0; | ||
219 | |||
220 | /* Switch on WEP if off */ | 270 | /* Switch on WEP if off */ |
221 | if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { | 271 | if (encode_alg != ORINOCO_ALG_WEP) { |
222 | setindex = index; | 272 | setindex = index; |
223 | encode_alg = IW_ENCODE_ALG_WEP; | 273 | encode_alg = ORINOCO_ALG_WEP; |
224 | } | 274 | } |
225 | } else { | 275 | } else { |
226 | /* Important note : if the user do "iwconfig eth0 enc off", | 276 | /* Important note : if the user do "iwconfig eth0 enc off", |
@@ -233,7 +283,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, | |||
233 | } | 283 | } |
234 | } else { | 284 | } else { |
235 | /* Set the index : Check that the key is valid */ | 285 | /* Set the index : Check that the key is valid */ |
236 | if (priv->keys[index].len == 0) { | 286 | if (priv->keys[index].key_len == 0) { |
237 | err = -EINVAL; | 287 | err = -EINVAL; |
238 | goto out; | 288 | goto out; |
239 | } | 289 | } |
@@ -242,17 +292,15 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, | |||
242 | } | 292 | } |
243 | 293 | ||
244 | if (erq->flags & IW_ENCODE_DISABLED) | 294 | if (erq->flags & IW_ENCODE_DISABLED) |
245 | encode_alg = IW_ENCODE_ALG_NONE; | 295 | encode_alg = ORINOCO_ALG_NONE; |
246 | if (erq->flags & IW_ENCODE_OPEN) | 296 | if (erq->flags & IW_ENCODE_OPEN) |
247 | restricted = 0; | 297 | restricted = 0; |
248 | if (erq->flags & IW_ENCODE_RESTRICTED) | 298 | if (erq->flags & IW_ENCODE_RESTRICTED) |
249 | restricted = 1; | 299 | restricted = 1; |
250 | 300 | ||
251 | if (erq->pointer && erq->length > 0) { | 301 | if (erq->pointer && erq->length > 0) { |
252 | priv->keys[index].len = cpu_to_le16(xlen); | 302 | err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf, |
253 | memset(priv->keys[index].data, 0, | 303 | erq->length, NULL, 0); |
254 | sizeof(priv->keys[index].data)); | ||
255 | memcpy(priv->keys[index].data, keybuf, erq->length); | ||
256 | } | 304 | } |
257 | priv->tx_key = setindex; | 305 | priv->tx_key = setindex; |
258 | 306 | ||
@@ -281,7 +329,6 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, | |||
281 | { | 329 | { |
282 | struct orinoco_private *priv = ndev_priv(dev); | 330 | struct orinoco_private *priv = ndev_priv(dev); |
283 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | 331 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; |
284 | u16 xlen = 0; | ||
285 | unsigned long flags; | 332 | unsigned long flags; |
286 | 333 | ||
287 | if (!priv->has_wep) | 334 | if (!priv->has_wep) |
@@ -303,11 +350,9 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, | |||
303 | else | 350 | else |
304 | erq->flags |= IW_ENCODE_OPEN; | 351 | erq->flags |= IW_ENCODE_OPEN; |
305 | 352 | ||
306 | xlen = le16_to_cpu(priv->keys[index].len); | 353 | erq->length = priv->keys[index].key_len; |
307 | 354 | ||
308 | erq->length = xlen; | 355 | memcpy(keybuf, priv->keys[index].key, erq->length); |
309 | |||
310 | memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); | ||
311 | 356 | ||
312 | orinoco_unlock(priv, &flags); | 357 | orinoco_unlock(priv, &flags); |
313 | return 0; | 358 | return 0; |
@@ -793,7 +838,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, | |||
793 | int idx, alg = ext->alg, set_key = 1; | 838 | int idx, alg = ext->alg, set_key = 1; |
794 | unsigned long flags; | 839 | unsigned long flags; |
795 | int err = -EINVAL; | 840 | int err = -EINVAL; |
796 | u16 key_len; | ||
797 | 841 | ||
798 | if (orinoco_lock(priv, &flags) != 0) | 842 | if (orinoco_lock(priv, &flags) != 0) |
799 | return -EBUSY; | 843 | return -EBUSY; |
@@ -825,25 +869,18 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, | |||
825 | /* Set the requested key first */ | 869 | /* Set the requested key first */ |
826 | switch (alg) { | 870 | switch (alg) { |
827 | case IW_ENCODE_ALG_NONE: | 871 | case IW_ENCODE_ALG_NONE: |
828 | priv->encode_alg = alg; | 872 | priv->encode_alg = ORINOCO_ALG_NONE; |
829 | priv->keys[idx].len = 0; | 873 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE, |
874 | NULL, 0, NULL, 0); | ||
830 | break; | 875 | break; |
831 | 876 | ||
832 | case IW_ENCODE_ALG_WEP: | 877 | case IW_ENCODE_ALG_WEP: |
833 | if (ext->key_len > SMALL_KEY_SIZE) | 878 | if (ext->key_len <= 0) |
834 | key_len = LARGE_KEY_SIZE; | ||
835 | else if (ext->key_len > 0) | ||
836 | key_len = SMALL_KEY_SIZE; | ||
837 | else | ||
838 | goto out; | 879 | goto out; |
839 | 880 | ||
840 | priv->encode_alg = alg; | 881 | priv->encode_alg = ORINOCO_ALG_WEP; |
841 | priv->keys[idx].len = cpu_to_le16(key_len); | 882 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP, |
842 | 883 | ext->key, ext->key_len, NULL, 0); | |
843 | key_len = min(ext->key_len, key_len); | ||
844 | |||
845 | memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); | ||
846 | memcpy(priv->keys[idx].data, ext->key, key_len); | ||
847 | break; | 884 | break; |
848 | 885 | ||
849 | case IW_ENCODE_ALG_TKIP: | 886 | case IW_ENCODE_ALG_TKIP: |
@@ -851,21 +888,22 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, | |||
851 | u8 *tkip_iv = NULL; | 888 | u8 *tkip_iv = NULL; |
852 | 889 | ||
853 | if (!priv->has_wpa || | 890 | if (!priv->has_wpa || |
854 | (ext->key_len > sizeof(priv->tkip_key[0]))) | 891 | (ext->key_len > sizeof(struct orinoco_tkip_key))) |
855 | goto out; | 892 | goto out; |
856 | 893 | ||
857 | priv->encode_alg = alg; | 894 | priv->encode_alg = ORINOCO_ALG_TKIP; |
858 | memset(&priv->tkip_key[idx], 0, | ||
859 | sizeof(priv->tkip_key[idx])); | ||
860 | memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); | ||
861 | 895 | ||
862 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) | 896 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) |
863 | tkip_iv = &ext->rx_seq[0]; | 897 | tkip_iv = &ext->rx_seq[0]; |
864 | 898 | ||
899 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP, | ||
900 | ext->key, ext->key_len, tkip_iv, | ||
901 | ORINOCO_SEQ_LEN); | ||
902 | |||
865 | err = __orinoco_hw_set_tkip_key(priv, idx, | 903 | err = __orinoco_hw_set_tkip_key(priv, idx, |
866 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | 904 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, |
867 | (u8 *) &priv->tkip_key[idx], | 905 | priv->keys[idx].key, |
868 | tkip_iv, NULL); | 906 | tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); |
869 | if (err) | 907 | if (err) |
870 | printk(KERN_ERR "%s: Error %d setting TKIP key" | 908 | printk(KERN_ERR "%s: Error %d setting TKIP key" |
871 | "\n", dev->name, err); | 909 | "\n", dev->name, err); |
@@ -914,22 +952,22 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, | |||
914 | encoding->flags = idx + 1; | 952 | encoding->flags = idx + 1; |
915 | memset(ext, 0, sizeof(*ext)); | 953 | memset(ext, 0, sizeof(*ext)); |
916 | 954 | ||
917 | ext->alg = priv->encode_alg; | ||
918 | switch (priv->encode_alg) { | 955 | switch (priv->encode_alg) { |
919 | case IW_ENCODE_ALG_NONE: | 956 | case ORINOCO_ALG_NONE: |
957 | ext->alg = IW_ENCODE_ALG_NONE; | ||
920 | ext->key_len = 0; | 958 | ext->key_len = 0; |
921 | encoding->flags |= IW_ENCODE_DISABLED; | 959 | encoding->flags |= IW_ENCODE_DISABLED; |
922 | break; | 960 | break; |
923 | case IW_ENCODE_ALG_WEP: | 961 | case ORINOCO_ALG_WEP: |
924 | ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), | 962 | ext->alg = IW_ENCODE_ALG_WEP; |
925 | max_key_len); | 963 | ext->key_len = min(priv->keys[idx].key_len, max_key_len); |
926 | memcpy(ext->key, priv->keys[idx].data, ext->key_len); | 964 | memcpy(ext->key, priv->keys[idx].key, ext->key_len); |
927 | encoding->flags |= IW_ENCODE_ENABLED; | 965 | encoding->flags |= IW_ENCODE_ENABLED; |
928 | break; | 966 | break; |
929 | case IW_ENCODE_ALG_TKIP: | 967 | case ORINOCO_ALG_TKIP: |
930 | ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), | 968 | ext->alg = IW_ENCODE_ALG_TKIP; |
931 | max_key_len); | 969 | ext->key_len = min(priv->keys[idx].key_len, max_key_len); |
932 | memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); | 970 | memcpy(ext->key, priv->keys[idx].key, ext->key_len); |
933 | encoding->flags |= IW_ENCODE_ENABLED; | 971 | encoding->flags |= IW_ENCODE_ENABLED; |
934 | break; | 972 | break; |
935 | } | 973 | } |
@@ -1136,7 +1174,6 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, | |||
1136 | union iwreq_data *wrqu, char *extra) | 1174 | union iwreq_data *wrqu, char *extra) |
1137 | { | 1175 | { |
1138 | struct orinoco_private *priv = ndev_priv(dev); | 1176 | struct orinoco_private *priv = ndev_priv(dev); |
1139 | hermes_t *hw = &priv->hw; | ||
1140 | struct iw_mlme *mlme = (struct iw_mlme *)extra; | 1177 | struct iw_mlme *mlme = (struct iw_mlme *)extra; |
1141 | unsigned long flags; | 1178 | unsigned long flags; |
1142 | int ret = 0; | 1179 | int ret = 0; |
@@ -1150,19 +1187,11 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, | |||
1150 | break; | 1187 | break; |
1151 | 1188 | ||
1152 | case IW_MLME_DISASSOC: | 1189 | case IW_MLME_DISASSOC: |
1153 | { | 1190 | |
1154 | struct { | 1191 | ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data, |
1155 | u8 addr[ETH_ALEN]; | 1192 | mlme->reason_code); |
1156 | __le16 reason_code; | ||
1157 | } __attribute__ ((packed)) buf; | ||
1158 | |||
1159 | memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); | ||
1160 | buf.reason_code = cpu_to_le16(mlme->reason_code); | ||
1161 | ret = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1162 | HERMES_RID_CNFDISASSOCIATE, | ||
1163 | &buf); | ||
1164 | break; | 1193 | break; |
1165 | } | 1194 | |
1166 | default: | 1195 | default: |
1167 | ret = -EOPNOTSUPP; | 1196 | ret = -EOPNOTSUPP; |
1168 | } | 1197 | } |