linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] mwl8k: Add HW crypto support for AP mode
@ 2010-12-28 23:01 Thomas Pedersen
  2010-12-28 23:01 ` [PATCH 1/4] mwl8k: Modify add_dma_header to include pad parameters Thomas Pedersen
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Thomas Pedersen @ 2010-12-28 23:01 UTC (permalink / raw)
  To: linux-wireless; +Cc: mwl8k-devel, buytenh

Hello,

These patches add support for HW crypto using the mwl8k driver when AP firmware
is loaded. The driver currently falls back to SW crypto in mac80211 when in STA
mode, but a future patch will address this. Crypto while an AP and STA both
appear to work fine. 

Thomas


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/4] mwl8k: Modify add_dma_header to include pad parameters
  2010-12-28 23:01 [PATCH 0/4] mwl8k: Add HW crypto support for AP mode Thomas Pedersen
@ 2010-12-28 23:01 ` Thomas Pedersen
  2010-12-28 23:01 ` [PATCH 2/4] mwl8k: Add encapsulation of data packet for crypto Thomas Pedersen
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Thomas Pedersen @ 2010-12-28 23:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: mwl8k-devel, buytenh, Nishant Sarmukadam, Pradeep Nemavat,
	Thomas Pedersen

From: Nishant Sarmukadam <nishants@marvell.com>

Add capability to add_dma_header to support padding at head
and tail of the data packet to be transmitted when crypto is
enabled. Padding is required for adding crypto information
in data packets for supporting 802.11 security modes.

Signed-off-by: Nishant Sarmukadam <nishants@marvell.com>
Signed-off-by: Pradeep Nemavat <pnemavat@marvell.com>
Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
---
 drivers/net/wireless/mwl8k.c |   20 ++++++++++++++------
 1 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 9ecf840..771283b 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -715,10 +715,12 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos)
 		skb_pull(skb, sizeof(*tr) - hdrlen);
 }
 
-static inline void mwl8k_add_dma_header(struct sk_buff *skb)
+static void
+mwl8k_add_dma_header(struct sk_buff *skb, int hdr_pad, int tail_pad)
 {
 	struct ieee80211_hdr *wh;
 	int hdrlen;
+	int reqd_hdrlen;
 	struct mwl8k_dma_data *tr;
 
 	/*
@@ -730,8 +732,10 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
 	wh = (struct ieee80211_hdr *)skb->data;
 
 	hdrlen = ieee80211_hdrlen(wh->frame_control);
-	if (hdrlen != sizeof(*tr))
-		skb_push(skb, sizeof(*tr) - hdrlen);
+	reqd_hdrlen = sizeof(*tr) + hdr_pad;
+
+	if (hdrlen != reqd_hdrlen)
+		skb_push(skb, reqd_hdrlen - hdrlen);
 
 	if (ieee80211_is_data_qos(wh->frame_control))
 		hdrlen -= 2;
@@ -739,8 +743,12 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
 	tr = (struct mwl8k_dma_data *)skb->data;
 	if (wh != &tr->wh)
 		memmove(&tr->wh, wh, hdrlen);
-	if (hdrlen != sizeof(tr->wh))
-		memset(((void *)&tr->wh) + hdrlen, 0, sizeof(tr->wh) - hdrlen);
+	if (hdrlen != sizeof(tr->wh) + hdr_pad)
+		memset(((void *)&tr->wh) + hdrlen, 0,
+					sizeof(tr->wh) + hdr_pad - hdrlen);
+
+	if (tail_pad)
+		skb_put(skb, tail_pad);
 
 	/*
 	 * Firmware length is the length of the fully formed "802.11
@@ -1443,7 +1451,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 	else
 		qos = 0;
 
-	mwl8k_add_dma_header(skb);
+	mwl8k_add_dma_header(skb, 0, 0);
 	wh = &((struct mwl8k_dma_data *)skb->data)->wh;
 
 	tx_info = IEEE80211_SKB_CB(skb);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/4] mwl8k: Add encapsulation of data packet for crypto
  2010-12-28 23:01 [PATCH 0/4] mwl8k: Add HW crypto support for AP mode Thomas Pedersen
  2010-12-28 23:01 ` [PATCH 1/4] mwl8k: Modify add_dma_header to include pad parameters Thomas Pedersen
@ 2010-12-28 23:01 ` Thomas Pedersen
  2010-12-29  9:14   ` Johannes Berg
  2010-12-28 23:01 ` [PATCH 3/4] mwl8k: Set mac80211 rx status flags appropriately when hw crypto is enabled Thomas Pedersen
  2010-12-28 23:01 ` [PATCH 4/4] mwl8k: Enable HW encryption for AP mode Thomas Pedersen
  3 siblings, 1 reply; 9+ messages in thread
