diff options
author | Nishant Sarmukadam <nishants@marvell.com> | 2010-12-30 14:23:33 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-01-19 11:36:06 -0500 |
commit | d9a07d4980514e701555c4f03b865a54c4c48b4a (patch) | |
tree | faefe4d3977cef4d6e6012cb409d50282c60b3f3 /drivers/net/wireless | |
parent | e53d9b964e2568172149d41b3157af9cde9accaf (diff) |
mwl8k: Set mac80211 rx status flags appropriately when hw crypto is enabled
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>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 101 |
1 files changed, 98 insertions, 3 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 95bbdca0ba87..2b76bbc5e612 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -251,6 +251,12 @@ struct mwl8k_vif { | |||
251 | u8 enabled; | 251 | u8 enabled; |
252 | u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN]; | 252 | u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN]; |
253 | } wep_key_conf[NUM_WEP_KEYS]; | 253 | } wep_key_conf[NUM_WEP_KEYS]; |
254 | |||
255 | /* BSSID */ | ||
256 | u8 bssid[ETH_ALEN]; | ||
257 | |||
258 | /* A flag to indicate is HW crypto is enabled for this bssid */ | ||
259 | bool is_hw_crypto_enabled; | ||
254 | }; | 260 | }; |
255 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) | 261 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) |
256 | 262 | ||
@@ -834,6 +840,13 @@ struct mwl8k_rxd_8366_ap { | |||
834 | 840 | ||
835 | #define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 | 841 | #define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 |
836 | 842 | ||
843 | /* 8366 AP rx_status bits */ | ||
844 | #define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK 0x80 | ||
845 | #define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF | ||
846 | #define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02 | ||
847 | #define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04 | ||
848 | #define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08 | ||
849 | |||
837 | static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) | 850 | static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) |
838 | { | 851 | { |
839 | struct mwl8k_rxd_8366_ap *rxd = _rxd; | 852 | struct mwl8k_rxd_8366_ap *rxd = _rxd; |
@@ -894,6 +907,11 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, | |||
894 | 907 | ||
895 | *qos = rxd->qos_control; | 908 | *qos = rxd->qos_control; |
896 | 909 | ||
910 | if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) && | ||
911 | (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) && | ||
912 | (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR)) | ||
913 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
914 | |||
897 | return le16_to_cpu(rxd->pkt_len); | 915 | return le16_to_cpu(rxd->pkt_len); |
898 | } | 916 | } |
899 | 917 | ||
@@ -932,6 +950,11 @@ struct mwl8k_rxd_sta { | |||
932 | #define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 | 950 | #define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 |
933 | 951 | ||
934 | #define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 | 952 | #define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 |
953 | #define MWL8K_STA_RX_CTRL_DECRYPT_ERROR 0x04 | ||
954 | /* ICV=0 or MIC=1 */ | ||
955 | #define MWL8K_STA_RX_CTRL_DEC_ERR_TYPE 0x08 | ||
956 | /* Key is uploaded only in failure case */ | ||
957 | #define MWL8K_STA_RX_CTRL_KEY_INDEX 0x30 | ||
935 | 958 | ||
936 | static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) | 959 | static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) |
937 | { | 960 | { |
@@ -990,6 +1013,9 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, | |||
990 | status->freq = ieee80211_channel_to_frequency(rxd->channel); | 1013 | status->freq = ieee80211_channel_to_frequency(rxd->channel); |
991 | 1014 | ||
992 | *qos = rxd->qos_control; | 1015 | *qos = rxd->qos_control; |
1016 | if ((rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DECRYPT_ERROR) && | ||
1017 | (rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DEC_ERR_TYPE)) | ||
1018 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
993 | 1019 | ||
994 | return le16_to_cpu(rxd->pkt_len); | 1020 | return le16_to_cpu(rxd->pkt_len); |
995 | } | 1021 | } |
@@ -1148,9 +1174,25 @@ static inline void mwl8k_save_beacon(struct ieee80211_hw *hw, | |||
1148 | ieee80211_queue_work(hw, &priv->finalize_join_worker); | 1174 | ieee80211_queue_work(hw, &priv->finalize_join_worker); |
1149 | } | 1175 | } |
1150 | 1176 | ||
1177 | static inline struct mwl8k_vif *mwl8k_find_vif_bss(struct list_head *vif_list, | ||
1178 | u8 *bssid) | ||
1179 | { | ||
1180 | struct mwl8k_vif *mwl8k_vif; | ||
1181 | |||
1182 | list_for_each_entry(mwl8k_vif, | ||
1183 | vif_list, list) { | ||
1184 | if (memcmp(bssid, mwl8k_vif->bssid, | ||
1185 | ETH_ALEN) == 0) | ||
1186 | return mwl8k_vif; | ||
1187 | } | ||
1188 | |||
1189 | return NULL; | ||
1190 | } | ||
1191 | |||
1151 | static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | 1192 | static int rxq_process(struct ieee80211_hw *hw, int index, int limit) |
1152 | { | 1193 | { |
1153 | struct mwl8k_priv *priv = hw->priv; | 1194 | struct mwl8k_priv *priv = hw->priv; |
1195 | struct mwl8k_vif *mwl8k_vif = NULL; | ||
1154 | struct mwl8k_rx_queue *rxq = priv->rxq + index; | 1196 | struct mwl8k_rx_queue *rxq = priv->rxq + index; |
1155 | int processed; | 1197 | int processed; |
1156 | 1198 | ||
@@ -1160,6 +1202,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | |||
1160 | void *rxd; | 1202 | void *rxd; |
1161 | int pkt_len; | 1203 | int pkt_len; |
1162 | struct ieee80211_rx_status status; | 1204 | struct ieee80211_rx_status status; |
1205 | struct ieee80211_hdr *wh; | ||
1163 | __le16 qos; | 1206 | __le16 qos; |
1164 | 1207 | ||
1165 | skb = rxq->buf[rxq->head].skb; | 1208 | skb = rxq->buf[rxq->head].skb; |
@@ -1186,8 +1229,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | |||
1186 | 1229 | ||
1187 | rxq->rxd_count--; | 1230 | rxq->rxd_count--; |
1188 | 1231 | ||
1189 | skb_put(skb, pkt_len); | 1232 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; |
1190 | mwl8k_remove_dma_header(skb, qos); | ||
1191 | 1233 | ||
1192 | /* | 1234 | /* |
1193 | * Check for a pending join operation. Save a | 1235 | * Check for a pending join operation. Save a |
@@ -1197,6 +1239,46 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | |||
1197 | if (mwl8k_capture_bssid(priv, (void *)skb->data)) | 1239 | if (mwl8k_capture_bssid(priv, (void *)skb->data)) |
1198 | mwl8k_save_beacon(hw, skb); | 1240 | mwl8k_save_beacon(hw, skb); |
1199 | 1241 | ||
1242 | if (ieee80211_has_protected(wh->frame_control)) { | ||
1243 | |||
1244 | /* Check if hw crypto has been enabled for | ||
1245 | * this bss. If yes, set the status flags | ||
1246 | * accordingly | ||
1247 | */ | ||
1248 | mwl8k_vif = mwl8k_find_vif_bss(&priv->vif_list, | ||
1249 | wh->addr1); | ||
1250 | |||
1251 | if (mwl8k_vif != NULL && | ||
1252 | mwl8k_vif->is_hw_crypto_enabled == true) { | ||
1253 | /* | ||
1254 | * When MMIC ERROR is encountered | ||
1255 | * by the firmware, payload is | ||
1256 | * dropped and only 32 bytes of | ||
1257 | * mwl8k Firmware header is sent | ||
1258 | * to the host. | ||
1259 | * | ||
1260 | * We need to add four bytes of | ||
1261 | * key information. In it | ||
1262 | * MAC80211 expects keyidx set to | ||
1263 | * 0 for triggering Counter | ||
1264 | * Measure of MMIC failure. | ||
1265 | */ | ||
1266 | if (status.flag & RX_FLAG_MMIC_ERROR) { | ||
1267 | struct mwl8k_dma_data *tr; | ||
1268 | tr = (struct mwl8k_dma_data *)skb->data; | ||
1269 | memset((void *)&(tr->data), 0, 4); | ||
1270 | pkt_len += 4; | ||
1271 | } | ||
1272 | |||
1273 | if (!ieee80211_is_auth(wh->frame_control)) | ||
1274 | status.flag |= RX_FLAG_IV_STRIPPED | | ||
1275 | RX_FLAG_DECRYPTED | | ||
1276 | RX_FLAG_MMIC_STRIPPED; | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | skb_put(skb, pkt_len); | ||
1281 | mwl8k_remove_dma_header(skb, qos); | ||
1200 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); | 1282 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); |
1201 | ieee80211_rx_irqsafe(hw, skb); | 1283 | ieee80211_rx_irqsafe(hw, skb); |
1202 | 1284 | ||
@@ -1499,7 +1581,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1499 | else | 1581 | else |
1500 | qos = 0; | 1582 | qos = 0; |
1501 | 1583 | ||
1502 | mwl8k_encapsulate_tx_frame(skb); | 1584 | if (priv->ap_fw) |
1585 | mwl8k_encapsulate_tx_frame(skb); | ||
1586 | else | ||
1587 | mwl8k_add_dma_header(skb, 0); | ||
1588 | |||
1503 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; | 1589 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; |
1504 | 1590 | ||
1505 | tx_info = IEEE80211_SKB_CB(skb); | 1591 | tx_info = IEEE80211_SKB_CB(skb); |
@@ -3525,6 +3611,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
3525 | mwl8k_vif->vif = vif; | 3611 | mwl8k_vif->vif = vif; |
3526 | mwl8k_vif->macid = macid; | 3612 | mwl8k_vif->macid = macid; |
3527 | mwl8k_vif->seqno = 0; | 3613 | mwl8k_vif->seqno = 0; |
3614 | memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN); | ||
3615 | mwl8k_vif->is_hw_crypto_enabled = false; | ||
3528 | 3616 | ||
3529 | /* Set the mac address. */ | 3617 | /* Set the mac address. */ |
3530 | mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); | 3618 | mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); |
@@ -3930,9 +4018,16 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, | |||
3930 | return 0; | 4018 | return 0; |
3931 | } | 4019 | } |
3932 | 4020 | ||
4021 | } else { | ||
4022 | ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta); | ||
3933 | return ret; | 4023 | return ret; |
3934 | } | 4024 | } |
3935 | 4025 | ||
4026 | for (i = 0; i < NUM_WEP_KEYS; i++) { | ||
4027 | key = IEEE80211_KEY_CONF(mwl8k_vif->wep_key_conf[i].key); | ||
4028 | if (mwl8k_vif->wep_key_conf[i].enabled) | ||
4029 | mwl8k_set_key(hw, SET_KEY, vif, sta, key); | ||
4030 | } | ||
3936 | return mwl8k_cmd_set_new_stn_add(hw, vif, sta); | 4031 | return mwl8k_cmd_set_new_stn_add(hw, vif, sta); |
3937 | } | 4032 | } |
3938 | 4033 | ||