]>
Commit | Line | Data |
---|---|---|
1b1c7a0e PK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Multipath TCP | |
3 | * | |
4 | * Copyright (c) 2019, Intel Corporation. | |
5 | */ | |
c85adced GT |
6 | #define pr_fmt(fmt) "MPTCP: " fmt |
7 | ||
1b1c7a0e PK |
8 | #include <linux/kernel.h> |
9 | #include <net/tcp.h> | |
10 | #include <net/mptcp.h> | |
11 | #include "protocol.h" | |
12 | ||
1b1c7a0e PK |
13 | /* path manager command handlers */ |
14 | ||
15 | int mptcp_pm_announce_addr(struct mptcp_sock *msk, | |
6a6c05a8 GT |
16 | const struct mptcp_addr_info *addr, |
17 | bool echo) | |
1b1c7a0e | 18 | { |
d91d322a GT |
19 | u8 add_addr = READ_ONCE(msk->pm.add_addr_signal); |
20 | ||
926bdeab PK |
21 | pr_debug("msk=%p, local_id=%d", msk, addr->id); |
22 | ||
23 | msk->pm.local = *addr; | |
d91d322a GT |
24 | add_addr |= BIT(MPTCP_ADD_ADDR_SIGNAL); |
25 | if (echo) | |
26 | add_addr |= BIT(MPTCP_ADD_ADDR_ECHO); | |
27 | WRITE_ONCE(msk->pm.add_addr_signal, add_addr); | |
926bdeab | 28 | return 0; |
1b1c7a0e PK |
29 | } |
30 | ||
31 | int mptcp_pm_remove_addr(struct mptcp_sock *msk, u8 local_id) | |
32 | { | |
b6c08380 GT |
33 | pr_debug("msk=%p, local_id=%d", msk, local_id); |
34 | ||
35 | msk->pm.rm_id = local_id; | |
36 | WRITE_ONCE(msk->pm.rm_addr_signal, true); | |
37 | return 0; | |
1b1c7a0e PK |
38 | } |
39 | ||
0ee4261a | 40 | int mptcp_pm_remove_subflow(struct mptcp_sock *msk, u8 local_id) |
1b1c7a0e | 41 | { |
0ee4261a GT |
42 | pr_debug("msk=%p, local_id=%d", msk, local_id); |
43 | ||
44 | spin_lock_bh(&msk->pm.lock); | |
45 | mptcp_pm_nl_rm_subflow_received(msk, local_id); | |
46 | spin_unlock_bh(&msk->pm.lock); | |
47 | return 0; | |
1b1c7a0e PK |
48 | } |
49 | ||
50 | /* path manager event handlers */ | |
51 | ||
52 | void mptcp_pm_new_connection(struct mptcp_sock *msk, int server_side) | |
53 | { | |
54 | struct mptcp_pm_data *pm = &msk->pm; | |
55 | ||
56 | pr_debug("msk=%p, token=%u side=%d", msk, msk->token, server_side); | |
57 | ||
58 | WRITE_ONCE(pm->server_side, server_side); | |
59 | } | |
60 | ||
61 | bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk) | |
62 | { | |
926bdeab | 63 | struct mptcp_pm_data *pm = &msk->pm; |
f58f065a | 64 | int ret = 0; |
926bdeab PK |
65 | |
66 | pr_debug("msk=%p subflows=%d max=%d allow=%d", msk, pm->subflows, | |
67 | pm->subflows_max, READ_ONCE(pm->accept_subflow)); | |
68 | ||
69 | /* try to avoid acquiring the lock below */ | |
70 | if (!READ_ONCE(pm->accept_subflow)) | |
71 | return false; | |
72 | ||
73 | spin_lock_bh(&pm->lock); | |
f58f065a GT |
74 | if (READ_ONCE(pm->accept_subflow)) { |
75 | ret = pm->subflows < pm->subflows_max; | |
76 | if (ret && ++pm->subflows == pm->subflows_max) | |
77 | WRITE_ONCE(pm->accept_subflow, false); | |
78 | } | |
926bdeab PK |
79 | spin_unlock_bh(&pm->lock); |
80 | ||
81 | return ret; | |
82 | } | |
83 | ||
84 | /* return true if the new status bit is currently cleared, that is, this event | |
85 | * can be server, eventually by an already scheduled work | |
86 | */ | |
87 | static bool mptcp_pm_schedule_work(struct mptcp_sock *msk, | |
88 | enum mptcp_pm_status new_status) | |
89 | { | |
90 | pr_debug("msk=%p status=%x new=%lx", msk, msk->pm.status, | |
91 | BIT(new_status)); | |
92 | if (msk->pm.status & BIT(new_status)) | |
93 | return false; | |
94 | ||
95 | msk->pm.status |= BIT(new_status); | |
ba8f48f7 | 96 | mptcp_schedule_work((struct sock *)msk); |
926bdeab | 97 | return true; |
1b1c7a0e PK |
98 | } |
99 | ||
100 | void mptcp_pm_fully_established(struct mptcp_sock *msk) | |
101 | { | |
926bdeab PK |
102 | struct mptcp_pm_data *pm = &msk->pm; |
103 | ||
1b1c7a0e | 104 | pr_debug("msk=%p", msk); |
926bdeab PK |
105 | |
106 | /* try to avoid acquiring the lock below */ | |
107 | if (!READ_ONCE(pm->work_pending)) | |
108 | return; | |
109 | ||
110 | spin_lock_bh(&pm->lock); | |
111 | ||
112 | if (READ_ONCE(pm->work_pending)) | |
113 | mptcp_pm_schedule_work(msk, MPTCP_PM_ESTABLISHED); | |
114 | ||
115 | spin_unlock_bh(&pm->lock); | |
1b1c7a0e PK |
116 | } |
117 | ||
118 | void mptcp_pm_connection_closed(struct mptcp_sock *msk) | |
119 | { | |
120 | pr_debug("msk=%p", msk); | |
121 | } | |
122 | ||
123 | void mptcp_pm_subflow_established(struct mptcp_sock *msk, | |
124 | struct mptcp_subflow_context *subflow) | |
125 | { | |
926bdeab PK |
126 | struct mptcp_pm_data *pm = &msk->pm; |
127 | ||
1b1c7a0e | 128 | pr_debug("msk=%p", msk); |
926bdeab PK |
129 | |
130 | if (!READ_ONCE(pm->work_pending)) | |
131 | return; | |
132 | ||
133 | spin_lock_bh(&pm->lock); | |
134 | ||
135 | if (READ_ONCE(pm->work_pending)) | |
136 | mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED); | |
137 | ||
138 | spin_unlock_bh(&pm->lock); | |
1b1c7a0e PK |
139 | } |
140 | ||
141 | void mptcp_pm_subflow_closed(struct mptcp_sock *msk, u8 id) | |
142 | { | |
143 | pr_debug("msk=%p", msk); | |
144 | } | |
145 | ||
146 | void mptcp_pm_add_addr_received(struct mptcp_sock *msk, | |
147 | const struct mptcp_addr_info *addr) | |
148 | { | |
926bdeab PK |
149 | struct mptcp_pm_data *pm = &msk->pm; |
150 | ||
151 | pr_debug("msk=%p remote_id=%d accept=%d", msk, addr->id, | |
152 | READ_ONCE(pm->accept_addr)); | |
153 | ||
926bdeab PK |
154 | spin_lock_bh(&pm->lock); |
155 | ||
6a6c05a8 GT |
156 | if (!READ_ONCE(pm->accept_addr)) |
157 | mptcp_pm_announce_addr(msk, addr, true); | |
158 | else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) | |
926bdeab PK |
159 | pm->remote = *addr; |
160 | ||
161 | spin_unlock_bh(&pm->lock); | |
1b1c7a0e PK |
162 | } |
163 | ||
d0876b22 GT |
164 | void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id) |
165 | { | |
166 | struct mptcp_pm_data *pm = &msk->pm; | |
167 | ||
168 | pr_debug("msk=%p remote_id=%d", msk, rm_id); | |
169 | ||
170 | spin_lock_bh(&pm->lock); | |
171 | mptcp_pm_schedule_work(msk, MPTCP_PM_RM_ADDR_RECEIVED); | |
172 | pm->rm_id = rm_id; | |
173 | spin_unlock_bh(&pm->lock); | |
174 | } | |
175 | ||
1b1c7a0e PK |
176 | /* path manager helpers */ |
177 | ||
f643b803 | 178 | bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining, |
6a6c05a8 | 179 | struct mptcp_addr_info *saddr, bool *echo) |
1b1c7a0e | 180 | { |
926bdeab PK |
181 | int ret = false; |
182 | ||
183 | spin_lock_bh(&msk->pm.lock); | |
184 | ||
185 | /* double check after the lock is acquired */ | |
f643b803 | 186 | if (!mptcp_pm_should_add_signal(msk)) |
926bdeab PK |
187 | goto out_unlock; |
188 | ||
d91d322a | 189 | *echo = mptcp_pm_should_add_signal_echo(msk); |
456afe01 MB |
190 | |
191 | if (remaining < mptcp_add_addr_len(msk->pm.local.family, *echo)) | |
926bdeab PK |
192 | goto out_unlock; |
193 | ||
194 | *saddr = msk->pm.local; | |
d91d322a | 195 | WRITE_ONCE(msk->pm.add_addr_signal, 0); |
926bdeab PK |
196 | ret = true; |
197 | ||
198 | out_unlock: | |
199 | spin_unlock_bh(&msk->pm.lock); | |
200 | return ret; | |
1b1c7a0e PK |
201 | } |
202 | ||
5cb104ae GT |
203 | bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, |
204 | u8 *rm_id) | |
205 | { | |
206 | int ret = false; | |
207 | ||
208 | spin_lock_bh(&msk->pm.lock); | |
209 | ||
210 | /* double check after the lock is acquired */ | |
211 | if (!mptcp_pm_should_rm_signal(msk)) | |
212 | goto out_unlock; | |
213 | ||
214 | if (remaining < TCPOLEN_MPTCP_RM_ADDR_BASE) | |
215 | goto out_unlock; | |
216 | ||
217 | *rm_id = msk->pm.rm_id; | |
218 | WRITE_ONCE(msk->pm.rm_addr_signal, false); | |
219 | ret = true; | |
220 | ||
221 | out_unlock: | |
222 | spin_unlock_bh(&msk->pm.lock); | |
223 | return ret; | |
224 | } | |
225 | ||
1b1c7a0e PK |
226 | int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) |
227 | { | |
01cacb00 | 228 | return mptcp_pm_nl_get_local_id(msk, skc); |
1b1c7a0e PK |
229 | } |
230 | ||
1b1c7a0e PK |
231 | void mptcp_pm_data_init(struct mptcp_sock *msk) |
232 | { | |
233 | msk->pm.add_addr_signaled = 0; | |
234 | msk->pm.add_addr_accepted = 0; | |
235 | msk->pm.local_addr_used = 0; | |
236 | msk->pm.subflows = 0; | |
5cb104ae | 237 | msk->pm.rm_id = 0; |
1b1c7a0e | 238 | WRITE_ONCE(msk->pm.work_pending, false); |
d91d322a | 239 | WRITE_ONCE(msk->pm.add_addr_signal, 0); |
5cb104ae | 240 | WRITE_ONCE(msk->pm.rm_addr_signal, false); |
1b1c7a0e PK |
241 | WRITE_ONCE(msk->pm.accept_addr, false); |
242 | WRITE_ONCE(msk->pm.accept_subflow, false); | |
243 | msk->pm.status = 0; | |
244 | ||
245 | spin_lock_init(&msk->pm.lock); | |
b6c08380 | 246 | INIT_LIST_HEAD(&msk->pm.anno_list); |
01cacb00 PA |
247 | |
248 | mptcp_pm_nl_data_init(msk); | |
1b1c7a0e PK |
249 | } |
250 | ||
d39dceca | 251 | void __init mptcp_pm_init(void) |
1b1c7a0e | 252 | { |
01cacb00 | 253 | mptcp_pm_nl_init(); |
1b1c7a0e | 254 | } |