1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/export.h>
3 #include <linux/if_vlan.h>
6 #include <asm/unaligned.h>
8 /* Calculate expected number of TX descriptors */
9 int tso_count_descs(const struct sk_buff
*skb
)
12 return skb_shinfo(skb
)->gso_segs
* 2 + skb_shinfo(skb
)->nr_frags
;
14 EXPORT_SYMBOL(tso_count_descs
);
16 void tso_build_hdr(const struct sk_buff
*skb
, char *hdr
, struct tso_t
*tso
,
17 int size
, bool is_last
)
19 int hdr_len
= skb_transport_offset(skb
) + tso
->tlen
;
20 int mac_hdr_len
= skb_network_offset(skb
);
22 memcpy(hdr
, skb
->data
, hdr_len
);
24 struct iphdr
*iph
= (void *)(hdr
+ mac_hdr_len
);
26 iph
->id
= htons(tso
->ip_id
);
27 iph
->tot_len
= htons(size
+ hdr_len
- mac_hdr_len
);
30 struct ipv6hdr
*iph
= (void *)(hdr
+ mac_hdr_len
);
32 iph
->payload_len
= htons(size
+ tso
->tlen
);
34 hdr
+= skb_transport_offset(skb
);
35 if (tso
->tlen
!= sizeof(struct udphdr
)) {
36 struct tcphdr
*tcph
= (struct tcphdr
*)hdr
;
38 put_unaligned_be32(tso
->tcp_seq
, &tcph
->seq
);
41 /* Clear all special flags for not last packet */
47 struct udphdr
*uh
= (struct udphdr
*)hdr
;
49 uh
->len
= htons(sizeof(*uh
) + size
);
52 EXPORT_SYMBOL(tso_build_hdr
);
54 void tso_build_data(const struct sk_buff
*skb
, struct tso_t
*tso
, int size
)
56 tso
->tcp_seq
+= size
; /* not worth avoiding this operation for UDP */
60 if ((tso
->size
== 0) &&
61 (tso
->next_frag_idx
< skb_shinfo(skb
)->nr_frags
)) {
62 skb_frag_t
*frag
= &skb_shinfo(skb
)->frags
[tso
->next_frag_idx
];
64 /* Move to next segment */
65 tso
->size
= skb_frag_size(frag
);
66 tso
->data
= skb_frag_address(frag
);
70 EXPORT_SYMBOL(tso_build_data
);
72 int tso_start(struct sk_buff
*skb
, struct tso_t
*tso
)
74 int tlen
= skb_is_gso_tcp(skb
) ? tcp_hdrlen(skb
) : sizeof(struct udphdr
);
75 int hdr_len
= skb_transport_offset(skb
) + tlen
;
78 tso
->ip_id
= ntohs(ip_hdr(skb
)->id
);
79 tso
->tcp_seq
= (tlen
!= sizeof(struct udphdr
)) ? ntohl(tcp_hdr(skb
)->seq
) : 0;
80 tso
->next_frag_idx
= 0;
81 tso
->ipv6
= vlan_get_protocol(skb
) == htons(ETH_P_IPV6
);
83 /* Build first data */
84 tso
->size
= skb_headlen(skb
) - hdr_len
;
85 tso
->data
= skb
->data
+ hdr_len
;
86 if ((tso
->size
== 0) &&
87 (tso
->next_frag_idx
< skb_shinfo(skb
)->nr_frags
)) {
88 skb_frag_t
*frag
= &skb_shinfo(skb
)->frags
[tso
->next_frag_idx
];
90 /* Move to next segment */
91 tso
->size
= skb_frag_size(frag
);
92 tso
->data
= skb_frag_address(frag
);
97 EXPORT_SYMBOL(tso_start
);