1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Multipath TCP |
3 | * |
4 | * Copyright (c) 2022, Intel Corporation. |
5 | */ |
6 | |
7 | #include "protocol.h" |
8 | #include "mib.h" |
9 | |
10 | void mptcp_free_local_addr_list(struct mptcp_sock *msk) |
11 | { |
12 | struct mptcp_pm_addr_entry *entry, *tmp; |
13 | struct sock *sk = (struct sock *)msk; |
14 | LIST_HEAD(free_list); |
15 | |
16 | if (!mptcp_pm_is_userspace(msk)) |
17 | return; |
18 | |
19 | spin_lock_bh(lock: &msk->pm.lock); |
20 | list_splice_init(list: &msk->pm.userspace_pm_local_addr_list, head: &free_list); |
21 | spin_unlock_bh(lock: &msk->pm.lock); |
22 | |
23 | list_for_each_entry_safe(entry, tmp, &free_list, list) { |
24 | sock_kfree_s(sk, mem: entry, size: sizeof(*entry)); |
25 | } |
26 | } |
27 | |
28 | static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk, |
29 | struct mptcp_pm_addr_entry *entry) |
30 | { |
31 | DECLARE_BITMAP(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); |
32 | struct mptcp_pm_addr_entry *match = NULL; |
33 | struct sock *sk = (struct sock *)msk; |
34 | struct mptcp_pm_addr_entry *e; |
35 | bool addr_match = false; |
36 | bool id_match = false; |
37 | int ret = -EINVAL; |
38 | |
39 | bitmap_zero(dst: id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); |
40 | |
41 | spin_lock_bh(lock: &msk->pm.lock); |
42 | list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) { |
43 | addr_match = mptcp_addresses_equal(a: &e->addr, b: &entry->addr, use_port: true); |
44 | if (addr_match && entry->addr.id == 0) |
45 | entry->addr.id = e->addr.id; |
46 | id_match = (e->addr.id == entry->addr.id); |
47 | if (addr_match && id_match) { |
48 | match = e; |
49 | break; |
50 | } else if (addr_match || id_match) { |
51 | break; |
52 | } |
53 | __set_bit(e->addr.id, id_bitmap); |
54 | } |
55 | |
56 | if (!match && !addr_match && !id_match) { |
57 | /* Memory for the entry is allocated from the |
58 | * sock option buffer. |
59 | */ |
60 | e = sock_kmalloc(sk, size: sizeof(*e), GFP_ATOMIC); |
61 | if (!e) { |
62 | ret = -ENOMEM; |
63 | goto append_err; |
64 | } |
65 | |
66 | *e = *entry; |
67 | if (!e->addr.id) |
68 | e->addr.id = find_next_zero_bit(addr: id_bitmap, |
69 | MPTCP_PM_MAX_ADDR_ID + 1, |
70 | offset: 1); |
71 | list_add_tail_rcu(new: &e->list, head: &msk->pm.userspace_pm_local_addr_list); |
72 | msk->pm.local_addr_used++; |
73 | ret = e->addr.id; |
74 | } else if (match) { |
75 | ret = entry->addr.id; |
76 | } |
77 | |
78 | append_err: |
79 | spin_unlock_bh(lock: &msk->pm.lock); |
80 | return ret; |
81 | } |
82 | |
83 | /* If the subflow is closed from the other peer (not via a |
84 | * subflow destroy command then), we want to keep the entry |
85 | * not to assign the same ID to another address and to be |
86 | * able to send RM_ADDR after the removal of the subflow. |
87 | */ |
88 | static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk, |
89 | struct mptcp_pm_addr_entry *addr) |
90 | { |
91 | struct mptcp_pm_addr_entry *entry, *tmp; |
92 | |
93 | list_for_each_entry_safe(entry, tmp, &msk->pm.userspace_pm_local_addr_list, list) { |
94 | if (mptcp_addresses_equal(a: &entry->addr, b: &addr->addr, use_port: false)) { |
95 | /* TODO: a refcount is needed because the entry can |
96 | * be used multiple times (e.g. fullmesh mode). |
97 | */ |
98 | list_del_rcu(entry: &entry->list); |
99 | kfree(objp: entry); |
100 | msk->pm.local_addr_used--; |
101 | return 0; |
102 | } |
103 | } |
104 | |
105 | return -EINVAL; |
106 | } |
107 | |
108 | int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, |
109 | unsigned int id, |
110 | u8 *flags, int *ifindex) |
111 | { |
112 | struct mptcp_pm_addr_entry *entry, *match = NULL; |
113 | |
114 | spin_lock_bh(lock: &msk->pm.lock); |
115 | list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) { |
116 | if (id == entry->addr.id) { |
117 | match = entry; |
118 | break; |
119 | } |
120 | } |
121 | spin_unlock_bh(lock: &msk->pm.lock); |
122 | if (match) { |
123 | *flags = match->flags; |
124 | *ifindex = match->ifindex; |
125 | } |
126 | |
127 | return 0; |
128 | } |
129 | |
130 | int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, |
131 | struct mptcp_addr_info *skc) |
132 | { |
133 | struct mptcp_pm_addr_entry new_entry; |
134 | __be16 msk_sport = ((struct inet_sock *) |
135 | inet_sk((struct sock *)msk))->inet_sport; |
136 | |
137 | memset(&new_entry, 0, sizeof(struct mptcp_pm_addr_entry)); |
138 | new_entry.addr = *skc; |
139 | new_entry.addr.id = 0; |
140 | new_entry.flags = MPTCP_PM_ADDR_FLAG_IMPLICIT; |
141 | |
142 | if (new_entry.addr.port == msk_sport) |
143 | new_entry.addr.port = 0; |
144 | |
145 | return mptcp_userspace_pm_append_new_local_addr(msk, entry: &new_entry); |
146 | } |
147 | |
148 | int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info) |
149 | { |
150 | struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN]; |
151 | struct nlattr *addr = info->attrs[MPTCP_PM_ATTR_ADDR]; |
152 | struct mptcp_pm_addr_entry addr_val; |
153 | struct mptcp_sock *msk; |
154 | int err = -EINVAL; |
155 | struct sock *sk; |
156 | u32 token_val; |
157 | |
158 | if (!addr || !token) { |
159 | GENL_SET_ERR_MSG(info, "missing required inputs" ); |
160 | return err; |
161 | } |
162 | |
163 | token_val = nla_get_u32(nla: token); |
164 | |
165 | msk = mptcp_token_get_sock(net: sock_net(sk: skb->sk), token: token_val); |
166 | if (!msk) { |
167 | NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token" ); |
168 | return err; |
169 | } |
170 | |
171 | sk = (struct sock *)msk; |
172 | |
173 | if (!mptcp_pm_is_userspace(msk)) { |
174 | GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected" ); |
175 | goto announce_err; |
176 | } |
177 | |
178 | err = mptcp_pm_parse_entry(attr: addr, info, require_family: true, entry: &addr_val); |
179 | if (err < 0) { |
180 | GENL_SET_ERR_MSG(info, "error parsing local address" ); |
181 | goto announce_err; |
182 | } |
183 | |
184 | if (addr_val.addr.id == 0 || !(addr_val.flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) { |
185 | GENL_SET_ERR_MSG(info, "invalid addr id or flags" ); |
186 | err = -EINVAL; |
187 | goto announce_err; |
188 | } |
189 | |
190 | err = mptcp_userspace_pm_append_new_local_addr(msk, entry: &addr_val); |
191 | if (err < 0) { |
192 | GENL_SET_ERR_MSG(info, "did not match address and id" ); |
193 | goto announce_err; |
194 | } |
195 | |
196 | lock_sock(sk); |
197 | spin_lock_bh(lock: &msk->pm.lock); |
198 | |
199 | if (mptcp_pm_alloc_anno_list(msk, addr: &addr_val.addr)) { |
200 | msk->pm.add_addr_signaled++; |
201 | mptcp_pm_announce_addr(msk, addr: &addr_val.addr, echo: false); |
202 | mptcp_pm_nl_addr_send_ack(msk); |
203 | } |
204 | |
205 | spin_unlock_bh(lock: &msk->pm.lock); |
206 | release_sock(sk); |
207 | |
208 | err = 0; |
209 | announce_err: |
210 | sock_put(sk); |
211 | return err; |
212 | } |
213 | |
214 | static int mptcp_userspace_pm_remove_id_zero_address(struct mptcp_sock *msk, |
215 | struct genl_info *info) |
216 | { |
217 | struct mptcp_rm_list list = { .nr = 0 }; |
218 | struct mptcp_subflow_context *subflow; |
219 | struct sock *sk = (struct sock *)msk; |
220 | bool has_id_0 = false; |
221 | int err = -EINVAL; |
222 | |
223 | lock_sock(sk); |
224 | mptcp_for_each_subflow(msk, subflow) { |
225 | if (subflow->local_id == 0) { |
226 | has_id_0 = true; |
227 | break; |
228 | } |
229 | } |
230 | if (!has_id_0) { |
231 | GENL_SET_ERR_MSG(info, "address with id 0 not found" ); |
232 | goto remove_err; |
233 | } |
234 | |
235 | list.ids[list.nr++] = 0; |
236 | |
237 | spin_lock_bh(lock: &msk->pm.lock); |
238 | mptcp_pm_remove_addr(msk, rm_list: &list); |
239 | spin_unlock_bh(lock: &msk->pm.lock); |
240 | |
241 | err = 0; |
242 | |
243 | remove_err: |
244 | release_sock(sk); |
245 | return err; |
246 | } |
247 | |
248 | int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) |
249 | { |
250 | struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN]; |
251 | struct nlattr *id = info->attrs[MPTCP_PM_ATTR_LOC_ID]; |
252 | struct mptcp_pm_addr_entry *match = NULL; |
253 | struct mptcp_pm_addr_entry *entry; |
254 | struct mptcp_sock *msk; |
255 | LIST_HEAD(free_list); |
256 | int err = -EINVAL; |
257 | struct sock *sk; |
258 | u32 token_val; |
259 | u8 id_val; |
260 | |
261 | if (!id || !token) { |
262 | GENL_SET_ERR_MSG(info, "missing required inputs" ); |
263 | return err; |
264 | } |
265 | |
266 | id_val = nla_get_u8(nla: id); |
267 | token_val = nla_get_u32(nla: token); |
268 | |
269 | msk = mptcp_token_get_sock(net: sock_net(sk: skb->sk), token: token_val); |
270 | if (!msk) { |
271 | NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token" ); |
272 | return err; |
273 | } |
274 | |
275 | sk = (struct sock *)msk; |
276 | |
277 | if (!mptcp_pm_is_userspace(msk)) { |
278 | GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected" ); |
279 | goto remove_err; |
280 | } |
281 | |
282 | if (id_val == 0) { |
283 | err = mptcp_userspace_pm_remove_id_zero_address(msk, info); |
284 | goto remove_err; |
285 | } |
286 | |
287 | lock_sock(sk); |
288 | |
289 | list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) { |
290 | if (entry->addr.id == id_val) { |
291 | match = entry; |
292 | break; |
293 | } |
294 | } |
295 | |
296 | if (!match) { |
297 | GENL_SET_ERR_MSG(info, "address with specified id not found" ); |
298 | release_sock(sk); |
299 | goto remove_err; |
300 | } |
301 | |
302 | list_move(list: &match->list, head: &free_list); |
303 | |
304 | mptcp_pm_remove_addrs(msk, rm_list: &free_list); |
305 | |
306 | release_sock(sk); |
307 | |
308 | list_for_each_entry_safe(match, entry, &free_list, list) { |
309 | sock_kfree_s(sk, mem: match, size: sizeof(*match)); |
310 | } |
311 | |
312 | err = 0; |
313 | remove_err: |
314 | sock_put(sk); |
315 | return err; |
316 | } |
317 | |
318 | int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) |
319 | { |
320 | struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE]; |
321 | struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN]; |
322 | struct nlattr *laddr = info->attrs[MPTCP_PM_ATTR_ADDR]; |
323 | struct mptcp_pm_addr_entry local = { 0 }; |
324 | struct mptcp_addr_info addr_r; |
325 | struct mptcp_addr_info addr_l; |
326 | struct mptcp_sock *msk; |
327 | int err = -EINVAL; |
328 | struct sock *sk; |
329 | u32 token_val; |
330 | |
331 | if (!laddr || !raddr || !token) { |
332 | GENL_SET_ERR_MSG(info, "missing required inputs" ); |
333 | return err; |
334 | } |
335 | |
336 | token_val = nla_get_u32(nla: token); |
337 | |
338 | msk = mptcp_token_get_sock(net: genl_info_net(info), token: token_val); |
339 | if (!msk) { |
340 | NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token" ); |
341 | return err; |
342 | } |
343 | |
344 | sk = (struct sock *)msk; |
345 | |
346 | if (!mptcp_pm_is_userspace(msk)) { |
347 | GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected" ); |
348 | goto create_err; |
349 | } |
350 | |
351 | err = mptcp_pm_parse_addr(attr: laddr, info, addr: &addr_l); |
352 | if (err < 0) { |
353 | NL_SET_ERR_MSG_ATTR(info->extack, laddr, "error parsing local addr" ); |
354 | goto create_err; |
355 | } |
356 | |
357 | err = mptcp_pm_parse_addr(attr: raddr, info, addr: &addr_r); |
358 | if (err < 0) { |
359 | NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr" ); |
360 | goto create_err; |
361 | } |
362 | |
363 | if (!mptcp_pm_addr_families_match(sk, loc: &addr_l, rem: &addr_r)) { |
364 | GENL_SET_ERR_MSG(info, "families mismatch" ); |
365 | err = -EINVAL; |
366 | goto create_err; |
367 | } |
368 | |
369 | local.addr = addr_l; |
370 | err = mptcp_userspace_pm_append_new_local_addr(msk, entry: &local); |
371 | if (err < 0) { |
372 | GENL_SET_ERR_MSG(info, "did not match address and id" ); |
373 | goto create_err; |
374 | } |
375 | |
376 | lock_sock(sk); |
377 | |
378 | err = __mptcp_subflow_connect(sk, loc: &addr_l, remote: &addr_r); |
379 | |
380 | release_sock(sk); |
381 | |
382 | spin_lock_bh(lock: &msk->pm.lock); |
383 | if (err) |
384 | mptcp_userspace_pm_delete_local_addr(msk, addr: &local); |
385 | else |
386 | msk->pm.subflows++; |
387 | spin_unlock_bh(lock: &msk->pm.lock); |
388 | |
389 | create_err: |
390 | sock_put(sk); |
391 | return err; |
392 | } |
393 | |
394 | static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk, |
395 | const struct mptcp_addr_info *local, |
396 | const struct mptcp_addr_info *remote) |
397 | { |
398 | struct mptcp_subflow_context *subflow; |
399 | |
400 | if (local->family != remote->family) |
401 | return NULL; |
402 | |
403 | mptcp_for_each_subflow(msk, subflow) { |
404 | const struct inet_sock *issk; |
405 | struct sock *ssk; |
406 | |
407 | ssk = mptcp_subflow_tcp_sock(subflow); |
408 | |
409 | if (local->family != ssk->sk_family) |
410 | continue; |
411 | |
412 | issk = inet_sk(ssk); |
413 | |
414 | switch (ssk->sk_family) { |
415 | case AF_INET: |
416 | if (issk->inet_saddr != local->addr.s_addr || |
417 | issk->inet_daddr != remote->addr.s_addr) |
418 | continue; |
419 | break; |
420 | #if IS_ENABLED(CONFIG_MPTCP_IPV6) |
421 | case AF_INET6: { |
422 | const struct ipv6_pinfo *pinfo = inet6_sk(sk: ssk); |
423 | |
424 | if (!ipv6_addr_equal(a1: &local->addr6, a2: &pinfo->saddr) || |
425 | !ipv6_addr_equal(a1: &remote->addr6, a2: &ssk->sk_v6_daddr)) |
426 | continue; |
427 | break; |
428 | } |
429 | #endif |
430 | default: |
431 | continue; |
432 | } |
433 | |
434 | if (issk->inet_sport == local->port && |
435 | issk->inet_dport == remote->port) |
436 | return ssk; |
437 | } |
438 | |
439 | return NULL; |
440 | } |
441 | |
442 | int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info) |
443 | { |
444 | struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE]; |
445 | struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN]; |
446 | struct nlattr *laddr = info->attrs[MPTCP_PM_ATTR_ADDR]; |
447 | struct mptcp_addr_info addr_l; |
448 | struct mptcp_addr_info addr_r; |
449 | struct mptcp_sock *msk; |
450 | struct sock *sk, *ssk; |
451 | int err = -EINVAL; |
452 | u32 token_val; |
453 | |
454 | if (!laddr || !raddr || !token) { |
455 | GENL_SET_ERR_MSG(info, "missing required inputs" ); |
456 | return err; |
457 | } |
458 | |
459 | token_val = nla_get_u32(nla: token); |
460 | |
461 | msk = mptcp_token_get_sock(net: genl_info_net(info), token: token_val); |
462 | if (!msk) { |
463 | NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token" ); |
464 | return err; |
465 | } |
466 | |
467 | sk = (struct sock *)msk; |
468 | |
469 | if (!mptcp_pm_is_userspace(msk)) { |
470 | GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected" ); |
471 | goto destroy_err; |
472 | } |
473 | |
474 | err = mptcp_pm_parse_addr(attr: laddr, info, addr: &addr_l); |
475 | if (err < 0) { |
476 | NL_SET_ERR_MSG_ATTR(info->extack, laddr, "error parsing local addr" ); |
477 | goto destroy_err; |
478 | } |
479 | |
480 | err = mptcp_pm_parse_addr(attr: raddr, info, addr: &addr_r); |
481 | if (err < 0) { |
482 | NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr" ); |
483 | goto destroy_err; |
484 | } |
485 | |
486 | if (addr_l.family != addr_r.family) { |
487 | GENL_SET_ERR_MSG(info, "address families do not match" ); |
488 | err = -EINVAL; |
489 | goto destroy_err; |
490 | } |
491 | |
492 | if (!addr_l.port || !addr_r.port) { |
493 | GENL_SET_ERR_MSG(info, "missing local or remote port" ); |
494 | err = -EINVAL; |
495 | goto destroy_err; |
496 | } |
497 | |
498 | lock_sock(sk); |
499 | ssk = mptcp_nl_find_ssk(msk, local: &addr_l, remote: &addr_r); |
500 | if (ssk) { |
501 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk: ssk); |
502 | struct mptcp_pm_addr_entry entry = { .addr = addr_l }; |
503 | |
504 | spin_lock_bh(lock: &msk->pm.lock); |
505 | mptcp_userspace_pm_delete_local_addr(msk, addr: &entry); |
506 | spin_unlock_bh(lock: &msk->pm.lock); |
507 | mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN); |
508 | mptcp_close_ssk(sk, ssk, subflow); |
509 | MPTCP_INC_STATS(net: sock_net(sk), field: MPTCP_MIB_RMSUBFLOW); |
510 | err = 0; |
511 | } else { |
512 | err = -ESRCH; |
513 | } |
514 | release_sock(sk); |
515 | |
516 | destroy_err: |
517 | sock_put(sk); |
518 | return err; |
519 | } |
520 | |
521 | int mptcp_userspace_pm_set_flags(struct net *net, struct nlattr *token, |
522 | struct mptcp_pm_addr_entry *loc, |
523 | struct mptcp_pm_addr_entry *rem, u8 bkup) |
524 | { |
525 | struct mptcp_sock *msk; |
526 | int ret = -EINVAL; |
527 | struct sock *sk; |
528 | u32 token_val; |
529 | |
530 | token_val = nla_get_u32(nla: token); |
531 | |
532 | msk = mptcp_token_get_sock(net, token: token_val); |
533 | if (!msk) |
534 | return ret; |
535 | |
536 | sk = (struct sock *)msk; |
537 | |
538 | if (!mptcp_pm_is_userspace(msk)) |
539 | goto set_flags_err; |
540 | |
541 | if (loc->addr.family == AF_UNSPEC || |
542 | rem->addr.family == AF_UNSPEC) |
543 | goto set_flags_err; |
544 | |
545 | lock_sock(sk); |
546 | ret = mptcp_pm_nl_mp_prio_send_ack(msk, addr: &loc->addr, rem: &rem->addr, bkup); |
547 | release_sock(sk); |
548 | |
549 | set_flags_err: |
550 | sock_put(sk); |
551 | return ret; |
552 | } |
553 | |