iwlwifi: mvm: report checksum is done also for IPv6 packets
authorSara Sharon <sara.sharon@intel.com>
Wed, 16 Mar 2016 11:57:50 +0000 (13:57 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Wed, 30 Mar 2016 13:21:28 +0000 (16:21 +0300)
Currently the code checks if hardware reported both L4 and L3
checksums as valid, and only then reports it as validated to
the stack.
However, IPv6 does not have checksum at all and the L3 checksum
valid bit is always off for IPv6 packets, with the result of the
stack re-validating L4 checksum.
Fix code to set CHECKSUM_UNNECESSARY also for IPv6 packets whose
TCP/UDP checksum was verified.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c

index 7a16e55df01230fea7b4a098a9392a3969baf5ec..4c086d04809765be7fbffe81ad9361ec5a854241 100644 (file)
@@ -268,12 +268,25 @@ enum iwl_rx_mpdu_amsdu_info {
        IWL_RX_MPDU_AMSDU_LAST_SUBFRAME         = 0x80,
 };
 
+enum iwl_rx_l3_proto_values {
+       IWL_RX_L3_TYPE_NONE,
+       IWL_RX_L3_TYPE_IPV4,
+       IWL_RX_L3_TYPE_IPV4_FRAG,
+       IWL_RX_L3_TYPE_IPV6_FRAG,
+       IWL_RX_L3_TYPE_IPV6,
+       IWL_RX_L3_TYPE_IPV6_IN_IPV4,
+       IWL_RX_L3_TYPE_ARP,
+       IWL_RX_L3_TYPE_EAPOL,
+};
+
+#define IWL_RX_L3_PROTO_POS 4
+
 enum iwl_rx_l3l4_flags {
        IWL_RX_L3L4_IP_HDR_CSUM_OK              = BIT(0),
        IWL_RX_L3L4_TCP_UDP_CSUM_OK             = BIT(1),
        IWL_RX_L3L4_TCP_FIN_SYN_RST_PSH         = BIT(2),
        IWL_RX_L3L4_TCP_ACK                     = BIT(3),
-       IWL_RX_L3L4_L3_PROTO_MASK               = 0xf << 4,
+       IWL_RX_L3L4_L3_PROTO_MASK               = 0xf << IWL_RX_L3_PROTO_POS,
        IWL_RX_L3L4_L4_PROTO_MASK               = 0xf << 8,
        IWL_RX_L3L4_RSS_HASH_MASK               = 0xf << 12,
 };
index 9a54f2d2a66b50897411a10368297a8416ca298a..b2bc3d96a13f6841b55de94d45858d53f8ea36f2 100644 (file)
@@ -294,10 +294,15 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
 {
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
+       u16 flags = le16_to_cpu(desc->l3l4_flags);
+       u8 l3_prot = (u8)((flags & IWL_RX_L3L4_L3_PROTO_MASK) >>
+                         IWL_RX_L3_PROTO_POS);
 
        if (mvmvif->features & NETIF_F_RXCSUM &&
-           desc->l3l4_flags & cpu_to_le16(IWL_RX_L3L4_IP_HDR_CSUM_OK) &&
-           desc->l3l4_flags & cpu_to_le16(IWL_RX_L3L4_TCP_UDP_CSUM_OK))
+           flags & IWL_RX_L3L4_TCP_UDP_CSUM_OK &&
+           (flags & IWL_RX_L3L4_IP_HDR_CSUM_OK ||
+            l3_prot == IWL_RX_L3_TYPE_IPV6 ||
+            l3_prot == IWL_RX_L3_TYPE_IPV6_FRAG))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 }