[SK_BUFF]: Introduce skb_network_offset()
[powerpc.git] / net / ipv6 / ip6_output.c
index 3055169..47d0021 100644 (file)
@@ -88,8 +88,8 @@ static inline int ip6_output_finish(struct sk_buff *skb)
 /* dev_loopback_xmit for use with netfilter. */
 static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
 {
-       newskb->mac.raw = newskb->data;
-       __skb_pull(newskb, newskb->nh.raw - newskb->data);
+       skb_reset_mac_header(newskb);
+       __skb_pull(newskb, skb_network_offset(newskb));
        newskb->pkt_type = PACKET_LOOPBACK;
        newskb->ip_summed = CHECKSUM_UNNECESSARY;
        BUG_TRAP(newskb->dst);
@@ -191,7 +191,9 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
                        ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
        }
 
-       hdr = skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, sizeof(struct ipv6hdr));
+       skb_push(skb, sizeof(struct ipv6hdr));
+       skb_reset_network_header(skb);
+       hdr = skb->nh.ipv6h;
 
        /*
         *      Fill in the IPv6 header
@@ -239,6 +241,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
        return -EMSGSIZE;
 }
 
+EXPORT_SYMBOL(ip6_xmit);
+
 /*
  *     To avoid extra problems ND packets are send through this
  *     routine. It's code duplication but I really want to avoid
@@ -624,7 +628,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
                __skb_pull(skb, hlen);
                fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr));
-               skb->nh.raw = __skb_push(skb, hlen);
+               __skb_push(skb, hlen);
+               skb_reset_network_header(skb);
                memcpy(skb->nh.raw, tmp_hdr, hlen);
 
                ipv6_select_ident(skb, fh);
@@ -647,7 +652,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                                frag->ip_summed = CHECKSUM_NONE;
                                frag->h.raw = frag->data;
                                fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr));
-                               frag->nh.raw = __skb_push(frag, hlen);
+                               __skb_push(frag, hlen);
+                               skb_reset_network_header(frag);
                                memcpy(frag->nh.raw, tmp_hdr, hlen);
                                offset += skb->len - hlen - sizeof(struct frag_hdr);
                                fh->nexthdr = nexthdr;
@@ -733,7 +739,7 @@ slow_path:
                ip6_copy_metadata(frag, skb);
                skb_reserve(frag, LL_RESERVED_SPACE(rt->u.dst.dev));
                skb_put(frag, len + hlen + sizeof(struct frag_hdr));
-               frag->nh.raw = frag->data;
+               skb_reset_network_header(frag);
                fh = (struct frag_hdr*)(frag->data + hlen);
                frag->h.raw = frag->data + hlen + sizeof(struct frag_hdr);
 
@@ -861,6 +867,41 @@ static int ip6_dst_lookup_tail(struct sock *sk,
                        goto out_err_release;
        }
 
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+               /*
+                * Here if the dst entry we've looked up
+                * has a neighbour entry that is in the INCOMPLETE
+                * state and the src address from the flow is
+                * marked as OPTIMISTIC, we release the found
+                * dst entry and replace it instead with the
+                * dst entry of the nexthop router
+                */
+               if (!((*dst)->neighbour->nud_state & NUD_VALID)) {
+                       struct inet6_ifaddr *ifp;
+                       struct flowi fl_gw;
+                       int redirect;
+
+                       ifp = ipv6_get_ifaddr(&fl->fl6_src, (*dst)->dev, 1);
+
+                       redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
+                       if (ifp)
+                               in6_ifa_put(ifp);
+
+                       if (redirect) {
+                               /*
+                                * We need to get the dst entry for the
+                                * default router instead
+                                */
+                               dst_release(*dst);
+                               memcpy(&fl_gw, fl, sizeof(struct flowi));
+                               memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
+                               *dst = ip6_route_output(sk, &fl_gw);
+                               if ((err = (*dst)->error))
+                                       goto out_err_release;
+                       }
+               }
+#endif
+
        return 0;
 
 out_err_release:
@@ -939,7 +980,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                skb_put(skb,fragheaderlen + transhdrlen);
 
                /* initialize network header pointer */
-               skb->nh.raw = skb->data;
+               skb_reset_network_header(skb);
 
                /* initialize protocol header pointer */
                skb->h.raw = skb->data + fragheaderlen;
@@ -1289,7 +1330,7 @@ int ip6_push_pending_frames(struct sock *sk)
 
        /* move skb->data to ip header from ext header */
        if (skb->data < skb->nh.raw)
-               __skb_pull(skb, skb->nh.raw - skb->data);
+               __skb_pull(skb, skb_network_offset(skb));
        while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
                __skb_pull(tmp_skb, skb->h.raw - skb->nh.raw);
                *tail_skb = tmp_skb;
@@ -1309,7 +1350,9 @@ int ip6_push_pending_frames(struct sock *sk)
        if (opt && opt->opt_nflen)
                ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst);
 
-       skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr));
+       skb_push(skb, sizeof(struct ipv6hdr));
+       skb_reset_network_header(skb);
+       hdr = skb->nh.ipv6h;
 
        *(__be32*)hdr = fl->fl6_flowlabel |
                     htonl(0x60000000 | ((int)np->cork.tclass << 20));