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(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(struct sk_buff
*skb
, char *hdr
, struct tso_t
*tso
,
17 int size
, bool is_last
)
20 int hdr_len
= skb_transport_offset(skb
) + tcp_hdrlen(skb
);
21 int mac_hdr_len
= skb_network_offset(skb
);
23 memcpy(hdr
, skb
->data
, hdr_len
);
25 struct iphdr
*iph
= (void *)(hdr
+ mac_hdr_len
);
27 iph
->id
= htons(tso
->ip_id
);
28 iph
->tot_len
= htons(size
+ hdr_len
- mac_hdr_len
);
31 struct ipv6hdr
*iph
= (void *)(hdr
+ mac_hdr_len
);
33 iph
->payload_len
= htons(size
+ tcp_hdrlen(skb
));
35 tcph
= (struct tcphdr
*)(hdr
+ skb_transport_offset(skb
));
36 put_unaligned_be32(tso
->tcp_seq
, &tcph
->seq
);
39 /* Clear all special flags for not last packet */
45 EXPORT_SYMBOL(tso_build_hdr
);
47 void tso_build_data(struct sk_buff
*skb
, struct tso_t
*tso
, int size
)
53 if ((tso
->size
== 0) &&
54 (tso
->next_frag_idx
< skb_shinfo(skb
)->nr_frags
)) {
55 skb_frag_t
*frag
= &skb_shinfo(skb
)->frags
[tso
->next_frag_idx
];
57 /* Move to next segment */
58 tso
->size
= frag
->size
;
59 tso
->data
= page_address(frag
->page
.p
) + frag
->page_offset
;
63 EXPORT_SYMBOL(tso_build_data
);
65 void tso_start(struct sk_buff
*skb
, struct tso_t
*tso
)
67 int hdr_len
= skb_transport_offset(skb
) + tcp_hdrlen(skb
);
69 tso
->ip_id
= ntohs(ip_hdr(skb
)->id
);
70 tso
->tcp_seq
= ntohl(tcp_hdr(skb
)->seq
);
71 tso
->next_frag_idx
= 0;
72 tso
->ipv6
= vlan_get_protocol(skb
) == htons(ETH_P_IPV6
);
74 /* Build first data */
75 tso
->size
= skb_headlen(skb
) - hdr_len
;
76 tso
->data
= skb
->data
+ hdr_len
;
77 if ((tso
->size
== 0) &&
78 (tso
->next_frag_idx
< skb_shinfo(skb
)->nr_frags
)) {
79 skb_frag_t
*frag
= &skb_shinfo(skb
)->frags
[tso
->next_frag_idx
];
81 /* Move to next segment */
82 tso
->size
= frag
->size
;
83 tso
->data
= page_address(frag
->page
.p
) + frag
->page_offset
;
87 EXPORT_SYMBOL(tso_start
);