From: Thomas Pedersen @ 2010-12-28 23:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: mwl8k-devel, buytenh, Nishant Sarmukadam, Pradeep Nemavat,
	Thomas Pedersen

From: Nishant Sarmukadam <nishants@marvell.com>

Different head and tail pads will be needed for crypto depending on
the crypto mode. Add support to encapsulate the packets with
appropriate pad values. Also, fill the header in case of CCMP.

Signed-off-by: Nishant Sarmukadam <nishants@marvell.com>
Signed-off-by: Pradeep Nemavat <pnemavat@marvell.com>
Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
---
 drivers/net/wireless/mwl8k.c |  114 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 109 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 771283b..508828c 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -232,6 +232,14 @@ struct mwl8k_priv {
 	struct completion firmware_loading_complete;
 };
 
+#define MAX_WEP_KEY_LEN         13
+#define NUM_WEP_KEYS            4
+
+struct mwl8k_ccmp_tx_iv {
+	__u16 tx_iv_pn_l2;
+	__u32 tx_iv_pn_u4;
+};
+
 /* Per interface specific private data */
 struct mwl8k_vif {
 	struct list_head list;
@@ -242,12 +250,23 @@ struct mwl8k_vif {
 
 	/* Non AMPDU sequence number assigned by driver.  */
 	u16 seqno;
+
+	/* Saved WEP keys */
+	struct {
+		u8 enabled;
+		u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN];
+	} wep_key_conf[NUM_WEP_KEYS];
+
+	/* CCMP Crypto counters for Group cast data */
+	struct mwl8k_ccmp_tx_iv ccmp_tx_iv;
 };
 #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
 
 struct mwl8k_sta {
 	/* Index into station database. Returned by UPDATE_STADB.  */
 	u8 peer_id;
+	/* CCMP crypto counter for station */
+	struct mwl8k_ccmp_tx_iv ccmp_tx_iv;
 };
 #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
 
@@ -747,17 +766,97 @@ mwl8k_add_dma_header(struct sk_buff *skb, int hdr_pad, int tail_pad)
 		memset(((void *)&tr->wh) + hdrlen, 0,
 					sizeof(tr->wh) + hdr_pad - hdrlen);
 
-	if (tail_pad)
-		skb_put(skb, tail_pad);
-
 	/*
 	 * Firmware length is the length of the fully formed "802.11
 	 * payload".  That is, everything except for the 802.11 header.
 	 * This includes all crypto material including the MIC.
 	 */
-	tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr));
+	tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad);
+}
+
+#define CCMP_EXT_IV (1<<5)
+
+static void
+fill_ccmp_header(u8 *ccmp_hdr, struct mwl8k_ccmp_tx_iv *tx_iv, u8 key_id)
+{
+	*(__le16 *)ccmp_hdr = cpu_to_le16(tx_iv->tx_iv_pn_l2);
+	ccmp_hdr[2] = 0;
+	ccmp_hdr[3] = CCMP_EXT_IV | key_id << 6;
+	*(__le32 *)&ccmp_hdr[4] = cpu_to_le32(tx_iv->tx_iv_pn_u4);
+
+	tx_iv->tx_iv_pn_l2++;
+	if (tx_iv->tx_iv_pn_l2 == 0)
+		tx_iv->tx_iv_pn_u4++;
 }
 
