Mat Martineau says: ==================== mptcp: Fixes for 5.19 Several categories of fixes from the mptcp tree: Patches 1-3 are fixes related to MP_FAIL and FASTCLOSE, to make sure MIBs are accurate, and to handle MP_FAIL transmission and responses at the correct times. sk_timer conflicts are also resolved. Patches 4 and 6 handle two separate race conditions, one at socket shutdown and one with unaccepted subflows. Patch 5 makes sure read operations are not blocked during fallback to TCP. Patch 7 improves the diag selftest, which were incorrectly failing on slow machines (like the VMs used for CI testing). Patch 8 avoids possible symbol redefinition errors in the userspace mptcp.h file. Patch 9 fixes a selftest build issue with gcc 12. ====================
Unified · Split
| @@ -2,16 +2,17 @@ · 1 unmodified line | |||
| 2 | #ifndef _UAPI_MPTCP_H | 2 | #ifndef _UAPI_MPTCP_H |
| 3 | #define _UAPI_MPTCP_H | 3 | #define _UAPI_MPTCP_H |
| 4 | 4 | ||
| 5 | #ifndef __KERNEL__ | ||
| 6 | #include <netinet/in.h> /* for sockaddr_in and sockaddr_in6 */ | ||
| 7 | #include <sys/socket.h> /* for struct sockaddr */ | ||
| 8 | #endif | ||
| 9 | |||
| 5 | #include <linux/const.h> | 10 | #include <linux/const.h> |
| 6 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 7 | #include <linux/in.h> /* for sockaddr_in */ | 12 | #include <linux/in.h> /* for sockaddr_in */ |
| 8 | #include <linux/in6.h> /* for sockaddr_in6 */ | 13 | #include <linux/in6.h> /* for sockaddr_in6 */ |
| 9 | #include <linux/socket.h> /* for sockaddr_storage and sa_family */ | 14 | #include <linux/socket.h> /* for sockaddr_storage and sa_family */ |
| 10 | 15 | ||
| 11 | #ifndef __KERNEL__ | ||
| 12 | #include <sys/socket.h> /* for struct sockaddr */ | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #define MPTCP_SUBFLOW_FLAG_MCAP_REM _BITUL(0) | 16 | #define MPTCP_SUBFLOW_FLAG_MCAP_REM _BITUL(0) |
| 16 | #define MPTCP_SUBFLOW_FLAG_MCAP_LOC _BITUL(1) | 17 | #define MPTCP_SUBFLOW_FLAG_MCAP_LOC _BITUL(1) |
| 17 | #define MPTCP_SUBFLOW_FLAG_JOIN_REM _BITUL(2) | 18 | #define MPTCP_SUBFLOW_FLAG_JOIN_REM _BITUL(2) |
| @@ -765,6 +765,7 @@ static noinline bool mptcp_established_options_rst(struct sock *sk, struct sk_bu · 764 unmodified lines | |||
| 765 | opts->suboptions |= OPTION_MPTCP_RST; | 765 | opts->suboptions |= OPTION_MPTCP_RST; |
| 766 | opts->reset_transient = subflow->reset_transient; | 766 | opts->reset_transient = subflow->reset_transient; |
| 767 | opts->reset_reason = subflow->reset_reason; | 767 | opts->reset_reason = subflow->reset_reason; |
| 768 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPRSTTX); | ||
| 768 | 769 | ||
| 769 | return true; | 770 | return true; |
| 770 | } | 771 | } |
| @@ -788,6 +789,7 @@ static bool mptcp_established_options_fastclose(struct sock *sk, · 17 unmodified lines | |||
| 788 | opts->rcvr_key = msk->remote_key; | 789 | opts->rcvr_key = msk->remote_key; |
| 789 | 790 | ||
| 790 | pr_debug("FASTCLOSE key=%llu", opts->rcvr_key); | 791 | pr_debug("FASTCLOSE key=%llu", opts->rcvr_key); |
| 792 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFASTCLOSETX); | ||
| 791 | return true; | 793 | return true; |
| 792 | } | 794 | } |
| 793 | 795 | ||
| @@ -809,6 +811,7 @@ static bool mptcp_established_options_mp_fail(struct sock *sk, · 15 unmodified lines | |||
| 809 | opts->fail_seq = subflow->map_seq; | 811 | opts->fail_seq = subflow->map_seq; |
| 810 | 812 | ||
| 811 | pr_debug("MP_FAIL fail_seq=%llu", opts->fail_seq); | 813 | pr_debug("MP_FAIL fail_seq=%llu", opts->fail_seq); |
| 814 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX); | ||
| 812 | 815 | ||
| 813 | return true; | 816 | return true; |
| 814 | } | 817 | } |
| @@ -833,13 +836,11 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, · 18 unmodified lines | |||
| 833 | mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) { | 836 | mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) { |
| 834 | *size += opt_size; | 837 | *size += opt_size; |
| 835 | remaining -= opt_size; | 838 | remaining -= opt_size; |
| 836 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFASTCLOSETX); | ||
| 837 | } | 839 | } |
| 838 | /* MP_RST can be used with MP_FASTCLOSE and MP_FAIL if there is room */ | 840 | /* MP_RST can be used with MP_FASTCLOSE and MP_FAIL if there is room */ |
| 839 | if (mptcp_established_options_rst(sk, skb, &opt_size, remaining, opts)) { | 841 | if (mptcp_established_options_rst(sk, skb, &opt_size, remaining, opts)) { |
| 840 | *size += opt_size; | 842 | *size += opt_size; |
| 841 | remaining -= opt_size; | 843 | remaining -= opt_size; |
| 842 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPRSTTX); | ||
| 843 | } | 844 | } |
| 844 | return true; | 845 | return true; |
| 845 | } | 846 | } |
| @@ -966,7 +967,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, · 120 unmodified lines | |||
| 966 | goto reset; | 967 | goto reset; |
| 967 | subflow->mp_capable = 0; | 968 | subflow->mp_capable = 0; |
| 968 | pr_fallback(msk); | 969 | pr_fallback(msk); |
| 969 | __mptcp_do_fallback(msk); | 970 | mptcp_do_fallback(ssk); |
| 970 | return false; | 971 | return false; |
| 971 | } | 972 | } |
| 972 | 973 | ||
| @@ -299,23 +299,21 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq) · 298 unmodified lines | |||
| 299 | { | 299 | { |
| 300 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); | 300 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); |
| 301 | struct mptcp_sock *msk = mptcp_sk(subflow->conn); | 301 | struct mptcp_sock *msk = mptcp_sk(subflow->conn); |
| 302 | struct sock *s = (struct sock *)msk; | ||
| 303 | 302 | ||
| 304 | pr_debug("fail_seq=%llu", fail_seq); | 303 | pr_debug("fail_seq=%llu", fail_seq); |
| 305 | 304 | ||
| 306 | if (!READ_ONCE(msk->allow_infinite_fallback)) | 305 | if (!READ_ONCE(msk->allow_infinite_fallback)) |
| 307 | return; | 306 | return; |
| 308 | 307 | ||
| 309 | if (!READ_ONCE(subflow->mp_fail_response_expect)) { | 308 | if (!subflow->fail_tout) { |
| 310 | pr_debug("send MP_FAIL response and infinite map"); | 309 | pr_debug("send MP_FAIL response and infinite map"); |
| 311 | 310 | ||
| 312 | subflow->send_mp_fail = 1; | 311 | subflow->send_mp_fail = 1; |
| 313 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX); | ||
| 314 | subflow->send_infinite_map = 1; | 312 | subflow->send_infinite_map = 1; |
| 315 | } else if (!sock_flag(sk, SOCK_DEAD)) { | 313 | tcp_send_ack(sk); |
| 314 | } else { | ||
| 316 | pr_debug("MP_FAIL response received"); | 315 | pr_debug("MP_FAIL response received"); |
| 317 | 316 | WRITE_ONCE(subflow->fail_tout, 0); | |
| 318 | sk_stop_timer(s, &s->sk_timer); | ||
| 319 | } | 317 | } |
| 320 | } | 318 | } |
| 321 | 319 | ||
| @@ -500,7 +500,7 @@ static void mptcp_set_timeout(struct sock *sk) · 499 unmodified lines | |||
| 500 | __mptcp_set_timeout(sk, tout); | 500 | __mptcp_set_timeout(sk, tout); |
| 501 | } | 501 | } |
| 502 | 502 | ||
| 503 | static bool tcp_can_send_ack(const struct sock *ssk) | 503 | static inline bool tcp_can_send_ack(const struct sock *ssk) |
| 504 | { | 504 | { |
| 505 | return !((1 << inet_sk_state_load(ssk)) & | 505 | return !((1 << inet_sk_state_load(ssk)) & |
| 506 | (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_TIME_WAIT | TCPF_CLOSE | TCPF_LISTEN)); | 506 | (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_TIME_WAIT | TCPF_CLOSE | TCPF_LISTEN)); |
| @@ -1245,7 +1245,7 @@ static void mptcp_update_infinite_map(struct mptcp_sock *msk, · 738 unmodified lines | |||
| 1245 | MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPTX); | 1245 | MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPTX); |
| 1246 | mptcp_subflow_ctx(ssk)->send_infinite_map = 0; | 1246 | mptcp_subflow_ctx(ssk)->send_infinite_map = 0; |
| 1247 | pr_fallback(msk); | 1247 | pr_fallback(msk); |
| 1248 | __mptcp_do_fallback(msk); | 1248 | mptcp_do_fallback(ssk); |
| 1249 | } | 1249 | } |
| 1250 | 1250 | ||
| 1251 | static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, | 1251 | static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, |
| @@ -2175,21 +2175,6 @@ static void mptcp_retransmit_timer(struct timer_list *t) · 923 unmodified lines | |||
| 2175 | sock_put(sk); | 2175 | sock_put(sk); |
| 2176 | } | 2176 | } |
| 2177 | 2177 | ||
| 2178 | static struct mptcp_subflow_context * | ||
| 2179 | mp_fail_response_expect_subflow(struct mptcp_sock *msk) | ||
| 2180 | { | ||
| 2181 | struct mptcp_subflow_context *subflow, *ret = NULL; | ||
| 2182 | |||
| 2183 | mptcp_for_each_subflow(msk, subflow) { | ||
| 2184 | if (READ_ONCE(subflow->mp_fail_response_expect)) { | ||
| 2185 | ret = subflow; | ||
| 2186 | break; | ||
| 2187 | } | ||
| 2188 | } | ||
| 2189 | |||
| 2190 | return ret; | ||
| 2191 | } | ||
| 2192 | |||
| 2193 | static void mptcp_timeout_timer(struct timer_list *t) | 2178 | static void mptcp_timeout_timer(struct timer_list *t) |
| 2194 | { | 2179 | { |
| 2195 | struct sock *sk = from_timer(sk, t, sk_timer); | 2180 | struct sock *sk = from_timer(sk, t, sk_timer); |
| @@ -2346,6 +2331,11 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk, · 150 unmodified lines | |||
| 2346 | kfree_rcu(subflow, rcu); | 2331 | kfree_rcu(subflow, rcu); |
| 2347 | } else { | 2332 | } else { |
| 2348 | /* otherwise tcp will dispose of the ssk and subflow ctx */ | 2333 | /* otherwise tcp will dispose of the ssk and subflow ctx */ |
| 2334 | if (ssk->sk_state == TCP_LISTEN) { | ||
| 2335 | tcp_set_state(ssk, TCP_CLOSE); | ||
| 2336 | mptcp_subflow_queue_clean(ssk); | ||
| 2337 | inet_csk_listen_stop(ssk); | ||
| 2338 | } | ||
| 2349 | __tcp_close(ssk, 0); | 2339 | __tcp_close(ssk, 0); |
| 2350 | 2340 | ||
| 2351 | /* close acquired an extra ref */ | 2341 | /* close acquired an extra ref */ |
| @@ -2518,27 +2508,50 @@ reset_timer: · 166 unmodified lines | |||
| 2518 | mptcp_reset_timer(sk); | 2508 | mptcp_reset_timer(sk); |
| 2519 | } | 2509 | } |
| 2520 | 2510 | ||
| 2511 | /* schedule the timeout timer for the relevant event: either close timeout | ||
| 2512 | * or mp_fail timeout. The close timeout takes precedence on the mp_fail one | ||
| 2513 | */ | ||
| 2514 | void mptcp_reset_timeout(struct mptcp_sock *msk, unsigned long fail_tout) | ||
| 2515 | { | ||
| 2516 | struct sock *sk = (struct sock *)msk; | ||
| 2517 | unsigned long timeout, close_timeout; | ||
| 2518 | |||
| 2519 | if (!fail_tout && !sock_flag(sk, SOCK_DEAD)) | ||
| 2520 | return; | ||
| 2521 | |||
| 2522 | close_timeout = inet_csk(sk)->icsk_mtup.probe_timestamp - tcp_jiffies32 + jiffies + TCP_TIMEWAIT_LEN; | ||
| 2523 | |||
| 2524 | /* the close timeout takes precedence on the fail one, and here at least one of | ||
| 2525 | * them is active | ||
| 2526 | */ | ||
| 2527 | timeout = sock_flag(sk, SOCK_DEAD) ? close_timeout : fail_tout; | ||
| 2528 | |||
| 2529 | sk_reset_timer(sk, &sk->sk_timer, timeout); | ||
| 2530 | } | ||
| 2531 | |||
| 2521 | static void mptcp_mp_fail_no_response(struct mptcp_sock *msk) | 2532 | static void mptcp_mp_fail_no_response(struct mptcp_sock *msk) |
| 2522 | { | 2533 | { |
| 2523 | struct mptcp_subflow_context *subflow; | 2534 | struct sock *ssk = msk->first; |
| 2524 | struct sock *ssk; | ||
| 2525 | bool slow; | 2535 | bool slow; |
| 2526 | 2536 | ||
| 2527 | subflow = mp_fail_response_expect_subflow(msk); | 2537 | if (!ssk) |
| 2528 | if (subflow) { | 2538 | return; |
| 2529 | pr_debug("MP_FAIL doesn't respond, reset the subflow"); | ||
| 2530 | 2539 | ||
| 2531 | ssk = mptcp_subflow_tcp_sock(subflow); | 2540 | pr_debug("MP_FAIL doesn't respond, reset the subflow"); |
| 2532 | slow = lock_sock_fast(ssk); | 2541 | |
| 2533 | mptcp_subflow_reset(ssk); | 2542 | slow = lock_sock_fast(ssk); |
| 2534 | unlock_sock_fast(ssk, slow); | 2543 | mptcp_subflow_reset(ssk); |
| 2535 | } | 2544 | WRITE_ONCE(mptcp_subflow_ctx(ssk)->fail_tout, 0); |
| 2545 | unlock_sock_fast(ssk, slow); | ||
| 2546 | |||
| 2547 | mptcp_reset_timeout(msk, 0); | ||
| 2536 | } | 2548 | } |
| 2537 | 2549 | ||
| 2538 | static void mptcp_worker(struct work_struct *work) | 2550 | static void mptcp_worker(struct work_struct *work) |
| 2539 | { | 2551 | { |
| 2540 | struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work); | 2552 | struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work); |
| 2541 | struct sock *sk = &msk->sk.icsk_inet.sk; | 2553 | struct sock *sk = &msk->sk.icsk_inet.sk; |
| 2554 | unsigned long fail_tout; | ||
| 2542 | int state; | 2555 | int state; |
| 2543 | 2556 | ||
| 2544 | lock_sock(sk); | 2557 | lock_sock(sk); |
| @@ -2575,7 +2588,9 @@ static void mptcp_worker(struct work_struct *work) · 30 unmodified lines | |||
| 2575 | if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags)) | 2588 | if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags)) |
| 2576 | __mptcp_retrans(sk); | 2589 | __mptcp_retrans(sk); |
| 2577 | 2590 | ||
| 2578 | mptcp_mp_fail_no_response(msk); | 2591 | fail_tout = msk->first ? READ_ONCE(mptcp_subflow_ctx(msk->first)->fail_tout) : 0; |
| 2592 | if (fail_tout && time_after(jiffies, fail_tout)) | ||
| 2593 | mptcp_mp_fail_no_response(msk); | ||
| 2579 | 2594 | ||
| 2580 | unlock: | 2595 | unlock: |
| 2581 | release_sock(sk); | 2596 | release_sock(sk); |
| @@ -2822,6 +2837,7 @@ static void __mptcp_destroy_sock(struct sock *sk) · 240 unmodified lines | |||
| 2822 | static void mptcp_close(struct sock *sk, long timeout) | 2837 | static void mptcp_close(struct sock *sk, long timeout) |
| 2823 | { | 2838 | { |
| 2824 | struct mptcp_subflow_context *subflow; | 2839 | struct mptcp_subflow_context *subflow; |
| 2840 | struct mptcp_sock *msk = mptcp_sk(sk); | ||
| 2825 | bool do_cancel_work = false; | 2841 | bool do_cancel_work = false; |
| 2826 | 2842 | ||
| 2827 | lock_sock(sk); | 2843 | lock_sock(sk); |
| @@ -2840,10 +2856,16 @@ static void mptcp_close(struct sock *sk, long timeout) · 12 unmodified lines | |||
| 2840 | cleanup: | 2856 | cleanup: |
| 2841 | /* orphan all the subflows */ | 2857 | /* orphan all the subflows */ |
| 2842 | inet_csk(sk)->icsk_mtup.probe_timestamp = tcp_jiffies32; | 2858 | inet_csk(sk)->icsk_mtup.probe_timestamp = tcp_jiffies32; |
| 2843 | mptcp_for_each_subflow(mptcp_sk(sk), subflow) { | 2859 | mptcp_for_each_subflow(msk, subflow) { |
| 2844 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | 2860 | struct sock *ssk = mptcp_subflow_tcp_sock(subflow); |
| 2845 | bool slow = lock_sock_fast_nested(ssk); | 2861 | bool slow = lock_sock_fast_nested(ssk); |
| 2846 | 2862 | ||
| 2863 | /* since the close timeout takes precedence on the fail one, | ||
| 2864 | * cancel the latter | ||
| 2865 | */ | ||
| 2866 | if (ssk == msk->first) | ||
| 2867 | subflow->fail_tout = 0; | ||
| 2868 | |||
| 2847 | sock_orphan(ssk); | 2869 | sock_orphan(ssk); |
| 2848 | unlock_sock_fast(ssk, slow); | 2870 | unlock_sock_fast(ssk, slow); |
| 2849 | } | 2871 | } |
| @@ -2852,13 +2874,13 @@ cleanup: · 2 unmodified lines | |||
| 2852 | sock_hold(sk); | 2874 | sock_hold(sk); |
| 2853 | pr_debug("msk=%p state=%d", sk, sk->sk_state); | 2875 | pr_debug("msk=%p state=%d", sk, sk->sk_state); |
| 2854 | if (mptcp_sk(sk)->token) | 2876 | if (mptcp_sk(sk)->token) |
| 2855 | mptcp_event(MPTCP_EVENT_CLOSED, mptcp_sk(sk), NULL, GFP_KERNEL); | 2877 | mptcp_event(MPTCP_EVENT_CLOSED, msk, NULL, GFP_KERNEL); |
| 2856 | 2878 | ||
| 2857 | if (sk->sk_state == TCP_CLOSE) { | 2879 | if (sk->sk_state == TCP_CLOSE) { |
| 2858 | __mptcp_destroy_sock(sk); | 2880 | __mptcp_destroy_sock(sk); |
| 2859 | do_cancel_work = true; | 2881 | do_cancel_work = true; |
| 2860 | } else { | 2882 | } else { |
| 2861 | sk_reset_timer(sk, &sk->sk_timer, jiffies + TCP_TIMEWAIT_LEN); | 2883 | mptcp_reset_timeout(msk, 0); |
| 2862 | } | 2884 | } |
| 2863 | release_sock(sk); | 2885 | release_sock(sk); |
| 2864 | if (do_cancel_work) | 2886 | if (do_cancel_work) |
| @@ -306,6 +306,7 @@ struct mptcp_sock { · 305 unmodified lines | |||
| 306 | 306 | ||
| 307 | u32 setsockopt_seq; | 307 | u32 setsockopt_seq; |
| 308 | char ca_name[TCP_CA_NAME_MAX]; | 308 | char ca_name[TCP_CA_NAME_MAX]; |
| 309 | struct mptcp_sock *dl_next; | ||
| 309 | }; | 310 | }; |
| 310 | 311 | ||
| 311 | #define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock) | 312 | #define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock) |
| @@ -468,7 +469,6 @@ struct mptcp_subflow_context { · 156 unmodified lines | |||
| 468 | local_id_valid : 1, /* local_id is correctly initialized */ | 469 | local_id_valid : 1, /* local_id is correctly initialized */ |
| 469 | valid_csum_seen : 1; /* at least one csum validated */ | 470 | valid_csum_seen : 1; /* at least one csum validated */ |
| 470 | enum mptcp_data_avail data_avail; | 471 | enum mptcp_data_avail data_avail; |
| 471 | bool mp_fail_response_expect; | ||
| 472 | u32 remote_nonce; | 472 | u32 remote_nonce; |
| 473 | u64 thmac; | 473 | u64 thmac; |
| 474 | u32 local_nonce; | 474 | u32 local_nonce; |
| @@ -482,6 +482,7 @@ struct mptcp_subflow_context { · 7 unmodified lines | |||
| 482 | u8 stale_count; | 482 | u8 stale_count; |
| 483 | 483 | ||
| 484 | long delegated_status; | 484 | long delegated_status; |
| 485 | unsigned long fail_tout; | ||
| 485 | 486 | ||
| 486 | ); | 487 | ); |
| 487 | 488 | ||
| @@ -608,6 +609,7 @@ void mptcp_close_ssk(struct sock *sk, struct sock *ssk, · 120 unmodified lines | |||
| 608 | struct mptcp_subflow_context *subflow); | 609 | struct mptcp_subflow_context *subflow); |
| 609 | void mptcp_subflow_send_ack(struct sock *ssk); | 610 | void mptcp_subflow_send_ack(struct sock *ssk); |
| 610 | void mptcp_subflow_reset(struct sock *ssk); | 611 | void mptcp_subflow_reset(struct sock *ssk); |
| 612 | void mptcp_subflow_queue_clean(struct sock *ssk); | ||
| 611 | void mptcp_sock_graft(struct sock *sk, struct socket *parent); | 613 | void mptcp_sock_graft(struct sock *sk, struct socket *parent); |
| 612 | struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk); | 614 | struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk); |
| 613 | 615 | ||
| @@ -662,6 +664,7 @@ void mptcp_get_options(const struct sk_buff *skb, · 48 unmodified lines | |||
| 662 | 664 | ||
| 663 | void mptcp_finish_connect(struct sock *sk); | 665 | void mptcp_finish_connect(struct sock *sk); |
| 664 | void __mptcp_set_connected(struct sock *sk); | 666 | void __mptcp_set_connected(struct sock *sk); |
| 667 | void mptcp_reset_timeout(struct mptcp_sock *msk, unsigned long fail_tout); | ||
| 665 | static inline bool mptcp_is_fully_established(struct sock *sk) | 668 | static inline bool mptcp_is_fully_established(struct sock *sk) |
| 666 | { | 669 | { |
| 667 | return inet_sk_state_load(sk) == TCP_ESTABLISHED && | 670 | return inet_sk_state_load(sk) == TCP_ESTABLISHED && |
| @@ -926,12 +929,25 @@ static inline void __mptcp_do_fallback(struct mptcp_sock *msk) · 258 unmodified lines | |||
| 926 | set_bit(MPTCP_FALLBACK_DONE, &msk->flags); | 929 | set_bit(MPTCP_FALLBACK_DONE, &msk->flags); |
| 927 | } | 930 | } |
| 928 | 931 | ||
| 929 | static inline void mptcp_do_fallback(struct sock *sk) | 932 | static inline void mptcp_do_fallback(struct sock *ssk) |
| 930 | { | 933 | { |
| 931 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); | 934 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); |
| 932 | struct mptcp_sock *msk = mptcp_sk(subflow->conn); | 935 | struct sock *sk = subflow->conn; |
| 936 | struct mptcp_sock *msk; | ||
| 933 | 937 | ||
| 938 | msk = mptcp_sk(sk); | ||
| 934 | __mptcp_do_fallback(msk); | 939 | __mptcp_do_fallback(msk); |
| 940 | if (READ_ONCE(msk->snd_data_fin_enable) && !(ssk->sk_shutdown & SEND_SHUTDOWN)) { | ||
| 941 | gfp_t saved_allocation = ssk->sk_allocation; | ||
| 942 | |||
| 943 | /* we are in a atomic (BH) scope, override ssk default for data | ||
| 944 | * fin allocation | ||
| 945 | */ | ||
| 946 | ssk->sk_allocation = GFP_ATOMIC; | ||
| 947 | ssk->sk_shutdown |= SEND_SHUTDOWN; | ||
| 948 | tcp_shutdown(ssk, SEND_SHUTDOWN); | ||
| 949 | ssk->sk_allocation = saved_allocation; | ||
| 950 | } | ||
| 935 | } | 951 | } |
| 936 | 952 | ||
| 937 | #define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=%p)", __func__, a) | 953 | #define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=%p)", __func__, a) |
| @@ -843,7 +843,8 @@ enum mapping_status { · 842 unmodified lines | |||
| 843 | MAPPING_INVALID, | 843 | MAPPING_INVALID, |
| 844 | MAPPING_EMPTY, | 844 | MAPPING_EMPTY, |
| 845 | MAPPING_DATA_FIN, | 845 | MAPPING_DATA_FIN, |
| 846 | MAPPING_DUMMY | 846 | MAPPING_DUMMY, |
| 847 | MAPPING_BAD_CSUM | ||
| 847 | }; | 848 | }; |
| 848 | 849 | ||
| 849 | static void dbg_bad_map(struct mptcp_subflow_context *subflow, u32 ssn) | 850 | static void dbg_bad_map(struct mptcp_subflow_context *subflow, u32 ssn) |
| @@ -958,11 +959,7 @@ static enum mapping_status validate_data_csum(struct sock *ssk, struct sk_buff * · 108 unmodified lines | |||
| 958 | subflow->map_data_csum); | 959 | subflow->map_data_csum); |
| 959 | if (unlikely(csum)) { | 960 | if (unlikely(csum)) { |
| 960 | MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DATACSUMERR); | 961 | MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DATACSUMERR); |
| 961 | if (subflow->mp_join || subflow->valid_csum_seen) { | 962 | return MAPPING_BAD_CSUM; |
| 962 | subflow->send_mp_fail = 1; | ||
| 963 | MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPFAILTX); | ||
| 964 | } | ||
| 965 | return subflow->mp_join ? MAPPING_INVALID : MAPPING_DUMMY; | ||
| 966 | } | 963 | } |
| 967 | 964 | ||
| 968 | subflow->valid_csum_seen = 1; | 965 | subflow->valid_csum_seen = 1; |
| @@ -974,7 +971,6 @@ static enum mapping_status get_mapping_status(struct sock *ssk, · 5 unmodified lines | |||
| 974 | { | 971 | { |
| 975 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); | 972 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); |
| 976 | bool csum_reqd = READ_ONCE(msk->csum_enabled); | 973 | bool csum_reqd = READ_ONCE(msk->csum_enabled); |
| 977 | struct sock *sk = (struct sock *)msk; | ||
| 978 | struct mptcp_ext *mpext; | 974 | struct mptcp_ext *mpext; |
| 979 | struct sk_buff *skb; | 975 | struct sk_buff *skb; |
| 980 | u16 data_len; | 976 | u16 data_len; |
| @@ -1016,9 +1012,6 @@ static enum mapping_status get_mapping_status(struct sock *ssk, · 35 unmodified lines | |||
| 1016 | pr_debug("infinite mapping received"); | 1012 | pr_debug("infinite mapping received"); |
| 1017 | MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPRX); | 1013 | MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPRX); |
| 1018 | subflow->map_data_len = 0; | 1014 | subflow->map_data_len = 0; |
| 1019 | if (!sock_flag(ssk, SOCK_DEAD)) | ||
| 1020 | sk_stop_timer(sk, &sk->sk_timer); | ||
| 1021 | |||
| 1022 | return MAPPING_INVALID; | 1015 | return MAPPING_INVALID; |
| 1023 | } | 1016 | } |
| 1024 | 1017 | ||
| @@ -1165,6 +1158,33 @@ static bool subflow_can_fallback(struct mptcp_subflow_context *subflow) · 140 unmodified lines | |||
| 1165 | return !subflow->fully_established; | 1158 | return !subflow->fully_established; |
| 1166 | } | 1159 | } |
| 1167 | 1160 | ||
| 1161 | static void mptcp_subflow_fail(struct mptcp_sock *msk, struct sock *ssk) | ||
| 1162 | { | ||
| 1163 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); | ||
| 1164 | unsigned long fail_tout; | ||
| 1165 | |||
| 1166 | /* greceful failure can happen only on the MPC subflow */ | ||
| 1167 | if (WARN_ON_ONCE(ssk != READ_ONCE(msk->first))) | ||
| 1168 | return; | ||
| 1169 | |||
| 1170 | /* since the close timeout take precedence on the fail one, | ||
| 1171 | * no need to start the latter when the first is already set | ||
| 1172 | */ | ||
| 1173 | if (sock_flag((struct sock *)msk, SOCK_DEAD)) | ||
| 1174 | return; | ||
| 1175 | |||
| 1176 | /* we don't need extreme accuracy here, use a zero fail_tout as special | ||
| 1177 | * value meaning no fail timeout at all; | ||
| 1178 | */ | ||
| 1179 | fail_tout = jiffies + TCP_RTO_MAX; | ||
| 1180 | if (!fail_tout) | ||
| 1181 | fail_tout = 1; | ||
| 1182 | WRITE_ONCE(subflow->fail_tout, fail_tout); | ||
| 1183 | tcp_send_ack(ssk); | ||
| 1184 | |||
| 1185 | mptcp_reset_timeout(msk, subflow->fail_tout); | ||
| 1186 | } | ||
| 1187 | |||
| 1168 | static bool subflow_check_data_avail(struct sock *ssk) | 1188 | static bool subflow_check_data_avail(struct sock *ssk) |
| 1169 | { | 1189 | { |
| 1170 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); | 1190 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); |
| @@ -1184,10 +1204,8 @@ static bool subflow_check_data_avail(struct sock *ssk) · 13 unmodified lines | |||
| 1184 | 1204 | ||
| 1185 | status = get_mapping_status(ssk, msk); | 1205 | status = get_mapping_status(ssk, msk); |
| 1186 | trace_subflow_check_data_avail(status, skb_peek(&ssk->sk_receive_queue)); | 1206 | trace_subflow_check_data_avail(status, skb_peek(&ssk->sk_receive_queue)); |
| 1187 | if (unlikely(status == MAPPING_INVALID)) | 1207 | if (unlikely(status == MAPPING_INVALID || status == MAPPING_DUMMY || |
| 1188 | goto fallback; | 1208 | status == MAPPING_BAD_CSUM)) |
| 1189 | |||
| 1190 | if (unlikely(status == MAPPING_DUMMY)) | ||
| 1191 | goto fallback; | 1209 | goto fallback; |
| 1192 | 1210 | ||
| 1193 | if (status != MAPPING_OK) | 1211 | if (status != MAPPING_OK) |
| @@ -1229,22 +1247,17 @@ no_data: · 35 unmodified lines | |||
| 1229 | fallback: | 1247 | fallback: |
| 1230 | if (!__mptcp_check_fallback(msk)) { | 1248 | if (!__mptcp_check_fallback(msk)) { |
| 1231 | /* RFC 8684 section 3.7. */ | 1249 | /* RFC 8684 section 3.7. */ |
| 1232 | if (subflow->send_mp_fail) { | 1250 | if (status == MAPPING_BAD_CSUM && |
| 1251 | (subflow->mp_join || subflow->valid_csum_seen)) { | ||
| 1252 | subflow->send_mp_fail = 1; | ||
| 1253 | |||
| 1233 | if (!READ_ONCE(msk->allow_infinite_fallback)) { | 1254 | if (!READ_ONCE(msk->allow_infinite_fallback)) { |
| 1234 | ssk->sk_err = EBADMSG; | ||
| 1235 | tcp_set_state(ssk, TCP_CLOSE); | ||
| 1236 | subflow->reset_transient = 0; | 1255 | subflow->reset_transient = 0; |
| 1237 | subflow->reset_reason = MPTCP_RST_EMIDDLEBOX; | 1256 | subflow->reset_reason = MPTCP_RST_EMIDDLEBOX; |
| 1238 | tcp_send_active_reset(ssk, GFP_ATOMIC); | 1257 | goto reset; |
| 1239 | while ((skb = skb_peek(&ssk->sk_receive_queue))) | ||
| 1240 | sk_eat_skb(ssk, skb); | ||
| 1241 | } else if (!sock_flag(ssk, SOCK_DEAD)) { | ||
| 1242 | WRITE_ONCE(subflow->mp_fail_response_expect, true); | ||
| 1243 | sk_reset_timer((struct sock *)msk, | ||
| 1244 | &((struct sock *)msk)->sk_timer, | ||
| 1245 | jiffies + TCP_RTO_MAX); | ||
| 1246 | } | 1258 | } |
| 1247 | WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA); | 1259 | mptcp_subflow_fail(msk, ssk); |
| 1260 | WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_DATA_AVAIL); | ||
| 1248 | return true; | 1261 | return true; |
| 1249 | } | 1262 | } |
| 1250 | 1263 | ||
| @@ -1252,16 +1265,20 @@ fallback: · 1 unmodified line | |||
| 1252 | /* fatal protocol error, close the socket. | 1265 | /* fatal protocol error, close the socket. |
| 1253 | * subflow_error_report() will introduce the appropriate barriers | 1266 | * subflow_error_report() will introduce the appropriate barriers |
| 1254 | */ | 1267 | */ |
| 1255 | ssk->sk_err = EBADMSG; | ||
| 1256 | tcp_set_state(ssk, TCP_CLOSE); | ||
| 1257 | subflow->reset_transient = 0; | 1268 | subflow->reset_transient = 0; |
| 1258 | subflow->reset_reason = MPTCP_RST_EMPTCP; | 1269 | subflow->reset_reason = MPTCP_RST_EMPTCP; |
| 1270 | |||
| 1271 | reset: | ||
| 1272 | ssk->sk_err = EBADMSG; | ||
| 1273 | tcp_set_state(ssk, TCP_CLOSE); | ||
| 1274 | while ((skb = skb_peek(&ssk->sk_receive_queue))) | ||
| 1275 | sk_eat_skb(ssk, skb); | ||
| 1259 | tcp_send_active_reset(ssk, GFP_ATOMIC); | 1276 | tcp_send_active_reset(ssk, GFP_ATOMIC); |
| 1260 | WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA); | 1277 | WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA); |
| 1261 | return false; | 1278 | return false; |
| 1262 | } | 1279 | } |
| 1263 | 1280 | ||
| 1264 | __mptcp_do_fallback(msk); | 1281 | mptcp_do_fallback(ssk); |
| 1265 | } | 1282 | } |
| 1266 | 1283 | ||
| 1267 | skb = skb_peek(&ssk->sk_receive_queue); | 1284 | skb = skb_peek(&ssk->sk_receive_queue); |
| @@ -1706,6 +1723,58 @@ static void subflow_state_change(struct sock *sk) · 438 unmodified lines | |||
| 1706 | } | 1723 | } |
| 1707 | } | 1724 | } |
| 1708 | 1725 | ||
| 1726 | void mptcp_subflow_queue_clean(struct sock *listener_ssk) | ||
| 1727 | { | ||
| 1728 | struct request_sock_queue *queue = &inet_csk(listener_ssk)->icsk_accept_queue; | ||
| 1729 | struct mptcp_sock *msk, *next, *head = NULL; | ||
| 1730 | struct request_sock *req; | ||
| 1731 | |||
| 1732 | /* build a list of all unaccepted mptcp sockets */ | ||
| 1733 | spin_lock_bh(&queue->rskq_lock); | ||
| 1734 | for (req = queue->rskq_accept_head; req; req = req->dl_next) { | ||
| 1735 | struct mptcp_subflow_context *subflow; | ||
| 1736 | struct sock *ssk = req->sk; | ||
| 1737 | struct mptcp_sock *msk; | ||
| 1738 | |||
| 1739 | if (!sk_is_mptcp(ssk)) | ||
| 1740 | continue; | ||
| 1741 | |||
| 1742 | subflow = mptcp_subflow_ctx(ssk); | ||
| 1743 | if (!subflow || !subflow->conn) | ||
| 1744 | continue; | ||
| 1745 | |||
| 1746 | /* skip if already in list */ | ||
| 1747 | msk = mptcp_sk(subflow->conn); | ||
| 1748 | if (msk->dl_next || msk == head) | ||
| 1749 | continue; | ||
| 1750 | |||
| 1751 | msk->dl_next = head; | ||
| 1752 | head = msk; | ||
| 1753 | } | ||
| 1754 | spin_unlock_bh(&queue->rskq_lock); | ||
| 1755 | if (!head) | ||
| 1756 | return; | ||
| 1757 | |||
| 1758 | /* can't acquire the msk socket lock under the subflow one, | ||
| 1759 | * or will cause ABBA deadlock | ||
| 1760 | */ | ||
| 1761 | release_sock(listener_ssk); | ||
| 1762 | |||
| 1763 | for (msk = head; msk; msk = next) { | ||
| 1764 | struct sock *sk = (struct sock *)msk; | ||
| 1765 | bool slow; | ||
| 1766 | |||
| 1767 | slow = lock_sock_fast_nested(sk); | ||
| 1768 | next = msk->dl_next; | ||
| 1769 | msk->first = NULL; | ||
| 1770 | msk->dl_next = NULL; | ||
| 1771 | unlock_sock_fast(sk, slow); | ||
| 1772 | } | ||
| 1773 | |||
| 1774 | /* we are still under the listener msk socket lock */ | ||
| 1775 | lock_sock_nested(listener_ssk, SINGLE_DEPTH_NESTING); | ||
| 1776 | } | ||
| 1777 | |||
| 1709 | static int subflow_ulp_init(struct sock *sk) | 1778 | static int subflow_ulp_init(struct sock *sk) |
| 1710 | { | 1779 | { |
| 1711 | struct inet_connection_sock *icsk = inet_csk(sk); | 1780 | struct inet_connection_sock *icsk = inet_csk(sk); |
| @@ -61,6 +61,39 @@ chk_msk_nr() · 60 unmodified lines | |||
| 61 | __chk_nr "grep -c token:" $* | 61 | __chk_nr "grep -c token:" $* |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | wait_msk_nr() | ||
| 65 | { | ||
| 66 | local condition="grep -c token:" | ||
| 67 | local expected=$1 | ||
| 68 | local timeout=20 | ||
| 69 | local msg nr | ||
| 70 | local max=0 | ||
| 71 | local i=0 | ||
| 72 | |||
| 73 | shift 1 | ||
| 74 | msg=$* | ||
| 75 | |||
| 76 | while [ $i -lt $timeout ]; do | ||
| 77 | nr=$(ss -inmHMN $ns | $condition) | ||
| 78 | [ $nr == $expected ] && break; | ||
| 79 | [ $nr -gt $max ] && max=$nr | ||
| 80 | i=$((i + 1)) | ||
| 81 | sleep 1 | ||
| 82 | done | ||
| 83 | |||
| 84 | printf "%-50s" "$msg" | ||
| 85 | if [ $i -ge $timeout ]; then | ||
| 86 | echo "[ fail ] timeout while expecting $expected max $max last $nr" | ||
| 87 | ret=$test_cnt | ||
| 88 | elif [ $nr != $expected ]; then | ||
| 89 | echo "[ fail ] expected $expected found $nr" | ||
| 90 | ret=$test_cnt | ||
| 91 | else | ||
| 92 | echo "[ ok ]" | ||
| 93 | fi | ||
| 94 | test_cnt=$((test_cnt+1)) | ||
| 95 | } | ||
| 96 | |||
| 64 | chk_msk_fallback_nr() | 97 | chk_msk_fallback_nr() |
| 65 | { | 98 | { |
| 66 | __chk_nr "grep -c fallback" $* | 99 | __chk_nr "grep -c fallback" $* |
| @@ -146,7 +179,7 @@ ip -n $ns link set dev lo up · 79 unmodified lines | |||
| 146 | echo "a" | \ | 179 | echo "a" | \ |
| 147 | timeout ${timeout_test} \ | 180 | timeout ${timeout_test} \ |
| 148 | ip netns exec $ns \ | 181 | ip netns exec $ns \ |
| 149 | ./mptcp_connect -p 10000 -l -t ${timeout_poll} \ | 182 | ./mptcp_connect -p 10000 -l -t ${timeout_poll} -w 20 \ |
| 150 | 0.0.0.0 >/dev/null & | 183 | 0.0.0.0 >/dev/null & |
| 151 | wait_local_port_listen $ns 10000 | 184 | wait_local_port_listen $ns 10000 |
| 152 | chk_msk_nr 0 "no msk on netns creation" | 185 | chk_msk_nr 0 "no msk on netns creation" |
| @@ -155,7 +188,7 @@ chk_msk_listen 10000 · 2 unmodified lines | |||
| 155 | echo "b" | \ | 188 | echo "b" | \ |
| 156 | timeout ${timeout_test} \ | 189 | timeout ${timeout_test} \ |
| 157 | ip netns exec $ns \ | 190 | ip netns exec $ns \ |
| 158 | ./mptcp_connect -p 10000 -r 0 -t ${timeout_poll} \ | 191 | ./mptcp_connect -p 10000 -r 0 -t ${timeout_poll} -w 20 \ |
| 159 | 127.0.0.1 >/dev/null & | 192 | 127.0.0.1 >/dev/null & |
| 160 | wait_connected $ns 10000 | 193 | wait_connected $ns 10000 |
| 161 | chk_msk_nr 2 "after MPC handshake " | 194 | chk_msk_nr 2 "after MPC handshake " |
| @@ -167,13 +200,13 @@ flush_pids · 5 unmodified lines | |||
| 167 | echo "a" | \ | 200 | echo "a" | \ |
| 168 | timeout ${timeout_test} \ | 201 | timeout ${timeout_test} \ |
| 169 | ip netns exec $ns \ | 202 | ip netns exec $ns \ |
| 170 | ./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} \ | 203 | ./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} -w 20 \ |
| 171 | 0.0.0.0 >/dev/null & | 204 | 0.0.0.0 >/dev/null & |
| 172 | wait_local_port_listen $ns 10001 | 205 | wait_local_port_listen $ns 10001 |
| 173 | echo "b" | \ | 206 | echo "b" | \ |
| 174 | timeout ${timeout_test} \ | 207 | timeout ${timeout_test} \ |
| 175 | ip netns exec $ns \ | 208 | ip netns exec $ns \ |
| 176 | ./mptcp_connect -p 10001 -r 0 -t ${timeout_poll} \ | 209 | ./mptcp_connect -p 10001 -r 0 -t ${timeout_poll} -w 20 \ |
| 177 | 127.0.0.1 >/dev/null & | 210 | 127.0.0.1 >/dev/null & |
| 178 | wait_connected $ns 10001 | 211 | wait_connected $ns 10001 |
| 179 | chk_msk_fallback_nr 1 "check fallback" | 212 | chk_msk_fallback_nr 1 "check fallback" |
| @@ -184,7 +217,7 @@ for I in `seq 1 $NR_CLIENTS`; do · 4 unmodified lines | |||
| 184 | echo "a" | \ | 217 | echo "a" | \ |
| 185 | timeout ${timeout_test} \ | 218 | timeout ${timeout_test} \ |
| 186 | ip netns exec $ns \ | 219 | ip netns exec $ns \ |
| 187 | ./mptcp_connect -p $((I+10001)) -l -w 10 \ | 220 | ./mptcp_connect -p $((I+10001)) -l -w 20 \ |
| 188 | -t ${timeout_poll} 0.0.0.0 >/dev/null & | 221 | -t ${timeout_poll} 0.0.0.0 >/dev/null & |
| 189 | done | 222 | done |
| 190 | wait_local_port_listen $ns $((NR_CLIENTS + 10001)) | 223 | wait_local_port_listen $ns $((NR_CLIENTS + 10001)) |
| @@ -193,12 +226,11 @@ for I in `seq 1 $NR_CLIENTS`; do · 2 unmodified lines | |||
| 193 | echo "b" | \ | 226 | echo "b" | \ |
| 194 | timeout ${timeout_test} \ | 227 | timeout ${timeout_test} \ |
| 195 | ip netns exec $ns \ | 228 | ip netns exec $ns \ |
| 196 | ./mptcp_connect -p $((I+10001)) -w 10 \ | 229 | ./mptcp_connect -p $((I+10001)) -w 20 \ |
| 197 | -t ${timeout_poll} 127.0.0.1 >/dev/null & | 230 | -t ${timeout_poll} 127.0.0.1 >/dev/null & |
| 198 | done | 231 | done |
| 199 | sleep 1.5 | ||
| 200 | 232 | ||
| 201 | chk_msk_nr $((NR_CLIENTS*2)) "many msk socket present" | 233 | wait_msk_nr $((NR_CLIENTS*2)) "many msk socket present" |
| 202 | flush_pids | 234 | flush_pids |
| 203 | 235 | ||
| 204 | exit $ret | 236 | exit $ret |
| @@ -265,7 +265,7 @@ static void sock_test_tcpulp(int sock, int proto, unsigned int line) · 264 unmodified lines | |||
| 265 | static int sock_listen_mptcp(const char * const listenaddr, | 265 | static int sock_listen_mptcp(const char * const listenaddr, |
| 266 | const char * const port) | 266 | const char * const port) |
| 267 | { | 267 | { |
| 268 | int sock; | 268 | int sock = -1; |
| 269 | struct addrinfo hints = { | 269 | struct addrinfo hints = { |
| 270 | .ai_protocol = IPPROTO_TCP, | 270 | .ai_protocol = IPPROTO_TCP, |
| 271 | .ai_socktype = SOCK_STREAM, | 271 | .ai_socktype = SOCK_STREAM, |
| @@ -88,7 +88,7 @@ static void xgetaddrinfo(const char *node, const char *service, · 87 unmodified lines | |||
| 88 | static int sock_listen_mptcp(const char * const listenaddr, | 88 | static int sock_listen_mptcp(const char * const listenaddr, |
| 89 | const char * const port) | 89 | const char * const port) |
| 90 | { | 90 | { |
| 91 | int sock; | 91 | int sock = -1; |
| 92 | struct addrinfo hints = { | 92 | struct addrinfo hints = { |
| 93 | .ai_protocol = IPPROTO_TCP, | 93 | .ai_protocol = IPPROTO_TCP, |
| 94 | .ai_socktype = SOCK_STREAM, | 94 | .ai_socktype = SOCK_STREAM, |
| @@ -136,7 +136,7 @@ static void xgetaddrinfo(const char *node, const char *service, · 135 unmodified lines | |||
| 136 | static int sock_listen_mptcp(const char * const listenaddr, | 136 | static int sock_listen_mptcp(const char * const listenaddr, |
| 137 | const char * const port) | 137 | const char * const port) |
| 138 | { | 138 | { |
| 139 | int sock; | 139 | int sock = -1; |
| 140 | struct addrinfo hints = { | 140 | struct addrinfo hints = { |
| 141 | .ai_protocol = IPPROTO_TCP, | 141 | .ai_protocol = IPPROTO_TCP, |
| 142 | .ai_socktype = SOCK_STREAM, | 142 | .ai_socktype = SOCK_STREAM, |