summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>2011-06-01 14:40:13 +0200
committerMathieu J. Poirier <mathieu.poirier@linaro.org>2011-11-10 11:04:46 -0700
commit32f37a6a0ff0e188e4f273c6af080587cad70a8b (patch)
tree118539ba6cb9d03bc354a98cfcb1cc6c6bd4d65f
parent0e3c385f604dbd9aba12247f127d12daea6d47bc (diff)
wireless-next: WAPI support for hardware-accelerated drivers
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/24551 Tested-by: Janusz DZIEDZIC <janusz.dziedzic@tieto.com> Reviewed-by: Janusz DZIEDZIC <janusz.dziedzic@tieto.com> Change-Id: I0300854865f8de07413164fd4461a9c8aae5dff3 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/26976 Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Tested-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33473 Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
-rw-r--r--include/linux/ieee80211.h3
-rw-r--r--include/linux/nl80211.h5
-rw-r--r--include/linux/wireless.h6
-rw-r--r--net/mac80211/Makefile1
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/key.c4
-rw-r--r--net/mac80211/key.h2
-rw-r--r--net/mac80211/main.c1
-rw-r--r--net/mac80211/rx.c4
-rw-r--r--net/mac80211/tx.c6
-rw-r--r--net/mac80211/wapi.c71
-rw-r--r--net/mac80211/wapi.h27
-rw-r--r--net/wireless/nl80211.c13
-rw-r--r--net/wireless/util.c8
-rw-r--r--net/wireless/wext-compat.c39
15 files changed, 180 insertions, 12 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 54c87896087..a721171ac77 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1316,6 +1316,7 @@ enum ieee80211_key_len {
WLAN_KEY_LEN_CCMP = 16,
WLAN_KEY_LEN_TKIP = 32,
WLAN_KEY_LEN_AES_CMAC = 16,
+ WLAN_KEY_LEN_SMS4 = 32,
};
/**
@@ -1442,12 +1443,14 @@ enum ieee80211_sa_query_action {
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
+#define WLAN_CIPHER_SUITE_SMS4 0x000FAC07
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
#define WLAN_AKM_SUITE_PSK 0x000FAC02
#define WLAN_AKM_SUITE_SAE 0x000FAC08
#define WLAN_AKM_SUITE_FT_OVER_SAE 0x000FAC09
+#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC03
#define WLAN_MAX_KEY_LEN 32
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 8ad70dcac3f..9d0c8ac8d6b 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1266,8 +1266,8 @@ enum nl80211_attrs {
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
#define NL80211_HT_CAPABILITY_LEN 26
-#define NL80211_MAX_NR_CIPHER_SUITES 5
-#define NL80211_MAX_NR_AKM_SUITES 2
+#define NL80211_MAX_NR_CIPHER_SUITES 6
+#define NL80211_MAX_NR_AKM_SUITES 3
/**
* enum nl80211_iftype - (virtual) interface types
@@ -2063,6 +2063,7 @@ enum nl80211_mfp {
enum nl80211_wpa_versions {
NL80211_WPA_VERSION_1 = 1 << 0,
NL80211_WPA_VERSION_2 = 1 << 1,
+ NL80211_WAPI_VERSION_1 = 1 << 2,
};
/**
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 4395b28bb86..f3e2375ee24 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -586,6 +586,7 @@
#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001
#define IW_AUTH_WPA_VERSION_WPA 0x00000002
#define IW_AUTH_WPA_VERSION_WPA2 0x00000004
+#define IW_AUTH_WPA_VERSION_WAPI 0x00000008
/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT
* values (bit field) */
@@ -595,10 +596,12 @@
#define IW_AUTH_CIPHER_CCMP 0x00000008
#define IW_AUTH_CIPHER_WEP104 0x00000010
#define IW_AUTH_CIPHER_AES_CMAC 0x00000020
+#define IW_AUTH_CIPHER_SMS4 0x00000040
/* IW_AUTH_KEY_MGMT values (bit field) */
#define IW_AUTH_KEY_MGMT_802_1X 1
#define IW_AUTH_KEY_MGMT_PSK 2
+#define IW_AUTH_KEY_MGMT_WAPI_PSK 4
/* IW_AUTH_80211_AUTH_ALG values (bit field) */
#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001
@@ -624,6 +627,7 @@
#define IW_ENCODE_ALG_CCMP 3
#define IW_ENCODE_ALG_PMK 4
#define IW_ENCODE_ALG_AES_CMAC 5
+#define IW_ENCODE_ALG_SMS4 6
/* struct iw_encode_ext ->ext_flags */
#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001
#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002
@@ -644,6 +648,8 @@
#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004
#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008
#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+#define IW_ENC_CAPA_WAPI 0x00000020
+#define IW_ENC_CAPA_CIPHER_SMS4 0x00000040
/* Event capability macros - in (struct iw_range *)->event_capa
* Because we have more than 32 possible events, we use an array of
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index fdb54e61d63..ed3dd35f708 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -6,6 +6,7 @@ mac80211-y := \
sta_info.o \
wep.o \
wpa.o \
+ wapi.o \
scan.o offchannel.o \
ht.o agg-tx.o agg-rx.o \
ibss.o \
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e34b986b472..1d4a81f4c1b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -42,7 +42,7 @@ struct ieee80211_local;
#define TOTAL_MAX_TX_BUFFER 512
/* Required encryption head and tailroom */
-#define IEEE80211_ENCRYPT_HEADROOM 8
+#define IEEE80211_ENCRYPT_HEADROOM 20
#define IEEE80211_ENCRYPT_TAILROOM 18
/* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 5150c6d11b5..1e8bf5d8298 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -409,6 +409,10 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
return ERR_PTR(err);
}
break;
+ case WLAN_CIPHER_SUITE_SMS4:
+ key->conf.iv_len = WAPI_IV_LEN;
+ key->conf.icv_len = WAPI_ICV_LEN;
+ break;
}
memcpy(key->conf.key, key_data, key_len);
INIT_LIST_HEAD(&key->list);
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 7d4e31f037d..455f1febd5b 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -29,6 +29,8 @@
#define TKIP_IV_LEN 8
#define TKIP_ICV_LEN 4
#define CMAC_PN_LEN 6
+#define WAPI_IV_LEN 18
+#define WAPI_ICV_LEN 16
#define NUM_RX_DATA_QUEUES 16
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index acb44230b25..64bb140bb67 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -695,6 +695,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_SMS4,
/* keep last -- depends on hw flags! */
WLAN_CIPHER_SUITE_AES_CMAC
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fe2c2a71779..a86e0df2fe8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -27,6 +27,7 @@
#include "wpa.h"
#include "tkip.h"
#include "wme.h"
+#include "wapi.h"
/*
* monitor mode reception
@@ -1053,6 +1054,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
case WLAN_CIPHER_SUITE_AES_CMAC:
result = ieee80211_crypto_aes_cmac_decrypt(rx);
break;
+ case WLAN_CIPHER_SUITE_SMS4:
+ result = ieee80211_crypto_wapi_decrypt(rx);
+ break;
default:
/*
* We can reach here only with HW-only algorithms
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 8cb0d2d0ac6..b80a0ff095e 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -30,6 +30,7 @@
#include "mesh.h"
#include "wep.h"
#include "wpa.h"
+#include "wapi.h"
#include "wme.h"
#include "rate.h"
@@ -587,6 +588,11 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
if (!ieee80211_is_mgmt(hdr->frame_control))
tx->key = NULL;
break;
+
+ case WLAN_CIPHER_SUITE_SMS4:
+ if (tx->ethertype == ETH_P_WAPI)
+ tx->key = NULL;
+ break;
}
if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED))
diff --git a/net/mac80211/wapi.c b/net/mac80211/wapi.c
new file mode 100644
index 00000000000..4780808ad2f
--- /dev/null
+++ b/net/mac80211/wapi.c
@@ -0,0 +1,71 @@
+/*
+ * Software WAPI encryption implementation
+ * Copyright (c) 2011, ST-Ericsson
+ * Author: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/compiler.h>
+#include <linux/crc32.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "wapi.h"
+
+
+static int ieee80211_wapi_decrypt(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_key *key)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ int data_len;
+
+ if (!(status->flag & RX_FLAG_DECRYPTED)) {
+ /* TODO - SMS4 decryption for firmware without
+ * SMS4 support */
+ return RX_DROP_UNUSABLE;
+ }
+
+
+ data_len = skb->len - hdrlen - WAPI_IV_LEN - WAPI_ICV_LEN;
+ if (data_len < 0)
+ return RX_DROP_UNUSABLE;
+
+ /* Trim ICV */
+ skb_trim(skb, skb->len - WAPI_ICV_LEN);
+
+ /* Remove IV */
+ memmove(skb->data + WAPI_IV_LEN, skb->data, hdrlen);
+ skb_pull(skb, WAPI_IV_LEN);
+
+ return RX_CONTINUE;
+}
+
+ieee80211_rx_result
+ieee80211_crypto_wapi_decrypt(struct ieee80211_rx_data *rx)
+{
+ struct sk_buff *skb = rx->skb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (!ieee80211_is_data(hdr->frame_control))
+ return RX_CONTINUE;
+
+ if (ieee80211_wapi_decrypt(rx->local, rx->skb, rx->key))
+ return RX_DROP_UNUSABLE;
+
+ return RX_CONTINUE;
+}
diff --git a/net/mac80211/wapi.h b/net/mac80211/wapi.h
new file mode 100644
index 00000000000..f06eee0cb7c
--- /dev/null
+++ b/net/mac80211/wapi.h
@@ -0,0 +1,27 @@
+/*
+ * Software WAPI encryption implementation
+ * Copyright (c) 2011, ST-Ericsson
+ * Author: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef WAPI_H
+#define WAPI_H
+
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include "ieee80211_i.h"
+#include "key.h"
+
+#ifndef ETH_P_WAPI
+#define ETH_P_WAPI 0x88B4
+#endif
+
+
+ieee80211_rx_result
+ieee80211_crypto_wapi_decrypt(struct ieee80211_rx_data *rx);
+
+#endif /* WAPI_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ea40d540a99..39180512bfc 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -92,7 +92,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
- [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+ [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
[NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
@@ -185,7 +185,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
[NL80211_KEY_IDX] = { .type = NLA_U8 },
[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
- [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+ [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
[NL80211_KEY_TYPE] = { .type = NLA_U32 },
@@ -3932,13 +3932,15 @@ static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
static bool nl80211_valid_wpa_versions(u32 wpa_versions)
{
return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
- NL80211_WPA_VERSION_2));
+ NL80211_WPA_VERSION_2 |
+ NL80211_WAPI_VERSION_1));
}
static bool nl80211_valid_akm_suite(u32 akm)
{
return akm == WLAN_AKM_SUITE_8021X ||
- akm == WLAN_AKM_SUITE_PSK;
+ akm == WLAN_AKM_SUITE_PSK ||
+ akm == WLAN_AKM_SUITE_WAPI_PSK;
}
static bool nl80211_valid_cipher_suite(u32 cipher)
@@ -3947,7 +3949,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher)
cipher == WLAN_CIPHER_SUITE_WEP104 ||
cipher == WLAN_CIPHER_SUITE_TKIP ||
cipher == WLAN_CIPHER_SUITE_CCMP ||
- cipher == WLAN_CIPHER_SUITE_AES_CMAC;
+ cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+ cipher == WLAN_CIPHER_SUITE_SMS4;
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index be75a3a0424..22cf49a59b5 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -199,6 +199,10 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
if (params->key_len != WLAN_KEY_LEN_AES_CMAC)
return -EINVAL;
break;
+ case WLAN_CIPHER_SUITE_SMS4:
+ if (params->key_len != WLAN_KEY_LEN_SMS4)
+ return -EINVAL;
+ break;
default:
/*
* We don't know anything about this algorithm,
@@ -222,6 +226,10 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
if (params->seq_len != 6)
return -EINVAL;
break;
+ case WLAN_CIPHER_SUITE_SMS4:
+ if (params->seq_len != 16)
+ return -EINVAL;
+ break;
}
}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 0bf169bb770..ac23c31c82c 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -214,6 +214,11 @@ int cfg80211_wext_giwrange(struct net_device *dev,
range->encoding_size[range->num_encoding_sizes++] =
WLAN_KEY_LEN_WEP104;
break;
+
+ case WLAN_CIPHER_SUITE_SMS4:
+ range->enc_capa |= (IW_ENC_CAPA_CIPHER_SMS4 |
+ IW_ENC_CAPA_WAPI);
+ break;
}
}
@@ -699,6 +704,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
case IW_ENCODE_ALG_AES_CMAC:
cipher = WLAN_CIPHER_SUITE_AES_CMAC;
break;
+ case IW_ENCODE_ALG_SMS4:
+ cipher = WLAN_CIPHER_SUITE_SMS4;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -959,17 +967,21 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
{
if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
IW_AUTH_WPA_VERSION_WPA2|
+ IW_AUTH_WPA_VERSION_WAPI|
IW_AUTH_WPA_VERSION_DISABLED))
return -EINVAL;
if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) &&
(wpa_versions & (IW_AUTH_WPA_VERSION_WPA|
- IW_AUTH_WPA_VERSION_WPA2)))
+ IW_AUTH_WPA_VERSION_WPA2|
+ IW_AUTH_WPA_VERSION_WAPI)))
return -EINVAL;
if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED)
wdev->wext.connect.crypto.wpa_versions &=
- ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2);
+ ~(NL80211_WPA_VERSION_1|
+ NL80211_WPA_VERSION_2|
+ NL80211_WAPI_VERSION_1);
if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
wdev->wext.connect.crypto.wpa_versions |=
@@ -979,6 +991,10 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
wdev->wext.connect.crypto.wpa_versions |=
NL80211_WPA_VERSION_2;
+ if (wpa_versions & IW_AUTH_WPA_VERSION_WAPI)
+ wdev->wext.connect.crypto.wpa_versions |=
+ NL80211_WAPI_VERSION_1;
+
return 0;
}
@@ -1001,6 +1017,9 @@ static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
WLAN_CIPHER_SUITE_AES_CMAC;
else if (cipher & IW_AUTH_CIPHER_NONE)
wdev->wext.connect.crypto.cipher_group = 0;
+ else if (cipher & IW_AUTH_CIPHER_SMS4)
+ wdev->wext.connect.crypto.cipher_group =
+ WLAN_CIPHER_SUITE_SMS4;
else
return -EINVAL;
@@ -1037,7 +1056,12 @@ static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher)
nr_ciphers++;
}
- BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5);
+ if (cipher & IW_AUTH_CIPHER_SMS4) {
+ ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_SMS4;
+ nr_ciphers++;
+ }
+
+ BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 6);
wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers;
@@ -1050,7 +1074,8 @@ static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
int nr_akm_suites = 0;
if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X |
- IW_AUTH_KEY_MGMT_PSK))
+ IW_AUTH_KEY_MGMT_PSK |
+ IW_AUTH_KEY_MGMT_WAPI_PSK))
return -EINVAL;
if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) {
@@ -1065,6 +1090,12 @@ static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
nr_akm_suites++;
}
+ if (key_mgt & IW_AUTH_KEY_MGMT_WAPI_PSK) {
+ wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
+ WLAN_AKM_SUITE_WAPI_PSK;
+ nr_akm_suites++;
+ }
+
wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites;
return 0;