|
@@ -3393,6 +3393,65 @@ static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len)
|
|
|
priv->rx_stats[idx].bytes += len;
|
|
|
}
|
|
|
|
|
|
+static u32 iwl4965_translate_rx_status(u32 decrypt_in)
|
|
|
+{
|
|
|
+ u32 decrypt_out = 0;
|
|
|
+
|
|
|
+ if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
|
|
|
+ RX_RES_STATUS_STATION_FOUND)
|
|
|
+ decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
|
|
|
+ RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
|
|
|
+
|
|
|
+ decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
|
|
|
+
|
|
|
+ /* packet was not encrypted */
|
|
|
+ if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
|
|
|
+ RX_RES_STATUS_SEC_TYPE_NONE)
|
|
|
+ return decrypt_out;
|
|
|
+
|
|
|
+ /* packet was encrypted with unknown alg */
|
|
|
+ if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
|
|
|
+ RX_RES_STATUS_SEC_TYPE_ERR)
|
|
|
+ return decrypt_out;
|
|
|
+
|
|
|
+ /* decryption was not done in HW */
|
|
|
+ if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
|
|
|
+ RX_MPDU_RES_STATUS_DEC_DONE_MSK)
|
|
|
+ return decrypt_out;
|
|
|
+
|
|
|
+ switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
|
|
|
+
|
|
|
+ case RX_RES_STATUS_SEC_TYPE_CCMP:
|
|
|
+ /* alg is CCM: check MIC only */
|
|
|
+ if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
|
|
|
+ /* Bad MIC */
|
|
|
+ decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
|
|
|
+ else
|
|
|
+ decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RX_RES_STATUS_SEC_TYPE_TKIP:
|
|
|
+ if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
|
|
|
+ /* Bad TTAK */
|
|
|
+ decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /* fall through if TTAK OK */
|
|
|
+ default:
|
|
|
+ if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
|
|
|
+ decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
|
|
|
+ else
|
|
|
+ decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
|
|
|
+ break;
|
|
|
+ };
|
|
|
+
|
|
|
+ IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n",
|
|
|
+ decrypt_in, decrypt_out);
|
|
|
+
|
|
|
+ return decrypt_out;
|
|
|
+}
|
|
|
+
|
|
|
static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
|
|
|
int include_phy,
|
|
|
struct iwl4965_rx_mem_buffer *rxb,
|
|
@@ -3406,6 +3465,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
|
|
|
__le32 *rx_end;
|
|
|
unsigned int skblen;
|
|
|
u32 ampdu_status;
|
|
|
+ u32 ampdu_status_legacy;
|
|
|
|
|
|
if (!include_phy && priv->last_phy_res[0])
|
|
|
rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
|
|
@@ -3442,6 +3502,12 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
|
|
|
ampdu_status = le32_to_cpu(*rx_end);
|
|
|
skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32);
|
|
|
|
|
|
+ if (!include_phy) {
|
|
|
+ /* New status scheme, need to translate */
|
|
|
+ ampdu_status_legacy = ampdu_status;
|
|
|
+ ampdu_status = iwl4965_translate_rx_status(ampdu_status);
|
|
|
+ }
|
|
|
+
|
|
|
/* start from MAC */
|
|
|
skb_reserve(rxb->skb, (void *)hdr - (void *)pkt);
|
|
|
skb_put(rxb->skb, len); /* end where data ends */
|