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 7a16e55..4c086d0 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 9a54f2d..b2bc3d9 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;
 }