.. | .. |
---|
147 | 147 | */ |
---|
148 | 148 | |
---|
149 | 149 | sk_for_each_bound(sk2, &tb->owners) { |
---|
150 | | - if (sk != sk2 && |
---|
151 | | - (!sk->sk_bound_dev_if || |
---|
152 | | - !sk2->sk_bound_dev_if || |
---|
153 | | - sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { |
---|
| 150 | + int bound_dev_if2; |
---|
| 151 | + |
---|
| 152 | + if (sk == sk2) |
---|
| 153 | + continue; |
---|
| 154 | + bound_dev_if2 = READ_ONCE(sk2->sk_bound_dev_if); |
---|
| 155 | + if ((!sk->sk_bound_dev_if || |
---|
| 156 | + !bound_dev_if2 || |
---|
| 157 | + sk->sk_bound_dev_if == bound_dev_if2)) { |
---|
154 | 158 | if (reuse && sk2->sk_reuse && |
---|
155 | 159 | sk2->sk_state != TCP_LISTEN) { |
---|
156 | 160 | if ((!relax || |
---|
.. | .. |
---|
912 | 916 | } |
---|
913 | 917 | EXPORT_SYMBOL(inet_csk_prepare_forced_close); |
---|
914 | 918 | |
---|
| 919 | +static int inet_ulp_can_listen(const struct sock *sk) |
---|
| 920 | +{ |
---|
| 921 | + const struct inet_connection_sock *icsk = inet_csk(sk); |
---|
| 922 | + |
---|
| 923 | + if (icsk->icsk_ulp_ops && !icsk->icsk_ulp_ops->clone) |
---|
| 924 | + return -EINVAL; |
---|
| 925 | + |
---|
| 926 | + return 0; |
---|
| 927 | +} |
---|
| 928 | + |
---|
915 | 929 | int inet_csk_listen_start(struct sock *sk, int backlog) |
---|
916 | 930 | { |
---|
917 | 931 | struct inet_connection_sock *icsk = inet_csk(sk); |
---|
918 | 932 | struct inet_sock *inet = inet_sk(sk); |
---|
919 | | - int err = -EADDRINUSE; |
---|
| 933 | + int err; |
---|
| 934 | + |
---|
| 935 | + err = inet_ulp_can_listen(sk); |
---|
| 936 | + if (unlikely(err)) |
---|
| 937 | + return err; |
---|
920 | 938 | |
---|
921 | 939 | reqsk_queue_alloc(&icsk->icsk_accept_queue); |
---|
922 | 940 | |
---|
.. | .. |
---|
928 | 946 | * It is OK, because this socket enters to hash table only |
---|
929 | 947 | * after validation is complete. |
---|
930 | 948 | */ |
---|
| 949 | + err = -EADDRINUSE; |
---|
931 | 950 | inet_sk_state_store(sk, TCP_LISTEN); |
---|
932 | 951 | if (!sk->sk_prot->get_port(sk, inet->inet_num)) { |
---|
933 | 952 | inet->inet_sport = htons(inet->inet_num); |
---|