Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/export.h>
0003 #include <linux/if_vlan.h>
0004 #include <net/ip.h>
0005 #include <net/tso.h>
0006 #include <asm/unaligned.h>
0007 
0008 /* Calculate expected number of TX descriptors */
0009 int tso_count_descs(const struct sk_buff *skb)
0010 {
0011     /* The Marvell Way */
0012     return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags;
0013 }
0014 EXPORT_SYMBOL(tso_count_descs);
0015 
0016 void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
0017            int size, bool is_last)
0018 {
0019     int hdr_len = skb_transport_offset(skb) + tso->tlen;
0020     int mac_hdr_len = skb_network_offset(skb);
0021 
0022     memcpy(hdr, skb->data, hdr_len);
0023     if (!tso->ipv6) {
0024         struct iphdr *iph = (void *)(hdr + mac_hdr_len);
0025 
0026         iph->id = htons(tso->ip_id);
0027         iph->tot_len = htons(size + hdr_len - mac_hdr_len);
0028         tso->ip_id++;
0029     } else {
0030         struct ipv6hdr *iph = (void *)(hdr + mac_hdr_len);
0031 
0032         iph->payload_len = htons(size + tso->tlen);
0033     }
0034     hdr += skb_transport_offset(skb);
0035     if (tso->tlen != sizeof(struct udphdr)) {
0036         struct tcphdr *tcph = (struct tcphdr *)hdr;
0037 
0038         put_unaligned_be32(tso->tcp_seq, &tcph->seq);
0039 
0040         if (!is_last) {
0041             /* Clear all special flags for not last packet */
0042             tcph->psh = 0;
0043             tcph->fin = 0;
0044             tcph->rst = 0;
0045         }
0046     } else {
0047         struct udphdr *uh = (struct udphdr *)hdr;
0048 
0049         uh->len = htons(sizeof(*uh) + size);
0050     }
0051 }
0052 EXPORT_SYMBOL(tso_build_hdr);
0053 
0054 void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size)
0055 {
0056     tso->tcp_seq += size; /* not worth avoiding this operation for UDP */
0057     tso->size -= size;
0058     tso->data += size;
0059 
0060     if ((tso->size == 0) &&
0061         (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) {
0062         skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx];
0063 
0064         /* Move to next segment */
0065         tso->size = skb_frag_size(frag);
0066         tso->data = skb_frag_address(frag);
0067         tso->next_frag_idx++;
0068     }
0069 }
0070 EXPORT_SYMBOL(tso_build_data);
0071 
0072 int tso_start(struct sk_buff *skb, struct tso_t *tso)
0073 {
0074     int tlen = skb_is_gso_tcp(skb) ? tcp_hdrlen(skb) : sizeof(struct udphdr);
0075     int hdr_len = skb_transport_offset(skb) + tlen;
0076 
0077     tso->tlen = tlen;
0078     tso->ip_id = ntohs(ip_hdr(skb)->id);
0079     tso->tcp_seq = (tlen != sizeof(struct udphdr)) ? ntohl(tcp_hdr(skb)->seq) : 0;
0080     tso->next_frag_idx = 0;
0081     tso->ipv6 = vlan_get_protocol(skb) == htons(ETH_P_IPV6);
0082 
0083     /* Build first data */
0084     tso->size = skb_headlen(skb) - hdr_len;
0085     tso->data = skb->data + hdr_len;
0086     if ((tso->size == 0) &&
0087         (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) {
0088         skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx];
0089 
0090         /* Move to next segment */
0091         tso->size = skb_frag_size(frag);
0092         tso->data = skb_frag_address(frag);
0093         tso->next_frag_idx++;
0094     }
0095     return hdr_len;
0096 }
0097 EXPORT_SYMBOL(tso_start);