diff options
author | David Kilroy <kilroyd@googlemail.com> | 2009-02-04 18:05:55 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-13 13:44:31 -0500 |
commit | 712a4342a0d89e855a03ba06fb11f7eb29456d45 (patch) | |
tree | e5b500f5e4e9f4b1e065009d7de2e19fba932ef5 /drivers/net/wireless/orinoco | |
parent | 5865d015cf85c619a51f8be93d44ec932bc90038 (diff) |
orinoco: Move hardware functions into separate file
No functional change.
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/orinoco')
-rw-r--r-- | drivers/net/wireless/orinoco/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hw.c | 586 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hw.h | 47 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/main.c | 583 |
4 files changed, 635 insertions, 583 deletions
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile index fecdbcec51a1..f40f54d31e59 100644 --- a/drivers/net/wireless/orinoco/Makefile +++ b/drivers/net/wireless/orinoco/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the orinoco wireless device drivers. | 2 | # Makefile for the orinoco wireless device drivers. |
3 | # | 3 | # |
4 | orinoco-objs := main.o fw.o mic.o scan.o | 4 | orinoco-objs := main.o fw.o hw.o mic.o scan.o |
5 | 5 | ||
6 | obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o | 6 | obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o |
7 | obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o | 7 | obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o |
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c new file mode 100644 index 000000000000..081428d9409e --- /dev/null +++ b/drivers/net/wireless/orinoco/hw.c | |||
@@ -0,0 +1,586 @@ | |||
1 | /* Encapsulate basic setting changes and retrieval on Hermes hardware | ||
2 | * | ||
3 | * See copyright notice in main.c | ||
4 | */ | ||
5 | #include <linux/kernel.h> | ||
6 | #include <linux/if_arp.h> | ||
7 | #include <linux/ieee80211.h> | ||
8 | #include <linux/wireless.h> | ||
9 | |||
10 | #include "hermes.h" | ||
11 | #include "hermes_rid.h" | ||
12 | #include "orinoco.h" | ||
13 | |||
14 | #include "hw.h" | ||
15 | |||
16 | /********************************************************************/ | ||
17 | /* Data tables */ | ||
18 | /********************************************************************/ | ||
19 | |||
20 | /* This tables gives the actual meanings of the bitrate IDs returned | ||
21 | * by the firmware. */ | ||
22 | static const struct { | ||
23 | int bitrate; /* in 100s of kilobits */ | ||
24 | int automatic; | ||
25 | u16 agere_txratectrl; | ||
26 | u16 intersil_txratectrl; | ||
27 | } bitrate_table[] = { | ||
28 | {110, 1, 3, 15}, /* Entry 0 is the default */ | ||
29 | {10, 0, 1, 1}, | ||
30 | {10, 1, 1, 1}, | ||
31 | {20, 0, 2, 2}, | ||
32 | {20, 1, 6, 3}, | ||
33 | {55, 0, 4, 4}, | ||
34 | {55, 1, 7, 7}, | ||
35 | {110, 0, 5, 8}, | ||
36 | }; | ||
37 | #define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) | ||
38 | |||
39 | int orinoco_get_bitratemode(int bitrate, int automatic) | ||
40 | { | ||
41 | int ratemode = -1; | ||
42 | int i; | ||
43 | |||
44 | if ((bitrate != 10) && (bitrate != 20) && | ||
45 | (bitrate != 55) && (bitrate != 110)) | ||
46 | return ratemode; | ||
47 | |||
48 | for (i = 0; i < BITRATE_TABLE_SIZE; i++) { | ||
49 | if ((bitrate_table[i].bitrate == bitrate) && | ||
50 | (bitrate_table[i].automatic == automatic)) { | ||
51 | ratemode = i; | ||
52 | break; | ||
53 | } | ||
54 | } | ||
55 | return ratemode; | ||
56 | } | ||
57 | |||
58 | void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) | ||
59 | { | ||
60 | BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); | ||
61 | |||
62 | *bitrate = bitrate_table[ratemode].bitrate * 100000; | ||
63 | *automatic = bitrate_table[ratemode].automatic; | ||
64 | } | ||
65 | |||
66 | /* Get tsc from the firmware */ | ||
67 | int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) | ||
68 | { | ||
69 | hermes_t *hw = &priv->hw; | ||
70 | int err = 0; | ||
71 | u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; | ||
72 | |||
73 | if ((key < 0) || (key > 4)) | ||
74 | return -EINVAL; | ||
75 | |||
76 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, | ||
77 | sizeof(tsc_arr), NULL, &tsc_arr); | ||
78 | if (!err) | ||
79 | memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); | ||
80 | |||
81 | return err; | ||
82 | } | ||
83 | |||
84 | int __orinoco_hw_set_bitrate(struct orinoco_private *priv) | ||
85 | { | ||
86 | hermes_t *hw = &priv->hw; | ||
87 | int ratemode = priv->bitratemode; | ||
88 | int err = 0; | ||
89 | |||
90 | if (ratemode >= BITRATE_TABLE_SIZE) { | ||
91 | printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", | ||
92 | priv->ndev->name, ratemode); | ||
93 | return -EINVAL; | ||
94 | } | ||
95 | |||
96 | switch (priv->firmware_type) { | ||
97 | case FIRMWARE_TYPE_AGERE: | ||
98 | err = hermes_write_wordrec(hw, USER_BAP, | ||
99 | HERMES_RID_CNFTXRATECONTROL, | ||
100 | bitrate_table[ratemode].agere_txratectrl); | ||
101 | break; | ||
102 | case FIRMWARE_TYPE_INTERSIL: | ||
103 | case FIRMWARE_TYPE_SYMBOL: | ||
104 | err = hermes_write_wordrec(hw, USER_BAP, | ||
105 | HERMES_RID_CNFTXRATECONTROL, | ||
106 | bitrate_table[ratemode].intersil_txratectrl); | ||
107 | break; | ||
108 | default: | ||
109 | BUG(); | ||
110 | } | ||
111 | |||
112 | return err; | ||
113 | } | ||
114 | |||
115 | int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate) | ||
116 | { | ||
117 | hermes_t *hw = &priv->hw; | ||
118 | int i; | ||
119 | int err = 0; | ||
120 | u16 val; | ||
121 | |||
122 | err = hermes_read_wordrec(hw, USER_BAP, | ||
123 | HERMES_RID_CURRENTTXRATE, &val); | ||
124 | if (err) | ||
125 | return err; | ||
126 | |||
127 | switch (priv->firmware_type) { | ||
128 | case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ | ||
129 | /* Note : in Lucent firmware, the return value of | ||
130 | * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, | ||
131 | * and therefore is totally different from the | ||
132 | * encoding of HERMES_RID_CNFTXRATECONTROL. | ||
133 | * Don't forget that 6Mb/s is really 5.5Mb/s */ | ||
134 | if (val == 6) | ||
135 | *bitrate = 5500000; | ||
136 | else | ||
137 | *bitrate = val * 1000000; | ||
138 | break; | ||
139 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ | ||
140 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ | ||
141 | for (i = 0; i < BITRATE_TABLE_SIZE; i++) | ||
142 | if (bitrate_table[i].intersil_txratectrl == val) | ||
143 | break; | ||
144 | |||
145 | if (i >= BITRATE_TABLE_SIZE) | ||
146 | printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", | ||
147 | priv->ndev->name, val); | ||
148 | |||
149 | *bitrate = bitrate_table[i].bitrate * 100000; | ||
150 | break; | ||
151 | default: | ||
152 | BUG(); | ||
153 | } | ||
154 | |||
155 | return err; | ||
156 | } | ||
157 | |||
158 | /* Set fixed AP address */ | ||
159 | int __orinoco_hw_set_wap(struct orinoco_private *priv) | ||
160 | { | ||
161 | int roaming_flag; | ||
162 | int err = 0; | ||
163 | hermes_t *hw = &priv->hw; | ||
164 | |||
165 | switch (priv->firmware_type) { | ||
166 | case FIRMWARE_TYPE_AGERE: | ||
167 | /* not supported */ | ||
168 | break; | ||
169 | case FIRMWARE_TYPE_INTERSIL: | ||
170 | if (priv->bssid_fixed) | ||
171 | roaming_flag = 2; | ||
172 | else | ||
173 | roaming_flag = 1; | ||
174 | |||
175 | err = hermes_write_wordrec(hw, USER_BAP, | ||
176 | HERMES_RID_CNFROAMINGMODE, | ||
177 | roaming_flag); | ||
178 | break; | ||
179 | case FIRMWARE_TYPE_SYMBOL: | ||
180 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
181 | HERMES_RID_CNFMANDATORYBSSID_SYMBOL, | ||
182 | &priv->desired_bssid); | ||
183 | break; | ||
184 | } | ||
185 | return err; | ||
186 | } | ||
187 | |||
188 | /* Change the WEP keys and/or the current keys. Can be called | ||
189 | * either from __orinoco_hw_setup_enc() or directly from | ||
190 | * orinoco_ioctl_setiwencode(). In the later case the association | ||
191 | * with the AP is not broken (if the firmware can handle it), | ||
192 | * which is needed for 802.1x implementations. */ | ||
193 | int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) | ||
194 | { | ||
195 | hermes_t *hw = &priv->hw; | ||
196 | int err = 0; | ||
197 | |||
198 | switch (priv->firmware_type) { | ||
199 | case FIRMWARE_TYPE_AGERE: | ||
200 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
201 | HERMES_RID_CNFWEPKEYS_AGERE, | ||
202 | &priv->keys); | ||
203 | if (err) | ||
204 | return err; | ||
205 | err = hermes_write_wordrec(hw, USER_BAP, | ||
206 | HERMES_RID_CNFTXKEY_AGERE, | ||
207 | priv->tx_key); | ||
208 | if (err) | ||
209 | return err; | ||
210 | break; | ||
211 | case FIRMWARE_TYPE_INTERSIL: | ||
212 | case FIRMWARE_TYPE_SYMBOL: | ||
213 | { | ||
214 | int keylen; | ||
215 | int i; | ||
216 | |||
217 | /* Force uniform key length to work around | ||
218 | * firmware bugs */ | ||
219 | keylen = le16_to_cpu(priv->keys[priv->tx_key].len); | ||
220 | |||
221 | if (keylen > LARGE_KEY_SIZE) { | ||
222 | printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", | ||
223 | priv->ndev->name, priv->tx_key, keylen); | ||
224 | return -E2BIG; | ||
225 | } | ||
226 | |||
227 | /* Write all 4 keys */ | ||
228 | for (i = 0; i < ORINOCO_MAX_KEYS; i++) { | ||
229 | err = hermes_write_ltv(hw, USER_BAP, | ||
230 | HERMES_RID_CNFDEFAULTKEY0 + i, | ||
231 | HERMES_BYTES_TO_RECLEN(keylen), | ||
232 | priv->keys[i].data); | ||
233 | if (err) | ||
234 | return err; | ||
235 | } | ||
236 | |||
237 | /* Write the index of the key used in transmission */ | ||
238 | err = hermes_write_wordrec(hw, USER_BAP, | ||
239 | HERMES_RID_CNFWEPDEFAULTKEYID, | ||
240 | priv->tx_key); | ||
241 | if (err) | ||
242 | return err; | ||
243 | } | ||
244 | break; | ||
245 | } | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | int __orinoco_hw_setup_enc(struct orinoco_private *priv) | ||
251 | { | ||
252 | hermes_t *hw = &priv->hw; | ||
253 | int err = 0; | ||
254 | int master_wep_flag; | ||
255 | int auth_flag; | ||
256 | int enc_flag; | ||
257 | |||
258 | /* Setup WEP keys for WEP and WPA */ | ||
259 | if (priv->encode_alg) | ||
260 | __orinoco_hw_setup_wepkeys(priv); | ||
261 | |||
262 | if (priv->wep_restrict) | ||
263 | auth_flag = HERMES_AUTH_SHARED_KEY; | ||
264 | else | ||
265 | auth_flag = HERMES_AUTH_OPEN; | ||
266 | |||
267 | if (priv->wpa_enabled) | ||
268 | enc_flag = 2; | ||
269 | else if (priv->encode_alg == IW_ENCODE_ALG_WEP) | ||
270 | enc_flag = 1; | ||
271 | else | ||
272 | enc_flag = 0; | ||
273 | |||
274 | switch (priv->firmware_type) { | ||
275 | case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ | ||
276 | if (priv->encode_alg == IW_ENCODE_ALG_WEP) { | ||
277 | /* Enable the shared-key authentication. */ | ||
278 | err = hermes_write_wordrec(hw, USER_BAP, | ||
279 | HERMES_RID_CNFAUTHENTICATION_AGERE, | ||
280 | auth_flag); | ||
281 | } | ||
282 | err = hermes_write_wordrec(hw, USER_BAP, | ||
283 | HERMES_RID_CNFWEPENABLED_AGERE, | ||
284 | enc_flag); | ||
285 | if (err) | ||
286 | return err; | ||
287 | |||
288 | if (priv->has_wpa) { | ||
289 | /* Set WPA key management */ | ||
290 | err = hermes_write_wordrec(hw, USER_BAP, | ||
291 | HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, | ||
292 | priv->key_mgmt); | ||
293 | if (err) | ||
294 | return err; | ||
295 | } | ||
296 | |||
297 | break; | ||
298 | |||
299 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ | ||
300 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ | ||
301 | if (priv->encode_alg == IW_ENCODE_ALG_WEP) { | ||
302 | if (priv->wep_restrict || | ||
303 | (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) | ||
304 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | | ||
305 | HERMES_WEP_EXCL_UNENCRYPTED; | ||
306 | else | ||
307 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; | ||
308 | |||
309 | err = hermes_write_wordrec(hw, USER_BAP, | ||
310 | HERMES_RID_CNFAUTHENTICATION, | ||
311 | auth_flag); | ||
312 | if (err) | ||
313 | return err; | ||
314 | } else | ||
315 | master_wep_flag = 0; | ||
316 | |||
317 | if (priv->iw_mode == IW_MODE_MONITOR) | ||
318 | master_wep_flag |= HERMES_WEP_HOST_DECRYPT; | ||
319 | |||
320 | /* Master WEP setting : on/off */ | ||
321 | err = hermes_write_wordrec(hw, USER_BAP, | ||
322 | HERMES_RID_CNFWEPFLAGS_INTERSIL, | ||
323 | master_wep_flag); | ||
324 | if (err) | ||
325 | return err; | ||
326 | |||
327 | break; | ||
328 | } | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /* key must be 32 bytes, including the tx and rx MIC keys. | ||
334 | * rsc must be 8 bytes | ||
335 | * tsc must be 8 bytes or NULL | ||
336 | */ | ||
337 | int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, | ||
338 | u8 *key, u8 *rsc, u8 *tsc) | ||
339 | { | ||
340 | struct { | ||
341 | __le16 idx; | ||
342 | u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; | ||
343 | u8 key[TKIP_KEYLEN]; | ||
344 | u8 tx_mic[MIC_KEYLEN]; | ||
345 | u8 rx_mic[MIC_KEYLEN]; | ||
346 | u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; | ||
347 | } __attribute__ ((packed)) buf; | ||
348 | int ret; | ||
349 | int err; | ||
350 | int k; | ||
351 | u16 xmitting; | ||
352 | |||
353 | key_idx &= 0x3; | ||
354 | |||
355 | if (set_tx) | ||
356 | key_idx |= 0x8000; | ||
357 | |||
358 | buf.idx = cpu_to_le16(key_idx); | ||
359 | memcpy(buf.key, key, | ||
360 | sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); | ||
361 | |||
362 | if (rsc == NULL) | ||
363 | memset(buf.rsc, 0, sizeof(buf.rsc)); | ||
364 | else | ||
365 | memcpy(buf.rsc, rsc, sizeof(buf.rsc)); | ||
366 | |||
367 | if (tsc == NULL) { | ||
368 | memset(buf.tsc, 0, sizeof(buf.tsc)); | ||
369 | buf.tsc[4] = 0x10; | ||
370 | } else { | ||
371 | memcpy(buf.tsc, tsc, sizeof(buf.tsc)); | ||
372 | } | ||
373 | |||
374 | /* Wait upto 100ms for tx queue to empty */ | ||
375 | k = 100; | ||
376 | do { | ||
377 | k--; | ||
378 | udelay(1000); | ||
379 | ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, | ||
380 | &xmitting); | ||
381 | if (ret) | ||
382 | break; | ||
383 | } while ((k > 0) && xmitting); | ||
384 | |||
385 | if (k == 0) | ||
386 | ret = -ETIMEDOUT; | ||
387 | |||
388 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
389 | HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, | ||
390 | &buf); | ||
391 | |||
392 | return ret ? ret : err; | ||
393 | } | ||
394 | |||
395 | int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) | ||
396 | { | ||
397 | hermes_t *hw = &priv->hw; | ||
398 | int err; | ||
399 | |||
400 | memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); | ||
401 | err = hermes_write_wordrec(hw, USER_BAP, | ||
402 | HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, | ||
403 | key_idx); | ||
404 | if (err) | ||
405 | printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", | ||
406 | priv->ndev->name, err, key_idx); | ||
407 | return err; | ||
408 | } | ||
409 | |||
410 | int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, | ||
411 | struct dev_addr_list *mc_list, | ||
412 | int mc_count, int promisc) | ||
413 | { | ||
414 | hermes_t *hw = &priv->hw; | ||
415 | int err = 0; | ||
416 | |||
417 | if (promisc != priv->promiscuous) { | ||
418 | err = hermes_write_wordrec(hw, USER_BAP, | ||
419 | HERMES_RID_CNFPROMISCUOUSMODE, | ||
420 | promisc); | ||
421 | if (err) { | ||
422 | printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", | ||
423 | priv->ndev->name, err); | ||
424 | } else | ||
425 | priv->promiscuous = promisc; | ||
426 | } | ||
427 | |||
428 | /* If we're not in promiscuous mode, then we need to set the | ||
429 | * group address if either we want to multicast, or if we were | ||
430 | * multicasting and want to stop */ | ||
431 | if (!promisc && (mc_count || priv->mc_count)) { | ||
432 | struct dev_mc_list *p = mc_list; | ||
433 | struct hermes_multicast mclist; | ||
434 | int i; | ||
435 | |||
436 | for (i = 0; i < mc_count; i++) { | ||
437 | /* paranoia: is list shorter than mc_count? */ | ||
438 | BUG_ON(!p); | ||
439 | /* paranoia: bad address size in list? */ | ||
440 | BUG_ON(p->dmi_addrlen != ETH_ALEN); | ||
441 | |||
442 | memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); | ||
443 | p = p->next; | ||
444 | } | ||
445 | |||
446 | if (p) | ||
447 | printk(KERN_WARNING "%s: Multicast list is " | ||
448 | "longer than mc_count\n", priv->ndev->name); | ||
449 | |||
450 | err = hermes_write_ltv(hw, USER_BAP, | ||
451 | HERMES_RID_CNFGROUPADDRESSES, | ||
452 | HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), | ||
453 | &mclist); | ||
454 | if (err) | ||
455 | printk(KERN_ERR "%s: Error %d setting multicast list.\n", | ||
456 | priv->ndev->name, err); | ||
457 | else | ||
458 | priv->mc_count = mc_count; | ||
459 | } | ||
460 | return err; | ||
461 | } | ||
462 | |||
463 | /* Return : < 0 -> error code ; >= 0 -> length */ | ||
464 | int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, | ||
465 | char buf[IW_ESSID_MAX_SIZE+1]) | ||
466 | { | ||
467 | hermes_t *hw = &priv->hw; | ||
468 | int err = 0; | ||
469 | struct hermes_idstring essidbuf; | ||
470 | char *p = (char *)(&essidbuf.val); | ||
471 | int len; | ||
472 | unsigned long flags; | ||
473 | |||
474 | if (orinoco_lock(priv, &flags) != 0) | ||
475 | return -EBUSY; | ||
476 | |||
477 | if (strlen(priv->desired_essid) > 0) { | ||
478 | /* We read the desired SSID from the hardware rather | ||
479 | than from priv->desired_essid, just in case the | ||
480 | firmware is allowed to change it on us. I'm not | ||
481 | sure about this */ | ||
482 | /* My guess is that the OWNSSID should always be whatever | ||
483 | * we set to the card, whereas CURRENT_SSID is the one that | ||
484 | * may change... - Jean II */ | ||
485 | u16 rid; | ||
486 | |||
487 | *active = 1; | ||
488 | |||
489 | rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : | ||
490 | HERMES_RID_CNFDESIREDSSID; | ||
491 | |||
492 | err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), | ||
493 | NULL, &essidbuf); | ||
494 | if (err) | ||
495 | goto fail_unlock; | ||
496 | } else { | ||
497 | *active = 0; | ||
498 | |||
499 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, | ||
500 | sizeof(essidbuf), NULL, &essidbuf); | ||
501 | if (err) | ||
502 | goto fail_unlock; | ||
503 | } | ||
504 | |||
505 | len = le16_to_cpu(essidbuf.len); | ||
506 | BUG_ON(len > IW_ESSID_MAX_SIZE); | ||
507 | |||
508 | memset(buf, 0, IW_ESSID_MAX_SIZE); | ||
509 | memcpy(buf, p, len); | ||
510 | err = len; | ||
511 | |||
512 | fail_unlock: | ||
513 | orinoco_unlock(priv, &flags); | ||
514 | |||
515 | return err; | ||
516 | } | ||
517 | |||
518 | int orinoco_hw_get_freq(struct orinoco_private *priv) | ||
519 | { | ||
520 | hermes_t *hw = &priv->hw; | ||
521 | int err = 0; | ||
522 | u16 channel; | ||
523 | int freq = 0; | ||
524 | unsigned long flags; | ||
525 | |||
526 | if (orinoco_lock(priv, &flags) != 0) | ||
527 | return -EBUSY; | ||
528 | |||
529 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, | ||
530 | &channel); | ||
531 | if (err) | ||
532 | goto out; | ||
533 | |||
534 | /* Intersil firmware 1.3.5 returns 0 when the interface is down */ | ||
535 | if (channel == 0) { | ||
536 | err = -EBUSY; | ||
537 | goto out; | ||
538 | } | ||
539 | |||
540 | if ((channel < 1) || (channel > NUM_CHANNELS)) { | ||
541 | printk(KERN_WARNING "%s: Channel out of range (%d)!\n", | ||
542 | priv->ndev->name, channel); | ||
543 | err = -EBUSY; | ||
544 | goto out; | ||
545 | |||
546 | } | ||
547 | freq = ieee80211_dsss_chan_to_freq(channel); | ||
548 | |||
549 | out: | ||
550 | orinoco_unlock(priv, &flags); | ||
551 | |||
552 | if (err > 0) | ||
553 | err = -EBUSY; | ||
554 | return err ? err : freq; | ||
555 | } | ||
556 | |||
557 | int orinoco_hw_get_bitratelist(struct orinoco_private *priv, | ||
558 | int *numrates, s32 *rates, int max) | ||
559 | { | ||
560 | hermes_t *hw = &priv->hw; | ||
561 | struct hermes_idstring list; | ||
562 | unsigned char *p = (unsigned char *)&list.val; | ||
563 | int err = 0; | ||
564 | int num; | ||
565 | int i; | ||
566 | unsigned long flags; | ||
567 | |||
568 | if (orinoco_lock(priv, &flags) != 0) | ||
569 | return -EBUSY; | ||
570 | |||
571 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, | ||
572 | sizeof(list), NULL, &list); | ||
573 | orinoco_unlock(priv, &flags); | ||
574 | |||
575 | if (err) | ||
576 | return err; | ||
577 | |||
578 | num = le16_to_cpu(list.len); | ||
579 | *numrates = num; | ||
580 | num = min(num, max); | ||
581 | |||
582 | for (i = 0; i < num; i++) | ||
583 | rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ | ||
584 | |||
585 | return 0; | ||
586 | } | ||
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h new file mode 100644 index 000000000000..dc3f23a9c1c7 --- /dev/null +++ b/drivers/net/wireless/orinoco/hw.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* Encapsulate basic setting changes on Hermes hardware | ||
2 | * | ||
3 | * See copyright notice in main.c | ||
4 | */ | ||
5 | #ifndef _ORINOCO_HW_H_ | ||
6 | #define _ORINOCO_HW_H_ | ||
7 | |||
8 | #include <linux/types.h> | ||
9 | #include <linux/wireless.h> | ||
10 | |||
11 | /* Hardware BAPs */ | ||
12 | #define USER_BAP 0 | ||
13 | #define IRQ_BAP 1 | ||
14 | |||
15 | /* WEP key sizes */ | ||
16 | #define SMALL_KEY_SIZE 5 | ||
17 | #define LARGE_KEY_SIZE 13 | ||
18 | |||
19 | /* Number of supported channels */ | ||
20 | #define NUM_CHANNELS 14 | ||
21 | |||
22 | /* Forward declarations */ | ||
23 | struct orinoco_private; | ||
24 | struct dev_addr_list; | ||
25 | |||
26 | int orinoco_get_bitratemode(int bitrate, int automatic); | ||
27 | void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); | ||
28 | |||
29 | int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc); | ||
30 | int __orinoco_hw_set_bitrate(struct orinoco_private *priv); | ||
31 | int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate); | ||
32 | int __orinoco_hw_set_wap(struct orinoco_private *priv); | ||
33 | int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); | ||
34 | int __orinoco_hw_setup_enc(struct orinoco_private *priv); | ||
35 | int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, | ||
36 | u8 *key, u8 *rsc, u8 *tsc); | ||
37 | int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); | ||
38 | int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, | ||
39 | struct dev_addr_list *mc_list, | ||
40 | int mc_count, int promisc); | ||
41 | int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, | ||
42 | char buf[IW_ESSID_MAX_SIZE+1]); | ||
43 | int orinoco_hw_get_freq(struct orinoco_private *priv); | ||
44 | int orinoco_hw_get_bitratelist(struct orinoco_private *priv, | ||
45 | int *numrates, s32 *rates, int max); | ||
46 | |||
47 | #endif /* _ORINOCO_HW_H_ */ | ||
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 3e20df7b6570..a340c7d75dd1 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -91,6 +91,7 @@ | |||
91 | 91 | ||
92 | #include "hermes_rid.h" | 92 | #include "hermes_rid.h" |
93 | #include "hermes_dld.h" | 93 | #include "hermes_dld.h" |
94 | #include "hw.h" | ||
94 | #include "scan.h" | 95 | #include "scan.h" |
95 | #include "mic.h" | 96 | #include "mic.h" |
96 | #include "fw.h" | 97 | #include "fw.h" |
@@ -151,15 +152,11 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | |||
151 | #define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) | 152 | #define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) |
152 | 153 | ||
153 | #define SYMBOL_MAX_VER_LEN (14) | 154 | #define SYMBOL_MAX_VER_LEN (14) |
154 | #define USER_BAP 0 | ||
155 | #define IRQ_BAP 1 | ||
156 | #define MAX_IRQLOOPS_PER_IRQ 10 | 155 | #define MAX_IRQLOOPS_PER_IRQ 10 |
157 | #define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of | 156 | #define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of |
158 | * how many events the | 157 | * how many events the |
159 | * device could | 158 | * device could |
160 | * legitimately generate */ | 159 | * legitimately generate */ |
161 | #define SMALL_KEY_SIZE 5 | ||
162 | #define LARGE_KEY_SIZE 13 | ||
163 | #define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ | 160 | #define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ |
164 | 161 | ||
165 | #define DUMMY_FID 0xFFFF | 162 | #define DUMMY_FID 0xFFFF |
@@ -179,31 +176,6 @@ static const struct iw_handler_def orinoco_handler_def; | |||
179 | static const struct ethtool_ops orinoco_ethtool_ops; | 176 | static const struct ethtool_ops orinoco_ethtool_ops; |
180 | 177 | ||
181 | /********************************************************************/ | 178 | /********************************************************************/ |
182 | /* Data tables */ | ||
183 | /********************************************************************/ | ||
184 | |||
185 | #define NUM_CHANNELS 14 | ||
186 | |||
187 | /* This tables gives the actual meanings of the bitrate IDs returned | ||
188 | * by the firmware. */ | ||
189 | static struct { | ||
190 | int bitrate; /* in 100s of kilobits */ | ||
191 | int automatic; | ||
192 | u16 agere_txratectrl; | ||
193 | u16 intersil_txratectrl; | ||
194 | } bitrate_table[] = { | ||
195 | {110, 1, 3, 15}, /* Entry 0 is the default */ | ||
196 | {10, 0, 1, 1}, | ||
197 | {10, 1, 1, 1}, | ||
198 | {20, 0, 2, 2}, | ||
199 | {20, 1, 6, 3}, | ||
200 | {55, 0, 4, 4}, | ||
201 | {55, 1, 7, 7}, | ||
202 | {110, 0, 5, 8}, | ||
203 | }; | ||
204 | #define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) | ||
205 | |||
206 | /********************************************************************/ | ||
207 | /* Data types */ | 179 | /* Data types */ |
208 | /********************************************************************/ | 180 | /********************************************************************/ |
209 | 181 | ||
@@ -282,33 +254,6 @@ static inline void set_port_type(struct orinoco_private *priv) | |||
282 | } | 254 | } |
283 | } | 255 | } |
284 | 256 | ||
285 | static int orinoco_get_bitratemode(int bitrate, int automatic) | ||
286 | { | ||
287 | int ratemode = -1; | ||
288 | int i; | ||
289 | |||
290 | if ((bitrate != 10) && (bitrate != 20) && | ||
291 | (bitrate != 55) && (bitrate != 110)) | ||
292 | return ratemode; | ||
293 | |||
294 | for (i = 0; i < BITRATE_TABLE_SIZE; i++) { | ||
295 | if ((bitrate_table[i].bitrate == bitrate) && | ||
296 | (bitrate_table[i].automatic == automatic)) { | ||
297 | ratemode = i; | ||
298 | break; | ||
299 | } | ||
300 | } | ||
301 | return ratemode; | ||
302 | } | ||
303 | |||
304 | static void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) | ||
305 | { | ||
306 | BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); | ||
307 | |||
308 | *bitrate = bitrate_table[ratemode].bitrate * 100000; | ||
309 | *automatic = bitrate_table[ratemode].automatic; | ||
310 | } | ||
311 | |||
312 | static inline u8 *orinoco_get_ie(u8 *data, size_t len, | 257 | static inline u8 *orinoco_get_ie(u8 *data, size_t len, |
313 | enum ieee80211_eid eid) | 258 | enum ieee80211_eid eid) |
314 | { | 259 | { |
@@ -933,25 +878,6 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, | |||
933 | stats->rx_dropped++; | 878 | stats->rx_dropped++; |
934 | } | 879 | } |
935 | 880 | ||
936 | /* Get tsc from the firmware */ | ||
937 | static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, | ||
938 | u8 *tsc) | ||
939 | { | ||
940 | hermes_t *hw = &priv->hw; | ||
941 | int err = 0; | ||
942 | u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; | ||
943 | |||
944 | if ((key < 0) || (key > 4)) | ||
945 | return -EINVAL; | ||
946 | |||
947 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, | ||
948 | sizeof(tsc_arr), NULL, &tsc_arr); | ||
949 | if (!err) | ||
950 | memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); | ||
951 | |||
952 | return err; | ||
953 | } | ||
954 | |||
955 | static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | 881 | static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) |
956 | { | 882 | { |
957 | struct orinoco_private *priv = netdev_priv(dev); | 883 | struct orinoco_private *priv = netdev_priv(dev); |
@@ -1790,334 +1716,6 @@ int orinoco_reinit_firmware(struct net_device *dev) | |||
1790 | } | 1716 | } |
1791 | EXPORT_SYMBOL(orinoco_reinit_firmware); | 1717 | EXPORT_SYMBOL(orinoco_reinit_firmware); |
1792 | 1718 | ||
1793 | static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) | ||
1794 | { | ||
1795 | hermes_t *hw = &priv->hw; | ||
1796 | int ratemode = priv->bitratemode; | ||
1797 | int err = 0; | ||
1798 | |||
1799 | if (ratemode >= BITRATE_TABLE_SIZE) { | ||
1800 | printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", | ||
1801 | priv->ndev->name, ratemode); | ||
1802 | return -EINVAL; | ||
1803 | } | ||
1804 | |||
1805 | switch (priv->firmware_type) { | ||
1806 | case FIRMWARE_TYPE_AGERE: | ||
1807 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1808 | HERMES_RID_CNFTXRATECONTROL, | ||
1809 | bitrate_table[ratemode].agere_txratectrl); | ||
1810 | break; | ||
1811 | case FIRMWARE_TYPE_INTERSIL: | ||
1812 | case FIRMWARE_TYPE_SYMBOL: | ||
1813 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1814 | HERMES_RID_CNFTXRATECONTROL, | ||
1815 | bitrate_table[ratemode].intersil_txratectrl); | ||
1816 | break; | ||
1817 | default: | ||
1818 | BUG(); | ||
1819 | } | ||
1820 | |||
1821 | return err; | ||
1822 | } | ||
1823 | |||
1824 | static int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, | ||
1825 | int *bitrate) | ||
1826 | { | ||
1827 | hermes_t *hw = &priv->hw; | ||
1828 | int i; | ||
1829 | int err = 0; | ||
1830 | u16 val; | ||
1831 | |||
1832 | err = hermes_read_wordrec(hw, USER_BAP, | ||
1833 | HERMES_RID_CURRENTTXRATE, &val); | ||
1834 | if (err) | ||
1835 | return err; | ||
1836 | |||
1837 | switch (priv->firmware_type) { | ||
1838 | case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ | ||
1839 | /* Note : in Lucent firmware, the return value of | ||
1840 | * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, | ||
1841 | * and therefore is totally different from the | ||
1842 | * encoding of HERMES_RID_CNFTXRATECONTROL. | ||
1843 | * Don't forget that 6Mb/s is really 5.5Mb/s */ | ||
1844 | if (val == 6) | ||
1845 | *bitrate = 5500000; | ||
1846 | else | ||
1847 | *bitrate = val * 1000000; | ||
1848 | break; | ||
1849 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ | ||
1850 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ | ||
1851 | for (i = 0; i < BITRATE_TABLE_SIZE; i++) | ||
1852 | if (bitrate_table[i].intersil_txratectrl == val) | ||
1853 | break; | ||
1854 | |||
1855 | if (i >= BITRATE_TABLE_SIZE) | ||
1856 | printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", | ||
1857 | priv->ndev->name, val); | ||
1858 | |||
1859 | *bitrate = bitrate_table[i].bitrate * 100000; | ||
1860 | break; | ||
1861 | default: | ||
1862 | BUG(); | ||
1863 | } | ||
1864 | |||
1865 | return err; | ||
1866 | } | ||
1867 | |||
1868 | /* Set fixed AP address */ | ||
1869 | static int __orinoco_hw_set_wap(struct orinoco_private *priv) | ||
1870 | { | ||
1871 | int roaming_flag; | ||
1872 | int err = 0; | ||
1873 | hermes_t *hw = &priv->hw; | ||
1874 | |||
1875 | switch (priv->firmware_type) { | ||
1876 | case FIRMWARE_TYPE_AGERE: | ||
1877 | /* not supported */ | ||
1878 | break; | ||
1879 | case FIRMWARE_TYPE_INTERSIL: | ||
1880 | if (priv->bssid_fixed) | ||
1881 | roaming_flag = 2; | ||
1882 | else | ||
1883 | roaming_flag = 1; | ||
1884 | |||
1885 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1886 | HERMES_RID_CNFROAMINGMODE, | ||
1887 | roaming_flag); | ||
1888 | break; | ||
1889 | case FIRMWARE_TYPE_SYMBOL: | ||
1890 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1891 | HERMES_RID_CNFMANDATORYBSSID_SYMBOL, | ||
1892 | &priv->desired_bssid); | ||
1893 | break; | ||
1894 | } | ||
1895 | return err; | ||
1896 | } | ||
1897 | |||
1898 | /* Change the WEP keys and/or the current keys. Can be called | ||
1899 | * either from __orinoco_hw_setup_enc() or directly from | ||
1900 | * orinoco_ioctl_setiwencode(). In the later case the association | ||
1901 | * with the AP is not broken (if the firmware can handle it), | ||
1902 | * which is needed for 802.1x implementations. */ | ||
1903 | static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) | ||
1904 | { | ||
1905 | hermes_t *hw = &priv->hw; | ||
1906 | int err = 0; | ||
1907 | |||
1908 | switch (priv->firmware_type) { | ||
1909 | case FIRMWARE_TYPE_AGERE: | ||
1910 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1911 | HERMES_RID_CNFWEPKEYS_AGERE, | ||
1912 | &priv->keys); | ||
1913 | if (err) | ||
1914 | return err; | ||
1915 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1916 | HERMES_RID_CNFTXKEY_AGERE, | ||
1917 | priv->tx_key); | ||
1918 | if (err) | ||
1919 | return err; | ||
1920 | break; | ||
1921 | case FIRMWARE_TYPE_INTERSIL: | ||
1922 | case FIRMWARE_TYPE_SYMBOL: | ||
1923 | { | ||
1924 | int keylen; | ||
1925 | int i; | ||
1926 | |||
1927 | /* Force uniform key length to work around | ||
1928 | * firmware bugs */ | ||
1929 | keylen = le16_to_cpu(priv->keys[priv->tx_key].len); | ||
1930 | |||
1931 | if (keylen > LARGE_KEY_SIZE) { | ||
1932 | printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", | ||
1933 | priv->ndev->name, priv->tx_key, keylen); | ||
1934 | return -E2BIG; | ||
1935 | } | ||
1936 | |||
1937 | /* Write all 4 keys */ | ||
1938 | for (i = 0; i < ORINOCO_MAX_KEYS; i++) { | ||
1939 | err = hermes_write_ltv(hw, USER_BAP, | ||
1940 | HERMES_RID_CNFDEFAULTKEY0 + i, | ||
1941 | HERMES_BYTES_TO_RECLEN(keylen), | ||
1942 | priv->keys[i].data); | ||
1943 | if (err) | ||
1944 | return err; | ||
1945 | } | ||
1946 | |||
1947 | /* Write the index of the key used in transmission */ | ||
1948 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1949 | HERMES_RID_CNFWEPDEFAULTKEYID, | ||
1950 | priv->tx_key); | ||
1951 | if (err) | ||
1952 | return err; | ||
1953 | } | ||
1954 | break; | ||
1955 | } | ||
1956 | |||
1957 | return 0; | ||
1958 | } | ||
1959 | |||
1960 | static int __orinoco_hw_setup_enc(struct orinoco_private *priv) | ||
1961 | { | ||
1962 | hermes_t *hw = &priv->hw; | ||
1963 | int err = 0; | ||
1964 | int master_wep_flag; | ||
1965 | int auth_flag; | ||
1966 | int enc_flag; | ||
1967 | |||
1968 | /* Setup WEP keys for WEP and WPA */ | ||
1969 | if (priv->encode_alg) | ||
1970 | __orinoco_hw_setup_wepkeys(priv); | ||
1971 | |||
1972 | if (priv->wep_restrict) | ||
1973 | auth_flag = HERMES_AUTH_SHARED_KEY; | ||
1974 | else | ||
1975 | auth_flag = HERMES_AUTH_OPEN; | ||
1976 | |||
1977 | if (priv->wpa_enabled) | ||
1978 | enc_flag = 2; | ||
1979 | else if (priv->encode_alg == IW_ENCODE_ALG_WEP) | ||
1980 | enc_flag = 1; | ||
1981 | else | ||
1982 | enc_flag = 0; | ||
1983 | |||
1984 | switch (priv->firmware_type) { | ||
1985 | case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ | ||
1986 | if (priv->encode_alg == IW_ENCODE_ALG_WEP) { | ||
1987 | /* Enable the shared-key authentication. */ | ||
1988 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1989 | HERMES_RID_CNFAUTHENTICATION_AGERE, | ||
1990 | auth_flag); | ||
1991 | } | ||
1992 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1993 | HERMES_RID_CNFWEPENABLED_AGERE, | ||
1994 | enc_flag); | ||
1995 | if (err) | ||
1996 | return err; | ||
1997 | |||
1998 | if (priv->has_wpa) { | ||
1999 | /* Set WPA key management */ | ||
2000 | err = hermes_write_wordrec(hw, USER_BAP, | ||
2001 | HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, | ||
2002 | priv->key_mgmt); | ||
2003 | if (err) | ||
2004 | return err; | ||
2005 | } | ||
2006 | |||
2007 | break; | ||
2008 | |||
2009 | case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ | ||
2010 | case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ | ||
2011 | if (priv->encode_alg == IW_ENCODE_ALG_WEP) { | ||
2012 | if (priv->wep_restrict || | ||
2013 | (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) | ||
2014 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | | ||
2015 | HERMES_WEP_EXCL_UNENCRYPTED; | ||
2016 | else | ||
2017 | master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; | ||
2018 | |||
2019 | err = hermes_write_wordrec(hw, USER_BAP, | ||
2020 | HERMES_RID_CNFAUTHENTICATION, | ||
2021 | auth_flag); | ||
2022 | if (err) | ||
2023 | return err; | ||
2024 | } else | ||
2025 | master_wep_flag = 0; | ||
2026 | |||
2027 | if (priv->iw_mode == IW_MODE_MONITOR) | ||
2028 | master_wep_flag |= HERMES_WEP_HOST_DECRYPT; | ||
2029 | |||
2030 | /* Master WEP setting : on/off */ | ||
2031 | err = hermes_write_wordrec(hw, USER_BAP, | ||
2032 | HERMES_RID_CNFWEPFLAGS_INTERSIL, | ||
2033 | master_wep_flag); | ||
2034 | if (err) | ||
2035 | return err; | ||
2036 | |||
2037 | break; | ||
2038 | } | ||
2039 | |||
2040 | return 0; | ||
2041 | } | ||
2042 | |||
2043 | /* key must be 32 bytes, including the tx and rx MIC keys. | ||
2044 | * rsc must be 8 bytes | ||
2045 | * tsc must be 8 bytes or NULL | ||
2046 | */ | ||
2047 | static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, | ||
2048 | u8 *key, u8 *rsc, u8 *tsc) | ||
2049 | { | ||
2050 | struct { | ||
2051 | __le16 idx; | ||
2052 | u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; | ||
2053 | u8 key[TKIP_KEYLEN]; | ||
2054 | u8 tx_mic[MIC_KEYLEN]; | ||
2055 | u8 rx_mic[MIC_KEYLEN]; | ||
2056 | u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; | ||
2057 | } __attribute__ ((packed)) buf; | ||
2058 | int ret; | ||
2059 | int err; | ||
2060 | int k; | ||
2061 | u16 xmitting; | ||
2062 | |||
2063 | key_idx &= 0x3; | ||
2064 | |||
2065 | if (set_tx) | ||
2066 | key_idx |= 0x8000; | ||
2067 | |||
2068 | buf.idx = cpu_to_le16(key_idx); | ||
2069 | memcpy(buf.key, key, | ||
2070 | sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); | ||
2071 | |||
2072 | if (rsc == NULL) | ||
2073 | memset(buf.rsc, 0, sizeof(buf.rsc)); | ||
2074 | else | ||
2075 | memcpy(buf.rsc, rsc, sizeof(buf.rsc)); | ||
2076 | |||
2077 | if (tsc == NULL) { | ||
2078 | memset(buf.tsc, 0, sizeof(buf.tsc)); | ||
2079 | buf.tsc[4] = 0x10; | ||
2080 | } else { | ||
2081 | memcpy(buf.tsc, tsc, sizeof(buf.tsc)); | ||
2082 | } | ||
2083 | |||
2084 | /* Wait upto 100ms for tx queue to empty */ | ||
2085 | k = 100; | ||
2086 | do { | ||
2087 | k--; | ||
2088 | udelay(1000); | ||
2089 | ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, | ||
2090 | &xmitting); | ||
2091 | if (ret) | ||
2092 | break; | ||
2093 | } while ((k > 0) && xmitting); | ||
2094 | |||
2095 | if (k == 0) | ||
2096 | ret = -ETIMEDOUT; | ||
2097 | |||
2098 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
2099 | HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, | ||
2100 | &buf); | ||
2101 | |||
2102 | return ret ? ret : err; | ||
2103 | } | ||
2104 | |||
2105 | static int orinoco_clear_tkip_key(struct orinoco_private *priv, | ||
2106 | int key_idx) | ||
2107 | { | ||
2108 | hermes_t *hw = &priv->hw; | ||
2109 | int err; | ||
2110 | |||
2111 | memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); | ||
2112 | err = hermes_write_wordrec(hw, USER_BAP, | ||
2113 | HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, | ||
2114 | key_idx); | ||
2115 | if (err) | ||
2116 | printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", | ||
2117 | priv->ndev->name, err, key_idx); | ||
2118 | return err; | ||
2119 | } | ||
2120 | |||
2121 | static int __orinoco_program_rids(struct net_device *dev) | 1719 | static int __orinoco_program_rids(struct net_device *dev) |
2122 | { | 1720 | { |
2123 | struct orinoco_private *priv = netdev_priv(dev); | 1721 | struct orinoco_private *priv = netdev_priv(dev); |
@@ -2347,59 +1945,6 @@ static int __orinoco_program_rids(struct net_device *dev) | |||
2347 | return 0; | 1945 | return 0; |
2348 | } | 1946 | } |
2349 | 1947 | ||
2350 | static int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, | ||
2351 | struct dev_addr_list *mc_list, | ||
2352 | int mc_count, int promisc) | ||
2353 | { | ||
2354 | hermes_t *hw = &priv->hw; | ||
2355 | int err = 0; | ||
2356 | |||
2357 | if (promisc != priv->promiscuous) { | ||
2358 | err = hermes_write_wordrec(hw, USER_BAP, | ||
2359 | HERMES_RID_CNFPROMISCUOUSMODE, | ||
2360 | promisc); | ||
2361 | if (err) { | ||
2362 | printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", | ||
2363 | priv->ndev->name, err); | ||
2364 | } else | ||
2365 | priv->promiscuous = promisc; | ||
2366 | } | ||
2367 | |||
2368 | /* If we're not in promiscuous mode, then we need to set the | ||
2369 | * group address if either we want to multicast, or if we were | ||
2370 | * multicasting and want to stop */ | ||
2371 | if (!promisc && (mc_count || priv->mc_count)) { | ||
2372 | struct dev_mc_list *p = mc_list; | ||
2373 | struct hermes_multicast mclist; | ||
2374 | int i; | ||
2375 | |||
2376 | for (i = 0; i < mc_count; i++) { | ||
2377 | /* paranoia: is list shorter than mc_count? */ | ||
2378 | BUG_ON(!p); | ||
2379 | /* paranoia: bad address size in list? */ | ||
2380 | BUG_ON(p->dmi_addrlen != ETH_ALEN); | ||
2381 | |||
2382 | memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); | ||
2383 | p = p->next; | ||
2384 | } | ||
2385 | |||
2386 | if (p) | ||
2387 | printk(KERN_WARNING "%s: Multicast list is " | ||
2388 | "longer than mc_count\n", priv->ndev->name); | ||
2389 | |||
2390 | err = hermes_write_ltv(hw, USER_BAP, | ||
2391 | HERMES_RID_CNFGROUPADDRESSES, | ||
2392 | HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), | ||
2393 | &mclist); | ||
2394 | if (err) | ||
2395 | printk(KERN_ERR "%s: Error %d setting multicast list.\n", | ||
2396 | priv->ndev->name, err); | ||
2397 | else | ||
2398 | priv->mc_count = mc_count; | ||
2399 | } | ||
2400 | return err; | ||
2401 | } | ||
2402 | |||
2403 | /* FIXME: return int? */ | 1948 | /* FIXME: return int? */ |
2404 | static void | 1949 | static void |
2405 | __orinoco_set_multicast_list(struct net_device *dev) | 1950 | __orinoco_set_multicast_list(struct net_device *dev) |
@@ -3170,132 +2715,6 @@ EXPORT_SYMBOL(free_orinocodev); | |||
3170 | /* Wireless extensions */ | 2715 | /* Wireless extensions */ |
3171 | /********************************************************************/ | 2716 | /********************************************************************/ |
3172 | 2717 | ||
3173 | /* Return : < 0 -> error code ; >= 0 -> length */ | ||
3174 | static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, | ||
3175 | char buf[IW_ESSID_MAX_SIZE+1]) | ||
3176 | { | ||
3177 | hermes_t *hw = &priv->hw; | ||
3178 | int err = 0; | ||
3179 | struct hermes_idstring essidbuf; | ||
3180 | char *p = (char *)(&essidbuf.val); | ||
3181 | int len; | ||
3182 | unsigned long flags; | ||
3183 | |||
3184 | if (orinoco_lock(priv, &flags) != 0) | ||
3185 | return -EBUSY; | ||
3186 | |||
3187 | if (strlen(priv->desired_essid) > 0) { | ||
3188 | /* We read the desired SSID from the hardware rather | ||
3189 | than from priv->desired_essid, just in case the | ||
3190 | firmware is allowed to change it on us. I'm not | ||
3191 | sure about this */ | ||
3192 | /* My guess is that the OWNSSID should always be whatever | ||
3193 | * we set to the card, whereas CURRENT_SSID is the one that | ||
3194 | * may change... - Jean II */ | ||
3195 | u16 rid; | ||
3196 | |||
3197 | *active = 1; | ||
3198 | |||
3199 | rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : | ||
3200 | HERMES_RID_CNFDESIREDSSID; | ||
3201 | |||
3202 | err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), | ||
3203 | NULL, &essidbuf); | ||
3204 | if (err) | ||
3205 | goto fail_unlock; | ||
3206 | } else { | ||
3207 | *active = 0; | ||
3208 | |||
3209 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, | ||
3210 | sizeof(essidbuf), NULL, &essidbuf); | ||
3211 | if (err) | ||
3212 | goto fail_unlock; | ||
3213 | } | ||
3214 | |||
3215 | len = le16_to_cpu(essidbuf.len); | ||
3216 | BUG_ON(len > IW_ESSID_MAX_SIZE); | ||
3217 | |||
3218 | memset(buf, 0, IW_ESSID_MAX_SIZE); | ||
3219 | memcpy(buf, p, len); | ||
3220 | err = len; | ||
3221 | |||
3222 | fail_unlock: | ||
3223 | orinoco_unlock(priv, &flags); | ||
3224 | |||
3225 | return err; | ||
3226 | } | ||
3227 | |||
3228 | static int orinoco_hw_get_freq(struct orinoco_private *priv) | ||
3229 | { | ||
3230 | |||
3231 | hermes_t *hw = &priv->hw; | ||
3232 | int err = 0; | ||
3233 | u16 channel; | ||
3234 | int freq = 0; | ||
3235 | unsigned long flags; | ||
3236 | |||
3237 | if (orinoco_lock(priv, &flags) != 0) | ||
3238 | return -EBUSY; | ||
3239 | |||
3240 | err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, | ||
3241 | &channel); | ||
3242 | if (err) | ||
3243 | goto out; | ||
3244 | |||
3245 | /* Intersil firmware 1.3.5 returns 0 when the interface is down */ | ||
3246 | if (channel == 0) { | ||
3247 | err = -EBUSY; | ||
3248 | goto out; | ||
3249 | } | ||
3250 | |||
3251 | if ((channel < 1) || (channel > NUM_CHANNELS)) { | ||
3252 | printk(KERN_WARNING "%s: Channel out of range (%d)!\n", | ||
3253 | priv->ndev->name, channel); | ||
3254 | err = -EBUSY; | ||
3255 | goto out; | ||
3256 | |||
3257 | } | ||
3258 | freq = ieee80211_dsss_chan_to_freq(channel); | ||
3259 | |||
3260 | out: | ||
3261 | orinoco_unlock(priv, &flags); | ||
3262 | |||
3263 | if (err > 0) | ||
3264 | err = -EBUSY; | ||
3265 | return err ? err : freq; | ||
3266 | } | ||
3267 | |||
3268 | static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, | ||
3269 | int *numrates, s32 *rates, int max) | ||
3270 | { | ||
3271 | hermes_t *hw = &priv->hw; | ||
3272 | struct hermes_idstring list; | ||
3273 | unsigned char *p = (unsigned char *)&list.val; | ||
3274 | int err = 0; | ||
3275 | int num; | ||
3276 | int i; | ||
3277 | unsigned long flags; | ||
3278 | |||
3279 | if (orinoco_lock(priv, &flags) != 0) | ||
3280 | return -EBUSY; | ||
3281 | |||
3282 | err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, | ||
3283 | sizeof(list), NULL, &list); | ||
3284 | orinoco_unlock(priv, &flags); | ||
3285 | |||
3286 | if (err) | ||
3287 | return err; | ||
3288 | |||
3289 | num = le16_to_cpu(list.len); | ||
3290 | *numrates = num; | ||
3291 | num = min(num, max); | ||
3292 | |||
3293 | for (i = 0; i < num; i++) | ||
3294 | rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ | ||
3295 | |||
3296 | return 0; | ||
3297 | } | ||
3298 | |||
3299 | static int orinoco_ioctl_getname(struct net_device *dev, | 2718 | static int orinoco_ioctl_getname(struct net_device *dev, |
3300 | struct iw_request_info *info, | 2719 | struct iw_request_info *info, |
3301 | char *name, | 2720 | char *name, |