Search Linux Wireless

Re: airo WPA

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



New patch against current git

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 074055e..5620c42 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -16,6 +16,7 @@
     Code was also integrated from the Cisco Aironet driver for Linux.
     Support for MPI350 cards was added by Fabrice Bellet
     <fabrice@xxxxxxxxxxx>.
+    (C) 2005-2007 Matthieu CASTET <castet.matthieu@xxxxxxx> for WPA support
 
 ======================================================================*/
 
@@ -92,6 +93,11 @@ static struct pci_driver airo_driver = {
 #include <linux/delay.h>
 #endif
 
+/* enable rx mic checking
+ *disable because it takes some time in ISR
+ */
+#define WPA_CHECK_RX_MIC
+
 /* Hack to do some power saving */
 #define POWER_ON_DOWN
 
@@ -224,6 +230,7 @@ static
 int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at.
 		       0 means no limit.  For old cards this was 4 */
 
+static int wpa_enabled; /* If set the card is in WPA mode. This is incompatible with WEP or open mode */
 static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */
 static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read
 		    the bap, needed on some older cards and buses. */
@@ -251,6 +258,9 @@ module_param(basic_rate, int, 0);
 module_param_array(rates, int, NULL, 0);
 module_param_array(ssids, charp, NULL, 0);
 module_param(auto_wep, int, 0);
+module_param(wpa_enabled, int, 0);
+MODULE_PARM_DESC(wpa_enabled, "If non-zero, the driver can use WPA \
+but Open and WEP mode won't be possible");
 MODULE_PARM_DESC(auto_wep, "If non-zero, the driver will keep looping through \
 the authentication options until an association is made.  The value of \
 auto_wep is number of the wep keys to check.  A value of 2 will try using \
@@ -453,6 +463,7 @@ static int do8bitIO = 0;
 #define RID_UNKNOWN22  0xFF22
 #define RID_LEAPUSERNAME 0xFF23
 #define RID_LEAPPASSWORD 0xFF24
+#define RID_WPA        0xFF25
 #define RID_STATUS     0xFF50
 #define RID_BEACON_HST 0xFF51
 #define RID_BUSY_HST   0xFF52
@@ -507,6 +518,14 @@ typedef struct {
 	u8 key[16];
 } WepKeyRid;
 
+typedef struct {
+	u16 len;
+	u16 kindex;
+	u8 mac[ETH_ALEN];
+	u16 klen;
+	u8 key[48];
+} WpaKeyRid;
+
 /* These structures are from the Aironet's PC4500 Developers Manual */
 typedef struct {
 	u16 len;
@@ -526,6 +545,19 @@ typedef struct {
 #define MOD_MOK 2
 } ModulationRid;
 
+/* Only present on firmware >= 5.30.17 */
+typedef struct {
+	u16 _reserved5[4];
+	u16 auth_cipher;
+#define AUTH_CIPHER_NONE 1
+#define AUTH_CIPHER_WEP 0xc
+#define AUTH_CIPHER_TKIP 0x210
+	u16 auth_key;
+#define AUTH_KEY_MGMT_NONE 1
+#define AUTH_KEY_MGMT_802_1X 4
+#define AUTH_KEY_MGMT_PSK 8
+} ConfigRidExtra;
+
 typedef struct {
 	u16 len; /* sizeof(ConfigRid) */
 	u16 opmode; /* operating mode */
@@ -581,6 +613,7 @@ typedef struct {
 #define AUTH_ENCRYPT 0x101
 #define AUTH_SHAREDKEY 0x102
 #define AUTH_ALLOW_UNENCRYPTED 0x200
+#define AUTH_ENCRYPT_WPA 0xc101
 	u16 associationTimeout;
 	u16 specifiedApTimeout;
 	u16 offlineScanInterval;
@@ -644,6 +677,8 @@ typedef struct {
 #define MAGIC_STAY_IN_CAM (1<<10)
 	u8 magicControl;
 	u16 autoWake;
+	/* Only present on firmware >= 5.30.17 */
+	ConfigRidExtra extra;
 } ConfigRid;
 
 typedef struct {
@@ -1143,6 +1178,8 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
 
 static void airo_networks_free(struct airo_info *ai);
 
+static void airo_interrupt_tasklet(unsigned long data);
+
 struct airo_info {
 	struct net_device_stats	stats;
 	struct net_device             *dev;
@@ -1229,6 +1266,19 @@ struct airo_info {
 	unsigned int bssListFirst;
 	unsigned int bssListNext;
 	unsigned int bssListRidLen;
+	unsigned int ConfigRidLen;
+	unsigned char wpa_tx_key [8];
+	unsigned char wpa_rx_key [8];
+	unsigned char wpa_rx_key_m [8];
+	unsigned char wpa_rx_key_m_old [8];
+	u8 LLC [10];
+	struct crypto_hash *tfm_michael;
+	int wpa_enabled;
+	int wpa_key_enabled;
+
+
+	spinlock_t tasklet_lock;
+	struct tasklet_struct isr_tasklet;
 
 	struct list_head network_list;
 	struct list_head network_free_list;
@@ -1725,6 +1775,55 @@ static void emmh32_final(emmh32_context *context, u8 digest[4])
 	digest[3] = val & 0xFF;
 }
 
+static void wpa_compute_mic(struct airo_info *ai ,char *pPacket, u8 *mic, int len, char *key)
+{
+	struct scatterlist sg[3];
+	struct hash_desc desc;
+
+	sg[0].page = virt_to_page(pPacket);
+	sg[0].offset = offset_in_page(pPacket);
+	sg[0].length = sizeof(etherHead);
+
+
+	sg[1].page = virt_to_page(ai->LLC);
+	sg[1].offset = offset_in_page(ai->LLC);
+	sg[1].length = sizeof(ai->LLC);
+
+	sg[2].page = virt_to_page(pPacket + sizeof(etherHead));
+	sg[2].offset = offset_in_page(pPacket + sizeof(etherHead));
+	sg[2].length = len - sizeof(etherHead);
+
+	crypto_hash_setkey(ai->tfm_michael, key, 8);
+
+	desc.tfm = ai->tfm_michael;
+	desc.flags = 0;
+
+	crypto_hash_digest(&desc, sg, len + sizeof(ai->LLC),
+			mic);
+}
+
+#ifdef WPA_CHECK_RX_MIC
+static int wpa_check_rx_mic(struct airo_info *ai ,char *buffer, int len)
+{
+	u8 mic[8];
+	/* multicast */
+	if (buffer[0] & 1) {
+		wpa_compute_mic(ai, buffer, mic, len, ai->wpa_rx_key_m);
+		if (memcmp(mic, buffer + len, 8)) {
+			/* we don't know the current index, try the old one */
+			wpa_compute_mic(ai, buffer, mic, len, ai->wpa_rx_key_m_old);
+			return memcmp(mic, buffer + len, 8);
+		}
+	}
+	else {
+		wpa_compute_mic(ai, buffer, mic, len, ai->wpa_rx_key);
+		return memcmp(mic, buffer + len, 8);
+	}
+	return 0;
+}
+#endif
+
+
 static int readBSSListRid(struct airo_info *ai, int first,
 		      BSSListRid *list) {
 	int rc;
@@ -1788,6 +1887,18 @@ static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lo
 	return rc;
 }
 
+static int writeWpaKeyRid(struct airo_info*ai, WpaKeyRid *pwkr, int lock) {
+	int rc;
+	WpaKeyRid wkr = *pwkr;
+
+	wkr.len = cpu_to_le16(wkr.len);
+	wkr.kindex = cpu_to_le16(wkr.kindex);
+	wkr.klen = cpu_to_le16(wkr.klen);
+	rc = PC4500_writerid(ai, RID_WPA, &wkr, sizeof(wkr), lock);
+	if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WPA set %x", rc);
+	return rc;
+}
+
 static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
 	int i;
 	int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
@@ -1818,7 +1929,7 @@ static int readConfigRid(struct airo_info*ai, int lock) {
 	if (ai->config.len)
 		return SUCCESS;
 
-	rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
+	rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, ai->ConfigRidLen, lock);
 	if (rc != SUCCESS)
 		return rc;
 
@@ -1881,7 +1992,7 @@ static int writeConfigRid(struct airo_info*ai, int lock) {
 	for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++)
 		*s = cpu_to_le16(*s);
 
-	return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
+	return PC4500_writerid( ai, RID_CONFIG, &cfgr, ai->ConfigRidLen, lock);
 }
 static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) {
 	int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
@@ -2068,7 +2179,20 @@ static int mpi_send_packet (struct net_device *dev)
 	 * Firmware automaticly puts 802 header on so
 	 * we don't need to account for it in the length
 	 */
-	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
+	if (ai->wpa_key_enabled) {
+		u8 mic [8];
+
+		*payloadLen = cpu_to_le16(len-sizeof(etherHead)+8);
+		ai->txfids[0].tx_desc.len += 8;
+
+		wpa_compute_mic(ai, buffer, mic, len, ai->wpa_tx_key);
+
+		dev->trans_start = jiffies;
+		/* copy data into airo dma buffer */
+		memcpy(sendbuf, buffer, len);
+		memcpy(sendbuf + len, mic, 8);
+	}
+    else if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
 		(ntohs(((u16 *)buffer)[6]) != 0x888E)) {
 		MICBuffer pMic;
 
@@ -2341,7 +2465,9 @@ static void airo_set_promisc(struct airo_info *ai) {
 	cmd.cmd=CMD_SETMODE;
 	clear_bit(JOB_PROMISC, &ai->jobs);
 	cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
-	issuecommand(ai, &cmd, &rsp);
+	/* when wpa is active, promisc mode can't be set */
+	if (ai->wpa_key_enabled && cmd.parm0 != PROMISC)
+		issuecommand(ai, &cmd, &rsp);
 	up(&ai->sem);
 }
 
@@ -2475,6 +2601,8 @@ void stop_airo_card( struct net_device *dev, int freeres )
 		}
         }
 	crypto_free_cipher(ai->tfm);
+	if (ai->tfm_michael)
+		crypto_free_hash(ai->tfm_michael);
 	del_airo_dev(ai);
 	free_netdev( dev );
 }
@@ -2628,6 +2756,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
 		goto free_auxmap;
 	}
 
+	tasklet_kill(&ai->isr_tasklet);
+
 	/*
 	 * Setup descriptor RX, TX, CONFIG
 	 */
@@ -2804,6 +2934,7 @@ static int airo_test_wpa_capable(struct airo_info *ai)
 	if ((cap_rid.softVer > 0x530)
 	  || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
 		airo_print_info("", "WPA is supported.");
+		airo_print_info("", "Version 5.41 is recomended");
 		return 1;
 	}
 
@@ -2830,6 +2961,11 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
 	}
 
 	ai = dev->priv;
+	/* this is needed for initialisation, the firware check will be done
+	 * latter. The windows driver, do it a different way : it reads
+	 * ConfigRid.len .
+	 */
+	ai->ConfigRidLen = sizeof(ConfigRid) - sizeof(ConfigRidExtra);
 	ai->wifidev = NULL;
 	ai->flags = 1 << FLAG_RADIO_DOWN;
 	ai->jobs = 0;
@@ -2838,6 +2974,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
 		airo_print_dbg("", "Found an MPI350 card");
 		set_bit(FLAG_MPI, &ai->flags);
 	}
