[PATCH 4/4] Initial hardware encryption implementation
Eugene Krasnikov
k.eugene.e at gmail.com
Mon May 27 07:39:52 EDT 2013
To enable HW encryption first driver must send
set_stakey and set_bsskey. After that for each
data frame set encryption flag inside BD.
Signed-off-by: Eugene Krasnikov <k.eugene.e at gmail.com>
---
dxe.c | 15 ++++++++++---
dxe.h | 6 ++++-
main.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
smd.c | 52 +++++++++++++++++++++++++++++++++++++++++++
smd.h | 11 ++++++++-
txrx.c | 26 +++++++++++++++++-----
txrx.h | 7 ++++--
wcn36xx.h | 5 +++++
8 files changed, 183 insertions(+), 15 deletions(-)
diff --git a/dxe.c b/dxe.c
index a5eba6c..6c7d290 100644
--- a/dxe.c
+++ b/dxe.c
@@ -429,7 +429,11 @@ void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn)
kfree(wcn->mgmt_mem_pool.bitmap);
}
-int wcn36xx_dxe_tx(struct wcn36xx *wcn, struct sk_buff *skb, u8 broadcast, bool is_high)
+int wcn36xx_dxe_tx(struct wcn36xx *wcn,
+ struct sk_buff *skb,
+ u8 broadcast,
+ bool is_high,
+ u32 header_len)
{
struct wcn36xx_dxe_ctl *cur_dxe_ctl = NULL;
struct wcn36xx_dxe_desc *cur_dxe_desc = NULL;
@@ -444,8 +448,13 @@ int wcn36xx_dxe_tx(struct wcn36xx *wcn, struct sk_buff *skb, u8 broadcast, bool
cur_ch = &wcn->dxe_tx_l_ch;
}
- wcn36xx_prepare_tx_bd(mem_pool->virt_addr, skb->len);
- wcn36xx_fill_tx_bd(wcn, mem_pool->virt_addr, broadcast);
+ wcn36xx_prepare_tx_bd(mem_pool->virt_addr, skb->len, header_len);
+ if (!is_high && WCN36XX_BSS_KEY == wcn->en_state) {
+ wcn36xx_dbg(WCN36XX_DBG_DXE, "DXE Encription enabled");
+ wcn36xx_fill_tx_bd(wcn, mem_pool->virt_addr, broadcast, 0);
+ } else {
+ wcn36xx_fill_tx_bd(wcn, mem_pool->virt_addr, broadcast, 1);
+ }
cur_dxe_ctl = cur_ch->head_blk_ctl;
cur_dxe_desc = cur_dxe_ctl->desc;
diff --git a/dxe.h b/dxe.h
index f67a89d..667bcac 100644
--- a/dxe.h
+++ b/dxe.h
@@ -236,5 +236,9 @@ void wcn36xx_dxe_free_ctl_blks(struct wcn36xx *wcn);
int wcn36xx_dxe_init(struct wcn36xx *wcn);
void wcn36xx_dxe_deinit(struct wcn36xx *wcn);
int wcn36xx_dxe_init_channels(struct wcn36xx *wcn);
-int wcn36xx_dxe_tx(struct wcn36xx *wcn, struct sk_buff *skb, u8 broadcast, bool is_high);
+int wcn36xx_dxe_tx(struct wcn36xx *wcn,
+ struct sk_buff *skb,
+ u8 broadcast,
+ bool is_high,
+ u32 header_len);
#endif /* _DXE_H_ */
diff --git a/main.c b/main.c
index 7db3a8e..64bb3a5 100644
--- a/main.c
+++ b/main.c
@@ -178,6 +178,7 @@ static void wcn36xx_tx(struct ieee80211_hw *hw,
{
struct ieee80211_mgmt *mgmt;
bool high, bcast;
+ u32 header_len = 0;
mgmt = (struct ieee80211_mgmt *)skb->data;
@@ -194,7 +195,69 @@ static void wcn36xx_tx(struct ieee80211_hw *hw,
wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "", skb->data, skb->len);
- wcn36xx_dxe_tx(hw->priv, skb, bcast, high);
+ header_len = ieee80211_is_data_qos(mgmt->frame_control) ?
+ sizeof(struct ieee80211_qos_hdr) :
+ sizeof(struct ieee80211_hdr_3addr);
+ wcn36xx_dxe_tx(hw->priv, skb, bcast, high, header_len);
+}
+
+static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key_conf)
+{
+ struct wcn36xx *wcn = hw->priv;
+ int ret = 0;
+ enum ani_ed_type enc_type;
+ wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 set key");
+ wcn36xx_dbg(WCN36XX_DBG_MAC, "Key: cmd=0x%x algo:0x%x, "
+ "id:%d, len:%d flags 0x%x",
+ cmd, key_conf->cipher, key_conf->keyidx,
+ key_conf->keylen, key_conf->flags);
+ wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "KEY: ",
+ key_conf->key,
+ key_conf->keylen);
+
+ switch (cmd) {
+ case SET_KEY:
+ switch (key_conf->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ enc_type = WCN36XX_HAL_ED_CCMP;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ enc_type = WCN36XX_HAL_ED_TKIP;
+ break;
+ default:
+ wcn36xx_error("Unsupported key type 0x%x",
+ key_conf->cipher);
+ ret = -EOPNOTSUPP;
+ goto out;
+ break;
+ }
+ break;
+ default:
+ wcn36xx_error("Unsupported key cmd 0x%x", cmd);
+ ret = -EOPNOTSUPP;
+ goto out;
+ break;
+ }
+
+ if (WCN36XX_STA_KEY == wcn->en_state) {
+ wcn36xx_smd_set_stakey(wcn,
+ enc_type,
+ key_conf->keyidx,
+ key_conf->keylen,
+ key_conf->key);
+ wcn->en_state = WCN36XX_BSS_KEY;
+ } else {
+ wcn36xx_smd_set_bsskey(wcn,
+ enc_type,
+ key_conf->keyidx,
+ key_conf->keylen,
+ key_conf->key);
+ }
+out:
+ return ret;
}
static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw)
@@ -258,7 +321,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->aid);
wcn->aid = bss_conf->aid;
-
+ wcn->en_state = WCN36XX_STA_KEY;
wcn36xx_smd_set_link_st(wcn, (u8*)bss_conf->bssid,
vif->addr,
WCN36XX_HAL_LINK_POSTASSOC_STATE);
@@ -274,6 +337,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
vif->addr,
bss_conf->aid);
wcn->aid = 0;
+ wcn->en_state = WCN36XX_STA_KEY;
wcn36xx_smd_delete_sta(wcn);
wcn36xx_smd_delete_bss(wcn);
wcn36xx_smd_set_link_st(wcn,
@@ -358,6 +422,7 @@ static const struct ieee80211_ops wcn36xx_ops = {
.config = wcn36xx_config,
.configure_filter = wcn36xx_configure_filter,
.tx = wcn36xx_tx,
+ .set_key = wcn36xx_set_key,
.sw_scan_start = wcn36xx_sw_scan_start,
.sw_scan_complete = wcn36xx_sw_scan_complete,
.bss_info_changed = wcn36xx_bss_info_changed,
@@ -521,6 +586,10 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
{
int ret = 0;
+ static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ };
wcn->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
@@ -539,6 +608,9 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
wcn->hw->wiphy->max_scan_ssids = 1;
+ wcn->hw->wiphy->cipher_suites = cipher_suites;
+ wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
// TODO make a conf file where to read this information from
wcn->hw->max_listen_interval = 200;
diff --git a/smd.c b/smd.c
index 7a2129d..285bc57 100644
--- a/smd.c
+++ b/smd.c
@@ -876,6 +876,56 @@ int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn, struct sk_buff *skb)
return wcn36xx_smd_send_and_wait(wcn, msg.header.len);
};
+int wcn36xx_smd_set_stakey(struct wcn36xx *wcn,
+ enum ani_ed_type enc_type,
+ u8 keyidx,
+ u8 keylen,
+ u8 *key)
+{
+ struct wcn36xx_hal_set_sta_key_req_msg msg_body;
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_STAKEY_REQ);
+
+ msg_body.set_sta_key_params.sta_index = wcn->current_vif->sta_index;
+ msg_body.set_sta_key_params.enc_type = enc_type;
+
+ msg_body.set_sta_key_params.key[0].id = keyidx;
+ msg_body.set_sta_key_params.key[0].unicast = 1;
+ msg_body.set_sta_key_params.key[0].direction = WCN36XX_HAL_TX_RX;
+ msg_body.set_sta_key_params.key[0].pae_role = 0;
+ msg_body.set_sta_key_params.key[0].length = keylen;
+ memcpy(msg_body.set_sta_key_params.key[0].key, key, keylen);
+ msg_body.set_sta_key_params.single_tid_rc = 1;
+
+ PREPARE_HAL_BUF(wcn->smd_buf, msg_body);
+
+ return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+}
+
+int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn,
+ enum ani_ed_type enc_type,
+ u8 keyidx,
+ u8 keylen,
+ u8 *key)
+{
+ struct wcn36xx_hal_set_bss_key_req_msg msg_body;
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_BSSKEY_REQ);
+ msg_body.bss_idx = 0;
+ msg_body.enc_type = enc_type;
+ msg_body.num_keys = 1;
+ msg_body.keys[0].id = keyidx;
+ msg_body.keys[0].unicast = 0;
+ msg_body.keys[0].direction = WCN36XX_HAL_RX_ONLY;
+ msg_body.keys[0].pae_role = 0;
+ msg_body.keys[0].length = keylen;
+ memcpy(msg_body.keys[0].key, key, keylen);
+
+ PREPARE_HAL_BUF(wcn->smd_buf, msg_body);
+
+ return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+}
+
static void wcn36xx_smd_notify(void *data, unsigned event)
{
struct wcn36xx *wcn = (struct wcn36xx *)data;
@@ -927,6 +977,8 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_SEND_BEACON_RSP:
case WCN36XX_HAL_SET_LINK_ST_RSP:
case WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP:
+ case WCN36XX_HAL_SET_BSSKEY_RSP:
+ case WCN36XX_HAL_SET_STAKEY_RSP:
if(wcn36xx_smd_rsp_status_check(buf, len)) {
wcn36xx_warn("error response from hal request %d",
msg_header->msg_type);
diff --git a/smd.h b/smd.h
index 8be34cd..f886394 100644
--- a/smd.h
+++ b/smd.h
@@ -67,7 +67,16 @@ int wcn36xx_smd_config_sta(struct wcn36xx *wcn, u8 *bssid, u8 *sta_mac);
int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct sk_buff *skb_beacon, u16 tim_off, u16 p2p_off);
int wcn36xx_smd_switch_channel_req(struct wcn36xx *wcn, int ch);
int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn, struct sk_buff *skb);
-
+int wcn36xx_smd_set_stakey(struct wcn36xx *wcn,
+ enum ani_ed_type enc_type,
+ u8 keyidx,
+ u8 keylen,
+ u8 *key);
+int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn,
+ enum ani_ed_type enc_type,
+ u8 keyidx,
+ u8 keylen,
+ u8 *key);
// WCN36XX configuration parameters
struct wcn36xx_fw_cfg {
u16 id;
diff --git a/txrx.c b/txrx.c
index 0ff50e9..6a22fe6 100644
--- a/txrx.c
+++ b/txrx.c
@@ -26,6 +26,11 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
struct ieee80211_hdr *hdr;
struct wcn36xx_rx_bd * bd;
+ /*
+ * All fields must be 0, otherwise it can lead to
+ * unexpected consequences.
+ */
+ memset(&status, 0, sizeof(status));
skb2 = skb_clone(skb, GFP_ATOMIC);
bd = (struct wcn36xx_rx_bd *)skb2->data;
buff_to_be((u32*)bd, sizeof(*bd)/sizeof(u32));
@@ -41,7 +46,14 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
status.rate_idx = 1;
status.flag = 0;
status.rx_flags = 0;
- memcpy(skb2->cb, &status, sizeof(struct ieee80211_rx_status));
+ status.flag |= RX_FLAG_IV_STRIPPED |
+ RX_FLAG_MMIC_STRIPPED |
+ RX_FLAG_DECRYPTED ;
+ wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x "
+ "status->vendor_radiotap_len=%x",
+ status.flag, status.vendor_radiotap_len);
+
+ memcpy(IEEE80211_SKB_RXCB(skb2), &status, sizeof(status));
hdr = (struct ieee80211_hdr *) skb2->data;
@@ -55,18 +67,21 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
return 0;
}
-void wcn36xx_prepare_tx_bd(void * pBd, u32 len)
+void wcn36xx_prepare_tx_bd(void *pBd, u32 len, u32 header_len)
{
struct wcn36xx_tx_bd * bd = (struct wcn36xx_tx_bd *)pBd;
// Must be clean every time because we can have some leftovers from the previous packet
memset(pBd, 0, (sizeof(struct wcn36xx_tx_bd)));
- bd->pdu.mpdu_header_len = WCN36XX_802_11_HEADER_LEN;
+ bd->pdu.mpdu_header_len = header_len;
bd->pdu.mpdu_header_off = sizeof(struct wcn36xx_tx_bd);
bd->pdu.mpdu_data_off = bd->pdu.mpdu_header_len +
bd->pdu.mpdu_header_off;
bd->pdu.mpdu_len = len;
}
-void wcn36xx_fill_tx_bd(struct wcn36xx *wcn, void *pBd, u8 broadcast)
+void wcn36xx_fill_tx_bd(struct wcn36xx *wcn,
+ void *pBd,
+ u8 broadcast,
+ u8 encrypt)
{
struct wcn36xx_tx_bd * bd = (struct wcn36xx_tx_bd *)pBd;
bd->dpu_rf = WCN36XX_BMU_WQ_TX;
@@ -93,8 +108,7 @@ void wcn36xx_fill_tx_bd(struct wcn36xx *wcn, void *pBd, u8 broadcast)
bd->sta_index = wcn->current_vif->sta_index;
bd->dpu_desc_idx = wcn->current_vif->dpu_desc_index;
- // no encription
- bd->dpu_ne = 1;
+ bd->dpu_ne = encrypt;
buff_to_be((u32*)bd, sizeof(*bd)/sizeof(u32));
bd->tx_bd_sign = 0xbdbdbdbd;
diff --git a/txrx.h b/txrx.h
index f7838c4..7a3b282 100644
--- a/txrx.h
+++ b/txrx.h
@@ -143,6 +143,9 @@ struct wcn36xx_tx_bd {
u32 reserved7:6;*/
};
int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb);
-void wcn36xx_prepare_tx_bd(void * pBd, u32 len);
-void wcn36xx_fill_tx_bd(struct wcn36xx *wcn, void *pBd, u8 broadcast);
+void wcn36xx_prepare_tx_bd(void *pBd, u32 len, u32 header_len);
+void wcn36xx_fill_tx_bd(struct wcn36xx *wcn,
+ void * pBd,
+ u8 broadcast,
+ u8 encrypt);
#endif /* _TXRX_H_ */
diff --git a/wcn36xx.h b/wcn36xx.h
index bd81222..bb58e41 100644
--- a/wcn36xx.h
+++ b/wcn36xx.h
@@ -69,6 +69,10 @@ enum wcn36xx_debug_mask {
DUMP_PREFIX_ADDRESS, 32, 1, \
buf, len, false);
+enum wcn36xx_encryption_state {
+ WCN36XX_STA_KEY,
+ WCN36XX_BSS_KEY
+};
static inline void buff_to_be(u32 *buf, size_t len)
{
@@ -107,6 +111,7 @@ struct wcn36xx {
u8 fw_version;
u8 fw_minor;
u8 fw_major;
+ enum wcn36xx_encryption_state en_state;
/* extra byte for the NULL termination */
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
--
1.7.11.3
More information about the wcn36xx
mailing list