Commit | Line | Data |
---|---|---|
4638de5a KM |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Multipath TCP | |
3 | * | |
4 | * Copyright (c) 2022, Intel Corporation. | |
5 | */ | |
6 | ||
7 | #include "protocol.h" | |
d2d21f17 | 8 | #include "mib.h" |
4638de5a KM |
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(&msk->pm.lock); | |
20 | list_splice_init(&msk->pm.userspace_pm_local_addr_list, &free_list); | |
21 | spin_unlock_bh(&msk->pm.lock); | |
22 | ||
23 | list_for_each_entry_safe(entry, tmp, &free_list, list) { | |
24 | sock_kfree_s(sk, entry, sizeof(*entry)); | |
25 | } | |
26 | } | |
27 | ||
aa5887dc GT |
28 | static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk, |
29 | struct mptcp_pm_addr_entry *entry) | |
4638de5a KM |
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(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); | |
40 | ||
41 | spin_lock_bh(&msk->pm.lock); | |
42 | list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) { | |
43 | addr_match = mptcp_addresses_equal(&e->addr, &entry->addr, 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, sizeof(*e), GFP_ATOMIC); | |
61 | if (!e) { | |
40c71f76 MB |
62 | ret = -ENOMEM; |
63 | goto append_err; | |
4638de5a KM |
64 | } |
65 | ||
66 | *e = *entry; | |
67 | if (!e->addr.id) | |
68 | e->addr.id = find_next_zero_bit(id_bitmap, | |
69 | MPTCP_PM_MAX_ADDR_ID + 1, | |
70 | 1); | |
71 | list_add_tail_rcu(&e->list, &msk->pm.userspace_pm_local_addr_list); | |
77e4b94a | 72 | msk->pm.local_addr_used++; |
4638de5a KM |
73 | ret = e->addr.id; |
74 | } else if (match) { | |
75 | ret = entry->addr.id; | |
76 | } | |
77 | ||
40c71f76 | 78 | append_err: |
4638de5a KM |
79 | spin_unlock_bh(&msk->pm.lock); |
80 | return ret; | |
81 | } | |
8b201370 | 82 | |
24430f8b GT |
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(&entry->addr, &addr->addr, 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->list); | |
99 | kfree(entry); | |
77e4b94a | 100 | msk->pm.local_addr_used--; |
24430f8b GT |
101 | return 0; |
102 | } | |
103 | } | |
104 | ||
105 | return -EINVAL; | |
106 | } | |
107 | ||
8b201370 KM |
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 | ||
8b201370 KM |
114 | spin_lock_bh(&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(&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, &new_entry); | |
146 | } | |
9ab4807c | 147 | |
1e07938e | 148 | int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info) |
9ab4807c KM |
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; | |
14cb0e0b | 155 | struct sock *sk; |
9ab4807c KM |
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(token); | |
164 | ||
165 | msk = mptcp_token_get_sock(sock_net(skb->sk), token_val); | |
166 | if (!msk) { | |
167 | NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token"); | |
168 | return err; | |
169 | } | |
170 | ||
14cb0e0b GT |
171 | sk = (struct sock *)msk; |
172 | ||
9ab4807c KM |
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(addr, info, true, &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"); | |
e0fe1123 | 186 | err = -EINVAL; |
9ab4807c KM |
187 | goto announce_err; |
188 | } | |
189 | ||
190 | err = mptcp_userspace_pm_append_new_local_addr(msk, &addr_val); | |
191 | if (err < 0) { | |
192 | GENL_SET_ERR_MSG(info, "did not match address and id"); | |
193 | goto announce_err; | |
194 | } | |
195 | ||
14cb0e0b | 196 | lock_sock(sk); |
9ab4807c KM |
197 | spin_lock_bh(&msk->pm.lock); |
198 | ||
528cb5f2 | 199 | if (mptcp_pm_alloc_anno_list(msk, &addr_val.addr)) { |
77e4b94a | 200 | msk->pm.add_addr_signaled++; |
9ab4807c KM |
201 | mptcp_pm_announce_addr(msk, &addr_val.addr, false); |
202 | mptcp_pm_nl_addr_send_ack(msk); | |
203 | } | |
204 | ||
205 | spin_unlock_bh(&msk->pm.lock); | |
14cb0e0b | 206 | release_sock(sk); |
9ab4807c KM |
207 | |
208 | err = 0; | |
209 | announce_err: | |
14cb0e0b | 210 | sock_put(sk); |
9ab4807c KM |
211 | return err; |
212 | } | |
d9a4594e | 213 | |
84c531f5 GT |
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(&msk->pm.lock); | |
238 | mptcp_pm_remove_addr(msk, &list); | |
239 | spin_unlock_bh(&msk->pm.lock); | |
240 | ||
241 | err = 0; | |
242 | ||
243 | remove_err: | |
244 | release_sock(sk); | |
245 | return err; | |
246 | } | |
247 | ||
1e07938e | 248 | int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info) |
d9a4594e KM |
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; | |
14cb0e0b | 257 | struct sock *sk; |
d9a4594e KM |
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(id); | |
267 | token_val = nla_get_u32(token); | |
268 | ||
269 | msk = mptcp_token_get_sock(sock_net(skb->sk), token_val); | |
270 | if (!msk) { | |
271 | NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token"); | |
272 | return err; | |
273 | } | |
274 | ||
14cb0e0b GT |
275 | sk = (struct sock *)msk; |
276 | ||
d9a4594e KM |
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 | ||
84c531f5 GT |
282 | if (id_val == 0) { |
283 | err = mptcp_userspace_pm_remove_id_zero_address(msk, info); | |
284 | goto remove_err; | |
285 | } | |
286 | ||
14cb0e0b | 287 | lock_sock(sk); |
d9a4594e KM |
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"); | |
14cb0e0b | 298 | release_sock(sk); |
d9a4594e KM |
299 | goto remove_err; |
300 | } | |
301 | ||
302 | list_move(&match->list, &free_list); | |
303 | ||
8b1c94da | 304 | mptcp_pm_remove_addrs(msk, &free_list); |
d9a4594e | 305 | |
14cb0e0b | 306 | release_sock(sk); |
d9a4594e KM |
307 | |
308 | list_for_each_entry_safe(match, entry, &free_list, list) { | |
14cb0e0b | 309 | sock_kfree_s(sk, match, sizeof(*match)); |
d9a4594e KM |
310 | } |
311 | ||
312 | err = 0; | |
313 | remove_err: | |
14cb0e0b | 314 | sock_put(sk); |
d9a4594e KM |
315 | return err; |
316 | } | |
702c2f64 | 317 | |
1e07938e | 318 | int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info) |
702c2f64 FW |
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]; | |
24430f8b | 323 | struct mptcp_pm_addr_entry local = { 0 }; |
702c2f64 FW |
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(token); | |
337 | ||
338 | msk = mptcp_token_get_sock(genl_info_net(info), token_val); | |
339 | if (!msk) { | |
340 | NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token"); | |
341 | return err; | |
342 | } | |
343 | ||
a6c85fc6 GT |
344 | sk = (struct sock *)msk; |
345 | ||
702c2f64 FW |
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(laddr, info, &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 | ||
702c2f64 FW |
357 | err = mptcp_pm_parse_addr(raddr, info, &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 | ||
fb00ee4f MB |
363 | if (!mptcp_pm_addr_families_match(sk, &addr_l, &addr_r)) { |
364 | GENL_SET_ERR_MSG(info, "families mismatch"); | |
365 | err = -EINVAL; | |
366 | goto create_err; | |
367 | } | |
368 | ||
24430f8b GT |
369 | local.addr = addr_l; |
370 | err = mptcp_userspace_pm_append_new_local_addr(msk, &local); | |
371 | if (err < 0) { | |
372 | GENL_SET_ERR_MSG(info, "did not match address and id"); | |
373 | goto create_err; | |
374 | } | |
375 | ||
702c2f64 FW |
376 | lock_sock(sk); |
377 | ||
378 | err = __mptcp_subflow_connect(sk, &addr_l, &addr_r); | |
379 | ||
380 | release_sock(sk); | |
381 | ||
24430f8b GT |
382 | spin_lock_bh(&msk->pm.lock); |
383 | if (err) | |
384 | mptcp_userspace_pm_delete_local_addr(msk, &local); | |
77e4b94a GT |
385 | else |
386 | msk->pm.subflows++; | |
24430f8b GT |
387 | spin_unlock_bh(&msk->pm.lock); |
388 | ||
702c2f64 | 389 | create_err: |
a6c85fc6 | 390 | sock_put(sk); |
702c2f64 FW |
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 | { | |
702c2f64 | 398 | struct mptcp_subflow_context *subflow; |
702c2f64 FW |
399 | |
400 | if (local->family != remote->family) | |
401 | return NULL; | |
402 | ||
702c2f64 FW |
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(ssk); | |
423 | ||
424 | if (!ipv6_addr_equal(&local->addr6, &pinfo->saddr) || | |
425 | !ipv6_addr_equal(&remote->addr6, &ssk->sk_v6_daddr)) | |
426 | continue; | |
427 | break; | |
428 | } | |
429 | #endif | |
430 | default: | |
431 | continue; | |
432 | } | |
433 | ||
434 | if (issk->inet_sport == local->port && | |
5ccecaec PA |
435 | issk->inet_dport == remote->port) |
436 | return ssk; | |
702c2f64 FW |
437 | } |
438 | ||
5ccecaec | 439 | return NULL; |
702c2f64 FW |
440 | } |
441 | ||
1e07938e | 442 | int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info) |
702c2f64 FW |
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(token); | |
460 | ||
461 | msk = mptcp_token_get_sock(genl_info_net(info), token_val); | |
462 | if (!msk) { | |
463 | NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token"); | |
464 | return err; | |
465 | } | |
466 | ||
a6c85fc6 GT |
467 | sk = (struct sock *)msk; |
468 | ||
702c2f64 FW |
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(laddr, info, &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(raddr, info, &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"); | |
e0fe1123 | 488 | err = -EINVAL; |
702c2f64 FW |
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"); | |
e0fe1123 | 494 | err = -EINVAL; |
702c2f64 FW |
495 | goto destroy_err; |
496 | } | |
497 | ||
5ccecaec | 498 | lock_sock(sk); |
702c2f64 FW |
499 | ssk = mptcp_nl_find_ssk(msk, &addr_l, &addr_r); |
500 | if (ssk) { | |
501 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); | |
24430f8b | 502 | struct mptcp_pm_addr_entry entry = { .addr = addr_l }; |
702c2f64 | 503 | |
24430f8b GT |
504 | spin_lock_bh(&msk->pm.lock); |
505 | mptcp_userspace_pm_delete_local_addr(msk, &entry); | |
506 | spin_unlock_bh(&msk->pm.lock); | |
702c2f64 FW |
507 | mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN); |
508 | mptcp_close_ssk(sk, ssk, subflow); | |
d2d21f17 | 509 | MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW); |
702c2f64 FW |
510 | err = 0; |
511 | } else { | |
512 | err = -ESRCH; | |
513 | } | |
5ccecaec | 514 | release_sock(sk); |
702c2f64 | 515 | |
5ccecaec | 516 | destroy_err: |
a6c85fc6 | 517 | sock_put(sk); |
702c2f64 FW |
518 | return err; |
519 | } | |
892f396c KM |
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; | |
14cb0e0b | 527 | struct sock *sk; |
892f396c KM |
528 | u32 token_val; |
529 | ||
530 | token_val = nla_get_u32(token); | |
531 | ||
532 | msk = mptcp_token_get_sock(net, token_val); | |
533 | if (!msk) | |
534 | return ret; | |
535 | ||
14cb0e0b GT |
536 | sk = (struct sock *)msk; |
537 | ||
892f396c KM |
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 | ||
14cb0e0b | 545 | lock_sock(sk); |
892f396c | 546 | ret = mptcp_pm_nl_mp_prio_send_ack(msk, &loc->addr, &rem->addr, bkup); |
14cb0e0b | 547 | release_sock(sk); |
892f396c KM |
548 | |
549 | set_flags_err: | |
14cb0e0b | 550 | sock_put(sk); |
892f396c KM |
551 | return ret; |
552 | } |