0001
0002
0003
0004
0005
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
0031
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
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
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
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 }