diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 39 |
1 files changed, 27 insertions, 12 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 47dcf8ce0..f47b4a103 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,13 +5,16 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: tcp_ipv6.c,v 1.119 2000/01/31 01:21:26 davem Exp $ + * $Id: tcp_ipv6.c,v 1.120 2000/02/27 19:51:49 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c * linux/net/ipv4/tcp_input.c * linux/net/ipv4/tcp_output.c * + * Fixes: + * Hideaki YOSHIFUJI : sin6_scope_id support + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -509,8 +512,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_type; int err; - if (addr_len < sizeof(struct sockaddr_in6)) - return(-EINVAL); + if (addr_len < SIN6_LEN_RFC2133) + return -EINVAL; if (usin->sin6_family != AF_INET6) return(-EAFNOSUPPORT); @@ -540,6 +543,24 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if(addr_type & IPV6_ADDR_MULTICAST) return -ENETUNREACH; + if (addr_type&IPV6_ADDR_LINKLOCAL) { + if (addr_len >= sizeof(struct sockaddr_in6) && + usin->sin6_scope_id) { + /* If interface is set while binding, indices + * must coincide. + */ + if (sk->bound_dev_if && + sk->bound_dev_if != usin->sin6_scope_id) + return -EINVAL; + + sk->bound_dev_if = usin->sin6_scope_id; + } + + /* Connect to link-local address requires an interface */ + if (sk->bound_dev_if == 0) + return -EINVAL; + } + if (tp->ts_recent_stamp && ipv6_addr_cmp(&np->daddr, &usin->sin6_addr)) { tp->ts_recent = 0; tp->ts_recent_stamp = 0; @@ -605,15 +626,6 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, goto failure; } - if (fl.oif == 0 && addr_type&IPV6_ADDR_LINKLOCAL) { - /* Ough! This guy tries to connect to link local - * address and did not specify interface. - * Actually we should kick him out, but - * we will be patient :) --ANK - */ - sk->bound_dev_if = dst->dev->ifindex; - } - ip6_dst_store(sk, dst, NULL); if (saddr == NULL) { @@ -1723,6 +1735,9 @@ static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) sin6->sin6_port = sk->dport; /* We do not store received flowlabel for TCP */ sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + if (sk->bound_dev_if && ipv6_addr_type(&sin6->sin6_addr)&IPV6_ADDR_LINKLOCAL) + sin6->sin6_scope_id = sk->bound_dev_if; } static int tcp_v6_remember_stamp(struct sock *sk) |