aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Kilroy <kilroyd@gmail.com>2008-08-21 18:28:02 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-22 19:28:06 -0400
commitd03032af511c56d3c1580fa4f54f6285f650e638 (patch)
treecf1820c9199769851d584d502d3c0f941d693751
parent409644a98bfffef79985f2c39924a06288b1dfcf (diff)
orinoco: Add WE-18 ioctls for WPA
Includes basic plumbing to get the data into firmware, and retrieve it. SIOCxIWGENIE simply record (and return) the IE, and do not act on it. SIOCxIWENCODEEXT, SIOCxIWAUTH and SIOCSIWMLME should be as functional as the driver will support. Signed-off-by: David Kilroy <kilroyd@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/hermes_rid.h16
-rw-r--r--drivers/net/wireless/orinoco.c526
-rw-r--r--drivers/net/wireless/orinoco.h20
3 files changed, 554 insertions, 8 deletions
diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h
index bcd9c82fe93a..42eb67dea1df 100644
--- a/drivers/net/wireless/hermes_rid.h
+++ b/drivers/net/wireless/hermes_rid.h
@@ -30,6 +30,7 @@
30#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 30#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20
31#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 31#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21
32#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 32#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21
33#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22
33#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 34#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23
34#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 35#define HERMES_RID_CNFDEFAULTKEY0 0xFC24
35#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 36#define HERMES_RID_CNFDEFAULTKEY1 0xFC25
@@ -85,7 +86,16 @@
85#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 86#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2
86#define HERMES_RID_CNFBASICRATES 0xFCB3 87#define HERMES_RID_CNFBASICRATES 0xFCB3
87#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 88#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4
89#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4
90#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5
91#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6
92#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7
93#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8
94#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9
95#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA
96#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB
88#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 97#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2
98#define HERMES_RID_CNFDISASSOCIATE 0xFCC8
89#define HERMES_RID_CNFTICKTIME 0xFCE0 99#define HERMES_RID_CNFTICKTIME 0xFCE0
90#define HERMES_RID_CNFSCANREQUEST 0xFCE1 100#define HERMES_RID_CNFSCANREQUEST 0xFCE1
91#define HERMES_RID_CNFJOINREQUEST 0xFCE2 101#define HERMES_RID_CNFJOINREQUEST 0xFCE2
@@ -138,6 +148,12 @@
138#define HERMES_RID_CURRENTTXRATE6 0xFD85 148#define HERMES_RID_CURRENTTXRATE6 0xFD85
139#define HERMES_RID_OWNMACADDR 0xFD86 149#define HERMES_RID_OWNMACADDR 0xFD86
140#define HERMES_RID_SCANRESULTSTABLE 0xFD88 150#define HERMES_RID_SCANRESULTSTABLE 0xFD88
151#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89
152#define HERMES_RID_CURRENT_WPA_IE 0xFD8A
153#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B
154#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C
155#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D
156#define HERMES_RID_TXQUEUEEMPTY 0xFD91
141#define HERMES_RID_PHYTYPE 0xFDC0 157#define HERMES_RID_PHYTYPE 0xFDC0
142#define HERMES_RID_CURRENTCHANNEL 0xFDC1 158#define HERMES_RID_CURRENTCHANNEL 0xFDC1
143#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 159#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index e91e240b637e..36b1dc2db893 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -79,6 +79,7 @@
79#include <linux/module.h> 79#include <linux/module.h>
80#include <linux/kernel.h> 80#include <linux/kernel.h>
81#include <linux/init.h> 81#include <linux/init.h>
82#include <linux/delay.h>
82#include <linux/netdevice.h> 83#include <linux/netdevice.h>
83#include <linux/etherdevice.h> 84#include <linux/etherdevice.h>
84#include <linux/ethtool.h> 85#include <linux/ethtool.h>
@@ -2038,7 +2039,7 @@ static int __orinoco_hw_set_wap(struct orinoco_private *priv)
2038} 2039}
2039 2040
2040/* Change the WEP keys and/or the current keys. Can be called 2041/* Change the WEP keys and/or the current keys. Can be called
2041 * either from __orinoco_hw_setup_wep() or directly from 2042 * either from __orinoco_hw_setup_enc() or directly from
2042 * orinoco_ioctl_setiwencode(). In the later case the association 2043 * orinoco_ioctl_setiwencode(). In the later case the association
2043 * with the AP is not broken (if the firmware can handle it), 2044 * with the AP is not broken (if the firmware can handle it),
2044 * which is needed for 802.1x implementations. */ 2045 * which is needed for 802.1x implementations. */
@@ -2098,7 +2099,7 @@ static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
2098 return 0; 2099 return 0;
2099} 2100}
2100 2101
2101static int __orinoco_hw_setup_wep(struct orinoco_private *priv) 2102static int __orinoco_hw_setup_enc(struct orinoco_private *priv)
2102{ 2103{
2103 hermes_t *hw = &priv->hw; 2104 hermes_t *hw = &priv->hw;
2104 int err = 0; 2105 int err = 0;
@@ -2106,7 +2107,8 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
2106 int auth_flag; 2107 int auth_flag;
2107 int enc_flag; 2108 int enc_flag;
2108 2109
2109 if (priv->encode_alg == IW_ENCODE_ALG_WEP) 2110 /* Setup WEP keys for WEP and WPA */
2111 if (priv->encode_alg)
2110 __orinoco_hw_setup_wepkeys(priv); 2112 __orinoco_hw_setup_wepkeys(priv);
2111 2113
2112 if (priv->wep_restrict) 2114 if (priv->wep_restrict)
@@ -2114,7 +2116,9 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
2114 else 2116 else
2115 auth_flag = HERMES_AUTH_OPEN; 2117 auth_flag = HERMES_AUTH_OPEN;
2116 2118
2117 if (priv->encode_alg == IW_ENCODE_ALG_WEP) 2119 if (priv->wpa_enabled)
2120 enc_flag = 2;
2121 else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
2118 enc_flag = 1; 2122 enc_flag = 1;
2119 else 2123 else
2120 enc_flag = 0; 2124 enc_flag = 0;
@@ -2132,6 +2136,16 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
2132 enc_flag); 2136 enc_flag);
2133 if (err) 2137 if (err)
2134 return err; 2138 return err;
2139
2140 if (priv->has_wpa) {
2141 /* Set WPA key management */
2142 err = hermes_write_wordrec(hw, USER_BAP,
2143 HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
2144 priv->key_mgmt);
2145 if (err)
2146 return err;
2147 }
2148
2135 break; 2149 break;
2136 2150
2137 case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ 2151 case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
@@ -2168,6 +2182,84 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
2168 return 0; 2182 return 0;
2169} 2183}
2170 2184
2185/* key must be 32 bytes, including the tx and rx MIC keys.
2186 * rsc must be 8 bytes
2187 * tsc must be 8 bytes or NULL
2188 */
2189static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
2190 u8 *key, u8 *rsc, u8 *tsc)
2191{
2192 struct {
2193 __le16 idx;
2194 u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
2195 u8 key[TKIP_KEYLEN];
2196 u8 tx_mic[MIC_KEYLEN];
2197 u8 rx_mic[MIC_KEYLEN];
2198 u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
2199 } __attribute__ ((packed)) buf;
2200 int ret;
2201 int err;
2202 int k;
2203 u16 xmitting;
2204
2205 key_idx &= 0x3;
2206
2207 if (set_tx)
2208 key_idx |= 0x8000;
2209
2210 buf.idx = cpu_to_le16(key_idx);
2211 memcpy(buf.key, key,
2212 sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
2213
2214 if (rsc == NULL)
2215 memset(buf.rsc, 0, sizeof(buf.rsc));
2216 else
2217 memcpy(buf.rsc, rsc, sizeof(buf.rsc));
2218
2219 if (tsc == NULL) {
2220 memset(buf.tsc, 0, sizeof(buf.tsc));
2221 buf.tsc[4] = 0x10;
2222 } else {
2223 memcpy(buf.tsc, tsc, sizeof(buf.tsc));
2224 }
2225
2226 /* Wait upto 100ms for tx queue to empty */
2227 k = 100;
2228 do {
2229 k--;
2230 udelay(1000);
2231 ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
2232 &xmitting);
2233 if (ret)
2234 break;
2235 } while ((k > 0) && xmitting);
2236
2237 if (k == 0)
2238 ret = -ETIMEDOUT;
2239
2240 err = HERMES_WRITE_RECORD(hw, USER_BAP,
2241 HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
2242 &buf);
2243
2244 return ret ? ret : err;
2245}
2246
2247static int orinoco_clear_tkip_key(struct orinoco_private *priv,
2248 int key_idx)
2249{
2250 hermes_t *hw = &priv->hw;
2251 int err;
2252
2253 memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
2254 err = hermes_write_wordrec(hw, USER_BAP,
2255 HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
2256 key_idx);
2257 if (err)
2258 printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
2259 priv->ndev->name, err, key_idx);
2260 return err;
2261}
2262
2171static int __orinoco_program_rids(struct net_device *dev) 2263static int __orinoco_program_rids(struct net_device *dev)
2172{ 2264{
2173 struct orinoco_private *priv = netdev_priv(dev); 2265 struct orinoco_private *priv = netdev_priv(dev);
@@ -2364,10 +2456,10 @@ static int __orinoco_program_rids(struct net_device *dev)
2364 } 2456 }
2365 2457
2366 /* Set up encryption */ 2458 /* Set up encryption */
2367 if (priv->has_wep) { 2459 if (priv->has_wep || priv->has_wpa) {
2368 err = __orinoco_hw_setup_wep(priv); 2460 err = __orinoco_hw_setup_enc(priv);
2369 if (err) { 2461 if (err) {
2370 printk(KERN_ERR "%s: Error %d activating WEP\n", 2462 printk(KERN_ERR "%s: Error %d activating encryption\n",
2371 dev->name, err); 2463 dev->name, err);
2372 return err; 2464 return err;
2373 } 2465 }
@@ -2720,6 +2812,7 @@ static int determine_firmware(struct net_device *dev)
2720 priv->has_big_wep = 0; 2812 priv->has_big_wep = 0;
2721 priv->has_alt_txcntl = 0; 2813 priv->has_alt_txcntl = 0;
2722 priv->has_ext_scan = 0; 2814 priv->has_ext_scan = 0;
2815 priv->has_wpa = 0;
2723 priv->do_fw_download = 0; 2816 priv->do_fw_download = 0;
2724 2817
2725 /* Determine capabilities from the firmware version */ 2818 /* Determine capabilities from the firmware version */
@@ -2744,6 +2837,7 @@ static int determine_firmware(struct net_device *dev)
2744 priv->broken_monitor = (firmver >= 0x80000); 2837 priv->broken_monitor = (firmver >= 0x80000);
2745 priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ 2838 priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
2746 priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ 2839 priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
2840 priv->has_wpa = (firmver >= 0x9002a);
2747 /* Tested with Agere firmware : 2841 /* Tested with Agere firmware :
2748 * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II 2842 * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
2749 * Tested CableTron firmware : 4.32 => Anton */ 2843 * Tested CableTron firmware : 4.32 => Anton */
@@ -2897,6 +2991,8 @@ static int orinoco_init(struct net_device *dev)
2897 else 2991 else
2898 printk("40-bit key\n"); 2992 printk("40-bit key\n");
2899 } 2993 }
2994 if (priv->has_wpa)
2995 printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
2900 2996
2901 /* Now we have the firmware capabilities, allocate appropiate 2997 /* Now we have the firmware capabilities, allocate appropiate
2902 * sized scan buffers */ 2998 * sized scan buffers */
@@ -3020,6 +3116,11 @@ static int orinoco_init(struct net_device *dev)
3020 priv->promiscuous = 0; 3116 priv->promiscuous = 0;
3021 priv->encode_alg = IW_ENCODE_ALG_NONE; 3117 priv->encode_alg = IW_ENCODE_ALG_NONE;
3022 priv->tx_key = 0; 3118 priv->tx_key = 0;
3119 priv->wpa_enabled = 0;
3120 priv->tkip_cm_active = 0;
3121 priv->key_mgmt = 0;
3122 priv->wpa_ie_len = 0;
3123 priv->wpa_ie = NULL;
3023 3124
3024 /* Make the hardware available, as long as it hasn't been 3125 /* Make the hardware available, as long as it hasn't been
3025 * removed elsewhere (e.g. by PCMCIA hot unplug) */ 3126 * removed elsewhere (e.g. by PCMCIA hot unplug) */
@@ -3095,6 +3196,8 @@ void free_orinocodev(struct net_device *dev)
3095{ 3196{
3096 struct orinoco_private *priv = netdev_priv(dev); 3197 struct orinoco_private *priv = netdev_priv(dev);
3097 3198
3199 priv->wpa_ie_len = 0;
3200 kfree(priv->wpa_ie);
3098 orinoco_bss_data_free(priv); 3201 orinoco_bss_data_free(priv);
3099 free_netdev(dev); 3202 free_netdev(dev);
3100} 3203}
@@ -3406,7 +3509,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
3406 memset(range, 0, sizeof(struct iw_range)); 3509 memset(range, 0, sizeof(struct iw_range));
3407 3510
3408 range->we_version_compiled = WIRELESS_EXT; 3511 range->we_version_compiled = WIRELESS_EXT;
3409 range->we_version_source = 14; 3512 range->we_version_source = 22;
3410 3513
3411 /* Set available channels/frequencies */ 3514 /* Set available channels/frequencies */
3412 range->num_channels = NUM_CHANNELS; 3515 range->num_channels = NUM_CHANNELS;
@@ -3436,6 +3539,9 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
3436 } 3539 }
3437 } 3540 }
3438 3541
3542 if (priv->has_wpa)
3543 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
3544
3439 if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ 3545 if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){
3440 /* Quality stats meaningless in ad-hoc mode */ 3546 /* Quality stats meaningless in ad-hoc mode */
3441 } else { 3547 } else {
@@ -3528,6 +3634,10 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
3528 if (orinoco_lock(priv, &flags) != 0) 3634 if (orinoco_lock(priv, &flags) != 0)
3529 return -EBUSY; 3635 return -EBUSY;
3530 3636
3637 /* Clear any TKIP key we have */
3638 if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP))
3639 (void) orinoco_clear_tkip_key(priv, setindex);
3640
3531 if (erq->length > 0) { 3641 if (erq->length > 0) {
3532 if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) 3642 if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
3533 index = priv->tx_key; 3643 index = priv->tx_key;
@@ -4192,6 +4302,399 @@ static int orinoco_ioctl_getpower(struct net_device *dev,
4192 return err; 4302 return err;
4193} 4303}
4194 4304
4305static int orinoco_ioctl_set_encodeext(struct net_device *dev,
4306 struct iw_request_info *info,
4307 union iwreq_data *wrqu,
4308 char *extra)
4309{
4310 struct orinoco_private *priv = netdev_priv(dev);
4311 struct iw_point *encoding = &wrqu->encoding;
4312 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
4313 int idx, alg = ext->alg, set_key = 1;
4314 unsigned long flags;
4315 int err = -EINVAL;
4316 u16 key_len;
4317
4318 if (orinoco_lock(priv, &flags) != 0)
4319 return -EBUSY;
4320
4321 /* Determine and validate the key index */
4322 idx = encoding->flags & IW_ENCODE_INDEX;
4323 if (idx) {
4324 if ((idx < 1) || (idx > WEP_KEYS))
4325 goto out;
4326 idx--;
4327 } else
4328 idx = priv->tx_key;
4329
4330 if (encoding->flags & IW_ENCODE_DISABLED)
4331 alg = IW_ENCODE_ALG_NONE;
4332
4333 if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
4334 /* Clear any TKIP TX key we had */
4335 (void) orinoco_clear_tkip_key(priv, priv->tx_key);
4336 }
4337
4338 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
4339 priv->tx_key = idx;
4340 set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
4341 (ext->key_len > 0)) ? 1 : 0;
4342 }
4343
4344 if (set_key) {
4345 /* Set the requested key first */
4346 switch (alg) {
4347 case IW_ENCODE_ALG_NONE:
4348 priv->encode_alg = alg;
4349 priv->keys[idx].len = 0;
4350 break;
4351
4352 case IW_ENCODE_ALG_WEP:
4353 if (ext->key_len > SMALL_KEY_SIZE)
4354 key_len = LARGE_KEY_SIZE;
4355 else if (ext->key_len > 0)
4356 key_len = SMALL_KEY_SIZE;
4357 else
4358 goto out;
4359
4360 priv->encode_alg = alg;
4361 priv->keys[idx].len = cpu_to_le16(key_len);
4362
4363 key_len = min(ext->key_len, key_len);
4364
4365 memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
4366 memcpy(priv->keys[idx].data, ext->key, key_len);
4367 break;
4368
4369 case IW_ENCODE_ALG_TKIP:
4370 {
4371 hermes_t *hw = &priv->hw;
4372 u8 *tkip_iv = NULL;
4373
4374 if (!priv->has_wpa ||
4375 (ext->key_len > sizeof(priv->tkip_key[0])))
4376 goto out;
4377
4378 priv->encode_alg = alg;
4379 memset(&priv->tkip_key[idx], 0,
4380 sizeof(priv->tkip_key[idx]));
4381 memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
4382
4383 if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
4384 tkip_iv = &ext->rx_seq[0];
4385
4386 err = __orinoco_hw_set_tkip_key(hw, idx,
4387 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
4388 (u8 *) &priv->tkip_key[idx],
4389 tkip_iv, NULL);
4390 if (err)
4391 printk(KERN_ERR "%s: Error %d setting TKIP key"
4392 "\n", dev->name, err);
4393
4394 goto out;
4395 }
4396 default:
4397 goto out;
4398 }
4399 }
4400 err = -EINPROGRESS;
4401 out:
4402 orinoco_unlock(priv, &flags);
4403
4404 return err;
4405}
4406
4407static int orinoco_ioctl_get_encodeext(struct net_device *dev,
4408 struct iw_request_info *info,
4409 union iwreq_data *wrqu,
4410 char *extra)
4411{
4412 struct orinoco_private *priv = netdev_priv(dev);
4413 struct iw_point *encoding = &wrqu->encoding;
4414 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
4415 int idx, max_key_len;
4416 unsigned long flags;
4417 int err;
4418
4419 if (orinoco_lock(priv, &flags) != 0)
4420 return -EBUSY;
4421
4422 err = -EINVAL;
4423 max_key_len = encoding->length - sizeof(*ext);
4424 if (max_key_len < 0)
4425 goto out;
4426
4427 idx = encoding->flags & IW_ENCODE_INDEX;
4428 if (idx) {
4429 if ((idx < 1) || (idx > WEP_KEYS))
4430 goto out;
4431 idx--;
4432 } else
4433 idx = priv->tx_key;
4434
4435 encoding->flags = idx + 1;
4436 memset(ext, 0, sizeof(*ext));
4437
4438 ext->alg = priv->encode_alg;
4439 switch (priv->encode_alg) {
4440 case IW_ENCODE_ALG_NONE:
4441 ext->key_len = 0;
4442 encoding->flags |= IW_ENCODE_DISABLED;
4443 break;
4444 case IW_ENCODE_ALG_WEP:
4445 ext->key_len = min(le16_to_cpu(priv->keys[idx].len),
4446 (u16) max_key_len);
4447 memcpy(ext->key, priv->keys[idx].data, ext->key_len);
4448 encoding->flags |= IW_ENCODE_ENABLED;
4449 break;
4450 case IW_ENCODE_ALG_TKIP:
4451 ext->key_len = min((u16) sizeof(struct orinoco_tkip_key),
4452 (u16) max_key_len);
4453 memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
4454 encoding->flags |= IW_ENCODE_ENABLED;
4455 break;
4456 }
4457
4458 err = 0;
4459 out:
4460 orinoco_unlock(priv, &flags);
4461
4462 return err;
4463}
4464
4465static int orinoco_ioctl_set_auth(struct net_device *dev,
4466 struct iw_request_info *info,
4467 union iwreq_data *wrqu, char *extra)
4468{
4469 struct orinoco_private *priv = netdev_priv(dev);
4470 hermes_t *hw = &priv->hw;
4471 struct iw_param *param = &wrqu->param;
4472 unsigned long flags;
4473 int ret = -EINPROGRESS;
4474
4475 if (orinoco_lock(priv, &flags) != 0)
4476 return -EBUSY;
4477
4478 switch (param->flags & IW_AUTH_INDEX) {
4479 case IW_AUTH_WPA_VERSION:
4480 case IW_AUTH_CIPHER_PAIRWISE:
4481 case IW_AUTH_CIPHER_GROUP:
4482 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
4483 case IW_AUTH_PRIVACY_INVOKED:
4484 case IW_AUTH_DROP_UNENCRYPTED:
4485 /*
4486 * orinoco does not use these parameters
4487 */
4488 break;
4489
4490 case IW_AUTH_KEY_MGMT:
4491 /* wl_lkm implies value 2 == PSK for Hermes I
4492 * which ties in with WEXT
4493 * no other hints tho :(
4494 */
4495 priv->key_mgmt = param->value;
4496 break;
4497
4498 case IW_AUTH_TKIP_COUNTERMEASURES:
4499 /* When countermeasures are enabled, shut down the
4500 * card; when disabled, re-enable the card. This must
4501 * take effect immediately.
4502 *
4503 * TODO: Make sure that the EAPOL message is getting
4504 * out before card disabled
4505 */
4506 if (param->value) {
4507 priv->tkip_cm_active = 1;
4508 ret = hermes_enable_port(hw, 0);
4509 } else {
4510 priv->tkip_cm_active = 0;
4511 ret = hermes_disable_port(hw, 0);
4512 }
4513 break;
4514
4515 case IW_AUTH_80211_AUTH_ALG:
4516 if (param->value & IW_AUTH_ALG_SHARED_KEY)
4517 priv->wep_restrict = 1;
4518 else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
4519 priv->wep_restrict = 0;
4520 else
4521 ret = -EINVAL;
4522 break;
4523
4524 case IW_AUTH_WPA_ENABLED:
4525 if (priv->has_wpa) {
4526 priv->wpa_enabled = param->value ? 1 : 0;
4527 } else {
4528 if (param->value)
4529 ret = -EOPNOTSUPP;
4530 /* else silently accept disable of WPA */
4531 priv->wpa_enabled = 0;
4532 }
4533 break;
4534
4535 default:
4536 ret = -EOPNOTSUPP;
4537 }
4538
4539 orinoco_unlock(priv, &flags);
4540 return ret;
4541}
4542
4543static int orinoco_ioctl_get_auth(struct net_device *dev,
4544 struct iw_request_info *info,
4545 union iwreq_data *wrqu, char *extra)
4546{
4547 struct orinoco_private *priv = netdev_priv(dev);
4548 struct iw_param *param = &wrqu->param;
4549 unsigned long flags;
4550 int ret = 0;
4551
4552 if (orinoco_lock(priv, &flags) != 0)
4553 return -EBUSY;
4554
4555 switch (param->flags & IW_AUTH_INDEX) {
4556 case IW_AUTH_KEY_MGMT:
4557 param->value = priv->key_mgmt;
4558 break;
4559
4560 case IW_AUTH_TKIP_COUNTERMEASURES:
4561 param->value = priv->tkip_cm_active;
4562 break;
4563
4564 case IW_AUTH_80211_AUTH_ALG:
4565 if (priv->wep_restrict)
4566 param->value = IW_AUTH_ALG_SHARED_KEY;
4567 else
4568 param->value = IW_AUTH_ALG_OPEN_SYSTEM;
4569 break;
4570
4571 case IW_AUTH_WPA_ENABLED:
4572 param->value = priv->wpa_enabled;
4573 break;
4574
4575 default:
4576 ret = -EOPNOTSUPP;
4577 }
4578
4579 orinoco_unlock(priv, &flags);
4580 return ret;
4581}
4582
4583static int orinoco_ioctl_set_genie(struct net_device *dev,
4584 struct iw_request_info *info,
4585 union iwreq_data *wrqu, char *extra)
4586{
4587 struct orinoco_private *priv = netdev_priv(dev);
4588 u8 *buf;
4589 unsigned long flags;
4590 int err = 0;
4591
4592 if ((wrqu->data.length > MAX_WPA_IE_LEN) ||
4593 (wrqu->data.length && (extra == NULL)))
4594 return -EINVAL;
4595
4596 if (orinoco_lock(priv, &flags) != 0)
4597 return -EBUSY;
4598
4599 if (wrqu->data.length) {
4600 buf = kmalloc(wrqu->data.length, GFP_KERNEL);
4601 if (buf == NULL) {
4602 err = -ENOMEM;
4603 goto out;
4604 }
4605
4606 memcpy(buf, extra, wrqu->data.length);
4607 kfree(priv->wpa_ie);
4608 priv->wpa_ie = buf;
4609 priv->wpa_ie_len = wrqu->data.length;
4610 } else {
4611 kfree(priv->wpa_ie);
4612 priv->wpa_ie = NULL;
4613 priv->wpa_ie_len = 0;
4614 }
4615
4616 if (priv->wpa_ie) {
4617 /* Looks like wl_lkm wants to check the auth alg, and
4618 * somehow pass it to the firmware.
4619 * Instead it just calls the key mgmt rid
4620 * - we do this in set auth.
4621 */
4622 }
4623
4624out:
4625 orinoco_unlock(priv, &flags);
4626 return err;
4627}
4628
4629static int orinoco_ioctl_get_genie(struct net_device *dev,
4630 struct iw_request_info *info,
4631 union iwreq_data *wrqu, char *extra)
4632{
4633 struct orinoco_private *priv = netdev_priv(dev);
4634 unsigned long flags;
4635 int err = 0;
4636
4637 if (orinoco_lock(priv, &flags) != 0)
4638 return -EBUSY;
4639
4640 if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
4641 wrqu->data.length = 0;
4642 goto out;
4643 }
4644
4645 if (wrqu->data.length < priv->wpa_ie_len) {
4646 err = -E2BIG;
4647 goto out;
4648 }
4649
4650 wrqu->data.length = priv->wpa_ie_len;
4651 memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
4652
4653out:
4654 orinoco_unlock(priv, &flags);
4655 return err;
4656}
4657
4658static int orinoco_ioctl_set_mlme(struct net_device *dev,
4659 struct iw_request_info *info,
4660 union iwreq_data *wrqu, char *extra)
4661{
4662 struct orinoco_private *priv = netdev_priv(dev);
4663 hermes_t *hw = &priv->hw;
4664 struct iw_mlme *mlme = (struct iw_mlme *)extra;
4665 unsigned long flags;
4666 int ret = 0;
4667
4668 if (orinoco_lock(priv, &flags) != 0)
4669 return -EBUSY;
4670
4671 switch (mlme->cmd) {
4672 case IW_MLME_DEAUTH:
4673 /* silently ignore */
4674 break;
4675
4676 case IW_MLME_DISASSOC:
4677 {
4678 struct {
4679 u8 addr[ETH_ALEN];
4680 __le16 reason_code;
4681 } __attribute__ ((packed)) buf;
4682
4683 memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN);
4684 buf.reason_code = cpu_to_le16(mlme->reason_code);
4685 ret = HERMES_WRITE_RECORD(hw, USER_BAP,
4686 HERMES_RID_CNFDISASSOCIATE,
4687 &buf);
4688 break;
4689 }
4690 default:
4691 ret = -EOPNOTSUPP;
4692 }
4693
4694 orinoco_unlock(priv, &flags);
4695 return ret;
4696}
4697
4195static int orinoco_ioctl_getretry(struct net_device *dev, 4698static int orinoco_ioctl_getretry(struct net_device *dev,
4196 struct iw_request_info *info, 4699 struct iw_request_info *info,
4197 struct iw_param *rrq, 4700 struct iw_param *rrq,
@@ -5078,6 +5581,13 @@ static const iw_handler orinoco_handler[] = {
5078 STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), 5581 STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode),
5079 STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), 5582 STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower),
5080 STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), 5583 STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower),
5584 STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie),
5585 STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie),
5586 STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme),
5587 STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth),
5588 STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth),
5589 STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
5590 STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
5081}; 5591};
5082 5592
5083 5593
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 5605fd30b81d..bfab88f51362 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -30,6 +30,15 @@ struct orinoco_key {
30 char data[ORINOCO_MAX_KEY_SIZE]; 30 char data[ORINOCO_MAX_KEY_SIZE];
31} __attribute__ ((packed)); 31} __attribute__ ((packed));
32 32
33#define TKIP_KEYLEN 16
34#define MIC_KEYLEN 8
35
36struct orinoco_tkip_key {
37 u8 tkip[TKIP_KEYLEN];
38 u8 tx_mic[MIC_KEYLEN];
39 u8 rx_mic[MIC_KEYLEN];
40};
41
33typedef enum { 42typedef enum {
34 FIRMWARE_TYPE_AGERE, 43 FIRMWARE_TYPE_AGERE,
35 FIRMWARE_TYPE_INTERSIL, 44 FIRMWARE_TYPE_INTERSIL,
@@ -93,6 +102,7 @@ struct orinoco_private {
93 unsigned int has_hostscan:1; 102 unsigned int has_hostscan:1;
94 unsigned int has_alt_txcntl:1; 103 unsigned int has_alt_txcntl:1;
95 unsigned int has_ext_scan:1; 104 unsigned int has_ext_scan:1;
105 unsigned int has_wpa:1;
96 unsigned int do_fw_download:1; 106 unsigned int do_fw_download:1;
97 unsigned int broken_disableport:1; 107 unsigned int broken_disableport:1;
98 unsigned int broken_monitor:1; 108 unsigned int broken_monitor:1;
@@ -128,6 +138,16 @@ struct orinoco_private {
128 138
129 int scan_inprogress; /* Scan pending... */ 139 int scan_inprogress; /* Scan pending... */
130 u32 scan_mode; /* Type of scan done */ 140 u32 scan_mode; /* Type of scan done */
141
142 /* WPA support */
143 u8 *wpa_ie;
144 int wpa_ie_len;
145
146 struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS];
147
148 unsigned int wpa_enabled:1;
149 unsigned int tkip_cm_active:1;
150 unsigned int key_mgmt:3;
131}; 151};
132 152
133#ifdef ORINOCO_DEBUG 153#ifdef ORINOCO_DEBUG