|
|
@@ -64,16 +64,65 @@ static void ip6_datagram_flow_key_init(struct flowi6 *fl6, struct sock *sk)
|
|
|
security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
|
|
|
}
|
|
|
|
|
|
+static int ip6_datagram_dst_update(struct sock *sk)
|
|
|
+{
|
|
|
+ struct ip6_flowlabel *flowlabel = NULL;
|
|
|
+ struct in6_addr *final_p, final;
|
|
|
+ struct ipv6_txoptions *opt;
|
|
|
+ struct dst_entry *dst;
|
|
|
+ struct inet_sock *inet = inet_sk(sk);
|
|
|
+ struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
+ struct flowi6 fl6;
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ if (np->sndflow && (np->flow_label & IPV6_FLOWLABEL_MASK)) {
|
|
|
+ flowlabel = fl6_sock_lookup(sk, np->flow_label);
|
|
|
+ if (!flowlabel)
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ ip6_datagram_flow_key_init(&fl6, sk);
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+ opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt);
|
|
|
+ final_p = fl6_update_dst(&fl6, opt, &final);
|
|
|
+ rcu_read_unlock();
|
|
|
+
|
|
|
+ dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
|
|
|
+ if (IS_ERR(dst)) {
|
|
|
+ err = PTR_ERR(dst);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ipv6_addr_any(&np->saddr))
|
|
|
+ np->saddr = fl6.saddr;
|
|
|
+
|
|
|
+ if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
|
|
|
+ sk->sk_v6_rcv_saddr = fl6.saddr;
|
|
|
+ inet->inet_rcv_saddr = LOOPBACK4_IPV6;
|
|
|
+ if (sk->sk_prot->rehash)
|
|
|
+ sk->sk_prot->rehash(sk);
|
|
|
+ }
|
|
|
+
|
|
|
+ ip6_dst_store(sk, dst,
|
|
|
+ ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ?
|
|
|
+ &sk->sk_v6_daddr : NULL,
|
|
|
+#ifdef CONFIG_IPV6_SUBTREES
|
|
|
+ ipv6_addr_equal(&fl6.saddr, &np->saddr) ?
|
|
|
+ &np->saddr :
|
|
|
+#endif
|
|
|
+ NULL);
|
|
|
+
|
|
|
+out:
|
|
|
+ fl6_sock_release(flowlabel);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|
|
{
|
|
|
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
|
|
|
struct inet_sock *inet = inet_sk(sk);
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
- struct in6_addr *daddr, *final_p, final;
|
|
|
- struct dst_entry *dst;
|
|
|
- struct flowi6 fl6;
|
|
|
- struct ip6_flowlabel *flowlabel = NULL;
|
|
|
- struct ipv6_txoptions *opt;
|
|
|
+ struct in6_addr *daddr;
|
|
|
int addr_type;
|
|
|
int err;
|
|
|
__be32 fl6_flowlabel = 0;
|
|
|
@@ -91,14 +140,8 @@ static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int a
|
|
|
if (usin->sin6_family != AF_INET6)
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
|
|
- if (np->sndflow) {
|
|
|
+ if (np->sndflow)
|
|
|
fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
|
|
|
- if (fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
|
|
|
- flowlabel = fl6_sock_lookup(sk, fl6_flowlabel);
|
|
|
- if (!flowlabel)
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
addr_type = ipv6_addr_type(&usin->sin6_addr);
|
|
|
|
|
|
@@ -178,45 +221,13 @@ ipv4_connected:
|
|
|
* destination cache for it.
|
|
|
*/
|
|
|
|
|
|
- ip6_datagram_flow_key_init(&fl6, sk);
|
|
|
-
|
|
|
- rcu_read_lock();
|
|
|
- opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt);
|
|
|
- final_p = fl6_update_dst(&fl6, opt, &final);
|
|
|
- rcu_read_unlock();
|
|
|
-
|
|
|
- dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
|
|
|
- err = 0;
|
|
|
- if (IS_ERR(dst)) {
|
|
|
- err = PTR_ERR(dst);
|
|
|
+ err = ip6_datagram_dst_update(sk);
|
|
|
+ if (err)
|
|
|
goto out;
|
|
|
- }
|
|
|
-
|
|
|
- /* source address lookup done in ip6_dst_lookup */
|
|
|
-
|
|
|
- if (ipv6_addr_any(&np->saddr))
|
|
|
- np->saddr = fl6.saddr;
|
|
|
-
|
|
|
- if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
|
|
|
- sk->sk_v6_rcv_saddr = fl6.saddr;
|
|
|
- inet->inet_rcv_saddr = LOOPBACK4_IPV6;
|
|
|
- if (sk->sk_prot->rehash)
|
|
|
- sk->sk_prot->rehash(sk);
|
|
|
- }
|
|
|
-
|
|
|
- ip6_dst_store(sk, dst,
|
|
|
- ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ?
|
|
|
- &sk->sk_v6_daddr : NULL,
|
|
|
-#ifdef CONFIG_IPV6_SUBTREES
|
|
|
- ipv6_addr_equal(&fl6.saddr, &np->saddr) ?
|
|
|
- &np->saddr :
|
|
|
-#endif
|
|
|
- NULL);
|
|
|
|
|
|
sk->sk_state = TCP_ESTABLISHED;
|
|
|
sk_set_txhash(sk);
|
|
|
out:
|
|
|
- fl6_sock_release(flowlabel);
|
|
|
return err;
|
|
|
}
|
|
|
|