]> Pileus Git - ~andy/linux/blobdiff - net/ipv4/ip_output.c
ipv4: fix DO and PROBE pmtu mode regarding local fragmentation with UFO/CORK
[~andy/linux] / net / ipv4 / ip_output.c
index 7d8357bb2ba654a88fbf564897beb88e412f4974..51be64e18e32e92ffaf898351142f01d9c9c42ec 100644 (file)
@@ -772,15 +772,20 @@ static inline int ip_ufo_append_data(struct sock *sk,
                /* initialize protocol header pointer */
                skb->transport_header = skb->network_header + fragheaderlen;
 
-               skb->ip_summed = CHECKSUM_PARTIAL;
                skb->csum = 0;
 
-               /* specify the length of each IP datagram fragment */
-               skb_shinfo(skb)->gso_size = maxfraglen - fragheaderlen;
-               skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+
                __skb_queue_tail(queue, skb);
+       } else if (skb_is_gso(skb)) {
+               goto append;
        }
 
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       /* specify the length of each IP datagram fragment */
+       skb_shinfo(skb)->gso_size = maxfraglen - fragheaderlen;
+       skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+
+append:
        return skb_append_datato_frags(sk, skb, getfrag, from,
                                       (length - transhdrlen));
 }
@@ -805,7 +810,7 @@ static int __ip_append_data(struct sock *sk,
        int copy;
        int err;
        int offset = 0;
-       unsigned int maxfraglen, fragheaderlen;
+       unsigned int maxfraglen, fragheaderlen, maxnonfragsize;
        int csummode = CHECKSUM_NONE;
        struct rtable *rt = (struct rtable *)cork->dst;
 
@@ -818,8 +823,10 @@ static int __ip_append_data(struct sock *sk,
 
        fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
        maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;
+       maxnonfragsize = (inet->pmtudisc >= IP_PMTUDISC_DO) ?
+                        mtu : 0xFFFF;
 
-       if (cork->length + length > 0xFFFF - fragheaderlen) {
+       if (cork->length + length > maxnonfragsize - fragheaderlen) {
                ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
                               mtu-exthdrlen);
                return -EMSGSIZE;
@@ -1117,7 +1124,7 @@ ssize_t   ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
        int mtu;
        int len;
        int err;
-       unsigned int maxfraglen, fragheaderlen, fraggap;
+       unsigned int maxfraglen, fragheaderlen, fraggap, maxnonfragsize;
 
        if (inet->hdrincl)
                return -EPERM;
@@ -1141,8 +1148,10 @@ ssize_t  ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
 
        fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
        maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;
+       maxnonfragsize = (inet->pmtudisc >= IP_PMTUDISC_DO) ?
+                        mtu : 0xFFFF;
 
-       if (cork->length + size > 0xFFFF - fragheaderlen) {
+       if (cork->length + size > maxnonfragsize - fragheaderlen) {
                ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, mtu);
                return -EMSGSIZE;
        }