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:1,
30 : : request_bkup:1;
31 : : u8 valid;
32 : : };
33 : :
34 : : #define COOKIE_JOIN_SLOTS 1024
35 : :
36 : : static struct join_entry join_entries[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp;
37 : : static spinlock_t join_entry_locks[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp;
38 : :
39 : 40 : static u32 mptcp_join_entry_hash(struct sk_buff *skb, struct net *net)
40 : : {
41 : 40 : static u32 mptcp_join_hash_secret __read_mostly;
42 : 40 : struct tcphdr *th = tcp_hdr(skb);
43 : 40 : u32 seq, i;
44 : :
45 [ + + + + ]: 40 : net_get_random_once(&mptcp_join_hash_secret,
46 : : sizeof(mptcp_join_hash_secret));
47 : :
48 [ + + ]: 40 : if (th->syn)
49 : 20 : seq = TCP_SKB_CB(skb)->seq;
50 : : else
51 : 20 : seq = TCP_SKB_CB(skb)->seq - 1;
52 : :
53 : 40 : i = jhash_3words(seq, net_hash_mix(net),
54 : 40 : (__force __u32)th->source << 16 | (__force __u32)th->dest,
55 : : mptcp_join_hash_secret);
56 : :
57 : 40 : return i % ARRAY_SIZE(join_entries);
58 : : }
59 : :
60 : 0 : static void mptcp_join_store_state(struct join_entry *entry,
61 : : const struct mptcp_subflow_request_sock *subflow_req)
62 : : {
63 : 20 : entry->token = subflow_req->token;
64 : 20 : entry->remote_nonce = subflow_req->remote_nonce;
65 : 20 : entry->local_nonce = subflow_req->local_nonce;
66 : 20 : entry->backup = subflow_req->backup;
67 : 20 : entry->request_bkup = subflow_req->request_bkup;
68 : 20 : entry->join_id = subflow_req->remote_id;
69 : 20 : entry->local_id = subflow_req->local_id;
70 : 20 : entry->valid = 1;
71 : : }
72 : :
73 : 20 : void subflow_init_req_cookie_join_save(const struct mptcp_subflow_request_sock *subflow_req,
74 : : struct sk_buff *skb)
75 : : {
76 : 20 : struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
77 : 20 : u32 i = mptcp_join_entry_hash(skb, net);
78 : :
79 : : /* No use in waiting if other cpu is already using this slot --
80 : : * would overwrite the data that got stored.
81 : : */
82 : 20 : spin_lock_bh(&join_entry_locks[i]);
83 : 20 : mptcp_join_store_state(&join_entries[i], subflow_req);
84 : 20 : spin_unlock_bh(&join_entry_locks[i]);
85 : 20 : }
86 : :
87 : : /* Called for a cookie-ack with MP_JOIN option present.
88 : : * Look up the saved state based on skb hash & check token matches msk
89 : : * in same netns.
90 : : *
91 : : * Caller will check msk can still accept another subflow. The hmac
92 : : * present in the cookie ACK mptcp option space will be checked later.
93 : : */
94 : 20 : bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subflow_req,
95 : : struct sk_buff *skb)
96 : : {
97 : 20 : struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
98 : 20 : u32 i = mptcp_join_entry_hash(skb, net);
99 : 20 : struct mptcp_sock *msk;
100 : 20 : struct join_entry *e;
101 : :
102 : 20 : e = &join_entries[i];
103 : :
104 : 20 : spin_lock_bh(&join_entry_locks[i]);
105 : :
106 [ - + ]: 20 : if (e->valid == 0) {
107 : 0 : spin_unlock_bh(&join_entry_locks[i]);
108 : 0 : return false;
109 : : }
110 : :
111 : 20 : e->valid = 0;
112 : :
113 : 20 : msk = mptcp_token_get_sock(net, e->token);
114 [ - + ]: 20 : if (!msk) {
115 : 0 : spin_unlock_bh(&join_entry_locks[i]);
116 : 0 : return false;
117 : : }
118 : :
119 : 20 : subflow_req->remote_nonce = e->remote_nonce;
120 : 20 : subflow_req->local_nonce = e->local_nonce;
121 : 20 : subflow_req->backup = e->backup;
122 : 20 : subflow_req->request_bkup = e->request_bkup;
123 : 20 : subflow_req->remote_id = e->join_id;
124 : 20 : subflow_req->local_id = e->local_id;
125 : 20 : subflow_req->token = e->token;
126 : 20 : subflow_req->msk = msk;
127 : 20 : spin_unlock_bh(&join_entry_locks[i]);
128 : 20 : return true;
129 : : }
130 : :
131 : 6 : void __init mptcp_join_cookie_init(void)
132 : : {
133 : 6 : int i;
134 : :
135 [ + + ]: 6150 : for (i = 0; i < COOKIE_JOIN_SLOTS; i++)
136 : 6144 : spin_lock_init(&join_entry_locks[i]);
137 : 6 : }
|