|
|
@@ -267,6 +267,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|
|
struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr;
|
|
|
struct net *net = sock_net(sk);
|
|
|
__be32 v4addr = 0;
|
|
|
+ int bound_dev_if;
|
|
|
int addr_type;
|
|
|
int err;
|
|
|
|
|
|
@@ -285,13 +286,6 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|
|
if (addr_type & IPV6_ADDR_MULTICAST)
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
|
- err = -EADDRINUSE;
|
|
|
- read_lock_bh(&l2tp_ip6_lock);
|
|
|
- if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr,
|
|
|
- sk->sk_bound_dev_if, addr->l2tp_conn_id))
|
|
|
- goto out_in_use;
|
|
|
- read_unlock_bh(&l2tp_ip6_lock);
|
|
|
-
|
|
|
lock_sock(sk);
|
|
|
|
|
|
err = -EINVAL;
|
|
|
@@ -301,28 +295,25 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|
|
if (sk->sk_state != TCP_CLOSE)
|
|
|
goto out_unlock;
|
|
|
|
|
|
+ bound_dev_if = sk->sk_bound_dev_if;
|
|
|
+
|
|
|
/* Check if the address belongs to the host. */
|
|
|
rcu_read_lock();
|
|
|
if (addr_type != IPV6_ADDR_ANY) {
|
|
|
struct net_device *dev = NULL;
|
|
|
|
|
|
if (addr_type & IPV6_ADDR_LINKLOCAL) {
|
|
|
- if (addr_len >= sizeof(struct sockaddr_in6) &&
|
|
|
- addr->l2tp_scope_id) {
|
|
|
- /* Override any existing binding, if another
|
|
|
- * one is supplied by user.
|
|
|
- */
|
|
|
- sk->sk_bound_dev_if = addr->l2tp_scope_id;
|
|
|
- }
|
|
|
+ if (addr->l2tp_scope_id)
|
|
|
+ bound_dev_if = addr->l2tp_scope_id;
|
|
|
|
|
|
/* Binding to link-local address requires an
|
|
|
- interface */
|
|
|
- if (!sk->sk_bound_dev_if)
|
|
|
+ * interface.
|
|
|
+ */
|
|
|
+ if (!bound_dev_if)
|
|
|
goto out_unlock_rcu;
|
|
|
|
|
|
err = -ENODEV;
|
|
|
- dev = dev_get_by_index_rcu(sock_net(sk),
|
|
|
- sk->sk_bound_dev_if);
|
|
|
+ dev = dev_get_by_index_rcu(sock_net(sk), bound_dev_if);
|
|
|
if (!dev)
|
|
|
goto out_unlock_rcu;
|
|
|
}
|
|
|
@@ -337,13 +328,22 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|
|
}
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
- inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
|
|
|
+ write_lock_bh(&l2tp_ip6_lock);
|
|
|
+ if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr, bound_dev_if,
|
|
|
+ addr->l2tp_conn_id)) {
|
|
|
+ write_unlock_bh(&l2tp_ip6_lock);
|
|
|
+ err = -EADDRINUSE;
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
+
|
|
|
+ inet->inet_saddr = v4addr;
|
|
|
+ inet->inet_rcv_saddr = v4addr;
|
|
|
+ sk->sk_bound_dev_if = bound_dev_if;
|
|
|
sk->sk_v6_rcv_saddr = addr->l2tp_addr;
|
|
|
np->saddr = addr->l2tp_addr;
|
|
|
|
|
|
l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id;
|
|
|
|
|
|
- write_lock_bh(&l2tp_ip6_lock);
|
|
|
sk_add_bind_node(sk, &l2tp_ip6_bind_table);
|
|
|
sk_del_node_init(sk);
|
|
|
write_unlock_bh(&l2tp_ip6_lock);
|
|
|
@@ -356,10 +356,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|
|
rcu_read_unlock();
|
|
|
out_unlock:
|
|
|
release_sock(sk);
|
|
|
- return err;
|
|
|
|
|
|
-out_in_use:
|
|
|
- read_unlock_bh(&l2tp_ip6_lock);
|
|
|
return err;
|
|
|
}
|
|
|
|