skbuff: introduce skb_gso_validate_mtu
[cascardo/linux.git] / net / core / skbuff.c
index f2b77e5..5ca562b 100644 (file)
@@ -3116,9 +3116,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 +3442,7 @@ done:
        NAPI_GRO_CB(skb)->same_flow = 1;
        return 0;
 }
+EXPORT_SYMBOL_GPL(skb_gro_receive);
 
 void __init skb_init(void)
 {
@@ -4387,6 +4392,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) {