+	spin_lock_init(&ai->tasklet_lock);
+	tasklet_init(&ai->isr_tasklet, airo_interrupt_tasklet, (unsigned long)dev);
 	spin_lock_init(&ai->aux_lock);
 	sema_init(&ai->sem, 1);
 	ai->config.len = 0;
@@ -2901,15 +3039,29 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
 	}
 
 	/* Test for WPA support */
-	if (airo_test_wpa_capable(ai)) {
+	if (airo_test_wpa_capable(ai) && wpa_enabled) {
+		char LLC1 [] = {0, 0, 0, 0, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
 		set_bit(FLAG_WPA_CAPABLE, &ai->flags);
 		ai->bssListFirst = RID_WPA_BSSLISTFIRST;
 		ai->bssListNext = RID_WPA_BSSLISTNEXT;
 		ai->bssListRidLen = sizeof(BSSListRid);
+		ai->ConfigRidLen = sizeof(ConfigRid);
+		memcpy(ai->LLC, LLC1, sizeof(ai->LLC));
+		ai->tfm_michael = crypto_alloc_hash("michael_mic", 0, CRYPTO_ALG_ASYNC);
+		if (ai->tfm_michael == NULL) {
+			printk(KERN_DEBUG "crypto API michael_mic failed. Removing WPA\n");
+		}
+		else {
+			ai->wpa_enabled = 1;
+			/* we don't want to enable wep mode : it will make the firmware 
+			 * hanging */
+			auto_wep = 0;
+		}
 	} else {
 		ai->bssListFirst = RID_BSSLISTFIRST;
 		ai->bssListNext = RID_BSSLISTNEXT;
 		ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
+		ai->ConfigRidLen = sizeof(ConfigRid) - sizeof(ConfigRidExtra);
 	}
 
 	strcpy(dev->name, "eth%d");
@@ -3177,36 +3329,31 @@ static int airo_thread(void *data) {
 	return 0;
 }
 
-static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
-	struct net_device *dev = (struct net_device *)dev_id;
+static void airo_interrupt_tasklet(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	unsigned long flags;
 	u16 status;
 	u16 fid;
 	struct airo_info *apriv = dev->priv;
-	u16 savedInterrupts = 0;
-	int handled = 0;
 
-	if (!netif_device_present(dev))
-		return IRQ_NONE;
+	spin_lock_irqsave(&apriv->tasklet_lock, flags);
 
 	for (;;) {
 		status = IN4500( apriv, EVSTAT );
 		if ( !(status & STATUS_INTS) || status == 0xffff ) break;
 
-		handled = 1;
-
 		if ( status & EV_AWAKE ) {
 			OUT4500( apriv, EVACK, EV_AWAKE );
 			OUT4500( apriv, EVACK, EV_AWAKE );
 		}
 
-		if (!savedInterrupts) {
-			savedInterrupts = IN4500( apriv, EVINTEN );
-			OUT4500( apriv, EVINTEN, 0 );
-		}
 
 		if ( status & EV_MIC ) {
 			OUT4500( apriv, EVACK, EV_MIC );
-			if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
+			if (apriv->wpa_enabled) {
+			}
+			else if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
 				set_bit(JOB_MIC, &apriv->jobs);
 				wake_up_interruptible(&apriv->thr_wait);
 			}
@@ -3250,6 +3397,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 			  leaving BSS */
 #define RC_NOAUTH 9 /* Station requesting (Re)Association is not
 		       Authenticated with the responding station */
+			printk("status : %x\n", newStatus);
+
 			if (newStatus == FORCELOSS && apriv->scan_timeout > 0)
 				scan_forceloss = 1;
 			if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
@@ -3376,7 +3525,9 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 			} else {
 				MICBuffer micbuf;
 				bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
-				if (apriv->micstats.enabled) {
+				if (apriv->wpa_key_enabled) {
+				}
+				else if (apriv->micstats.enabled) {
 					bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
 					if (ntohs(micbuf.typelen) > 0x05DC)
 						bap_setup (apriv, fid, 0x44, BAP0);
@@ -3389,7 +3540,20 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 					}
 				}
 				bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
-				if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
+				if (apriv->wpa_key_enabled) {
+					len -= 8;
+
+					//this is easy to do, but take some time in ISR
+#ifdef WPA_CHECK_RX_MIC
+					if (wpa_check_rx_mic(apriv, skb->data, len + hdrlen)) {
+						airo_print_err(apriv->dev->name, "Bad mic on RX");
+						goto badmic;
+					}
+	
+#endif
+					skb_trim (skb, len + hdrlen);
+				}
+				else if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
 badmic:
 					dev_kfree_skb_irq (skb);
 badrx:
@@ -3428,8 +3592,10 @@ badrx:
 				skb->pkt_type = PACKET_OTHERHOST;
 				skb->dev = apriv->wifidev;
 				skb->protocol = htons(ETH_P_802_2);
-			} else
+			} else {
+				skb->dev = dev;
 				skb->protocol = eth_type_trans(skb,dev);
+			}
 			skb->dev->last_rx = jiffies;
 			skb->ip_summed = CHECKSUM_NONE;
 
@@ -3495,8 +3661,28 @@ exittx:
 				status & ~STATUS_INTS & ~IGNORE_INTS );
 	}
 
