1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/export.h>
3 #include <linux/if_vlan.h>
6 #include <linux/unaligned.h>
8 void tso_build_hdr(const struct sk_buff
*skb
, char *hdr
, struct tso_t
*tso
,
9 int size
, bool is_last
)
11 int hdr_len
= skb_transport_offset(skb
) + tso
->tlen
;
12 int mac_hdr_len
= skb_network_offset(skb
);
14 memcpy(hdr
, skb
->data
, hdr_len
);
16 struct iphdr
*iph
= (void *)(hdr
+ mac_hdr_len
);
18 iph
->id
= htons(tso
->ip_id
);
19 iph
->tot_len
= htons(size
+ hdr_len
- mac_hdr_len
);
22 struct ipv6hdr
*iph
= (void *)(hdr
+ mac_hdr_len
);
24 iph
->payload_len
= htons(size
+ tso
->tlen
);
26 hdr
+= skb_transport_offset(skb
);
27 if (tso
->tlen
!= sizeof(struct udphdr
)) {
28 struct tcphdr
*tcph
= (struct tcphdr
*)hdr
;
30 put_unaligned_be32(tso
->tcp_seq
, &tcph
->seq
);
33 /* Clear all special flags for not last packet */
39 struct udphdr
*uh
= (struct udphdr
*)hdr
;
41 uh
->len
= htons(sizeof(*uh
) + size
);
44 EXPORT_SYMBOL(tso_build_hdr
);
46 void tso_build_data(const struct sk_buff
*skb
, struct tso_t
*tso
, int size
)
48 tso
->tcp_seq
+= size
; /* not worth avoiding this operation for UDP */
52 if ((tso
->size
== 0) &&
53 (tso
->next_frag_idx
< skb_shinfo(skb
)->nr_frags
)) {
54 skb_frag_t
*frag
= &skb_shinfo(skb
)->frags
[tso
->next_frag_idx
];
56 /* Move to next segment */
57 tso
->size
= skb_frag_size(frag
);
58 tso
->data
= skb_frag_address(frag
);
62 EXPORT_SYMBOL(tso_build_data
);
64 int tso_start(struct sk_buff
*skb
, struct tso_t
*tso
)
66 int tlen
= skb_is_gso_tcp(skb
) ? tcp_hdrlen(skb
) : sizeof(struct udphdr
);
67 int hdr_len
= skb_transport_offset(skb
) + tlen
;
70 tso
->ip_id
= ntohs(ip_hdr(skb
)->id
);
71 tso
->tcp_seq
= (tlen
!= sizeof(struct udphdr
)) ? ntohl(tcp_hdr(skb
)->seq
) : 0;
72 tso
->next_frag_idx
= 0;
73 tso
->ipv6
= vlan_get_protocol(skb
) == htons(ETH_P_IPV6
);
75 /* Build first data */
76 tso
->size
= skb_headlen(skb
) - hdr_len
;
77 tso
->data
= skb
->data
+ hdr_len
;
78 if ((tso
->size
== 0) &&
79 (tso
->next_frag_idx
< skb_shinfo(skb
)->nr_frags
)) {
80 skb_frag_t
*frag
= &skb_shinfo(skb
)->frags
[tso
->next_frag_idx
];
82 /* Move to next segment */
83 tso
->size
= skb_frag_size(frag
);
84 tso
->data
= skb_frag_address(frag
);
89 EXPORT_SYMBOL(tso_start
);