Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : #include <linux/skbuff.h>
3 : :
4 : : #include "protocol.h"
5 : :
6 : : /* Syncookies do not work for JOIN requests.
7 : : *
8 : : * Unlike MP_CAPABLE, where the ACK cookie contains the needed MPTCP
9 : : * options to reconstruct the initial syn state, MP_JOIN does not contain
10 : : * the token to obtain the mptcp socket nor the server-generated nonce
11 : : * that was used in the cookie SYN/ACK response.
12 : : *
13 : : * Keep a small best effort state table to store the syn/synack data,
14 : : * indexed by skb hash.
15 : : *
16 : : * A MP_JOIN SYN packet handled by syn cookies is only stored if the 32bit
17 : : * token matches a known mptcp connection that can still accept more subflows.
18 : : *
19 : : * There is no timeout handling -- state is only re-constructed
20 : : * when the TCP ACK passed the cookie validation check.
21 : : */
22 : :
23 : : struct join_entry {
24 : : u32 token;
25 : : u32 remote_nonce;
26 : : u32 local_nonce;
27 : : u8 join_id;
28 : : u8 local_id;
29 : : u8 backup;
30 : : u8 valid;
31 : : };
32 : :
33 : : #define COOKIE_JOIN_SLOTS 1024
34 : :
35 : : static struct join_entry join_entries[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp;
36 : : static spinlock_t join_entry_locks[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp;
37 : :
38 : 40 : static u32 mptcp_join_entry_hash(struct sk_buff *skb, struct net *net)
39 : : {
40 : 40 : static u32 mptcp_join_hash_secret __read_mostly;
41 : 40 : struct tcphdr *th = tcp_hdr(skb);
42 : 40 : u32 seq, i;
43 : :
44 [ + + + + ]: 40 : net_get_random_once(&mptcp_join_hash_secret,
45 : : sizeof(mptcp_join_hash_secret));
46 : :
47 [ + + ]: 40 : if (th->syn)
48 : 20 : seq = TCP_SKB_CB(skb)->seq;
49 : : else
50 : 20 : seq = TCP_SKB_CB(skb)->seq - 1;
51 : :
52 : 40 : i = jhash_3words(seq, net_hash_mix(net),
53 : 40 : (__force __u32)th->source << 16 | (__force __u32)th->dest,
54 : : mptcp_join_hash_secret);
55 : :
56 : 40 : return i % ARRAY_SIZE(join_entries);
57 : : }
58 : :
59 : 0 : static void mptcp_join_store_state(struct join_entry *entry,
60 : : const struct mptcp_subflow_request_sock *subflow_req)
61 : : {
62 : 20 : entry->token = subflow_req->token;
63 : 20 : entry->remote_nonce = subflow_req->remote_nonce;
64 : 20 : entry->local_nonce = subflow_req->local_nonce;
65 : 20 : entry->backup = subflow_req->backup;
66 : 20 : entry->join_id = subflow_req->remote_id;
67 : 20 : entry->local_id = subflow_req->local_id;
68 : 20 : entry->valid = 1;
69 : : }
70 : :
71 : 20 : void subflow_init_req_cookie_join_save(const struct mptcp_subflow_request_sock *subflow_req,
72 : : struct sk_buff *skb)
73 : : {
74 : 20 : struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
75 : 20 : u32 i = mptcp_join_entry_hash(skb, net);
76 : :
77 : : /* No use in waiting if other cpu is already using this slot --
78 : : * would overwrite the data that got stored.
79 : : */
80 : 20 : spin_lock_bh(&join_entry_locks[i]);
81 : 20 : mptcp_join_store_state(&join_entries[i], subflow_req);
82 : 20 : spin_unlock_bh(&join_entry_locks[i]);
83 : 20 : }
84 : :
85 : : /* Called for a cookie-ack with MP_JOIN option present.
86 : : * Look up the saved state based on skb hash & check token matches msk
87 : : * in same netns.
88 : : *
89 : : * Caller will check msk can still accept another subflow. The hmac
90 : : * present in the cookie ACK mptcp option space will be checked later.
91 : : */
92 : 20 : bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subflow_req,
93 : : struct sk_buff *skb)
94 : : {
95 : 20 : struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
96 : 20 : u32 i = mptcp_join_entry_hash(skb, net);
97 : 20 : struct mptcp_sock *msk;
98 : 20 : struct join_entry *e;
99 : :
100 : 20 : e = &join_entries[i];
101 : :
102 : 20 : spin_lock_bh(&join_entry_locks[i]);
103 : :
104 [ - + ]: 20 : if (e->valid == 0) {
105 : 0 : spin_unlock_bh(&join_entry_locks[i]);
106 : 0 : return false;
107 : : }
108 : :
109 : 20 : e->valid = 0;
110 : :
111 : 20 : msk = mptcp_token_get_sock(net, e->token);
112 [ - + ]: 20 : if (!msk) {
113 : 0 : spin_unlock_bh(&join_entry_locks[i]);
114 : 0 : return false;
115 : : }
116 : :
117 : 20 : subflow_req->remote_nonce = e->remote_nonce;
118 : 20 : subflow_req->local_nonce = e->local_nonce;
119 : 20 : subflow_req->backup = e->backup;
120 : 20 : subflow_req->remote_id = e->join_id;
121 : 20 : subflow_req->token = e->token;
122 : 20 : subflow_req->msk = msk;
123 : 20 : spin_unlock_bh(&join_entry_locks[i]);
124 : 20 : return true;
125 : : }
126 : :
127 : 4 : void __init mptcp_join_cookie_init(void)
128 : : {
129 : 4 : int i;
130 : :
131 [ + + ]: 4100 : for (i = 0; i < COOKIE_JOIN_SLOTS; i++)
132 : 4096 : spin_lock_init(&join_entry_locks[i]);
133 : 4 : }
|