-	if (savedInterrupts)
-		OUT4500( apriv, EVINTEN, savedInterrupts );
+	enable_interrupts(apriv);
+
+	spin_unlock_irqrestore(&apriv->tasklet_lock, flags);
+}
+
+static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct airo_info *apriv = dev->priv;
+	int handled;
+	u16 status;
+
+	if (!netif_device_present(dev))
+		return IRQ_NONE;
+	status = IN4500( apriv, EVSTAT );
+	if ( !(status & STATUS_INTS) || status == 0xffff )
+		handled = 0;
+	else {
+		handled = 1;
+		disable_interrupts(apriv);
+		tasklet_schedule(&apriv->isr_tasklet);
+	}
+
 
 	/* done.. */
 	return IRQ_RETVAL(handled);
@@ -3624,7 +3810,9 @@ static void mpi_receive_802_3(struct airo_info *ai)
 		}
 		buffer = skb_put(skb,len);
 		memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
-		if (ai->micstats.enabled) {
+		if (ai->wpa_key_enabled) {
+		}
+		else if (ai->micstats.enabled) {
 			memcpy(&micbuf,
 				ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
 				sizeof(micbuf));
@@ -3639,7 +3827,19 @@ static void mpi_receive_802_3(struct airo_info *ai)
 		memcpy(buffer + ETH_ALEN * 2,
 			ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
 			len - ETH_ALEN * 2 - off);
-		if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
+		if (ai->wpa_key_enabled) {
+			len -= 8;
+
+#ifdef WPA_CHECK_RX_MIC
+			if (wpa_check_rx_mic(ai, buffer, len)) {
+				airo_print_err(ai->dev->name, "Bad mic on RX");
+				goto badmic;
+			}
+#endif
+
+			skb_trim (skb, len);
+		}
+		else if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
 badmic:
 			dev_kfree_skb_irq (skb);
 			goto badrx;
@@ -3658,6 +3858,7 @@ badmic:
 		}
 #endif /* WIRELESS_SPY */
 
+		skb->dev = ai->dev;
 		skb->ip_summed = CHECKSUM_NONE;
 		skb->protocol = eth_type_trans(skb, ai->dev);
 		skb->dev->last_rx = jiffies;
@@ -4332,7 +4533,10 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 	}
 	len -= ETH_ALEN * 2;
 
