* [PATCH 5/7] staging: wlags49_h2: Make key setting more reliable
2011-10-09 11:11 [PATCH 0/7] Enable WPA with wlags49_h2 David Kilroy
` (2 preceding siblings ...)
2011-10-09 11:11 ` [PATCH 4/7] staging: wlags49_h2: Report WPA IE in scan results with IWEVGENIE David Kilroy
@ 2011-10-09 11:11 ` David Kilroy
2011-10-09 11:11 ` [PATCH 6/7] staging: wlags49_h2: Fixup IW_AUTH handling David Kilroy
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: David Kilroy @ 2011-10-09 11:11 UTC (permalink / raw)
To: linux-kernel, greg; +Cc: pe1dnn, David Kilroy
Share logic between encodeext and encode, so that we can handle
subtle differences between them (implied set_tx), and clear the
appropriate keys if you attempt to switch straight from WPA to
WEP and vice versa.
Also reinstate the TX buffer flush, and ensure the key index is
written to the card little endian.
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
drivers/staging/wlags49_h2/wl_internal.h | 6 +
drivers/staging/wlags49_h2/wl_wext.c | 655 +++++++++++++++---------------
2 files changed, 340 insertions(+), 321 deletions(-)
diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h
index 9ed2857..5753408 100644
--- a/drivers/staging/wlags49_h2/wl_internal.h
+++ b/drivers/staging/wlags49_h2/wl_internal.h
@@ -980,6 +980,12 @@ struct wl_private
#ifdef USE_WDS
WVLAN_WDS_IF wds_port[NUM_WDS_PORTS];
#endif // USE_WDS
+
+ /* Track whether the card is using WEP encryption or WPA
+ * so we know what to disable next time through.
+ * IW_ENCODE_ALG_NONE, IW_ENCODE_ALG_WEP, IW_ENCODE_ALG_TKIP
+ */
+ int wext_enc;
}; // wl_private
#define wl_priv(dev) ((struct wl_private *) netdev_priv(dev))
diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c
index af9fec5..567a0dc 100644
--- a/drivers/staging/wlags49_h2/wl_wext.c
+++ b/drivers/staging/wlags49_h2/wl_wext.c
@@ -83,7 +83,223 @@ extern dbg_info_t *DbgInfo;
#endif // DBG
+/* Set up the LTV to program the appropriate key */
+static int hermes_set_tkip_keys(ltv_t *ltv, u16 key_idx, u8 *addr,
+ int set_tx, u8 *seq, u8 *key, size_t key_len)
+{
+ int ret = -EINVAL;
+ int buf_idx = 0;
+ hcf_8 tsc[IW_ENCODE_SEQ_MAX_SIZE] =
+ { 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
+
+ DBG_ENTER(DbgInfo);
+
+ /*
+ * Check the key index here; if 0, load as Pairwise Key, otherwise,
+ * load as a group key. Note that for the Hermes, the RIDs for
+ * group/pairwise keys are different from each other and different
+ * than the default WEP keys as well.
+ */
+ switch (key_idx) {
+ case 0:
+ ltv->len = 28;
+ ltv->typ = CFG_ADD_TKIP_MAPPED_KEY;
+
+ /* Load the BSSID */
+ memcpy(<v->u.u8[buf_idx], addr, ETH_ALEN);
+ buf_idx += ETH_ALEN;
+
+ /* Load the TKIP key */
+ memcpy(<v->u.u8[buf_idx], &key[0], 16);
+ buf_idx += 16;
+
+ /* Load the TSC */
+ memcpy(<v->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE);
+ buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+
+ /* Load the RSC */
+ memcpy(<v->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE);
+ buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+
+ /* Load the TxMIC key */
+ memcpy(<v->u.u8[buf_idx], &key[16], 8);
+ buf_idx += 8;
+
+ /* Load the RxMIC key */
+ memcpy(<v->u.u8[buf_idx], &key[24], 8);
+
+ ret = 0;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ ltv->len = 26;
+ ltv->typ = CFG_ADD_TKIP_DEFAULT_KEY;
+
+ /* Load the key Index */
+
+ /* If this is a Tx Key, set bit 8000 */
+ if (set_tx)
+ key_idx |= 0x8000;
+ ltv->u.u16[buf_idx] = cpu_to_le16(key_idx);
+ buf_idx += 2;
+
+ /* Load the RSC */
+ memcpy(<v->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE);
+ buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+
+ /* Load the TKIP, TxMIC, and RxMIC keys in one shot, because in
+ CFG_ADD_TKIP_DEFAULT_KEY they are back-to-back */
+ memcpy(<v->u.u8[buf_idx], key, key_len);
+ buf_idx += key_len;
+
+ /* Load the TSC */
+ memcpy(<v->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE);
+
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+ DBG_LEAVE(DbgInfo);
+ return ret;
+}
+
+/* Set up the LTV to clear the appropriate key */
+static int hermes_clear_tkip_keys(ltv_t *ltv, u16 key_idx, u8 *addr)
+{
+ int ret;
+
+ switch (key_idx) {
+ case 0:
+ if (memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) {
+ ltv->len = 7;
+ ltv->typ = CFG_REMOVE_TKIP_MAPPED_KEY;
+ memcpy(<v->u.u8[0], addr, ETH_ALEN);
+ ret = 0;
+ }
+ break;
+ case 1:
+ case 2:
+ case 3:
+ /* Clear the Group TKIP keys by index */
+ ltv->len = 2;
+ ltv->typ = CFG_REMOVE_TKIP_DEFAULT_KEY;
+ ltv->u.u16[0] = cpu_to_le16(key_idx);
+
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Set the WEP keys in the wl_private structure */
+static int hermes_set_wep_keys(struct wl_private *lp, u16 key_idx,
+ u8 *key, size_t key_len,
+ bool enable, bool set_tx)
+{
+ hcf_8 encryption_state = lp->EnableEncryption;
+ int tk = lp->TransmitKeyID - 1; /* current key */
+ int ret = 0;
+
+ /* Is encryption supported? */
+ if (!wl_has_wep(&(lp->hcfCtx))) {
+ DBG_WARNING(DbgInfo, "WEP not supported on this device\n");
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ DBG_NOTICE(DbgInfo, "pointer: %p, length: %d\n",
+ key, key_len);
+
+ /* Check the size of the key */
+ switch (key_len) {
+ case MIN_KEY_SIZE:
+ case MAX_KEY_SIZE:
+
+ /* Check the index */
+ if ((key_idx < 0) || (key_idx >= MAX_KEYS))
+ key_idx = tk;
+
+ /* Cleanup */
+ memset(lp->DefaultKeys.key[key_idx].key, 0, MAX_KEY_SIZE);
+
+ /* Copy the key in the driver */
+ memcpy(lp->DefaultKeys.key[key_idx].key, key, key_len);
+
+ /* Set the length */
+ lp->DefaultKeys.key[key_idx].len = key_len;
+
+ DBG_NOTICE(DbgInfo, "encoding.length: %d\n", key_len);
+ DBG_NOTICE(DbgInfo, "set key: %s(%d) [%d]\n",
+ lp->DefaultKeys.key[key_idx].key,
+ lp->DefaultKeys.key[key_idx].len, key_idx);
+
+ /* Enable WEP (if possible) */
+ if ((key_idx == tk) && (lp->DefaultKeys.key[tk].len > 0))
+ lp->EnableEncryption = 1;
+
+ break;
+
+ case 0:
+ /* Do we want to just set the current transmit key? */
+ if (set_tx && (key_idx >= 0) && (key_idx < MAX_KEYS)) {
+ DBG_NOTICE(DbgInfo, "index: %d; len: %d\n", key_idx,
+ lp->DefaultKeys.key[key_idx].len);
+
+ if (lp->DefaultKeys.key[key_idx].len > 0) {
+ lp->TransmitKeyID = key_idx + 1;
+ lp->EnableEncryption = 1;
+ } else {
+ DBG_WARNING(DbgInfo, "Problem setting the current TxKey\n");
+ ret = -EINVAL;
+ }
+ }
+ break;
+
+ default:
+ DBG_WARNING(DbgInfo, "Invalid Key length\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Read the flags */
+ if (enable) {
+ lp->EnableEncryption = 1;
+ lp->wext_enc = IW_ENCODE_ALG_WEP;
+ } else {
+ lp->EnableEncryption = 0; /* disable encryption */
+ lp->wext_enc = IW_ENCODE_ALG_NONE;
+ }
+
+ DBG_TRACE(DbgInfo, "encryption_state : %d\n", encryption_state);
+ DBG_TRACE(DbgInfo, "lp->EnableEncryption : %d\n", lp->EnableEncryption);
+ DBG_TRACE(DbgInfo, "erq->length : %d\n", key_len);
+
+ /* Write the changes to the card */
+ if (ret == 0) {
+ DBG_NOTICE(DbgInfo, "encrypt: %d, ID: %d\n", lp->EnableEncryption,
+ lp->TransmitKeyID);
+
+ if (lp->EnableEncryption == encryption_state) {
+ if (key_len != 0) {
+ /* Dynamic WEP key update */
+ wl_set_wep_keys(lp);
+ }
+ } else {
+ /* To switch encryption on/off, soft reset is
+ * required */
+ wl_apply(lp);
+ }
+ }
+
+out:
+ return ret;
+}
/*******************************************************************************
* wireless_commit()
@@ -1116,152 +1332,39 @@ static int wireless_set_encode(struct net_device *dev, struct iw_request_info *i
{
struct wl_private *lp = wl_priv(dev);
unsigned long flags;
- int ret = 0;
- hcf_8 encryption_state;
- /*------------------------------------------------------------------------*/
-
+ int key_idx = (erq->flags & IW_ENCODE_INDEX) - 1;
+ int ret = 0;
+ bool enable = true;
- DBG_FUNC( "wireless_set_encode" );
- DBG_ENTER( DbgInfo );
+ DBG_ENTER(DbgInfo);
- if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
ret = -EBUSY;
goto out;
}
- wl_lock( lp, &flags );
-
- wl_act_int_off( lp );
-
- /* Is encryption supported? */
- if( !wl_has_wep( &( lp->hcfCtx ))) {
- DBG_WARNING( DbgInfo, "WEP not supported on this device\n" );
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
-
- DBG_NOTICE( DbgInfo, "pointer: %p, length: %d, flags: %#x\n",
- keybuf, erq->length,
- erq->flags);
-
- /* Save state of Encryption switch */
- encryption_state = lp->EnableEncryption;
-
- /* Basic checking: do we have a key to set? */
- if((erq->length) != 0) {
- int index = ( erq->flags & IW_ENCODE_INDEX ) - 1;
- int tk = lp->TransmitKeyID - 1; // current key
-
-
- /* Check the size of the key */
- switch(erq->length) {
- case 0:
- break;
-
- case MIN_KEY_SIZE:
- case MAX_KEY_SIZE:
-
- /* Check the index */
- if(( index < 0 ) || ( index >= MAX_KEYS )) {
- index = tk;
- }
-
- /* Cleanup */
- memset( lp->DefaultKeys.key[index].key, 0, MAX_KEY_SIZE );
-
- /* Copy the key in the driver */
- memcpy( lp->DefaultKeys.key[index].key, keybuf, erq->length);
-
- /* Set the length */
- lp->DefaultKeys.key[index].len = erq->length;
-
- DBG_NOTICE( DbgInfo, "encoding.length: %d\n", erq->length );
- DBG_NOTICE( DbgInfo, "set key: %s(%d) [%d]\n", lp->DefaultKeys.key[index].key,
- lp->DefaultKeys.key[index].len, index );
-
- /* Enable WEP (if possible) */
- if(( index == tk ) && ( lp->DefaultKeys.key[tk].len > 0 )) {
- lp->EnableEncryption = 1;
- }
-
- break;
-
- default:
- DBG_WARNING( DbgInfo, "Invalid Key length\n" );
- ret = -EINVAL;
- goto out_unlock;
- }
- } else {
- int index = ( erq->flags & IW_ENCODE_INDEX ) - 1;
-
-
- /* Do we want to just set the current transmit key? */
- if(( index >= 0 ) && ( index < MAX_KEYS )) {
- DBG_NOTICE( DbgInfo, "index: %d; len: %d\n", index,
- lp->DefaultKeys.key[index].len );
-
- if( lp->DefaultKeys.key[index].len > 0 ) {
- lp->TransmitKeyID = index + 1;
- lp->EnableEncryption = 1;
- } else {
- DBG_WARNING( DbgInfo, "Problem setting the current TxKey\n" );
- ret = -EINVAL;
- }
- }
- }
-
- /* Read the flags */
- if( erq->flags & IW_ENCODE_DISABLED ) {
- lp->EnableEncryption = 0; // disable encryption
- } else {
- lp->EnableEncryption = 1;
- }
+ if (erq->flags & IW_ENCODE_DISABLED)
+ enable = false;
- if( erq->flags & IW_ENCODE_RESTRICTED ) {
- DBG_WARNING( DbgInfo, "IW_ENCODE_RESTRICTED invalid\n" );
- ret = -EINVAL; // Invalid
- }
+ wl_lock(lp, &flags);
- DBG_TRACE( DbgInfo, "encryption_state : %d\n", encryption_state );
- DBG_TRACE( DbgInfo, "lp->EnableEncryption : %d\n", lp->EnableEncryption );
- DBG_TRACE( DbgInfo, "erq->length : %d\n",
- erq->length);
- DBG_TRACE( DbgInfo, "erq->flags : 0x%x\n",
- erq->flags);
+ wl_act_int_off(lp);
- /* Write the changes to the card */
- if( ret == 0 ) {
- DBG_NOTICE( DbgInfo, "encrypt: %d, ID: %d\n", lp->EnableEncryption,
- lp->TransmitKeyID );
-
- if( lp->EnableEncryption == encryption_state ) {
- if( erq->length != 0 ) {
- /* Dynamic WEP key update */
- wl_set_wep_keys( lp );
- }
- } else {
- /* To switch encryption on/off, soft reset is required */
- wl_apply( lp );
- }
- }
+ ret = hermes_set_wep_keys(lp, key_idx, keybuf, erq->length,
+ enable, true);
/* Send an event that Encryption has been set */
- wl_wext_event_encode( dev );
+ if (ret == 0)
+ wl_wext_event_encode(dev);
-out_unlock:
-
- wl_act_int_on( lp );
+ wl_act_int_on(lp);
wl_unlock(lp, &flags);
out:
- DBG_LEAVE( DbgInfo );
+ DBG_LEAVE(DbgInfo);
return ret;
-} // wireless_set_encode
-/*============================================================================*/
-
-
-
+}
/*******************************************************************************
* wireless_get_encode()
@@ -2911,243 +3014,153 @@ out:
/*============================================================================*/
-
-static int hermes_set_key(ltv_t *ltv, int alg, int key_idx, u8 *addr,
- int set_tx, u8 *seq, u8 *key, size_t key_len)
+static void flush_tx(struct wl_private *lp)
{
- int ret = -EINVAL;
- // int count = 0;
- int buf_idx = 0;
- hcf_8 tsc[IW_ENCODE_SEQ_MAX_SIZE] =
- { 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };
-
- DBG_FUNC( "hermes_set_key" );
- DBG_ENTER( DbgInfo );
+ ltv_t ltv;
+ int count;
/*
- * Check the key index here; if 0, load as Pairwise Key, otherwise,
- * load as a group key. Note that for the Hermes, the RIDs for
- * group/pariwise keys are different from each other and different
- * than the default WEP keys as well.
- */
- switch (alg)
- {
- case IW_ENCODE_ALG_TKIP:
- DBG_TRACE( DbgInfo, "IW_ENCODE_ALG_TKIP: key(%d)\n", key_idx);
-#if 0
- /*
- * Make sure that there is no data queued up in the firmware
- * before setting the TKIP keys. If this check is not
- * performed, some data may be sent out with incorrect MIC
- * and cause synchronizarion errors with the AP
- */
- /* Check every 1ms for 100ms */
- for( count = 0; count < 100; count++ )
- {
- usleep( 1000 );
+ * Make sure that there is no data queued up in the firmware
+ * before setting the TKIP keys. If this check is not
+ * performed, some data may be sent out with incorrect MIC
+ * and cause synchronizarion errors with the AP
+ */
+ /* Check every 1ms for 100ms */
+ for (count = 0; count < 100; count++) {
+ udelay(1000);
+
+ ltv.len = 2;
+ ltv.typ = 0xFD91; /* This RID not defined in HCF yet!!! */
+ ltv.u.u16[0] = 0;
+
+ hcf_get_info(&(lp->hcfCtx), (LTVP)<v);
+
+ if (ltv.u.u16[0] == 0)
+ break;
+ }
- ltv.len = 2;
- ltv.typ = 0xFD91; // This RID not defined in HCF yet!!!
- ltv.u.u16[0] = 0;
+ if (count >= 100)
+ DBG_TRACE(DbgInfo, "Timed out waiting for TxQ flush!\n");
- wl_get_info( sock, <v, ifname );
+}
- if( ltv.u.u16[0] == 0 )
- {
- break;
- }
- }
+static int wireless_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
+{
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret;
+ int key_idx = (erq->flags & IW_ENCODE_INDEX) - 1;
+ ltv_t ltv;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)keybuf;
+ bool enable = true;
+ bool set_tx = false;
- if( count == 100 )
- {
- wpa_printf( MSG_DEBUG, "Timed out waiting for TxQ!" );
- }
-#endif
+ DBG_ENTER(DbgInfo);
- switch (key_idx) {
- case 0:
- ltv->len = 28;
- ltv->typ = CFG_ADD_TKIP_MAPPED_KEY;
+ if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
- /* Load the BSSID */
- memcpy(<v->u.u8[buf_idx], addr, ETH_ALEN);
- buf_idx += ETH_ALEN;
+ if (erq->flags & IW_ENCODE_DISABLED) {
+ ext->alg = IW_ENCODE_ALG_NONE;
+ enable = false;
+ }
- /* Load the TKIP key */
- memcpy(<v->u.u8[buf_idx], &key[0], 16);
- buf_idx += 16;
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ set_tx = true;
- /* Load the TSC */
- memcpy(<v->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE);
- buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+ wl_lock(lp, &flags);
- /* Load the RSC */
- memcpy(<v->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE);
- buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+ wl_act_int_off(lp);
- /* Load the TxMIC key */
- memcpy(<v->u.u8[buf_idx], &key[16], 8);
- buf_idx += 8;
+ memset(<v, 0, sizeof(ltv));
- /* Load the RxMIC key */
- memcpy(<v->u.u8[buf_idx], &key[24], 8);
+ switch (ext->alg) {
+ case IW_ENCODE_ALG_TKIP:
+ DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_TKIP: key(%d)\n", key_idx);
- ret = 0;
- break;
- case 1:
- case 2:
- case 3:
- ltv->len = 26;
- ltv->typ = CFG_ADD_TKIP_DEFAULT_KEY;
+ if (sizeof(ext->rx_seq) != 8) {
+ DBG_TRACE(DbgInfo, "rx_seq size mismatch\n");
+ DBG_LEAVE(DbgInfo);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
- /* Load the key Index */
- ltv->u.u16[buf_idx] = key_idx;
- /* If this is a Tx Key, set bit 8000 */
- if(set_tx)
- ltv->u.u16[buf_idx] |= 0x8000;
- buf_idx += 2;
+ ret = hermes_set_tkip_keys(<v, key_idx, ext->addr.sa_data,
+ set_tx,
+ ext->rx_seq, ext->key, ext->key_len);
- /* Load the RSC */
- memcpy(<v->u.u8[buf_idx], seq, IW_ENCODE_SEQ_MAX_SIZE);
- buf_idx += IW_ENCODE_SEQ_MAX_SIZE;
+ if (ret != 0) {
+ DBG_TRACE(DbgInfo, "hermes_set_tkip_keys returned != 0, key not set\n");
+ goto out_unlock;
+ }
- /* Load the TKIP, TxMIC, and RxMIC keys in one shot, because in
- CFG_ADD_TKIP_DEFAULT_KEY they are back-to-back */
- memcpy(<v->u.u8[buf_idx], key, key_len);
- buf_idx += key_len;
+ flush_tx(lp);
- /* Load the TSC */
- memcpy(<v->u.u8[buf_idx], tsc, IW_ENCODE_SEQ_MAX_SIZE);
+ lp->wext_enc = IW_ENCODE_ALG_TKIP;
- ltv->u.u16[0] = CNV_INT_TO_LITTLE(ltv->u.u16[0]);
+ /* Write the key */
+ ret = hcf_put_info(&(lp->hcfCtx), (LTVP)<v);
+ break;
- ret = 0;
- break;
- default:
- break;
+ case IW_ENCODE_ALG_WEP:
+ DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_WEP: key(%d)\n", key_idx);
+
+ if (erq->flags & IW_ENCODE_RESTRICTED) {
+ DBG_WARNING(DbgInfo, "IW_ENCODE_RESTRICTED invalid\n");
+ ret = -EINVAL;
+ goto out_unlock;
}
- break;
+ ret = hermes_set_wep_keys(lp, key_idx, ext->key, ext->key_len,
+ enable, set_tx);
- case IW_ENCODE_ALG_WEP:
- DBG_TRACE( DbgInfo, "IW_ENCODE_ALG_WEP: key(%d)\n", key_idx);
break;
case IW_ENCODE_ALG_CCMP:
- DBG_TRACE( DbgInfo, "IW_ENCODE_ALG_CCMP: key(%d)\n", key_idx);
+ DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_CCMP: key(%d)\n", key_idx);
+ ret = -EOPNOTSUPP;
break;
case IW_ENCODE_ALG_NONE:
- DBG_TRACE( DbgInfo, "IW_ENCODE_ALG_NONE: key(%d)\n", key_idx);
- switch (key_idx) {
- case 0:
- if (memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) {
- //if (addr != NULL) {
- ltv->len = 7;
- ltv->typ = CFG_REMOVE_TKIP_MAPPED_KEY;
- memcpy(<v->u.u8[0], addr, ETH_ALEN);
- ret = 0;
- }
- break;
- case 1:
- case 2:
- case 3:
- /* Clear the Group TKIP keys by index */
- ltv->len = 2;
- ltv->typ = CFG_REMOVE_TKIP_DEFAULT_KEY;
- ltv->u.u16[0] = key_idx;
-
+ DBG_TRACE(DbgInfo, "IW_ENCODE_ALG_NONE: key(%d)\n", key_idx);
+
+ if (lp->wext_enc == IW_ENCODE_ALG_TKIP) {
+ ret = hermes_clear_tkip_keys(<v, key_idx,
+ ext->addr.sa_data);
+ flush_tx(lp);
+ lp->wext_enc = IW_ENCODE_ALG_NONE;
+ ret = hcf_put_info(&(lp->hcfCtx), (LTVP)<v);
+
+ } else if (lp->wext_enc == IW_ENCODE_ALG_WEP) {
+ ret = hermes_set_wep_keys(lp, key_idx,
+ ext->key, ext->key_len,
+ false, false);
+ } else {
ret = 0;
- break;
- default:
- break;
}
+
break;
+
default:
DBG_TRACE( DbgInfo, "IW_ENCODE_??: key(%d)\n", key_idx);
+ ret = -EOPNOTSUPP;
break;
}
- DBG_LEAVE( DbgInfo );
- return ret;
-} // hermes_set_key
-/*============================================================================*/
-
-
-
-static int wireless_set_encodeext (struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *keybuf)
-{
- struct wl_private *lp = wl_priv(dev);
- unsigned long flags;
- int ret;
- int key_idx = (erq->flags&IW_ENCODE_INDEX) - 1;
- ltv_t ltv;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)keybuf;
-
- DBG_FUNC( "wireless_set_encodeext" );
- DBG_ENTER( DbgInfo );
-
- if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
- ret = -EBUSY;
- goto out;
- }
-
- if (sizeof(ext->rx_seq) != 8) {
- DBG_TRACE(DbgInfo, "rz_seq size mismatch\n");
- DBG_LEAVE(DbgInfo);
- return -EINVAL;
- }
-
- /* Handle WEP keys via the old set encode procedure */
- if(ext->alg == IW_ENCODE_ALG_WEP) {
- struct iw_point wep_erq;
- char *wep_keybuf;
-
- /* Build request structure */
- wep_erq.flags = erq->flags; // take over flags with key index
- wep_erq.length = ext->key_len; // take length from extended key info
- wep_keybuf = ext->key; // pointer to the key text
-
- /* Call wireless_set_encode tot handle the WEP key */
- ret = wireless_set_encode(dev, info, &wep_erq, wep_keybuf);
- goto out;
- }
-
- /* Proceed for extended encode functions for WAP and NONE */
- wl_lock( lp, &flags );
-
- wl_act_int_off( lp );
-
- memset(<v, 0, sizeof(ltv));
- ret = hermes_set_key(<v, ext->alg, key_idx, ext->addr.sa_data,
- ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
- ext->rx_seq, ext->key, ext->key_len);
-
- if (ret != 0) {
- DBG_TRACE( DbgInfo, "hermes_set_key returned != 0, key not set\n");
- goto out_unlock;
- }
-
- /* Put the key in HCF */
- ret = hcf_put_info(&(lp->hcfCtx), (LTVP)<v);
-
out_unlock:
- if(ret == HCF_SUCCESS) {
- DBG_TRACE( DbgInfo, "Put key info succes\n");
- } else {
- DBG_TRACE( DbgInfo, "Put key info failed, key not set\n");
- }
- wl_act_int_on( lp );
+ wl_act_int_on(lp);
wl_unlock(lp, &flags);
out:
- DBG_LEAVE( DbgInfo );
+ DBG_LEAVE(DbgInfo);
return ret;
-} // wireless_set_encodeext
+}
/*============================================================================*/
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 6/7] staging: wlags49_h2: Fixup IW_AUTH handling
2011-10-09 11:11 [PATCH 0/7] Enable WPA with wlags49_h2 David Kilroy
` (3 preceding siblings ...)
2011-10-09 11:11 ` [PATCH 5/7] staging: wlags49_h2: Make key setting more reliable David Kilroy
@ 2011-10-09 11:11 ` David Kilroy
2011-10-09 11:11 ` [PATCH 7/7] staging: wlags49_h2: Fixup SIOCSIWGENIE David Kilroy
[not found] ` <1318158697-15979-4-git-send-email-kilroyd@googlemail.com>
6 siblings, 0 replies; 9+ messages in thread
From: David Kilroy @ 2011-10-09 11:11 UTC (permalink / raw)
To: linux-kernel, greg; +Cc: pe1dnn, David Kilroy
Handle more cases in IW_AUTH.
Avoid reporting errors (invalid parameter) on operations that we
can't do anything with.
Return -EINPROGRESS from some operations to get wpa_supplicant to
batch and commit changes.
In other operations apply the changes immediately.
Avoid writing WEP keys from the commit handler when WEP is not
being used.
Accept WPA_VERSION_DISABLED, which is received from wpa_supplicant
during WEP.
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
drivers/staging/wlags49_h2/wl_main.c | 6 +-
drivers/staging/wlags49_h2/wl_wext.c | 179 ++++++++++++++++++++--------------
2 files changed, 109 insertions(+), 76 deletions(-)
diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c
index 6d45ab3..483eee1 100644
--- a/drivers/staging/wlags49_h2/wl_main.c
+++ b/drivers/staging/wlags49_h2/wl_main.c
@@ -1993,8 +1993,10 @@ int wl_put_ltv( struct wl_private *lp )
lp->ltvRecord.typ = CFG_SET_WPA_AUTH_KEY_MGMT_SUITE;
lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->AuthKeyMgmtSuite );
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
- /* WEP Keys */
- wl_set_wep_keys( lp );
+
+ /* If WEP (or no) keys are being used, write (or clear) them */
+ if (lp->wext_enc != IW_ENCODE_ALG_TKIP)
+ wl_set_wep_keys(lp);
/* Country Code */
/* countryInfo, ltvCountryInfo, CFG_CNF_COUNTRY_INFO */
diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c
index 567a0dc..9884320 100644
--- a/drivers/staging/wlags49_h2/wl_wext.c
+++ b/drivers/staging/wlags49_h2/wl_wext.c
@@ -2894,7 +2894,24 @@ out:
} // wireless_get_scan
/*============================================================================*/
-
+#if DBG
+static const char * const auth_names[] = {
+ "IW_AUTH_WPA_VERSION",
+ "IW_AUTH_CIPHER_PAIRWISE",
+ "IW_AUTH_CIPHER_GROUP",
+ "IW_AUTH_KEY_MGMT",
+ "IW_AUTH_TKIP_COUNTERMEASURES",
+ "IW_AUTH_DROP_UNENCRYPTED",
+ "IW_AUTH_80211_AUTH_ALG",
+ "IW_AUTH_WPA_ENABLED",
+ "IW_AUTH_RX_UNENCRYPTED_EAPOL",
+ "IW_AUTH_ROAMING_CONTROL",
+ "IW_AUTH_PRIVACY_INVOKED",
+ "IW_AUTH_CIPHER_GROUP_MGMT",
+ "IW_AUTH_MFP",
+ "Unsupported"
+};
+#endif
static int wireless_set_auth(struct net_device *dev,
struct iw_request_info *info,
@@ -2902,14 +2919,15 @@ static int wireless_set_auth(struct net_device *dev,
{
struct wl_private *lp = wl_priv(dev);
unsigned long flags;
- int ret;
- int iwa_idx = data->flags & IW_AUTH_INDEX;
- int iwa_val = data->value;
+ ltv_t ltv;
+ int ret;
+ int iwa_idx = data->flags & IW_AUTH_INDEX;
+ int iwa_val = data->value;
DBG_FUNC( "wireless_set_auth" );
DBG_ENTER( DbgInfo );
- if(lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
ret = -EBUSY;
goto out;
}
@@ -2918,89 +2936,102 @@ static int wireless_set_auth(struct net_device *dev,
wl_act_int_off( lp );
+ if (iwa_idx > IW_AUTH_MFP)
+ iwa_idx = IW_AUTH_MFP + 1;
+ DBG_TRACE(DbgInfo, "%s\n", auth_names[iwa_idx]);
switch (iwa_idx) {
- case IW_AUTH_WPA_VERSION:
- DBG_TRACE( DbgInfo, "IW_AUTH_WPA_VERSION\n");
- /* We do support WPA only; how should DISABLED be treated? */
- if (iwa_val == IW_AUTH_WPA_VERSION_WPA)
- ret = 0;
- else
- ret = -EINVAL;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- DBG_TRACE( DbgInfo, "IW_AUTH_WPA_ENABLED: val = %d\n", iwa_val);
- if (iwa_val)
- lp->EnableEncryption = 2;
- else
- lp->EnableEncryption = 0;
+ case IW_AUTH_WPA_VERSION:
+ /* We do support WPA */
+ if ((iwa_val == IW_AUTH_WPA_VERSION_WPA) ||
+ (iwa_val == IW_AUTH_WPA_VERSION_DISABLED))
ret = 0;
- break;
+ else
+ ret = -EINVAL;
+ break;
- case IW_AUTH_TKIP_COUNTERMEASURES:
- DBG_TRACE( DbgInfo, "IW_AUTH_TKIP_COUNTERMEASURES\n");
- lp->driverEnable = !iwa_val;
- if(lp->driverEnable)
- hcf_cntl(&(lp->hcfCtx), HCF_CNTL_ENABLE | HCF_PORT_0);
- else
- hcf_cntl(&(lp->hcfCtx), HCF_CNTL_DISABLE | HCF_PORT_0);
- ret = 0;
- break;
+ case IW_AUTH_WPA_ENABLED:
+ DBG_TRACE(DbgInfo, "val = %d\n", iwa_val);
+ if (iwa_val)
+ lp->EnableEncryption = 2;
+ else
+ lp->EnableEncryption = 0;
- case IW_AUTH_DROP_UNENCRYPTED:
- DBG_TRACE( DbgInfo, "IW_AUTH_DROP_UNENCRYPTED\n");
- /* We do not actually do anything here, just to silence
- * wpa_supplicant */
- ret = 0;
- break;
+ /* Write straight to the card */
+ ltv.len = 2;
+ ltv.typ = CFG_CNF_ENCRYPTION;
+ ltv.u.u16[0] = cpu_to_le16(lp->EnableEncryption);
+ ret = hcf_put_info(&lp->hcfCtx, (LTVP)<v);
- case IW_AUTH_CIPHER_PAIRWISE:
- DBG_TRACE( DbgInfo, "IW_AUTH_CIPHER_PAIRWISE\n");
- /* not implemented, return an error */
- ret = -EINVAL;
- break;
+ break;
- case IW_AUTH_CIPHER_GROUP:
- DBG_TRACE( DbgInfo, "IW_AUTH_CIPHER_GROUP\n");
- /* not implemented, return an error */
- ret = -EINVAL;
- break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
- case IW_AUTH_KEY_MGMT:
- DBG_TRACE( DbgInfo, "IW_AUTH_KEY_MGMT\n");
- /* not implemented, return an error */
- ret = -EINVAL;
- break;
+ /* Immediately disable card */
+ lp->driverEnable = !iwa_val;
+ if (lp->driverEnable)
+ hcf_cntl(&(lp->hcfCtx), HCF_CNTL_ENABLE | HCF_PORT_0);
+ else
+ hcf_cntl(&(lp->hcfCtx), HCF_CNTL_DISABLE | HCF_PORT_0);
+ ret = 0;
+ break;
- case IW_AUTH_80211_AUTH_ALG:
- DBG_TRACE( DbgInfo, "IW_AUTH_80211_AUTH_ALG\n");
- /* not implemented, return an error */
+ case IW_AUTH_MFP:
+ /* Management Frame Protection not supported.
+ * Only fail if set to required.
+ */
+ if (iwa_val == IW_AUTH_MFP_REQUIRED)
ret = -EINVAL;
- break;
+ else
+ ret = 0;
+ break;
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- DBG_TRACE( DbgInfo, "IW_AUTH_RX_UNENCRYPTED_EAPOL\n");
- /* not implemented, return an error */
- ret = -EINVAL;
- break;
+ case IW_AUTH_KEY_MGMT:
- case IW_AUTH_ROAMING_CONTROL:
- DBG_TRACE( DbgInfo, "IW_AUTH_ROAMING_CONTROL\n");
- /* not implemented, return an error */
- ret = -EINVAL;
- break;
+ /* Record required management suite.
+ * Will take effect on next commit */
+ if (iwa_val != 0)
+ lp->AuthKeyMgmtSuite = 4;
+ else
+ lp->AuthKeyMgmtSuite = 0;
- case IW_AUTH_PRIVACY_INVOKED:
- DBG_TRACE( DbgInfo, "IW_AUTH_PRIVACY_INVOKED\n");
- /* not implemented, return an error */
- ret = -EINVAL;
- break;
+ ret = -EINPROGRESS;
+ break;
- default:
- DBG_TRACE( DbgInfo, "IW_AUTH_?? (%d) unknown\n", iwa_idx);
- /* return an error */
+ case IW_AUTH_80211_AUTH_ALG:
+
+ /* Just record whether open or shared is required.
+ * Will take effect on next commit */
+ ret = -EINPROGRESS;
+
+ if (iwa_val & IW_AUTH_ALG_SHARED_KEY)
+ lp->authentication = 1;
+ else if (iwa_val & IW_AUTH_ALG_OPEN_SYSTEM)
+ lp->authentication = 0;
+ else
ret = -EINVAL;
- break;
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ /* Only needed for AP */
+ lp->ExcludeUnencrypted = iwa_val;
+ ret = -EINPROGRESS;
+ break;
+
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ /* Not used. May need to do something with
+ * CIPHER_PAIRWISE and CIPHER_GROUP*/
+ ret = -EINPROGRESS;
+ break;
+
+ default:
+ DBG_TRACE(DbgInfo, "IW_AUTH_?? (%d) unknown\n", iwa_idx);
+ /* return an error */
+ ret = -EOPNOTSUPP;
+ break;
}
wl_act_int_on( lp );
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread