diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 40 |
1 files changed, 17 insertions, 23 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index decc21d19c53..5b2d63ed793e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -83,24 +83,12 @@ int ip6_local_out(struct sk_buff *skb) | |||
83 | } | 83 | } |
84 | EXPORT_SYMBOL_GPL(ip6_local_out); | 84 | EXPORT_SYMBOL_GPL(ip6_local_out); |
85 | 85 | ||
86 | /* dev_loopback_xmit for use with netfilter. */ | ||
87 | static int ip6_dev_loopback_xmit(struct sk_buff *newskb) | ||
88 | { | ||
89 | skb_reset_mac_header(newskb); | ||
90 | __skb_pull(newskb, skb_network_offset(newskb)); | ||
91 | newskb->pkt_type = PACKET_LOOPBACK; | ||
92 | newskb->ip_summed = CHECKSUM_UNNECESSARY; | ||
93 | WARN_ON(!skb_dst(newskb)); | ||
94 | |||
95 | netif_rx_ni(newskb); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static int ip6_finish_output2(struct sk_buff *skb) | 86 | static int ip6_finish_output2(struct sk_buff *skb) |
100 | { | 87 | { |
101 | struct dst_entry *dst = skb_dst(skb); | 88 | struct dst_entry *dst = skb_dst(skb); |
102 | struct net_device *dev = dst->dev; | 89 | struct net_device *dev = dst->dev; |
103 | struct neighbour *neigh; | 90 | struct neighbour *neigh; |
91 | struct rt6_info *rt; | ||
104 | 92 | ||
105 | skb->protocol = htons(ETH_P_IPV6); | 93 | skb->protocol = htons(ETH_P_IPV6); |
106 | skb->dev = dev; | 94 | skb->dev = dev; |
@@ -121,7 +109,7 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
121 | if (newskb) | 109 | if (newskb) |
122 | NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, | 110 | NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, |
123 | newskb, NULL, newskb->dev, | 111 | newskb, NULL, newskb->dev, |
124 | ip6_dev_loopback_xmit); | 112 | dev_loopback_xmit); |
125 | 113 | ||
126 | if (ipv6_hdr(skb)->hop_limit == 0) { | 114 | if (ipv6_hdr(skb)->hop_limit == 0) { |
127 | IP6_INC_STATS(dev_net(dev), idev, | 115 | IP6_INC_STATS(dev_net(dev), idev, |
@@ -136,9 +124,10 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
136 | } | 124 | } |
137 | 125 | ||
138 | rcu_read_lock(); | 126 | rcu_read_lock(); |
139 | neigh = dst_get_neighbour_noref(dst); | 127 | rt = (struct rt6_info *) dst; |
128 | neigh = rt->n; | ||
140 | if (neigh) { | 129 | if (neigh) { |
141 | int res = neigh_output(neigh, skb); | 130 | int res = dst_neigh_output(dst, neigh, skb); |
142 | 131 | ||
143 | rcu_read_unlock(); | 132 | rcu_read_unlock(); |
144 | return res; | 133 | return res; |
@@ -463,6 +452,7 @@ int ip6_forward(struct sk_buff *skb) | |||
463 | */ | 452 | */ |
464 | if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) { | 453 | if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) { |
465 | struct in6_addr *target = NULL; | 454 | struct in6_addr *target = NULL; |
455 | struct inet_peer *peer; | ||
466 | struct rt6_info *rt; | 456 | struct rt6_info *rt; |
467 | 457 | ||
468 | /* | 458 | /* |
@@ -476,14 +466,15 @@ int ip6_forward(struct sk_buff *skb) | |||
476 | else | 466 | else |
477 | target = &hdr->daddr; | 467 | target = &hdr->daddr; |
478 | 468 | ||
479 | if (!rt->rt6i_peer) | 469 | peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); |
480 | rt6_bind_peer(rt, 1); | ||
481 | 470 | ||
482 | /* Limit redirects both by destination (here) | 471 | /* Limit redirects both by destination (here) |
483 | and by source (inside ndisc_send_redirect) | 472 | and by source (inside ndisc_send_redirect) |
484 | */ | 473 | */ |
485 | if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ)) | 474 | if (inet_peer_xrlim_allow(peer, 1*HZ)) |
486 | ndisc_send_redirect(skb, target); | 475 | ndisc_send_redirect(skb, target); |
476 | if (peer) | ||
477 | inet_putpeer(peer); | ||
487 | } else { | 478 | } else { |
488 | int addrtype = ipv6_addr_type(&hdr->saddr); | 479 | int addrtype = ipv6_addr_type(&hdr->saddr); |
489 | 480 | ||
@@ -604,12 +595,13 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | |||
604 | 595 | ||
605 | if (rt && !(rt->dst.flags & DST_NOPEER)) { | 596 | if (rt && !(rt->dst.flags & DST_NOPEER)) { |
606 | struct inet_peer *peer; | 597 | struct inet_peer *peer; |
598 | struct net *net; | ||
607 | 599 | ||
608 | if (!rt->rt6i_peer) | 600 | net = dev_net(rt->dst.dev); |
609 | rt6_bind_peer(rt, 1); | 601 | peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); |
610 | peer = rt->rt6i_peer; | ||
611 | if (peer) { | 602 | if (peer) { |
612 | fhdr->identification = htonl(inet_getid(peer, 0)); | 603 | fhdr->identification = htonl(inet_getid(peer, 0)); |
604 | inet_putpeer(peer); | ||
613 | return; | 605 | return; |
614 | } | 606 | } |
615 | } | 607 | } |
@@ -960,6 +952,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
960 | struct net *net = sock_net(sk); | 952 | struct net *net = sock_net(sk); |
961 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | 953 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
962 | struct neighbour *n; | 954 | struct neighbour *n; |
955 | struct rt6_info *rt; | ||
963 | #endif | 956 | #endif |
964 | int err; | 957 | int err; |
965 | 958 | ||
@@ -988,7 +981,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
988 | * dst entry of the nexthop router | 981 | * dst entry of the nexthop router |
989 | */ | 982 | */ |
990 | rcu_read_lock(); | 983 | rcu_read_lock(); |
991 | n = dst_get_neighbour_noref(*dst); | 984 | rt = (struct rt6_info *) *dst; |
985 | n = rt->n; | ||
992 | if (n && !(n->nud_state & NUD_VALID)) { | 986 | if (n && !(n->nud_state & NUD_VALID)) { |
993 | struct inet6_ifaddr *ifp; | 987 | struct inet6_ifaddr *ifp; |
994 | struct flowi6 fl_gw6; | 988 | struct flowi6 fl_gw6; |