[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