+static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *wh;
+	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_key_conf *key_conf;
+	int header_pad;
+	int data_pad;
+
+	wh = (struct ieee80211_hdr *)skb->data;
+
+	tx_info = IEEE80211_SKB_CB(skb);
+
+	key_conf = NULL;
+	if (ieee80211_is_data(wh->frame_control))
+		key_conf = tx_info->control.hw_key;
+
+	/*
+	 * Make sure the packet header is in the DMA header format
+	 * (4-address without QoS), and insert the necessary crypto
+	 * padding between the header and the payload.
+	 *
+	 * We have the following header/trailer padding requirements:
+	 * - WEP: 4 header bytes (IV), 4 trailer bytes (ICV)
+	 * - TKIP: 8 header bytes (IV/EIV), 12 trailer bytes (8 MIC + 4 ICV)
+	 * - CCMP: 8 header bytes (PN/KeyId), 8 trailer bytes (MIC)
+	 */
+	header_pad = 0;
+	data_pad = 0;
+	if (key_conf != NULL) {
+		if (key_conf->alg == ALG_WEP) {
+			header_pad = 4;
+			data_pad = 4;
+		} else {
+			header_pad = 8;
+			if (key_conf->alg == ALG_TKIP)
+				data_pad = 12;
+			else /* CCMP */
+				data_pad = 8;
+		}
+	}
+
+	mwl8k_add_dma_header(skb, header_pad, data_pad);
+
+	wh = &((struct mwl8k_dma_data *)skb->data)->wh;
+
+	/*
+	 * Fill CCMP header.
+	 */
+	if ((key_conf != NULL) && key_conf->alg == ALG_CCMP) {
+		void *ccmp_hdr;
+		u8 key_id;
+		struct mwl8k_ccmp_tx_iv *tx_iv;
+
+		ccmp_hdr = skb->data + sizeof(struct mwl8k_dma_data);
+		/*
+		 * The key id is 1 for groupcast traffic and 0 for
+		 * unicast/pairwise traffic.
+		 */
+		if (is_multicast_ether_addr(wh->addr1)) {
+			key_id = 1;
+			tx_iv = &(MWL8K_VIF(tx_info->control.vif)->ccmp_tx_iv);
+		} else {
+			key_id = 0;
+			tx_iv = &(MWL8K_STA(tx_info->control.sta)->ccmp_tx_iv);
+		}
+		fill_ccmp_header(ccmp_hdr, tx_iv, key_id);
+	}
+}
 
 /*
  * Packet reception for 88w8366 AP firmware.
@@ -1451,7 +1550,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 	else
 		qos = 0;
 
-	mwl8k_add_dma_header(skb, 0, 0);
+	mwl8k_encapsulate_tx_frame(skb);
 	wh = &((struct mwl8k_dma_data *)skb->data)->wh;
 
 	tx_info = IEEE80211_SKB_CB(skb);
@@ -3477,6 +3576,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
 	mwl8k_vif->vif = vif;
 	mwl8k_vif->macid = macid;
 	mwl8k_vif->seqno = 0;
+	mwl8k_vif->ccmp_tx_iv.tx_iv_pn_l2 = 1;
+	mwl8k_vif->ccmp_tx_iv.tx_iv_pn_u4 = 0;
 
 	/* Set the mac address.  */
 	mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
@@ -3875,6 +3976,9 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
 	struct mwl8k_priv *priv = hw->priv;
 	int ret;
 
