summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Nuorvala <vnourval@tcs.hut.fi>2003-08-17 13:14:52 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2003-08-17 13:14:52 -0700
commit0e7caa2a709942e13472b368fe5f92c413708504 (patch)
tree3995b7dbe1d81508c35d50c69f88a2704fc3b0f7
parentf8d1f5ed4de2ab01e0d2d922813a78902a6f1d40 (diff)
[IPV6]: Fix ip6_dst_lookup() route corruption.
-rw-r--r--include/net/ipv6.h4
-rw-r--r--net/ipv6/icmp.c8
-rw-r--r--net/ipv6/ip6_output.c45
-rw-r--r--net/ipv6/raw.c4
-rw-r--r--net/ipv6/tcp_ipv6.c55
-rw-r--r--net/ipv6/udp.c20
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) {