|
@@ -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
|
|
|
+}
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|