Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * sctp_offload - GRO/GSO Offloading for SCTP
0004  *
0005  * Copyright (C) 2015, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/kprobes.h>
0012 #include <linux/socket.h>
0013 #include <linux/sctp.h>
0014 #include <linux/proc_fs.h>
0015 #include <linux/vmalloc.h>
0016 #include <linux/module.h>
0017 #include <linux/kfifo.h>
0018 #include <linux/time.h>
0019 #include <net/net_namespace.h>
0020 
0021 #include <linux/skbuff.h>
0022 #include <net/sctp/sctp.h>
0023 #include <net/sctp/checksum.h>
0024 #include <net/protocol.h>
0025 
0026 static __le32 sctp_gso_make_checksum(struct sk_buff *skb)
0027 {
0028     skb->ip_summed = CHECKSUM_NONE;
0029     skb->csum_not_inet = 0;
0030     /* csum and csum_start in GSO CB may be needed to do the UDP
0031      * checksum when it's a UDP tunneling packet.
0032      */
0033     SKB_GSO_CB(skb)->csum = (__force __wsum)~0;
0034     SKB_GSO_CB(skb)->csum_start = skb_headroom(skb) + skb->len;
0035     return sctp_compute_cksum(skb, skb_transport_offset(skb));
0036 }
0037 
0038 static struct sk_buff *sctp_gso_segment(struct sk_buff *skb,
0039                     netdev_features_t features)
0040 {
0041     struct sk_buff *segs = ERR_PTR(-EINVAL);
0042     struct sctphdr *sh;
0043 
0044     if (!skb_is_gso_sctp(skb))
0045         goto out;
0046 
0047     sh = sctp_hdr(skb);
0048     if (!pskb_may_pull(skb, sizeof(*sh)))
0049         goto out;
0050 
0051     __skb_pull(skb, sizeof(*sh));
0052 
0053     if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
0054         /* Packet is from an untrusted source, reset gso_segs. */
0055         struct skb_shared_info *pinfo = skb_shinfo(skb);
0056         struct sk_buff *frag_iter;
0057 
0058         pinfo->gso_segs = 0;
0059         if (skb->len != skb->data_len) {
0060             /* Means we have chunks in here too */
0061             pinfo->gso_segs++;
0062         }
0063 
0064         skb_walk_frags(skb, frag_iter)
0065             pinfo->gso_segs++;
0066 
0067         segs = NULL;
0068         goto out;
0069     }
0070 
0071     segs = skb_segment(skb, (features | NETIF_F_HW_CSUM) & ~NETIF_F_SG);
0072     if (IS_ERR(segs))
0073         goto out;
0074 
0075     /* All that is left is update SCTP CRC if necessary */
0076     if (!(features & NETIF_F_SCTP_CRC)) {
0077         for (skb = segs; skb; skb = skb->next) {
0078             if (skb->ip_summed == CHECKSUM_PARTIAL) {
0079                 sh = sctp_hdr(skb);
0080                 sh->checksum = sctp_gso_make_checksum(skb);
0081             }
0082         }
0083     }
0084 
0085 out:
0086     return segs;
0087 }
0088 
0089 static const struct net_offload sctp_offload = {
0090     .callbacks = {
0091         .gso_segment = sctp_gso_segment,
0092     },
0093 };
0094 
0095 static const struct net_offload sctp6_offload = {
0096     .callbacks = {
0097         .gso_segment = sctp_gso_segment,
0098     },
0099 };
0100 
0101 int __init sctp_offload_init(void)
0102 {
0103     int ret;
0104 
0105     ret = inet_add_offload(&sctp_offload, IPPROTO_SCTP);
0106     if (ret)
0107         goto out;
0108 
0109     ret = inet6_add_offload(&sctp6_offload, IPPROTO_SCTP);
0110     if (ret)
0111         goto ipv4;
0112 
0113     crc32c_csum_stub = &sctp_csum_ops;
0114     return ret;
0115 
0116 ipv4:
0117     inet_del_offload(&sctp_offload, IPPROTO_SCTP);
0118 out:
0119     return ret;
0120 }