aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/orinoco/wext.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/orinoco/wext.c')
-rw-r--r--drivers/net/wireless/orinoco/wext.c173
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 */
27static 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
74free_key:
75 kfree(priv->keys[index].key);
76 priv->keys[index].key = NULL;
77
78nomem:
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
25static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) 86static 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 }