-	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && 
+	if (ai->wpa_key_enabled) {
+		miclen = 8;
+	}
+	else if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && 
 	    (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
 		if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
 			return ERROR;
@@ -4346,9 +4550,27 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 	payloadLen = cpu_to_le16(len + miclen);
 	bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
 	bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
-	if (miclen)
-		bap_write(ai, (const u16*)&pMic, miclen, BAP1);
-	bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
+	if (ai->wpa_key_enabled) {
+		u8 mic[8];
+
+		wpa_compute_mic(ai, pPacket, mic, len + sizeof(etherHead), ai->wpa_tx_key);
+		//XXX ugly hack because we write per 16 bits packet
+		bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len - (len&1), BAP1);
+		if (len&1) {
+			u8 tmp [2];
+			tmp [0] = pPacket [sizeof(etherHead) + len-1];
+			tmp [1] = mic[0];
+			bap_write(ai, (const u16*)tmp, 2, BAP1);
+			bap_write(ai, (const u16*)(mic+1), sizeof(mic)-1, BAP1);
+		}
+		else
+			bap_write(ai, (const u16*)mic, sizeof(mic), BAP1);
+	}
+	else {
+		if (miclen)
+			bap_write(ai, (const u16*)&pMic, miclen, BAP1);
+		bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
+	}
 	// issue the transmit command
 	memset( &cmd, 0, sizeof( cmd ) );
 	cmd.cmd = CMD_TRANSMIT;
