summaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2011-07-25 13:59:46 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-07-25 14:53:52 -0400
commit5f00bcb38ef9a980a33c6dbdc0044964b05f22dd (patch)
tree3175fb9375aecb50bde1be0bf4fa8aa8155131d6 /net/ipv6/ip6_output.c
parent34006cee28f7344f9557a4be3816c7891b1bbab1 (diff)
parentb6844e8f64920cdee620157252169ba63afb0c89 (diff)
downloadlinux-5f00bcb38ef9a980a33c6dbdc0044964b05f22dd.tar.bz2
Merge branch 'master' into devel and apply fixup from Stephen Rothwell:
vfs/nfs: fixup for nfs_open_context change Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c58
1 files changed, 44 insertions, 14 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 9d4b165837d6..32e5339db0c8 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -100,6 +100,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct net_device *dev = dst->dev;
+ struct neighbour *neigh;
skb->protocol = htons(ETH_P_IPV6);
skb->dev = dev;
@@ -134,10 +135,9 @@ static int ip6_finish_output2(struct sk_buff *skb)
skb->len);
}
- if (dst->hh)
- return neigh_hh_output(dst->hh, skb);
- else if (dst->neighbour)
- return dst->neighbour->output(skb);
+ neigh = dst_get_neighbour(dst);
+ if (neigh)
+ return neigh_output(neigh, skb);
IP6_INC_STATS_BH(dev_net(dst->dev),
ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
@@ -385,6 +385,7 @@ int ip6_forward(struct sk_buff *skb)
struct ipv6hdr *hdr = ipv6_hdr(skb);
struct inet6_skb_parm *opt = IP6CB(skb);
struct net *net = dev_net(dst->dev);
+ struct neighbour *n;
u32 mtu;
if (net->ipv6.devconf_all->forwarding == 0)
@@ -459,11 +460,10 @@ int ip6_forward(struct sk_buff *skb)
send redirects to source routed frames.
We don't send redirects to frames decapsulated from IPsec.
*/
- if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 &&
- !skb_sec_path(skb)) {
+ n = dst_get_neighbour(dst);
+ if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) {
struct in6_addr *target = NULL;
struct rt6_info *rt;
- struct neighbour *n = dst->neighbour;
/*
* incoming and outgoing devices are the same
@@ -596,6 +596,31 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
return offset;
}
+void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
+{
+ static atomic_t ipv6_fragmentation_id;
+ int old, new;
+
+ if (rt) {
+ struct inet_peer *peer;
+
+ if (!rt->rt6i_peer)
+ rt6_bind_peer(rt, 1);
+ peer = rt->rt6i_peer;
+ if (peer) {
+ fhdr->identification = htonl(inet_getid(peer, 0));
+ return;
+ }
+ }
+ do {
+ old = atomic_read(&ipv6_fragmentation_id);
+ new = old + 1;
+ if (!new)
+ new = 1;
+ } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old);
+ fhdr->identification = htonl(new);
+}
+
int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
struct sk_buff *frag;
@@ -680,7 +705,7 @@ 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(fh);
+ ipv6_select_ident(fh, rt);
fh->nexthdr = nexthdr;
fh->reserved = 0;
fh->frag_off = htons(IP6_MF);
@@ -826,7 +851,7 @@ slow_path:
fh->nexthdr = nexthdr;
fh->reserved = 0;
if (!frag_id) {
- ipv6_select_ident(fh);
+ ipv6_select_ident(fh, rt);
frag_id = fh->identification;
} else
fh->identification = frag_id;
@@ -920,8 +945,11 @@ out:
static int ip6_dst_lookup_tail(struct sock *sk,
struct dst_entry **dst, struct flowi6 *fl6)
{
- int err;
struct net *net = sock_net(sk);
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ struct neighbour *n;
+#endif
+ int err;
if (*dst == NULL)
*dst = ip6_route_output(net, sk, fl6);
@@ -947,7 +975,8 @@ static int ip6_dst_lookup_tail(struct sock *sk,
* dst entry and replace it instead with the
* dst entry of the nexthop router
*/
- if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) {
+ n = dst_get_neighbour(*dst);
+ if (n && !(n->nud_state & NUD_VALID)) {
struct inet6_ifaddr *ifp;
struct flowi6 fl_gw6;
int redirect;
@@ -1072,7 +1101,8 @@ static inline int ip6_ufo_append_data(struct sock *sk,
int getfrag(void *from, char *to, int offset, int len,
int odd, struct sk_buff *skb),
void *from, int length, int hh_len, int fragheaderlen,
- int transhdrlen, int mtu,unsigned int flags)
+ int transhdrlen, int mtu,unsigned int flags,
+ struct rt6_info *rt)
{
struct sk_buff *skb;
@@ -1116,7 +1146,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
sizeof(struct frag_hdr)) & ~7;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
- ipv6_select_ident(&fhdr);
+ ipv6_select_ident(&fhdr, rt);
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
__skb_queue_tail(&sk->sk_write_queue, skb);
@@ -1282,7 +1312,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
err = ip6_ufo_append_data(sk, getfrag, from, length,
hh_len, fragheaderlen,
- transhdrlen, mtu, flags);
+ transhdrlen, mtu, flags, rt);
if (err)
goto error;
return 0;