Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-block.git] / net / ipv6 / ip6_output.c
index 87f8419a68fdf888b37a2643345d89b85005671d..93beee944657f12c61482996b941dd6b9cf1f7be 100644 (file)
 
 static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 
-static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
-{
-       static u32 ipv6_fragmentation_id = 1;
-       static DEFINE_SPINLOCK(ip6_id_lock);
-
-       spin_lock_bh(&ip6_id_lock);
-       fhdr->identification = htonl(ipv6_fragmentation_id);
-       if (++ipv6_fragmentation_id == 0)
-               ipv6_fragmentation_id = 1;
-       spin_unlock_bh(&ip6_id_lock);
-}
-
 int __ip6_local_out(struct sk_buff *skb)
 {
        int len;
@@ -706,7 +694,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
 
-               ipv6_select_ident(skb, fh);
+               ipv6_select_ident(fh);
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                fh->frag_off = htons(IP6_MF);
@@ -844,7 +832,7 @@ slow_path:
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                if (!frag_id) {
-                       ipv6_select_ident(skb, fh);
+                       ipv6_select_ident(fh);
                        frag_id = fh->identification;
                } else
                        fh->identification = frag_id;
@@ -1087,11 +1075,13 @@ static inline int ip6_ufo_append_data(struct sock *sk,
        if (!err) {
                struct frag_hdr fhdr;
 
-               /* specify the length of each IP datagram fragment*/
-               skb_shinfo(skb)->gso_size = mtu - fragheaderlen -
-                                           sizeof(struct frag_hdr);
+               /* Specify the length of each IPv6 datagram fragment.
+                * It has to be a multiple of 8.
+                */
+               skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
+                                            sizeof(struct frag_hdr)) & ~7;
                skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
-               ipv6_select_ident(skb, &fhdr);
+               ipv6_select_ident(&fhdr);
                skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
                __skb_queue_tail(&sk->sk_write_queue, skb);