@@ -6350,6 +6572,10 @@ static int airo_set_encode(struct net_device *dev,
 	int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
 	u16 currentAuthType = local->config.authType;
 
+	/* In wpa mode, only wpa is allowed */
+	if (local->wpa_enabled)
+		return -EINVAL;
+
 	/* Is WEP supported ? */
 	readCapabilityRid(local, &cap_rid, 1);
 	/* Older firmware doesn't support this...
@@ -6445,6 +6671,7 @@ static int airo_get_encode(struct net_device *dev,
 	readConfigRid(local, 1);
 	/* Check encryption mode */
 	switch(local->config.authType)	{
+		case AUTH_ENCRYPT_WPA:
 		case AUTH_ENCRYPT:
 			dwrq->flags = IW_ENCODE_OPEN;
 			break;
@@ -6476,6 +6703,85 @@ static int airo_get_encode(struct net_device *dev,
 /*
  * Wireless Handler : set extended Encryption parameters
  */
+static int airo_set_encodeext_wpa(struct airo_info *local,
+							struct iw_encode_ext *ext,
+							struct iw_point *encoding)
+{
+	static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
+	WpaKeyRid wkr;
+	int index = (encoding->flags & IW_ENCODE_INDEX) - 1;
+
+	printk("set wpa : %d %d %d %x\n", ext->alg, ext->key_len, index, ext->ext_flags);
+
+	memset(&wkr, 0, sizeof(wkr));
+	wkr.len = sizeof(wkr);
+
+	if ((encoding->flags & IW_ENCODE_DISABLED) ||
+			ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) {
+		wkr.kindex = index;
+		memcpy( wkr.mac, macaddr, ETH_ALEN );
+		printk(KERN_INFO "Wpa Removing key %d\n", index);
+		memset(local->wpa_tx_key, 0, 8);
+		memset(local->wpa_rx_key, 0, 8);
+		memset(local->wpa_rx_key_m, 0, 8);
+		memset(local->wpa_rx_key_m_old, 0, 8);
+		local->wpa_key_enabled = 0;
+	}
+	else if (ext->alg == IW_ENCODE_ALG_WEP)
+		return -EOPNOTSUPP;
+	else if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) {
+		// we cannot set a WPA key in a non-WPA mode
+		if (local->config.authType != AUTH_ENCRYPT_WPA)
+			return -EINVAL;
+		wkr.kindex = index;
+		memcpy( wkr.mac, macaddr, ETH_ALEN );
+		wkr.klen = 0x30;
+
+		/* firmware use ndis order + a hole at 16-21 */
+		memcpy(wkr.key, ext->key, 16); /* temporal key */
+		memcpy(wkr.key + 40, ext->key + 16, 8); /*TX*/
+		memcpy(wkr.key + 32, ext->key + 24, 8); /*RX*/
+
+		if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+			memcpy(wkr.key + 22, ext->rx_seq, 6);
+		}
+
+		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+			memcpy(local->wpa_rx_key_m_old, local->wpa_rx_key_m, 8);
+			memcpy(local->wpa_rx_key_m, ext->key+24, 8);
+		}
+		else {
+			memcpy(local->wpa_tx_key, ext->key+16, 8);
+			memcpy(local->wpa_rx_key, ext->key+24, 8);
+		}
+	}
+	else
+		return -EINVAL;
+
+
+
+	if (down_interruptible(&local->sem))
+		return ERROR;
+
+	writeWpaKeyRid(local, &wkr, 0);
+
+	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+		memset(&wkr, 0, sizeof(wkr));
+		wkr.len = sizeof(wkr);
+		wkr.kindex = 0xffff;
+		wkr.mac[0] = (char)index;
+		wkr.klen = 0x30;
+
+		printk(KERN_INFO "Setting default tx key to %d\n", index);
+		writeWpaKeyRid(local, &wkr, 0);
+
+		local->wpa_key_enabled = 1;
+	}
+
+	up(&local->sem);
+	return 0;
+}
+
 static int airo_set_encodeext(struct net_device *dev,
 			   struct iw_request_info *info,
 			    union iwreq_data *wrqu,
@@ -6498,6 +6804,8 @@ static int airo_set_encodeext(struct net_device *dev,
 	} */
 	readConfigRid(local, 1);
 
+	if (local->wpa_enabled)
+		return airo_set_encodeext_wpa(local, ext, encoding);
 	/* Determine and validate the key index */
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
@@ -6572,6 +6880,7 @@ static int airo_get_encodeext(struct net_device *dev,
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	CapabilityRid cap_rid;		/* Card capability info */
 	int idx, max_key_len;
+	printk("get_encode\n");
 
 	/* Is it supported ? */
 	readCapabilityRid(local, &cap_rid, 1);
@@ -6597,6 +6906,7 @@ static int airo_get_encodeext(struct net_device *dev,
 
 	/* Check encryption mode */
 	switch(local->config.authType) {
+		case AUTH_ENCRYPT_WPA:
 		case AUTH_ENCRYPT:
 			encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
 			break;
@@ -6622,6 +6932,20 @@ static int airo_get_encodeext(struct net_device *dev,
 }
 
 
+static void wpa_off(struct airo_info *local)
+{
+	printk(KERN_INFO"WPA dis\n");
+	local->config.authType=AUTH_OPEN;
+	local->config.extra.auth_key=AUTH_KEY_MGMT_NONE;
+}
+
+static void wpa_on(struct airo_info *local)
+{
+	printk(KERN_INFO"WPA enable\n");
+	local->config.authType=AUTH_ENCRYPT_WPA;
+	local->config.extra.auth_cipher=AUTH_CIPHER_TKIP;
+	//local->config.extra._reserved5[0]=0x40;
+}
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : set extended authentication parameters
@@ -6636,17 +6960,55 @@ static int airo_set_auth(struct net_device *dev,
 
 	switch (param->flags & IW_AUTH_INDEX) {
 	case IW_AUTH_WPA_VERSION:
+		if (param->value == IW_AUTH_WPA_VERSION_WPA)
+			wpa_on(local);
+		else if (param->value == IW_AUTH_WPA_VERSION_DISABLED)
+			wpa_off(local);
+		else
+			return -EINVAL;
+		break;
 	case IW_AUTH_CIPHER_PAIRWISE:
 	case IW_AUTH_CIPHER_GROUP:
+		if ((param->value == IW_AUTH_CIPHER_TKIP) && (local->config.authType == AUTH_ENCRYPT_WPA))
+			return 0;
+		else if (((param->value == IW_AUTH_CIPHER_WEP40) ||(param->value == IW_AUTH_CIPHER_WEP104))
+				&& (local->config.authType != AUTH_ENCRYPT_WPA))
+			return 0;
+		else if ((param->value == IW_AUTH_CIPHER_NONE) && (local->config.authType != AUTH_ENCRYPT_WPA))
+			local->config.authType = AUTH_OPEN;
+		else
+			return -EINVAL;
+		break;
 	case IW_AUTH_KEY_MGMT:
-	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		if (local->config.authType != AUTH_ENCRYPT_WPA)
+			return -EINVAL;
+		if (param->value == IW_AUTH_KEY_MGMT_802_1X)
+			local->config.extra.auth_key=AUTH_KEY_MGMT_802_1X;
+		else if (param->value == IW_AUTH_KEY_MGMT_PSK)
+			local->config.extra.auth_key=AUTH_KEY_MGMT_PSK;
+		else
+			return -EINVAL;
+		break;
 	case IW_AUTH_PRIVACY_INVOKED:
+		if (!param->value) {
+			if (local->config.authType == AUTH_ENCRYPT_WPA)
+				wpa_off(local);
+			else
+				wpa_on(local);
+		}
+		else
+			return 0;
+		break;
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+	case IW_AUTH_TKIP_COUNTERMEASURES:
 		/*
 		 * airo does not use these parameters
 		 */
 		break;
 
 	case IW_AUTH_DROP_UNENCRYPTED:
+		if (local->wpa_enabled)
+			break;
 		if (param->value) {
 			/* Only change auth type if unencrypted */
 			if (currentAuthType == AUTH_OPEN)
@@ -6655,15 +7017,16 @@ static int airo_set_auth(struct net_device *dev,
 			local->config.authType = AUTH_OPEN;
 		}
 
-		/* Commit the changes to flags if needed */
-		if (local->config.authType != currentAuthType)
-			set_bit (FLAG_COMMIT, &local->flags);
 		break;
 
 	case IW_AUTH_80211_AUTH_ALG: {
 			/* FIXME: What about AUTH_OPEN?  This API seems to
 			 * disallow setting our auth to AUTH_OPEN.
 			 */
+			/* does not make sense with WPA */
+			if (local->config.authType == AUTH_ENCRYPT_WPA)
+				return 0;
+
 			if (param->value & IW_AUTH_ALG_SHARED_KEY) {
 				local->config.authType = AUTH_SHAREDKEY;
 			} else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
@@ -6671,21 +7034,20 @@ static int airo_set_auth(struct net_device *dev,
 			} else
 				return -EINVAL;
 			break;
-
-			/* Commit the changes to flags if needed */
-			if (local->config.authType != currentAuthType)
-				set_bit (FLAG_COMMIT, &local->flags);
 		}
 
 	case IW_AUTH_WPA_ENABLED:
-		/* Silently accept disable of WPA */
-		if (param->value > 0)
-			return -EOPNOTSUPP;
+		if (param->value == 0)
+			wpa_off(local);
+		else
+			wpa_on(local);
 		break;
 
 	default:
 		return -EOPNOTSUPP;
 	}
+
+	set_bit (FLAG_COMMIT, &local->flags);
 	return -EINPROGRESS;
 }
 
@@ -6737,6 +7099,28 @@ static int airo_get_auth(struct net_device *dev,
 	return 0;
 }
 
+static int airo_disasociate(struct net_device *dev,
+		struct iw_request_info *info,
+		struct iw_point *data, char *extra)
+{
+	struct airo_info *local = dev->priv;
+	SsidRid SSID_rid;		/* SSIDs */
+
+	/* reset the list */
+	memset(&SSID_rid, 0, sizeof(SSID_rid));
+
+	/* Set the SSID */
+	strcpy(SSID_rid.ssids[0].ssid, "tsunami");
+	SSID_rid.ssids[0].len = 7;
+	SSID_rid.len = sizeof(SSID_rid);
+	/* Write it to the card */
+	disable_MAC(local, 1);
+	writeSsidRid(local, &SSID_rid, 1);
+	enable_MAC(local, 1);
+
+	return 0;
+}
+
 
 /*------------------------------------------------------------------*/
 /*
@@ -7553,6 +7937,7 @@ static const iw_handler		airo_handler[] =
 	(iw_handler) airo_set_encodeext,	/* SIOCSIWENCODEEXT */
 	(iw_handler) airo_get_encodeext,	/* SIOCGIWENCODEEXT */
 	(iw_handler) NULL,			/* SIOCSIWPMKSA */
+	[SIOCSIWMLME-SIOCSIWCOMMIT] = (iw_handler) airo_disasociate,
 };
 
 /* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
Chiacchiera con i tuoi amici in tempo reale! 
 http://it.yahoo.com/mail_it/foot/*http://it.messenger.yahoo.com 
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux