Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9af0ab5 authored by Sean Tranchetti's avatar Sean Tranchetti Committed by Gerrit - the friendly Code Review server
Browse files

net: qualcomm: rmnet: treat IPv4 UDP zero checksum as valid



UDPv4 zero checksum packets are marked as having an invalid checksum by
the hardware. This can cause problems when segmenting coalesced packets
with zero checksum, as RmNet will build a bad checksum for them, thinking
that the packets need to be dropped by the stack.

Change-Id: I4f5eb13fb6ae3664185d3f6703aaff978bcdfb4e
Signed-off-by: default avatarSean Tranchetti <stranche@codeaurora.org>
parent 70fe4cf2
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -670,6 +670,12 @@ static void __rmnet_frag_segment_data(struct rmnet_frag_descriptor *coal_desc,
		new_frag->tcp_seq_set = 1;
		new_frag->tcp_seq = htonl(ntohl(th->seq) +
					  coal_desc->data_offset);
	} else if (coal_desc->trans_proto == IPPROTO_UDP) {
		struct udphdr *uh;

		uh = (struct udphdr *)(hdr_start + coal_desc->ip_len);
		if (coal_desc->ip_proto == 4 && !uh->check)
			csum_valid = true;
	}

	if (coal_desc->ip_proto == 4) {
@@ -734,6 +740,7 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
	u8 pkt, total_pkt = 0;
	u8 nlo;
	bool gro = coal_desc->dev->features & NETIF_F_GRO_HW;
	bool zero_csum = false;

	/* Pull off the headers we no longer need */
	if (!rmnet_frag_pull(coal_desc, port, sizeof(struct rmnet_map_header)))
@@ -794,7 +801,12 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
		th = (struct tcphdr *)((u8 *)iph + coal_desc->ip_len);
		coal_desc->trans_len = th->doff * 4;
	} else if (coal_desc->trans_proto == IPPROTO_UDP) {
		coal_desc->trans_len = sizeof(struct udphdr);
		struct udphdr *uh;

		uh = (struct udphdr *)((u8 *)iph + coal_desc->ip_len);
		coal_desc->trans_len = sizeof(*uh);
		if (coal_desc->ip_proto == 4 && !uh->check)
			zero_csum = true;
	} else {
		priv->stats.coal.coal_trans_invalid++;
		return;
@@ -802,7 +814,7 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,

	coal_desc->hdrs_valid = 1;

	if (rmnet_map_v5_csum_buggy(coal_hdr)) {
	if (rmnet_map_v5_csum_buggy(coal_hdr) && !zero_csum) {
		/* Mark the checksum as valid if it checks out */
		if (rmnet_frag_validate_csum(coal_desc))
			coal_desc->csum_valid = true;
+9 −2
Original line number Diff line number Diff line
@@ -716,6 +716,7 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
	struct rmnet_priv *priv = netdev_priv(coal_skb->dev);
	__sum16 *check = NULL;
	u32 alloc_len;
	bool zero_csum = false;

	/* We can avoid copying the data if the SKB we got from the lower-level
	 * drivers was nonlinear.
@@ -747,6 +748,8 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,

		uh->len = htons(skbn->len);
		check = &uh->check;
		if (coal_meta->ip_proto == 4 && !uh->check)
			zero_csum = true;
	}

	/* Push IP header and update necessary fields */
@@ -767,7 +770,7 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
	}

	/* Handle checksum status */
	if (likely(csum_valid)) {
	if (likely(csum_valid) || zero_csum) {
		/* Set the partial checksum information */
		rmnet_map_partial_csum(skbn, coal_meta);
	} else if (check) {
@@ -865,6 +868,7 @@ static void rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
	u8 pkt, total_pkt = 0;
	u8 nlo;
	bool gro = coal_skb->dev->features & NETIF_F_GRO_HW;
	bool zero_csum = false;

	memset(&coal_meta, 0, sizeof(coal_meta));

@@ -926,12 +930,15 @@ static void rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
		uh = (struct udphdr *)((u8 *)iph + coal_meta.ip_len);
		coal_meta.trans_len = sizeof(*uh);
		coal_meta.trans_header = uh;
		/* Check for v4 zero checksum */
		if (coal_meta.ip_proto == 4 && !uh->check)
			zero_csum = true;
	} else {
		priv->stats.coal.coal_trans_invalid++;
		return;
	}

	if (rmnet_map_v5_csum_buggy(coal_hdr)) {
	if (rmnet_map_v5_csum_buggy(coal_hdr) && !zero_csum) {
		rmnet_map_move_headers(coal_skb);
		/* Mark as valid if it checks out */
		if (rmnet_map_validate_csum(coal_skb, &coal_meta))