Commit 3111b920 authored by Kazunori Miyazawa's avatar Kazunori Miyazawa Committed by Stephen Hemminger

[IPV6]: Fix authentication error with TCP, with help from Joy Latten (latten@austin.ibm.com).

This patch makes the kernel consider extension header length in a dst.
parent 99c2a902
...@@ -353,9 +353,7 @@ extern int ip6_push_pending_frames(struct sock *sk); ...@@ -353,9 +353,7 @@ extern int ip6_push_pending_frames(struct sock *sk);
extern void ip6_flush_pending_frames(struct sock *sk); extern void ip6_flush_pending_frames(struct sock *sk);
extern int ip6_dst_lookup(struct sock *sk, extern struct dst_entry * ip6_dst_lookup(struct sock *sk, struct flowi *fl);
struct dst_entry **dst,
struct flowi *fl);
/* /*
* skb processing functions * skb processing functions
......
...@@ -355,8 +355,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, ...@@ -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)) if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif; fl.oif = np->mcast_oif;
err = ip6_dst_lookup(sk, &dst, &fl); dst = ip6_dst_lookup(sk, &fl);
if (err) goto out; if (dst->error) goto out;
if (hlimit < 0) { if (hlimit < 0) {
if (ipv6_addr_is_multicast(&fl.fl6_dst)) if (ipv6_addr_is_multicast(&fl.fl6_dst))
...@@ -434,9 +434,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb) ...@@ -434,9 +434,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif; fl.oif = np->mcast_oif;
err = ip6_dst_lookup(sk, &dst, &fl); dst = ip6_dst_lookup(sk, &fl);
if (err) goto out; if (dst->error) goto out;
if (hlimit < 0) { if (hlimit < 0) {
if (ipv6_addr_is_multicast(&fl.fl6_dst)) if (ipv6_addr_is_multicast(&fl.fl6_dst))
......
...@@ -211,10 +211,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, ...@@ -211,10 +211,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
u32 mtu; u32 mtu;
int err = 0; int err = 0;
if ((err = xfrm_lookup(&skb->dst, fl, sk, 0)) < 0) {
return err;
}
if (opt) { if (opt) {
int head_room; int head_room;
...@@ -1141,72 +1137,73 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) ...@@ -1141,72 +1137,73 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
return err; return err;
} }
int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) struct dst_entry *ip6_dst_lookup(struct sock *sk, struct flowi *fl)
{ {
struct ipv6_pinfo *np = inet6_sk(sk); struct dst_entry *dst = NULL;
int err = 0; int err = 0;
*dst = __sk_dst_check(sk, np->dst_cookie); if (sk) {
if (*dst) { struct ipv6_pinfo *np = inet6_sk(sk);
struct rt6_info *rt = (struct rt6_info*)*dst;
dst = __sk_dst_check(sk, np->dst_cookie);
/* Yes, checking route validity in not connected if (dst) {
case is not very simple. Take into account, struct rt6_info *rt = (struct rt6_info*)dst;
that we do not support routing by source, TOS,
and MSG_DONTROUTE --ANK (980726) /* Yes, checking route validity in not connected
case is not very simple. Take into account,
1. If route was host route, check that that we do not support routing by source, TOS,
cached destination is current. and MSG_DONTROUTE --ANK (980726)
If it is network route, we still may
check its validity using saved pointer 1. If route was host route, check that
to the last used address: daddr_cache. cached destination is current.
We do not want to save whole address now, If it is network route, we still may
(because main consumer of this service check its validity using saved pointer
is tcp, which has not this problem), to the last used address: daddr_cache.
so that the last trick works only on connected We do not want to save whole address now,
sockets. (because main consumer of this service
2. oif also should be the same. is tcp, which has not this problem),
*/ so that the last trick works only on connected
sockets.
if (((rt->rt6i_dst.plen != 128 || 2. oif also should be the same.
ipv6_addr_cmp(&fl->fl6_dst, &rt->rt6i_dst.addr)) */
&& (np->daddr_cache == NULL ||
ipv6_addr_cmp(&fl->fl6_dst, np->daddr_cache))) if (((rt->rt6i_dst.plen != 128 ||
|| (fl->oif && fl->oif != (*dst)->dev->ifindex)) { ipv6_addr_cmp(&fl->fl6_dst, &rt->rt6i_dst.addr))
*dst = NULL; && (np->daddr_cache == NULL ||
} else ipv6_addr_cmp(&fl->fl6_dst, np->daddr_cache)))
dst_hold(*dst); || (fl->oif && fl->oif != dst->dev->ifindex)) {
dst = NULL;
} else
dst_hold(dst);
}
} }
if (*dst == NULL) if (dst == NULL)
*dst = ip6_route_output(sk, fl); dst = ip6_route_output(sk, fl);
if ((*dst)->error) { if (dst->error)
IP6_INC_STATS(Ip6OutNoRoutes); return dst;
dst_release(*dst);
return -ENETUNREACH;
}
if (ipv6_addr_any(&fl->fl6_src)) { 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 (err) {
#if IP6_DEBUG >= 2 #if IP6_DEBUG >= 2
printk(KERN_DEBUG "ip6_build_xmit: " printk(KERN_DEBUG "ip6_build_xmit: "
"no available source address\n"); "no available source address\n");
#endif #endif
return err; dst->error = err;
return dst;
} }
} }
if (*dst) { if (dst) {
if ((err = xfrm_lookup(dst, fl, sk, 0)) < 0) { if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) {
dst_release(*dst); dst->error = -ENETUNREACH;
return -ENETUNREACH;
} }
} }
return 0; return dst;
} }
int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb),
......
...@@ -658,8 +658,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg ...@@ -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)) if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif; fl.oif = np->mcast_oif;
err = ip6_dst_lookup(sk, &dst, &fl); dst = ip6_dst_lookup(sk, &fl);
if (err) if (dst->error)
goto out; goto out;
if (hlimit < 0) { if (hlimit < 0) {
......
...@@ -663,7 +663,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -663,7 +663,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
} }
dst = ip6_route_output(sk, &fl); dst = ip6_dst_lookup(sk, &fl);
if ((err = dst->error) != 0) { if ((err = dst->error) != 0) {
dst_release(dst); dst_release(dst);
...@@ -691,6 +691,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -691,6 +691,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tp->ext_header_len = 0; tp->ext_header_len = 0;
if (np->opt) if (np->opt)
tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen; tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
tp->ext2_header_len = dst->header_len;
tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
inet->dport = usin->sin6_port; inet->dport = usin->sin6_port;
...@@ -788,7 +790,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -788,7 +790,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
fl.fl_ip_dport = inet->dport; fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport; fl.fl_ip_sport = inet->sport;
dst = ip6_route_output(sk, &fl); dst = ip6_dst_lookup(sk, &fl);
} else } else
dst_hold(dst); dst_hold(dst);
...@@ -889,7 +891,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req, ...@@ -889,7 +891,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req,
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
} }
dst = ip6_route_output(sk, &fl); dst = ip6_dst_lookup(sk, &fl);
if (dst->error) if (dst->error)
goto done; goto done;
} }
...@@ -1018,7 +1020,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) ...@@ -1018,7 +1020,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
fl.fl_ip_sport = t1->source; fl.fl_ip_sport = t1->source;
/* sk = NULL, but it is safe for now. RST socket required. */ /* sk = NULL, but it is safe for now. RST socket required. */
buff->dst = ip6_route_output(NULL, &fl); buff->dst = ip6_dst_lookup(NULL, &fl);
if (buff->dst->error == 0) { if (buff->dst->error == 0) {
ip6_xmit(NULL, buff, &fl, NULL, 0); ip6_xmit(NULL, buff, &fl, NULL, 0);
...@@ -1081,7 +1083,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ...@@ -1081,7 +1083,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_dport = t1->dest;
fl.fl_ip_sport = t1->source; fl.fl_ip_sport = t1->source;
buff->dst = ip6_route_output(NULL, &fl); buff->dst = ip6_dst_lookup(NULL, &fl);
if (buff->dst->error == 0) { if (buff->dst->error == 0) {
ip6_xmit(NULL, buff, &fl, NULL, 0); ip6_xmit(NULL, buff, &fl, NULL, 0);
...@@ -1329,7 +1331,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1329,7 +1331,7 @@ 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_dport = req->rmt_port;
fl.fl_ip_sport = inet_sk(sk)->sport; fl.fl_ip_sport = inet_sk(sk)->sport;
dst = ip6_route_output(sk, &fl); dst = ip6_dst_lookup(sk, &fl);
} }
if (dst->error) if (dst->error)
...@@ -1401,6 +1403,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1401,6 +1403,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
if (newnp->opt) if (newnp->opt)
newtp->ext_header_len = newnp->opt->opt_nflen + newtp->ext_header_len = newnp->opt->opt_nflen +
newnp->opt->opt_flen; newnp->opt->opt_flen;
newtp->ext2_header_len = dst->header_len;
tcp_sync_mss(newsk, dst_pmtu(dst)); tcp_sync_mss(newsk, dst_pmtu(dst));
newtp->advmss = dst_metric(dst, RTAX_ADVMSS); newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
...@@ -1727,7 +1730,7 @@ static int tcp_v6_rebuild_header(struct sock *sk) ...@@ -1727,7 +1730,7 @@ static int tcp_v6_rebuild_header(struct sock *sk)
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
} }
dst = ip6_route_output(sk, &fl); dst = ip6_dst_lookup(sk, &fl);
if (dst->error) { if (dst->error) {
err = dst->error; err = dst->error;
...@@ -1770,7 +1773,7 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok) ...@@ -1770,7 +1773,7 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
dst = __sk_dst_check(sk, np->dst_cookie); dst = __sk_dst_check(sk, np->dst_cookie);
if (dst == NULL) { if (dst == NULL) {
dst = ip6_route_output(sk, &fl); dst = ip6_dst_lookup(sk, &fl);
if (dst->error) { if (dst->error) {
sk->sk_err_soft = -dst->error; sk->sk_err_soft = -dst->error;
......
...@@ -928,8 +928,8 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg ...@@ -928,8 +928,8 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif; fl.oif = np->mcast_oif;
err = ip6_dst_lookup(sk, &dst, &fl); dst = ip6_dst_lookup(sk, &fl);
if (err) if (dst->error)
goto out; goto out;
if (hlimit < 0) { if (hlimit < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment