diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/ip_output.c | 10 | ||||
-rw-r--r-- | net/ipv4/route.c | 14 |
2 files changed, 16 insertions, 8 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ccaaa851ab42..77d3eded665a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -204,9 +204,15 @@ static inline int ip_finish_output2(struct sk_buff *skb) | |||
204 | skb = skb2; | 204 | skb = skb2; |
205 | } | 205 | } |
206 | 206 | ||
207 | rcu_read_lock(); | ||
207 | neigh = dst_get_neighbour(dst); | 208 | neigh = dst_get_neighbour(dst); |
208 | if (neigh) | 209 | if (neigh) { |
209 | return neigh_output(neigh, skb); | 210 | int res = neigh_output(neigh, skb); |
211 | |||
212 | rcu_read_unlock(); | ||
213 | return res; | ||
214 | } | ||
215 | rcu_read_unlock(); | ||
210 | 216 | ||
211 | if (net_ratelimit()) | 217 | if (net_ratelimit()) |
212 | printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n"); | 218 | printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n"); |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 1730689f560e..6afc4eb50591 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1628,16 +1628,18 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | |||
1628 | { | 1628 | { |
1629 | struct rtable *rt = (struct rtable *) dst; | 1629 | struct rtable *rt = (struct rtable *) dst; |
1630 | __be32 orig_gw = rt->rt_gateway; | 1630 | __be32 orig_gw = rt->rt_gateway; |
1631 | struct neighbour *n; | 1631 | struct neighbour *n, *old_n; |
1632 | 1632 | ||
1633 | dst_confirm(&rt->dst); | 1633 | dst_confirm(&rt->dst); |
1634 | 1634 | ||
1635 | neigh_release(dst_get_neighbour(&rt->dst)); | ||
1636 | dst_set_neighbour(&rt->dst, NULL); | ||
1637 | |||
1638 | rt->rt_gateway = peer->redirect_learned.a4; | 1635 | rt->rt_gateway = peer->redirect_learned.a4; |
1639 | rt_bind_neighbour(rt); | 1636 | |
1640 | n = dst_get_neighbour(&rt->dst); | 1637 | n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); |
1638 | if (IS_ERR(n)) | ||
1639 | return PTR_ERR(n); | ||
1640 | old_n = xchg(&rt->dst._neighbour, n); | ||
1641 | if (old_n) | ||
1642 | neigh_release(old_n); | ||
1641 | if (!n || !(n->nud_state & NUD_VALID)) { | 1643 | if (!n || !(n->nud_state & NUD_VALID)) { |
1642 | if (n) | 1644 | if (n) |
1643 | neigh_event_send(n, NULL); | 1645 | neigh_event_send(n, NULL); |