|
@@ -251,6 +251,12 @@ struct mwl8k_vif {
|
|
u8 enabled;
|
|
u8 enabled;
|
|
u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN];
|
|
u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN];
|
|
} wep_key_conf[NUM_WEP_KEYS];
|
|
} wep_key_conf[NUM_WEP_KEYS];
|
|
|
|
+
|
|
|
|
+ /* 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))
|
|
#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
|
|
|
|
|
|
@@ -834,6 +840,13 @@ struct mwl8k_rxd_8366_ap {
|
|
|
|
|
|
#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80
|
|
#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)
|
|
static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
|
|
{
|
|
{
|
|
struct mwl8k_rxd_8366_ap *rxd = _rxd;
|
|
struct mwl8k_rxd_8366_ap *rxd = _rxd;
|
|
@@ -894,6 +907,11 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
|
|
|
|
|
|
*qos = rxd->qos_control;
|
|
*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);
|
|
return le16_to_cpu(rxd->pkt_len);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -932,6 +950,11 @@ struct mwl8k_rxd_sta {
|
|
#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001
|
|
#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001
|
|
|
|
|
|
#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02
|
|
#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)
|
|
static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr)
|
|
{
|
|
{
|
|
@@ -990,6 +1013,9 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
|
|
status->freq = ieee80211_channel_to_frequency(rxd->channel);
|
|
status->freq = ieee80211_channel_to_frequency(rxd->channel);
|
|
|
|
|
|
*qos = rxd->qos_control;
|
|
*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);
|
|
return le16_to_cpu(rxd->pkt_len);
|
|
}
|
|
}
|
|
@@ -1148,9 +1174,25 @@ static inline void mwl8k_save_beacon(struct ieee80211_hw *hw,
|
|
ieee80211_queue_work(hw, &priv->finalize_join_worker);
|
|
ieee80211_queue_work(hw, &priv->finalize_join_worker);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline 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)
|
|
static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
|
|
{
|
|
{
|
|
struct mwl8k_priv *priv = hw->priv;
|
|
struct mwl8k_priv *priv = hw->priv;
|
|
|
|
+ struct mwl8k_vif *mwl8k_vif = NULL;
|
|
struct mwl8k_rx_queue *rxq = priv->rxq + index;
|
|
struct mwl8k_rx_queue *rxq = priv->rxq + index;
|
|
int processed;
|
|
int processed;
|
|
|
|
|
|
@@ -1160,6 +1202,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
|
|
void *rxd;
|
|
void *rxd;
|
|
int pkt_len;
|
|
int pkt_len;
|
|
struct ieee80211_rx_status status;
|
|
struct ieee80211_rx_status status;
|
|
|
|
+ struct ieee80211_hdr *wh;
|
|
__le16 qos;
|
|
__le16 qos;
|
|
|
|
|
|
skb = rxq->buf[rxq->head].skb;
|
|
skb = rxq->buf[rxq->head].skb;
|
|
@@ -1186,8 +1229,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
|
|
|
|
|
|
rxq->rxd_count--;
|
|
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
|
|
* Check for a pending join operation. Save a
|
|
@@ -1197,6 +1239,46 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
|
|
if (mwl8k_capture_bssid(priv, (void *)skb->data))
|
|
if (mwl8k_capture_bssid(priv, (void *)skb->data))
|
|
mwl8k_save_beacon(hw, skb);
|
|
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));
|
|
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
|
|
ieee80211_rx_irqsafe(hw, skb);
|
|
ieee80211_rx_irqsafe(hw, skb);
|
|
|
|
|
|
@@ -1499,7 +1581,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
|
|
else
|
|
else
|
|
qos = 0;
|
|
qos = 0;
|
|
|
|
|
|
- mwl8k_encapsulate_tx_frame(skb);
|
|
|
|
|
|
+ if (priv->ap_fw)
|
|
|
|
+ mwl8k_encapsulate_tx_frame(skb);
|
|
|
|
+ else
|
|
|
|
+ mwl8k_add_dma_header(skb, 0);
|
|
|
|
+
|
|
wh = &((struct mwl8k_dma_data *)skb->data)->wh;
|
|
wh = &((struct mwl8k_dma_data *)skb->data)->wh;
|
|
|
|
|
|
tx_info = IEEE80211_SKB_CB(skb);
|
|
tx_info = IEEE80211_SKB_CB(skb);
|
|
@@ -3525,6 +3611,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
|
|
mwl8k_vif->vif = vif;
|
|
mwl8k_vif->vif = vif;
|
|
mwl8k_vif->macid = macid;
|
|
mwl8k_vif->macid = macid;
|
|
mwl8k_vif->seqno = 0;
|
|
mwl8k_vif->seqno = 0;
|
|
|
|
+ memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN);
|
|
|
|
+ mwl8k_vif->is_hw_crypto_enabled = false;
|
|
|
|
|
|
/* Set the mac address. */
|
|
/* Set the mac address. */
|
|
mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
|
|
mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
|
|
@@ -3930,9 +4018,16 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ } else {
|
|
|
|
+ ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta);
|
|
return ret;
|
|
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);
|
|
return mwl8k_cmd_set_new_stn_add(hw, vif, sta);
|
|
}
|
|
}
|
|
|
|
|