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

Commit 0985aa84 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "net: qualcomm: rmnet: Set partial checksum on single segments"

parents 574b311f 673195ca
Loading
Loading
Loading
Loading
+20 −7
Original line number Diff line number Diff line
@@ -375,12 +375,28 @@ static void rmnet_frag_gso_stamp(struct sk_buff *skb,
				 struct rmnet_frag_descriptor *frag_desc)
{
	struct skb_shared_info *shinfo = skb_shinfo(skb);

	if (frag_desc->trans_proto == IPPROTO_TCP)
		shinfo->gso_type = (frag_desc->ip_proto == 4) ?
				   SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
	else
		shinfo->gso_type = SKB_GSO_UDP_L4;

	shinfo->gso_size = frag_desc->gso_size;
	shinfo->gso_segs = frag_desc->gso_segs;
}

/* Set the partial checksum information. Sets the transport checksum tot he
 * pseudoheader checksum and sets the offload metadata.
 */
static void rmnet_frag_partial_csum(struct sk_buff *skb,
				    struct rmnet_frag_descriptor *frag_desc)
{
	struct iphdr *iph = (struct iphdr *)skb->data;
	__sum16 pseudo;
	u16 pkt_len = skb->len - frag_desc->ip_len;
	bool ipv4 = frag_desc->ip_proto == 4;

	if (ipv4) {
	if (frag_desc->ip_proto == 4) {
		iph->tot_len = htons(skb->len);
		iph->check = 0;
		iph->check = ip_fast_csum(iph, iph->ihl);
@@ -401,7 +417,6 @@ static void rmnet_frag_gso_stamp(struct sk_buff *skb,
				    ((u8 *)iph + frag_desc->ip_len);

		tp->check = pseudo;
		shinfo->gso_type = (ipv4) ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
		skb->csum_offset = offsetof(struct tcphdr, check);
	} else {
		struct udphdr *up = (struct udphdr *)
@@ -409,14 +424,11 @@ static void rmnet_frag_gso_stamp(struct sk_buff *skb,

		up->len = htons(pkt_len);
		up->check = pseudo;
		shinfo->gso_type = SKB_GSO_UDP_L4;
		skb->csum_offset = offsetof(struct udphdr, check);
	}

	skb->ip_summed = CHECKSUM_PARTIAL;
	skb->csum_start = (u8 *)iph + frag_desc->ip_len - skb->head;
	shinfo->gso_size = frag_desc->gso_size;
	shinfo->gso_segs = frag_desc->gso_segs;
}

/* Allocate and populate an skb to contain the packet represented by the
@@ -542,7 +554,8 @@ static struct sk_buff *rmnet_alloc_skb(struct rmnet_frag_descriptor *frag_desc,

	/* Handle csum offloading */
	if (frag_desc->csum_valid) {
		head_skb->ip_summed = CHECKSUM_UNNECESSARY;
		/* Set the partial checksum information */
		rmnet_frag_partial_csum(head_skb, frag_desc);
	} else if (frag_desc->hdrs_valid &&
		   (frag_desc->trans_proto == IPPROTO_TCP ||
		    frag_desc->trans_proto == IPPROTO_UDP)) {
+23 −8
Original line number Diff line number Diff line
@@ -656,12 +656,28 @@ static void rmnet_map_gso_stamp(struct sk_buff *skb,
				struct rmnet_map_coal_metadata *coal_meta)
{
	struct skb_shared_info *shinfo = skb_shinfo(skb);

	if (coal_meta->trans_proto == IPPROTO_TCP)
		shinfo->gso_type = (coal_meta->ip_proto == 4) ?
				   SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
	else
		shinfo->gso_type = SKB_GSO_UDP_L4;

	shinfo->gso_size = coal_meta->data_len;
	shinfo->gso_segs = coal_meta->pkt_count;
}

/* Handles setting up the partial checksum in the skb. Sets the transport
 * checksum to the pseudoheader checksum and sets the csum offload metadata
 */
static void rmnet_map_partial_csum(struct sk_buff *skb,
				   struct rmnet_map_coal_metadata *coal_meta)
{
	unsigned char *data = skb->data;
	__sum16 pseudo;
	u16 pkt_len = skb->len - coal_meta->ip_len;
	bool ipv4 = coal_meta->ip_proto == 4;

	if (ipv4) {
	if (coal_meta->ip_proto == 4) {
		struct iphdr *iph = (struct iphdr *)data;

		pseudo = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
@@ -678,20 +694,16 @@ static void rmnet_map_gso_stamp(struct sk_buff *skb,
		struct tcphdr *tp = (struct tcphdr *)(data + coal_meta->ip_len);

		tp->check = pseudo;
		shinfo->gso_type = (ipv4) ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
		skb->csum_offset = offsetof(struct tcphdr, check);
	} else {
		struct udphdr *up = (struct udphdr *)(data + coal_meta->ip_len);

		up->check = pseudo;
		shinfo->gso_type = SKB_GSO_UDP_L4;
		skb->csum_offset = offsetof(struct udphdr, check);
	}

	skb->ip_summed = CHECKSUM_PARTIAL;
	skb->csum_start = skb->data + coal_meta->ip_len - skb->head;
	shinfo->gso_size = coal_meta->data_len;
	shinfo->gso_segs = coal_meta->pkt_count;
}

static void
@@ -756,7 +768,8 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,

	/* Handle checksum status */
	if (likely(csum_valid)) {
		skbn->ip_summed = CHECKSUM_UNNECESSARY;
		/* Set the partial checksum information */
		rmnet_map_partial_csum(skbn, coal_meta);
	} else if (check) {
		/* Unfortunately, we have to fake a bad checksum here, since
		 * the original bad value is lost by the hardware. The only
@@ -938,8 +951,10 @@ static void rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
		coal_meta.data_len = ntohs(coal_hdr->nl_pairs[0].pkt_len);
		coal_meta.data_len -= coal_meta.ip_len + coal_meta.trans_len;
		coal_meta.pkt_count = coal_hdr->nl_pairs[0].num_packets;
		if (coal_meta.pkt_count > 1)
		if (coal_meta.pkt_count > 1) {
			rmnet_map_partial_csum(coal_skb, &coal_meta);
			rmnet_map_gso_stamp(coal_skb, &coal_meta);
		}

		__skb_queue_tail(list, coal_skb);
		return;