sctp: Add GSO support
[cascardo/linux.git] / net / core / skbuff.c
index f2b77e5..b6e0f95 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/slab.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/sctp.h>
 #include <linux/netdevice.h>
 #ifdef CONFIG_NET_CLS_ACT
 #include <net/pkt_sched.h>
@@ -3116,9 +3117,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
                int hsize;
                int size;
 
-               len = head_skb->len - offset;
-               if (len > mss)
-                       len = mss;
+               if (unlikely(mss == GSO_BY_FRAGS)) {
+                       len = list_skb->len;
+               } else {
+                       len = head_skb->len - offset;
+                       if (len > mss)
+                               len = mss;
+               }
 
                hsize = skb_headlen(head_skb) - offset;
                if (hsize < 0)
@@ -3438,6 +3443,7 @@ done:
        NAPI_GRO_CB(skb)->same_flow = 1;
        return 0;
 }
+EXPORT_SYMBOL_GPL(skb_gro_receive);
 
 void __init skb_init(void)
 {
@@ -4378,6 +4384,8 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
                        thlen += inner_tcp_hdrlen(skb);
        } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
                thlen = tcp_hdrlen(skb);
+       } else if (unlikely(shinfo->gso_type & SKB_GSO_SCTP)) {
+               thlen = sizeof(struct sctphdr);
        }
        /* UFO sets gso_size to the size of the fragmentation
         * payload, i.e. the size of the L4 (UDP) header is already
@@ -4387,6 +4395,37 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
 
+/**
+ * skb_gso_validate_mtu - Return in case such skb fits a given MTU
+ *
+ * @skb: GSO skb
+ *
+ * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU
+ * once split.
+ */
+bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu)
+{
+       const struct skb_shared_info *shinfo = skb_shinfo(skb);
+       const struct sk_buff *iter;
+       unsigned int hlen;
+
+       hlen = skb_gso_network_seglen(skb);
+
+       if (shinfo->gso_size != GSO_BY_FRAGS)
+               return hlen <= mtu;
+
+       /* Undo this so we can re-use header sizes */
+       hlen -= GSO_BY_FRAGS;
+
+       skb_walk_frags(skb, iter) {
+               if (hlen + skb_headlen(iter) > mtu)
+                       return false;
+       }
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(skb_gso_validate_mtu);
+
 static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
 {
        if (skb_cow(skb, skb_headroom(skb)) < 0) {