diff options
| author | Ville Nuorvala <vnourval@tcs.hut.fi> | 2003-08-17 13:14:52 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2003-08-17 13:14:52 -0700 |
| commit | 0e7caa2a709942e13472b368fe5f92c413708504 (patch) | |
| tree | 3995b7dbe1d81508c35d50c69f88a2704fc3b0f7 | |
| parent | f8d1f5ed4de2ab01e0d2d922813a78902a6f1d40 (diff) | |
[IPV6]: Fix ip6_dst_lookup() route corruption.
| -rw-r--r-- | include/net/ipv6.h | 4 | ||||
| -rw-r--r-- | net/ipv6/icmp.c | 8 | ||||
| -rw-r--r-- | net/ipv6/ip6_output.c | 45 | ||||
| -rw-r--r-- | net/ipv6/raw.c | 4 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 55 | ||||
| -rw-r--r-- | net/ipv6/udp.c | 20 |
6 files changed, 57 insertions, 79 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9ed62a7db079..8aeb974d8592 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -353,7 +353,9 @@ extern int ip6_push_pending_frames(struct sock *sk); extern void ip6_flush_pending_frames(struct sock *sk); -extern struct dst_entry * ip6_dst_lookup(struct sock *sk, struct flowi *fl); +extern int ip6_dst_lookup(struct sock *sk, + struct dst_entry **dst, + struct flowi *fl); /* * skb processing functions diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index cbf54afae93b..727b681325aa 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -355,8 +355,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) fl.oif = np->mcast_oif; - dst = ip6_dst_lookup(sk, &fl); - if (dst->error) goto out; + err = ip6_dst_lookup(sk, &dst, &fl); + if (err) goto out; if (hlimit < 0) { if (ipv6_addr_is_multicast(&fl.fl6_dst)) @@ -434,9 +434,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb) if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) fl.oif = np->mcast_oif; - dst = ip6_dst_lookup(sk, &fl); + err = ip6_dst_lookup(sk, &dst, &fl); - if (dst->error) goto out; + if (err) goto out; if (hlimit < 0) { if (ipv6_addr_is_multicast(&fl.fl6_dst)) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 840d4117d419..7fa2d84faa85 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1136,17 +1136,16 @@ fail: return err; } -struct dst_entry *ip6_dst_lookup(struct sock *sk, struct flowi *fl) +int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) { - struct dst_entry *dst = NULL; int err = 0; if (sk) { struct ipv6_pinfo *np = inet6_sk(sk); - dst = __sk_dst_check(sk, np->dst_cookie); - if (dst) { - struct rt6_info *rt = (struct rt6_info*)dst; + *dst = __sk_dst_check(sk, np->dst_cookie); + if (*dst) { + struct rt6_info *rt = (struct rt6_info*)*dst; /* Yes, checking route validity in not connected case is not very simple. Take into account, @@ -1170,39 +1169,41 @@ struct dst_entry *ip6_dst_lookup(struct sock *sk, struct flowi *fl) ipv6_addr_cmp(&fl->fl6_dst, &rt->rt6i_dst.addr)) && (np->daddr_cache == NULL || ipv6_addr_cmp(&fl->fl6_dst, np->daddr_cache))) - || (fl->oif && fl->oif != dst->dev->ifindex)) { - dst = NULL; + || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { + *dst = NULL; } else - dst_hold(dst); + dst_hold(*dst); } } - if (dst == NULL) - dst = ip6_route_output(sk, fl); + if (*dst == NULL) + *dst = ip6_route_output(sk, fl); - if (dst->error) - return dst; + if ((err = (*dst)->error)) + goto out_err_release; if (ipv6_addr_any(&fl->fl6_src)) { - err = ipv6_get_saddr(dst, &fl->fl6_dst, &fl->fl6_src); + err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); if (err) { #if IP6_DEBUG >= 2 - printk(KERN_DEBUG "ip6_build_xmit: " + printk(KERN_DEBUG "ip6_dst_lookup: " "no available source address\n"); #endif - dst->error = err; - return dst; + goto out_err_release; } } - - if (dst) { - if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) { - dst->error = -ENETUNREACH; - } + if ((err = xfrm_lookup(dst, fl, sk, 0)) < 0) { + err = -ENETUNREACH; + goto out_err_release; } - return dst; + return 0; + +out_err_release: + dst_release(*dst); + *dst = NULL; + return err; } int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index e77772fbe9a7..18c94441ca91 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -658,8 +658,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) fl.oif = np->mcast_oif; - dst = ip6_dst_lookup(sk, &fl); - if ((err = dst->error)) + err = ip6_dst_lookup(sk, &dst, &fl); + if (err) goto out; if (hlimit < 0) { diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0f27706023fc..22c20e24a6ee 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -663,19 +663,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ipv6_addr_copy(&fl.fl6_dst, rt0->addr); } - dst = ip6_dst_lookup(sk, &fl); + err = ip6_dst_lookup(sk, &dst, &fl); - if ((err = dst->error) != 0) { - dst_release(dst); + if (err) goto failure; - } if (saddr == NULL) { - err = ipv6_get_saddr(dst, &np->daddr, &fl.fl6_src); - if (err) { - dst_release(dst); - goto failure; - } saddr = &fl.fl6_src; ipv6_addr_copy(&np->rcv_saddr, saddr); } @@ -790,13 +783,14 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, fl.fl_ip_dport = inet->dport; fl.fl_ip_sport = inet->sport; - dst = ip6_dst_lookup(sk, &fl); + if ((err = ip6_dst_lookup(sk, &dst, &fl))) { + sk->sk_err_soft = -err; + goto out; + } } else dst_hold(dst); - if (dst->error) { - sk->sk_err_soft = -dst->error; - } else if (tp->pmtu_cookie > dst_pmtu(dst)) { + if (tp->pmtu_cookie > dst_pmtu(dst)) { tcp_sync_mss(sk, dst_pmtu(dst)); tcp_simple_retransmit(sk); } /* else let the usual retransmit timer handle it */ @@ -891,8 +885,8 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req, ipv6_addr_copy(&fl.fl6_dst, rt0->addr); } - dst = ip6_dst_lookup(sk, &fl); - if (dst->error) + err = ip6_dst_lookup(sk, &dst, &fl); + if (err) goto done; } @@ -1020,9 +1014,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) fl.fl_ip_sport = t1->source; /* sk = NULL, but it is safe for now. RST socket required. */ - buff->dst = ip6_dst_lookup(NULL, &fl); - - if (buff->dst->error == 0) { + if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { ip6_xmit(NULL, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TcpOutSegs); TCP_INC_STATS_BH(TcpOutRsts); @@ -1083,9 +1075,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 fl.fl_ip_dport = t1->dest; fl.fl_ip_sport = t1->source; - buff->dst = ip6_dst_lookup(NULL, &fl); - - if (buff->dst->error == 0) { + if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { ip6_xmit(NULL, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TcpOutSegs); return; @@ -1331,11 +1321,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, fl.fl_ip_dport = req->rmt_port; fl.fl_ip_sport = inet_sk(sk)->sport; - dst = ip6_dst_lookup(sk, &fl); - } - - if (dst->error) - goto out; + if (ip6_dst_lookup(sk, &dst, &fl)) + goto out; + } newsk = tcp_create_openreq_child(sk, req, skb); if (newsk == NULL) @@ -1730,11 +1718,9 @@ static int tcp_v6_rebuild_header(struct sock *sk) ipv6_addr_copy(&fl.fl6_dst, rt0->addr); } - dst = ip6_dst_lookup(sk, &fl); + err = ip6_dst_lookup(sk, &dst, &fl); - if (dst->error) { - err = dst->error; - dst_release(dst); + if (err) { sk->sk_route_caps = 0; return err; } @@ -1774,12 +1760,11 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok) dst = __sk_dst_check(sk, np->dst_cookie); if (dst == NULL) { - dst = ip6_dst_lookup(sk, &fl); + int err = ip6_dst_lookup(sk, &dst, &fl); - if (dst->error) { - sk->sk_err_soft = -dst->error; - dst_release(dst); - return -sk->sk_err_soft; + if (err) { + sk->sk_err_soft = -err; + return err; } ip6_dst_store(sk, dst, NULL); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 699cbc866c77..a3fa7829dbec 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -330,21 +330,11 @@ ipv4_connected: ipv6_addr_copy(&fl.fl6_dst, rt0->addr); } - dst = ip6_route_output(sk, &fl); - - if ((err = dst->error) != 0) { - dst_release(dst); + err = ip6_dst_lookup(sk, &dst, &fl); + if (err) goto out; - } - - /* get the source address used in the appropriate device */ - err = ipv6_get_saddr(dst, daddr, &fl.fl6_src); - - if (err) { - dst_release(dst); - goto out; - } + /* source address lookup done in ip6_dst_lookup */ if (ipv6_addr_any(&np->saddr)) ipv6_addr_copy(&np->saddr, &fl.fl6_src); @@ -930,8 +920,8 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) fl.oif = np->mcast_oif; - dst = ip6_dst_lookup(sk, &fl); - if ((err = dst->error)) + err = ip6_dst_lookup(sk, &dst, &fl); + if (err) goto out; if (hlimit < 0) { |