+	MWL8K_STA(sta)->ccmp_tx_iv.tx_iv_pn_l2 = 1;
+	MWL8K_STA(sta)->ccmp_tx_iv.tx_iv_pn_u4 = 0;
+
 	if (!priv->ap_fw) {
 		ret = mwl8k_cmd_update_stadb_add(hw, vif, sta);
 		if (ret >= 0) {
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/4] mwl8k: Set mac80211 rx status flags appropriately when hw crypto is enabled
  2010-12-28 23:01 [PATCH 0/4] mwl8k: Add HW crypto support for AP mode Thomas Pedersen
  2010-12-28 23:01 ` [PATCH 1/4] mwl8k: Modify add_dma_header to include pad parameters Thomas Pedersen
  2010-12-28 23:01 ` [PATCH 2/4] mwl8k: Add encapsulation of data packet for crypto Thomas Pedersen
@ 2010-12-28 23:01 ` Thomas Pedersen
  2010-12-29  9:15   ` Johannes Berg
  2010-12-28 23:01 ` [PATCH 4/4] mwl8k: Enable HW encryption for AP mode Thomas Pedersen
  3 siblings, 1 reply; 9+ messages in thread
From: Thomas Pedersen @ 2010-12-28 23:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: mwl8k-devel, buytenh, Nishant Sarmukadam, yogesh powar,
	Thomas Pedersen

From: Nishant Sarmukadam <nishants@marvell.com>

When hw crypto is enabled, set rx status flags appropriately depending on
whether hw crypto is enabled for a particular bss.
Also report MIC errors to mac80211, so that counter measures can be
initiated

Signed-off-by: Nishant Sarmukadam <nishants@marvell.com>
Signed-off-by: yogesh powar <yogeshp@marvell.com>
Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
---
 drivers/net/wireless/mwl8k.c |  100 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 97 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 508828c..75200d5 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -259,6 +259,12 @@ struct mwl8k_vif {
 
 	/* CCMP Crypto counters for Group cast data */
 	struct mwl8k_ccmp_tx_iv ccmp_tx_iv;
+
+	/* BSSID */
+	u8 bssid[ETH_ALEN];
+
+	/* A flag to indicate is HW crypto is enabled for this bssid */
+	bool is_hw_crypto_enabled;
 };
 #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
 
@@ -885,6 +891,13 @@ struct mwl8k_rxd_8366_ap {
 
 #define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST	0x80
 
+/* 8366 AP rx_status bits */
+#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK		0x80
+#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR	0xFF
+#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR	0x02
+#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR	0x04
+#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR	0x08
+
 static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
 {
 	struct mwl8k_rxd_8366_ap *rxd = _rxd;
@@ -945,6 +958,11 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
 
 	*qos = rxd->qos_control;
 
+	if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
+		(rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) &&
+		(rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
+			status->flag |= RX_FLAG_MMIC_ERROR;
+
 	return le16_to_cpu(rxd->pkt_len);
 }
 
@@ -983,6 +1001,11 @@ struct mwl8k_rxd_sta {
 #define MWL8K_STA_RATE_INFO_MCS_FORMAT		0x0001
 
 #define MWL8K_STA_RX_CTRL_OWNED_BY_HOST		0x02
+#define MWL8K_STA_RX_CTRL_DECRYPT_ERROR		0x04
+/* ICV=0 or MIC=1 */
+#define MWL8K_STA_RX_CTRL_DEC_ERR_TYPE		0x08
+/* Key is uploaded only in failure case */
+#define MWL8K_STA_RX_CTRL_KEY_INDEX			0x30
 
 static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr)
 {
@@ -1041,6 +1064,9 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
 	status->freq = ieee80211_channel_to_frequency(rxd->channel);
 
 	*qos = rxd->qos_control;
+	if ((rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DECRYPT_ERROR) &&
+			(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DEC_ERR_TYPE))
+				status->flag |= RX_FLAG_MMIC_ERROR;
 
 	return le16_to_cpu(rxd->pkt_len);
 }
@@ -1199,9 +1225,24 @@ static inline void mwl8k_save_beacon(struct ieee80211_hw *hw,
 		ieee80211_queue_work(hw, &priv->finalize_join_worker);
 }
 
+struct mwl8k_vif *mwl8k_find_vif_bss(struct list_head *vif_list, u8 *bssid)
+{
+	struct mwl8k_vif *mwl8k_vif;
+
+	list_for_each_entry(mwl8k_vif,
+			vif_list, list) {
+		if (memcmp(bssid, mwl8k_vif->bssid,
+				 ETH_ALEN) == 0)
+			return mwl8k_vif;
+	}
+
+	return NULL;
+}
+
 static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 {
 	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_vif *mwl8k_vif = NULL;
 	struct mwl8k_rx_queue *rxq = priv->rxq + index;
 	int processed;
 
@@ -1211,6 +1252,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 		void *rxd;
 		int pkt_len;
 		struct ieee80211_rx_status status;
+		struct ieee80211_hdr *wh;
 		__le16 qos;
 
 		skb = rxq->buf[rxq->head].skb;
@@ -1237,8 +1279,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 
 		rxq->rxd_count--;
 
-		skb_put(skb, pkt_len);
-		mwl8k_remove_dma_header(skb, qos);
+		wh = &((struct mwl8k_dma_data *)skb->data)->wh;
 
 		/*
 		 * Check for a pending join operation.  Save a
@@ -1248,6 +1289,46 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 		if (mwl8k_capture_bssid(priv, (void *)skb->data))
 			mwl8k_save_beacon(hw, skb);
 
+		if (ieee80211_has_protected(wh->frame_control)) {
+
+			/* Check if hw crypto has been enabled for
+			 * this bss. If yes, set the status flags
+			 * accordingly
+			 */
+			mwl8k_vif = mwl8k_find_vif_bss(&priv->vif_list,
+								wh->addr1);
+
+			if (mwl8k_vif != NULL &&
+				mwl8k_vif->is_hw_crypto_enabled == true) {
+				/*
+				 * When MMIC ERROR is encountered
+				 * by the firmware, payload is
+				 * dropped and only 32 bytes of
+				 * mwl8k Firmware header is sent
+				 * to the host.
+				 *
+				 * We need to add four bytes of
+				 * key information.  In it
+				 * MAC80211 expects keyidx set to
+				 * 0 for triggering Counter
+				 * Measure of MMIC failure.
+				 */
+				if (status.flag & RX_FLAG_MMIC_ERROR) {
+					struct mwl8k_dma_data *tr;
+					tr = (struct mwl8k_dma_data *)skb->data;
+					memset((void *)&(tr->data), 0, 4);
+					pkt_len += 4;
+				}
+
+				if (!ieee80211_is_auth(wh->frame_control))
+					status.flag |= RX_FLAG_IV_STRIPPED |
+							RX_FLAG_DECRYPTED |
+							RX_FLAG_MMIC_STRIPPED;
+			}
+		}
+
+		skb_put(skb, pkt_len);
+		mwl8k_remove_dma_header(skb, qos);
 		memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
 		ieee80211_rx_irqsafe(hw, skb);
 
@@ -1550,7 +1631,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
 	else
 		qos = 0;
 
-	mwl8k_encapsulate_tx_frame(skb);
+	if (priv->ap_fw)
+		mwl8k_encapsulate_tx_frame(skb);
+	else
+		mwl8k_add_dma_header(skb, 0, 0);
+
 	wh = &((struct mwl8k_dma_data *)skb->data)->wh;
 
 	tx_info = IEEE80211_SKB_CB(skb);
@@ -3578,6 +3663,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
 	mwl8k_vif->seqno = 0;
 	mwl8k_vif->ccmp_tx_iv.tx_iv_pn_l2 = 1;
 	mwl8k_vif->ccmp_tx_iv.tx_iv_pn_u4 = 0;
+	memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN);
+	mwl8k_vif->is_hw_crypto_enabled = false;
 
 	/* Set the mac address.  */
 	mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
@@ -3986,9 +4073,16 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
 			return 0;
 		}
 
+	} else {
+		ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta);
 		return ret;
 	}
 
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		key = IEEE80211_KEY_CONF(mwl8k_vif->wep_key_conf[i].key);
+		if (mwl8k_vif->wep_key_conf[i].enabled)
+			mwl8k_set_key(hw, SET_KEY, vif, sta, key);
+	}
 	return mwl8k_cmd_set_new_stn_add(hw, vif, sta);
 }
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/4] mwl8k: Enable HW encryption for AP mode
  2010-12-28 23:01 [PATCH 0/4] mwl8k: Add HW crypto support for AP mode Thomas Pedersen
                   ` (2 preceding siblings ...)
  2010-12-28 23:01 ` [PATCH 3/4] mwl8k: Set mac80211 rx status flags appropriately when hw crypto is enabled Thomas Pedersen
@ 2010-12-28 23:01 ` Thomas Pedersen
  2010-12-29  9:17   ` Johannes Berg
  3 siblings, 1 reply; 9+ messages in thread
From: Thomas Pedersen @ 2010-12-28 23:01 UTC (permalink / raw)
  To: linux-wireless
  Cc: mwl8k-devel, buytenh, Nishant Sarmukadam, Pradeep Nemavat,
	Thomas Pedersen

From: Nishant Sarmukadam <nishants@marvell.com>

set_key callback is defined for mac80211 to install keys for HW crypto in AP
mode. Driver currently falls back to SW crypto in STA mode.  Add support to
configure the keys appropriately in the hardware after the set_key routine is
called.

Signed-off-by: Nishant Sarmukadam <nishants@marvell.com>
Signed-off-by: Pradeep Nemavat <pnemavat@marvell.com>
Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
---
 drivers/net/wireless/mwl8k.c |  300 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 290 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 75200d5..046ddfd 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -267,6 +267,7 @@ struct mwl8k_vif {
 	bool is_hw_crypto_enabled;
 };
 #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
+#define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8))
 
 struct mwl8k_sta {
 	/* Index into station database. Returned by UPDATE_STADB.  */
@@ -362,6 +363,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
 #define MWL8K_CMD_SET_RATEADAPT_MODE	0x0203
 #define MWL8K_CMD_BSS_START		0x1100		/* per-vif */
 #define MWL8K_CMD_SET_NEW_STN		0x1111		/* per-vif */
+#define MWL8K_CMD_UPDATE_ENCRYPTION	0x1122		/* per-vif */
 #define MWL8K_CMD_UPDATE_STADB		0x1123
 
 static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
@@ -400,6 +402,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
 		MWL8K_CMDNAME(SET_RATEADAPT_MODE);
 		MWL8K_CMDNAME(BSS_START);
 		MWL8K_CMDNAME(SET_NEW_STN);
+		MWL8K_CMDNAME(UPDATE_ENCRYPTION);
 		MWL8K_CMDNAME(UPDATE_STADB);
 	default:
 		snprintf(buf, bufsize, "0x%x", cmd);
@@ -824,15 +827,22 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
 	header_pad = 0;
 	data_pad = 0;
 	if (key_conf != NULL) {
-		if (key_conf->alg == ALG_WEP) {
+		switch (key_conf->cipher) {
+		case WLAN_CIPHER_SUITE_WEP40:
+		case WLAN_CIPHER_SUITE_WEP104:
 			header_pad = 4;
 			data_pad = 4;
-		} else {
+			break;
+		case WLAN_CIPHER_SUITE_TKIP:
 			header_pad = 8;
-			if (key_conf->alg == ALG_TKIP)
-				data_pad = 12;
-			else /* CCMP */
-				data_pad = 8;
+			data_pad = 12;
+			break;
+		case WLAN_CIPHER_SUITE_CCMP:
+			header_pad = 8;
+			data_pad = 8;
+			break;
+		default:
+			return -ENOTSUPP;
 		}
 	}
 
@@ -843,7 +853,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
 	/*
 	 * Fill CCMP header.
 	 */
-	if ((key_conf != NULL) && key_conf->alg == ALG_CCMP) {
+	if (key_conf != NULL && key_conf->cipher == WLAN_CIPHER_SUITE_CCMP) {
 		void *ccmp_hdr;
 		u8 key_id;
 		struct mwl8k_ccmp_tx_iv *tx_iv;
@@ -3291,6 +3301,273 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw,
 }
 
 /*
+ * CMD_UPDATE_ENCRYPTION.
+ */
+
+#define MAX_ENCR_KEY_LENGTH	16
+#define MIC_KEY_LENGTH		8
+
+struct mwl8k_cmd_update_encryption {
+	struct mwl8k_cmd_pkt header;
+
+	__le32 action;
+	__le32 reserved;
+	__u8 mac_addr[6];
+	__u8 encr_type;
+
+} __attribute__((packed));
+
+struct mwl8k_cmd_set_key {
+	struct mwl8k_cmd_pkt header;
+
+	__le32 action;
+	__le32 reserved;
+	__le16 length;
+	__le16 key_type_id;
+	__le32 key_info;
+	__le32 key_id;
+	__le16 key_len;
+	__u8 key_material[MAX_ENCR_KEY_LENGTH];
+	__u8 tkip_tx_mic_key[MIC_KEY_LENGTH];
+	__u8 tkip_rx_mic_key[MIC_KEY_LENGTH];
+	__le16 tkip_rsc_low;
+	__le32 tkip_rsc_high;
+	__le16 tkip_tsc_low;
+	__le32 tkip_tsc_high;
+	__u8 mac_addr[6];
+} __attribute__((packed));
+
+enum {
+	MWL8K_ENCR_ENABLE,
+	MWL8K_ENCR_SET_KEY,
+	MWL8K_ENCR_REMOVE_KEY,
+	MWL8K_ENCR_SET_GROUP_KEY,
+};
+
+#define MWL8K_UPDATE_ENCRYPTION_TYPE_WEP	0
+#define MWL8K_UPDATE_ENCRYPTION_TYPE_DISABLE	1
+#define MWL8K_UPDATE_ENCRYPTION_TYPE_TKIP	4
+#define MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED	7
+#define MWL8K_UPDATE_ENCRYPTION_TYPE_AES	8
+
+enum {
+	MWL8K_ALG_WEP,
+	MWL8K_ALG_TKIP,
+	MWL8K_ALG_CCMP,
+};
+
+#define MWL8K_KEY_FLAG_TXGROUPKEY	0x00000004
+#define MWL8K_KEY_FLAG_PAIRWISE		0x00000008
+#define MWL8K_KEY_FLAG_TSC_VALID	0x00000040
+#define MWL8K_KEY_FLAG_WEP_TXKEY	0x01000000
+#define MWL8K_KEY_FLAG_MICKEY_VALID	0x02000000
+
+static int mwl8k_cmd_update_encryption_enable(struct ieee80211_hw *hw,
+					      struct ieee80211_vif *vif,
+					      u8 *addr,
+					      u8 encr_type)
+{
+	struct mwl8k_cmd_update_encryption *cmd;
+	int rc;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+	cmd->action = cpu_to_le32(MWL8K_ENCR_ENABLE);
+	memcpy(cmd->mac_addr, addr, ETH_ALEN);
+	cmd->encr_type = encr_type;
+
+	rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+	kfree(cmd);
+
+	return rc;
+}
+
+static int mwl8k_encryption_set_cmd_info(struct mwl8k_cmd_set_key *cmd,
+						u8 *addr,
+						struct ieee80211_key_conf *key)
+{
+	cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION);
+	cmd->header.length = cpu_to_le16(sizeof(*cmd));
+	cmd->length = cpu_to_le16(sizeof(*cmd) -
+				offsetof(struct mwl8k_cmd_set_key, length));
+	cmd->key_id = cpu_to_le32(key->keyidx);
+	cmd->key_len = cpu_to_le16(key->keylen);
+	memcpy(cmd->mac_addr, addr, ETH_ALEN);
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		cmd->key_type_id = cpu_to_le16(MWL8K_ALG_WEP);
+		if (key->keyidx == 0)
+			cmd->key_info =	cpu_to_le32(MWL8K_KEY_FLAG_WEP_TXKEY);
+
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		cmd->key_type_id = cpu_to_le16(MWL8K_ALG_TKIP);
+		cmd->key_info =	(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+			? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE)
+			: cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY);
+		cmd->key_info |= cpu_to_le32(MWL8K_KEY_FLAG_MICKEY_VALID
+						| MWL8K_KEY_FLAG_TSC_VALID);
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		cmd->key_type_id = cpu_to_le16(MWL8K_ALG_CCMP);
+		cmd->key_info =	(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+			? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE)
+			: cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY);
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw,
+						struct ieee80211_vif *vif,
+						u8 *addr,
+						struct ieee80211_key_conf *key)
+{
+	struct mwl8k_cmd_set_key *cmd;
+	int rc;
+	int keymlen;
+	u32 action;
+	u8 idx;
+	struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	rc = mwl8k_encryption_set_cmd_info(cmd, addr, key);
+	if (rc < 0)
+		goto done;
+
+	idx = key->keyidx;
+
+	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+		action = MWL8K_ENCR_SET_KEY;
+	else
+		action = MWL8K_ENCR_SET_GROUP_KEY;
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		if (!mwl8k_vif->wep_key_conf[idx].enabled) {
+			memcpy(mwl8k_vif->wep_key_conf[idx].key, key,
+						sizeof(*key) + key->keylen);
+			mwl8k_vif->wep_key_conf[idx].enabled = 1;
+		}
+
+		keymlen = 0;
+		action = MWL8K_ENCR_SET_KEY;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		keymlen = key->keylen;
+		break;
+	default:
+		rc = -ENOTSUPP;
+		goto done;
+	}
+
+	memcpy(cmd->key_material, key->key, keymlen);
+	cmd->action = cpu_to_le32(action);
+
+	rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+done:
+	kfree(cmd);
+
+	return rc;
+}
+
+static int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw,
+						struct ieee80211_vif *vif,
+						u8 *addr,
+						struct ieee80211_key_conf *key)
+{
+	struct mwl8k_cmd_set_key *cmd;
+	int rc;
+	struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENOMEM;
+
+	rc = mwl8k_encryption_set_cmd_info(cmd, addr, key);
+	if (rc < 0)
+		goto done;
+
+	if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+			WLAN_CIPHER_SUITE_WEP104)
+		mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0;
+
+	cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY);
+
+	rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+done:
+	kfree(cmd);
+
+	return rc;
+}
+
+static int mwl8k_set_key(struct ieee80211_hw *hw,
+			 enum set_key_cmd cmd_param,
+			 struct ieee80211_vif *vif,
+			 struct ieee80211_sta *sta,
+			 struct ieee80211_key_conf *key)
+{
+	int rc = 0;
+	u8 encr_type;
+	u8 *addr;
+	struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+
+	if (vif->type == NL80211_IFTYPE_STATION)
+		return -EOPNOTSUPP;
+
+	if (sta == NULL)
+		addr = hw->wiphy->perm_addr;
+	else
+		addr = sta->addr;
+
+	if (cmd_param == SET_KEY) {
+		rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key);
+		if (rc)
+			goto out;
+
+		if ((key->cipher == WLAN_CIPHER_SUITE_WEP40)
+				|| (key->cipher == WLAN_CIPHER_SUITE_WEP104))
+			encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_WEP;
+		else
+			encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED;
+
+		rc = mwl8k_cmd_update_encryption_enable(hw, vif, addr,
+								encr_type);
+		if (rc)
+			goto out;
+
+		mwl8k_vif->is_hw_crypto_enabled = true;
+
+	} else {
+		rc = mwl8k_cmd_encryption_remove_key(hw, vif, addr, key);
+
+		if (rc)
+			goto out;
+
+		mwl8k_vif->is_hw_crypto_enabled = false;
+
+	}
+out:
+	return rc;
+}
+
+/*
  * CMD_UPDATE_STADB.
  */
 struct ewc_ht_info {
@@ -4062,6 +4339,9 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
 {
 	struct mwl8k_priv *priv = hw->priv;
 	int ret;
+	int i;
+	struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+	struct ieee80211_key_conf *key;
 
 	MWL8K_STA(sta)->ccmp_tx_iv.tx_iv_pn_l2 = 1;
 	MWL8K_STA(sta)->ccmp_tx_iv.tx_iv_pn_u4 = 0;
@@ -4070,12 +4350,11 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
 		ret = mwl8k_cmd_update_stadb_add(hw, vif, sta);
 		if (ret >= 0) {
 			MWL8K_STA(sta)->peer_id = ret;
-			return 0;
+			ret = 0;
 		}
 
 	} else {
 		ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta);
-		return ret;
 	}
 
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -4083,7 +4362,7 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
 		if (mwl8k_vif->wep_key_conf[i].enabled)
 			mwl8k_set_key(hw, SET_KEY, vif, sta, key);
 	}
-	return mwl8k_cmd_set_new_stn_add(hw, vif, sta);
+	return ret;
 }
 
 static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
@@ -4161,6 +4440,7 @@ static const struct ieee80211_ops mwl8k_ops = {
 	.bss_info_changed	= mwl8k_bss_info_changed,
 	.prepare_multicast	= mwl8k_prepare_multicast,
 	.configure_filter	= mwl8k_configure_filter,
+	.set_key                = mwl8k_set_key,
 	.set_rts_threshold	= mwl8k_set_rts_threshold,
 	.sta_add		= mwl8k_sta_add,
 	.sta_remove		= mwl8k_sta_remove,
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/4] mwl8k: Add encapsulation of data packet for crypto
  2010-12-28 23:01 ` [PATCH 2/4] mwl8k: Add encapsulation of data packet for crypto Thomas Pedersen
@ 2010-12-29  9:14   ` Johannes Berg
  0 siblings, 0 replies; 9+ messages in thread
From: Johannes Berg @ 2010-12-29  9:14 UTC (permalink / raw)
  To: Thomas Pedersen
  Cc: linux-wireless, mwl8k-devel, buytenh, Nishant Sarmukadam,
	Pradeep Nemavat

On Tue, 2010-12-28 at 15:01 -0800, Thomas Pedersen wrote:

> Different head and tail pads will be needed for crypto depending on
> the crypto mode. Add support to encapsulate the packets with
> appropriate pad values. Also, fill the header in case of CCMP.

Err, mac80211 is perfectly capable of generating the CCMP header, you
should use that functionality (and maybe memmove it elsewhere if needed)

johannes


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/4] mwl8k: Set mac80211 rx status flags appropriately when hw crypto is enabled
  2010-12-28 23:01 ` [PATCH 3/4] mwl8k: Set mac80211 rx status flags appropriately when hw crypto is enabled Thomas Pedersen
@ 2010-12-29  9:15   ` Johannes Berg
  0 siblings, 0 replies; 9+ messages in thread
From: Johannes Berg @ 2010-12-29  9:15 UTC (permalink / raw)
  To: Thomas Pedersen
  Cc: linux-wireless, mwl8k-devel, buytenh, Nishant Sarmukadam,
	yogesh powar

On Tue, 2010-12-28 at 15:01 -0800, Thomas Pedersen wrote:
> From: Nishant Sarmukadam <nishants@marvell.com>
> 
> When hw crypto is enabled, set rx status flags appropriately depending on
> whether hw crypto is enabled for a particular bss.
> Also report MIC errors to mac80211, so that counter measures can be
> initiated

> +	if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
> +		(rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) &&
> +		(rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
> +			status->flag |= RX_FLAG_MMIC_ERROR;

It's not my driver, so I don't care a whole lot, but this patch has some
pretty messed up indentation.

johannes


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 4/4] mwl8k: Enable HW encryption for AP mode
  2010-12-28 23:01 ` [PATCH 4/4] mwl8k: Enable HW encryption for AP mode Thomas Pedersen
@ 2010-12-29  9:17   ` Johannes Berg
  2010-12-29  9:18     ` Johannes Berg
  0 siblings, 1 reply; 9+ messages in thread
From: Johannes Berg @ 2010-12-29  9:17 UTC (permalink / raw)
  To: Thomas Pedersen
  Cc: linux-wireless, mwl8k-devel, buytenh, Nishant Sarmukadam,
	Pradeep Nemavat

On Tue, 2010-12-28 at 15:01 -0800, Thomas Pedersen wrote:

> @@ -824,15 +827,22 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
>  	header_pad = 0;
>  	data_pad = 0;
>  	if (key_conf != NULL) {
> -		if (key_conf->alg == ALG_WEP) {
> +		switch (key_conf->cipher) {

how can this patch possibly apply? key_conf->alg hasn't existed in a
LONG time, so I don't see how you can be removing a line containing it?!

johannes


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 4/4] mwl8k: Enable HW encryption for AP mode
  2010-12-29  9:17   ` Johannes Berg
@ 2010-12-29  9:18     ` Johannes Berg
  0 siblings, 0 replies; 9+ messages in thread
From: Johannes Berg @ 2010-12-29  9:18 UTC (permalink / raw)
  To: Thomas Pedersen
  Cc: linux-wireless, mwl8k-devel, buytenh, Nishant Sarmukadam,
	Pradeep Nemavat

On Wed, 2010-12-29 at 10:17 +0100, Johannes Berg wrote:
> On Tue, 2010-12-28 at 15:01 -0800, Thomas Pedersen wrote:
> 
> > @@ -824,15 +827,22 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
> >  	header_pad = 0;
> >  	data_pad = 0;
> >  	if (key_conf != NULL) {
> > -		if (key_conf->alg == ALG_WEP) {
> > +		switch (key_conf->cipher) {
> 
> how can this patch possibly apply? key_conf->alg hasn't existed in a
> LONG time, so I don't see how you can be removing a line containing it?!

Oh, never mind, patch 2/4 is adding this code, so it can never
compile...........

johannes


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2010-12-29  9:18 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-28 23:01 [PATCH 0/4] mwl8k: Add HW crypto support for AP mode Thomas Pedersen
2010-12-28 23:01 ` [PATCH 1/4] mwl8k: Modify add_dma_header to include pad parameters Thomas Pedersen
2010-12-28 23:01 ` [PATCH 2/4] mwl8k: Add encapsulation of data packet for crypto Thomas Pedersen
2010-12-29  9:14   ` Johannes Berg
2010-12-28 23:01 ` [PATCH 3/4] mwl8k: Set mac80211 rx status flags appropriately when hw crypto is enabled Thomas Pedersen
2010-12-29  9:15   ` Johannes Berg
2010-12-28 23:01 ` [PATCH 4/4] mwl8k: Enable HW encryption for AP mode Thomas Pedersen
2010-12-29  9:17   ` Johannes Berg
2010-12-29  9:18     ` Johannes Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).