]> Git Repo - linux.git/blob - net/mptcp/pm_userspace.c
init/modpost: conditionally check section mismatch to __meminit*
[linux.git] / net / mptcp / pm_userspace.c
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 #include "mptcp_pm_gen.h"
10
11 void mptcp_free_local_addr_list(struct mptcp_sock *msk)
12 {
13         struct mptcp_pm_addr_entry *entry, *tmp;
14         struct sock *sk = (struct sock *)msk;
15         LIST_HEAD(free_list);
16
17         if (!mptcp_pm_is_userspace(msk))
18                 return;
19
20         spin_lock_bh(&msk->pm.lock);
21         list_splice_init(&msk->pm.userspace_pm_local_addr_list, &free_list);
22         spin_unlock_bh(&msk->pm.lock);
23
24         list_for_each_entry_safe(entry, tmp, &free_list, list) {
25                 sock_kfree_s(sk, entry, sizeof(*entry));
26         }
27 }
28
29 static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
30                                                     struct mptcp_pm_addr_entry *entry,
31                                                     bool needs_id)
32 {
33         DECLARE_BITMAP(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
34         struct mptcp_pm_addr_entry *match = NULL;
35         struct sock *sk = (struct sock *)msk;
36         struct mptcp_pm_addr_entry *e;
37         bool addr_match = false;
38         bool id_match = false;
39         int ret = -EINVAL;
40
41         bitmap_zero(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
42
43         spin_lock_bh(&msk->pm.lock);
44         list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) {
45                 addr_match = mptcp_addresses_equal(&e->addr, &entry->addr, true);
46                 if (addr_match && entry->addr.id == 0 && needs_id)
47                         entry->addr.id = e->addr.id;
48                 id_match = (e->addr.id == entry->addr.id);
49                 if (addr_match && id_match) {
50                         match = e;
51                         break;
52                 } else if (addr_match || id_match) {
53                         break;
54                 }
55                 __set_bit(e->addr.id, id_bitmap);
56         }
57
58         if (!match && !addr_match && !id_match) {
59                 /* Memory for the entry is allocated from the
60                  * sock option buffer.
61                  */
62                 e = sock_kmalloc(sk, sizeof(*e), GFP_ATOMIC);
63                 if (!e) {
64                         ret = -ENOMEM;
65                         goto append_err;
66                 }
67
68                 *e = *entry;
69                 if (!e->addr.id && needs_id)
70                         e->addr.id = find_next_zero_bit(id_bitmap,
71                                                         MPTCP_PM_MAX_ADDR_ID + 1,
72                                                         1);
73                 list_add_tail_rcu(&e->list, &msk->pm.userspace_pm_local_addr_list);
74                 msk->pm.local_addr_used++;
75                 ret = e->addr.id;
76         } else if (match) {
77                 ret = entry->addr.id;
78         }
79
80 append_err:
81         spin_unlock_bh(&msk->pm.lock);
82         return ret;
83 }
84
85 /* If the subflow is closed from the other peer (not via a
86  * subflow destroy command then), we want to keep the entry
87  * not to assign the same ID to another address and to be
88  * able to send RM_ADDR after the removal of the subflow.
89  */
90 static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk,
91                                                 struct mptcp_pm_addr_entry *addr)
92 {
93         struct mptcp_pm_addr_entry *entry, *tmp;
94
95         list_for_each_entry_safe(entry, tmp, &msk->pm.userspace_pm_local_addr_list, list) {
96                 if (mptcp_addresses_equal(&entry->addr, &addr->addr, false)) {
97                         /* TODO: a refcount is needed because the entry can
98                          * be used multiple times (e.g. fullmesh mode).
99                          */
100                         list_del_rcu(&entry->list);
101                         kfree(entry);
102                         msk->pm.local_addr_used--;
103                         return 0;
104                 }
105         }
106
107         return -EINVAL;
108 }
109
110 static struct mptcp_pm_addr_entry *
111 mptcp_userspace_pm_lookup_addr_by_id(struct mptcp_sock *msk, unsigned int id)
112 {
113         struct mptcp_pm_addr_entry *entry;
114
115         list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
116                 if (entry->addr.id == id)
117                         return entry;
118         }
119         return NULL;
120 }
121
122 int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
123                                                    unsigned int id,
124                                                    u8 *flags, int *ifindex)
125 {
126         struct mptcp_pm_addr_entry *match;
127
128         spin_lock_bh(&msk->pm.lock);
129         match = mptcp_userspace_pm_lookup_addr_by_id(msk, id);
130         spin_unlock_bh(&msk->pm.lock);
131         if (match) {
132                 *flags = match->flags;
133                 *ifindex = match->ifindex;
134         }
135
136         return 0;
137 }
138
139 int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk,
140                                     struct mptcp_addr_info *skc)
141 {
142         struct mptcp_pm_addr_entry *entry = NULL, *e, new_entry;
143         __be16 msk_sport =  ((struct inet_sock *)
144                              inet_sk((struct sock *)msk))->inet_sport;
145
146         spin_lock_bh(&msk->pm.lock);
147         list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) {
148                 if (mptcp_addresses_equal(&e->addr, skc, false)) {
149                         entry = e;
150                         break;
151                 }
152         }
153         spin_unlock_bh(&msk->pm.lock);
154         if (entry)
155                 return entry->addr.id;
156
157         memset(&new_entry, 0, sizeof(struct mptcp_pm_addr_entry));
158         new_entry.addr = *skc;
159         new_entry.addr.id = 0;
160         new_entry.flags = MPTCP_PM_ADDR_FLAG_IMPLICIT;
161
162         if (new_entry.addr.port == msk_sport)
163                 new_entry.addr.port = 0;
164
165         return mptcp_userspace_pm_append_new_local_addr(msk, &new_entry, true);
166 }
167
168 int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info)
169 {
170         struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
171         struct nlattr *addr = info->attrs[MPTCP_PM_ATTR_ADDR];
172         struct mptcp_pm_addr_entry addr_val;
173         struct mptcp_sock *msk;
174         int err = -EINVAL;
175         struct sock *sk;
176         u32 token_val;
177
178         if (!addr || !token) {
179                 GENL_SET_ERR_MSG(info, "missing required inputs");
180                 return err;
181         }
182
183         token_val = nla_get_u32(token);
184
185         msk = mptcp_token_get_sock(sock_net(skb->sk), token_val);
186         if (!msk) {
187                 NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
188                 return err;
189         }
190
191         sk = (struct sock *)msk;
192
193         if (!mptcp_pm_is_userspace(msk)) {
194                 GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected");
195                 goto announce_err;
196         }
197
198         err = mptcp_pm_parse_entry(addr, info, true, &addr_val);
199         if (err < 0) {
200                 GENL_SET_ERR_MSG(info, "error parsing local address");
201                 goto announce_err;
202         }
203
204         if (addr_val.addr.id == 0 || !(addr_val.flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) {
205                 GENL_SET_ERR_MSG(info, "invalid addr id or flags");
206                 err = -EINVAL;
207                 goto announce_err;
208         }
209
210         err = mptcp_userspace_pm_append_new_local_addr(msk, &addr_val, false);
211         if (err < 0) {
212                 GENL_SET_ERR_MSG(info, "did not match address and id");
213                 goto announce_err;
214         }
215
216         lock_sock(sk);
217         spin_lock_bh(&msk->pm.lock);
218
219         if (mptcp_pm_alloc_anno_list(msk, &addr_val.addr)) {
220                 msk->pm.add_addr_signaled++;
221                 mptcp_pm_announce_addr(msk, &addr_val.addr, false);
222                 mptcp_pm_nl_addr_send_ack(msk);
223         }
224
225         spin_unlock_bh(&msk->pm.lock);
226         release_sock(sk);
227
228         err = 0;
229  announce_err:
230         sock_put(sk);
231         return err;
232 }
233
234 static int mptcp_userspace_pm_remove_id_zero_address(struct mptcp_sock *msk,
235                                                      struct genl_info *info)
236 {
237         struct mptcp_rm_list list = { .nr = 0 };
238         struct mptcp_subflow_context *subflow;
239         struct sock *sk = (struct sock *)msk;
240         bool has_id_0 = false;
241         int err = -EINVAL;
242
243         lock_sock(sk);
244         mptcp_for_each_subflow(msk, subflow) {
245                 if (READ_ONCE(subflow->local_id) == 0) {
246                         has_id_0 = true;
247                         break;
248                 }
249         }
250         if (!has_id_0) {
251                 GENL_SET_ERR_MSG(info, "address with id 0 not found");
252                 goto remove_err;
253         }
254
255         list.ids[list.nr++] = 0;
256
257         spin_lock_bh(&msk->pm.lock);
258         mptcp_pm_remove_addr(msk, &list);
259         spin_unlock_bh(&msk->pm.lock);
260
261         err = 0;
262
263 remove_err:
264         release_sock(sk);
265         return err;
266 }
267
268 int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info)
269 {
270         struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
271         struct nlattr *id = info->attrs[MPTCP_PM_ATTR_LOC_ID];
272         struct mptcp_pm_addr_entry *match;
273         struct mptcp_pm_addr_entry *entry;
274         struct mptcp_sock *msk;
275         LIST_HEAD(free_list);
276         int err = -EINVAL;
277         struct sock *sk;
278         u32 token_val;
279         u8 id_val;
280
281         if (!id || !token) {
282                 GENL_SET_ERR_MSG(info, "missing required inputs");
283                 return err;
284         }
285
286         id_val = nla_get_u8(id);
287         token_val = nla_get_u32(token);
288
289         msk = mptcp_token_get_sock(sock_net(skb->sk), token_val);
290         if (!msk) {
291                 NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
292                 return err;
293         }
294
295         sk = (struct sock *)msk;
296
297         if (!mptcp_pm_is_userspace(msk)) {
298                 GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected");
299                 goto out;
300         }
301
302         if (id_val == 0) {
303                 err = mptcp_userspace_pm_remove_id_zero_address(msk, info);
304                 goto out;
305         }
306
307         lock_sock(sk);
308
309         match = mptcp_userspace_pm_lookup_addr_by_id(msk, id_val);
310         if (!match) {
311                 GENL_SET_ERR_MSG(info, "address with specified id not found");
312                 release_sock(sk);
313                 goto out;
314         }
315
316         list_move(&match->list, &free_list);
317
318         mptcp_pm_remove_addrs(msk, &free_list);
319
320         release_sock(sk);
321
322         list_for_each_entry_safe(match, entry, &free_list, list) {
323                 sock_kfree_s(sk, match, sizeof(*match));
324         }
325
326         err = 0;
327 out:
328         sock_put(sk);
329         return err;
330 }
331
332 int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info)
333 {
334         struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
335         struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
336         struct nlattr *laddr = info->attrs[MPTCP_PM_ATTR_ADDR];
337         struct mptcp_pm_addr_entry local = { 0 };
338         struct mptcp_addr_info addr_r;
339         struct mptcp_sock *msk;
340         int err = -EINVAL;
341         struct sock *sk;
342         u32 token_val;
343
344         if (!laddr || !raddr || !token) {
345                 GENL_SET_ERR_MSG(info, "missing required inputs");
346                 return err;
347         }
348
349         token_val = nla_get_u32(token);
350
351         msk = mptcp_token_get_sock(genl_info_net(info), token_val);
352         if (!msk) {
353                 NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
354                 return err;
355         }
356
357         sk = (struct sock *)msk;
358
359         if (!mptcp_pm_is_userspace(msk)) {
360                 GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected");
361                 goto create_err;
362         }
363
364         err = mptcp_pm_parse_entry(laddr, info, true, &local);
365         if (err < 0) {
366                 NL_SET_ERR_MSG_ATTR(info->extack, laddr, "error parsing local addr");
367                 goto create_err;
368         }
369
370         if (local.flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
371                 GENL_SET_ERR_MSG(info, "invalid addr flags");
372                 err = -EINVAL;
373                 goto create_err;
374         }
375         local.flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW;
376
377         err = mptcp_pm_parse_addr(raddr, info, &addr_r);
378         if (err < 0) {
379                 NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr");
380                 goto create_err;
381         }
382
383         if (!mptcp_pm_addr_families_match(sk, &local.addr, &addr_r)) {
384                 GENL_SET_ERR_MSG(info, "families mismatch");
385                 err = -EINVAL;
386                 goto create_err;
387         }
388
389         err = mptcp_userspace_pm_append_new_local_addr(msk, &local, false);
390         if (err < 0) {
391                 GENL_SET_ERR_MSG(info, "did not match address and id");
392                 goto create_err;
393         }
394
395         lock_sock(sk);
396
397         err = __mptcp_subflow_connect(sk, &local.addr, &addr_r);
398
399         release_sock(sk);
400
401         spin_lock_bh(&msk->pm.lock);
402         if (err)
403                 mptcp_userspace_pm_delete_local_addr(msk, &local);
404         else
405                 msk->pm.subflows++;
406         spin_unlock_bh(&msk->pm.lock);
407
408  create_err:
409         sock_put(sk);
410         return err;
411 }
412
413 static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
414                                       const struct mptcp_addr_info *local,
415                                       const struct mptcp_addr_info *remote)
416 {
417         struct mptcp_subflow_context *subflow;
418
419         if (local->family != remote->family)
420                 return NULL;
421
422         mptcp_for_each_subflow(msk, subflow) {
423                 const struct inet_sock *issk;
424                 struct sock *ssk;
425
426                 ssk = mptcp_subflow_tcp_sock(subflow);
427
428                 if (local->family != ssk->sk_family)
429                         continue;
430
431                 issk = inet_sk(ssk);
432
433                 switch (ssk->sk_family) {
434                 case AF_INET:
435                         if (issk->inet_saddr != local->addr.s_addr ||
436                             issk->inet_daddr != remote->addr.s_addr)
437                                 continue;
438                         break;
439 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
440                 case AF_INET6: {
441                         const struct ipv6_pinfo *pinfo = inet6_sk(ssk);
442
443                         if (!ipv6_addr_equal(&local->addr6, &pinfo->saddr) ||
444                             !ipv6_addr_equal(&remote->addr6, &ssk->sk_v6_daddr))
445                                 continue;
446                         break;
447                 }
448 #endif
449                 default:
450                         continue;
451                 }
452
453                 if (issk->inet_sport == local->port &&
454                     issk->inet_dport == remote->port)
455                         return ssk;
456         }
457
458         return NULL;
459 }
460
461 int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info)
462 {
463         struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
464         struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
465         struct nlattr *laddr = info->attrs[MPTCP_PM_ATTR_ADDR];
466         struct mptcp_addr_info addr_l;
467         struct mptcp_addr_info addr_r;
468         struct mptcp_sock *msk;
469         struct sock *sk, *ssk;
470         int err = -EINVAL;
471         u32 token_val;
472
473         if (!laddr || !raddr || !token) {
474                 GENL_SET_ERR_MSG(info, "missing required inputs");
475                 return err;
476         }
477
478         token_val = nla_get_u32(token);
479
480         msk = mptcp_token_get_sock(genl_info_net(info), token_val);
481         if (!msk) {
482                 NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
483                 return err;
484         }
485
486         sk = (struct sock *)msk;
487
488         if (!mptcp_pm_is_userspace(msk)) {
489                 GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected");
490                 goto destroy_err;
491         }
492
493         err = mptcp_pm_parse_addr(laddr, info, &addr_l);
494         if (err < 0) {
495                 NL_SET_ERR_MSG_ATTR(info->extack, laddr, "error parsing local addr");
496                 goto destroy_err;
497         }
498
499         err = mptcp_pm_parse_addr(raddr, info, &addr_r);
500         if (err < 0) {
501                 NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr");
502                 goto destroy_err;
503         }
504
505 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
506         if (addr_l.family == AF_INET && ipv6_addr_v4mapped(&addr_r.addr6)) {
507                 ipv6_addr_set_v4mapped(addr_l.addr.s_addr, &addr_l.addr6);
508                 addr_l.family = AF_INET6;
509         }
510         if (addr_r.family == AF_INET && ipv6_addr_v4mapped(&addr_l.addr6)) {
511                 ipv6_addr_set_v4mapped(addr_r.addr.s_addr, &addr_r.addr6);
512                 addr_r.family = AF_INET6;
513         }
514 #endif
515         if (addr_l.family != addr_r.family) {
516                 GENL_SET_ERR_MSG(info, "address families do not match");
517                 err = -EINVAL;
518                 goto destroy_err;
519         }
520
521         if (!addr_l.port || !addr_r.port) {
522                 GENL_SET_ERR_MSG(info, "missing local or remote port");
523                 err = -EINVAL;
524                 goto destroy_err;
525         }
526
527         lock_sock(sk);
528         ssk = mptcp_nl_find_ssk(msk, &addr_l, &addr_r);
529         if (ssk) {
530                 struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
531                 struct mptcp_pm_addr_entry entry = { .addr = addr_l };
532
533                 spin_lock_bh(&msk->pm.lock);
534                 mptcp_userspace_pm_delete_local_addr(msk, &entry);
535                 spin_unlock_bh(&msk->pm.lock);
536                 mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN);
537                 mptcp_close_ssk(sk, ssk, subflow);
538                 MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW);
539                 err = 0;
540         } else {
541                 err = -ESRCH;
542         }
543         release_sock(sk);
544
545 destroy_err:
546         sock_put(sk);
547         return err;
548 }
549
550 int mptcp_userspace_pm_set_flags(struct sk_buff *skb, struct genl_info *info)
551 {
552         struct mptcp_pm_addr_entry loc = { .addr = { .family = AF_UNSPEC }, };
553         struct mptcp_pm_addr_entry rem = { .addr = { .family = AF_UNSPEC }, };
554         struct nlattr *attr_rem = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
555         struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
556         struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
557         struct net *net = sock_net(skb->sk);
558         struct mptcp_sock *msk;
559         int ret = -EINVAL;
560         struct sock *sk;
561         u32 token_val;
562         u8 bkup = 0;
563
564         token_val = nla_get_u32(token);
565
566         msk = mptcp_token_get_sock(net, token_val);
567         if (!msk) {
568                 NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
569                 return ret;
570         }
571
572         sk = (struct sock *)msk;
573
574         if (!mptcp_pm_is_userspace(msk)) {
575                 GENL_SET_ERR_MSG(info, "userspace PM not selected");
576                 goto set_flags_err;
577         }
578
579         ret = mptcp_pm_parse_entry(attr, info, false, &loc);
580         if (ret < 0)
581                 goto set_flags_err;
582
583         if (attr_rem) {
584                 ret = mptcp_pm_parse_entry(attr_rem, info, false, &rem);
585                 if (ret < 0)
586                         goto set_flags_err;
587         }
588
589         if (loc.addr.family == AF_UNSPEC ||
590             rem.addr.family == AF_UNSPEC) {
591                 GENL_SET_ERR_MSG(info, "invalid address families");
592                 ret = -EINVAL;
593                 goto set_flags_err;
594         }
595
596         if (loc.flags & MPTCP_PM_ADDR_FLAG_BACKUP)
597                 bkup = 1;
598
599         lock_sock(sk);
600         ret = mptcp_pm_nl_mp_prio_send_ack(msk, &loc.addr, &rem.addr, bkup);
601         release_sock(sk);
602
603 set_flags_err:
604         sock_put(sk);
605         return ret;
606 }
607
608 int mptcp_userspace_pm_dump_addr(struct sk_buff *msg,
609                                  struct netlink_callback *cb)
610 {
611         struct id_bitmap {
612                 DECLARE_BITMAP(map, MPTCP_PM_MAX_ADDR_ID + 1);
613         } *bitmap;
614         const struct genl_info *info = genl_info_dump(cb);
615         struct net *net = sock_net(msg->sk);
616         struct mptcp_pm_addr_entry *entry;
617         struct mptcp_sock *msk;
618         struct nlattr *token;
619         int ret = -EINVAL;
620         struct sock *sk;
621         void *hdr;
622
623         bitmap = (struct id_bitmap *)cb->ctx;
624         token = info->attrs[MPTCP_PM_ATTR_TOKEN];
625
626         msk = mptcp_token_get_sock(net, nla_get_u32(token));
627         if (!msk) {
628                 NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
629                 return ret;
630         }
631
632         sk = (struct sock *)msk;
633
634         if (!mptcp_pm_is_userspace(msk)) {
635                 GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected");
636                 goto out;
637         }
638
639         lock_sock(sk);
640         spin_lock_bh(&msk->pm.lock);
641         list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
642                 if (test_bit(entry->addr.id, bitmap->map))
643                         continue;
644
645                 hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid,
646                                   cb->nlh->nlmsg_seq, &mptcp_genl_family,
647                                   NLM_F_MULTI, MPTCP_PM_CMD_GET_ADDR);
648                 if (!hdr)
649                         break;
650
651                 if (mptcp_nl_fill_addr(msg, entry) < 0) {
652                         genlmsg_cancel(msg, hdr);
653                         break;
654                 }
655
656                 __set_bit(entry->addr.id, bitmap->map);
657                 genlmsg_end(msg, hdr);
658         }
659         spin_unlock_bh(&msk->pm.lock);
660         release_sock(sk);
661         ret = msg->len;
662
663 out:
664         sock_put(sk);
665         return ret;
666 }
667
668 int mptcp_userspace_pm_get_addr(struct sk_buff *skb,
669                                 struct genl_info *info)
670 {
671         struct nlattr *attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR];
672         struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
673         struct mptcp_pm_addr_entry addr, *entry;
674         struct net *net = sock_net(skb->sk);
675         struct mptcp_sock *msk;
676         struct sk_buff *msg;
677         int ret = -EINVAL;
678         struct sock *sk;
679         void *reply;
680
681         msk = mptcp_token_get_sock(net, nla_get_u32(token));
682         if (!msk) {
683                 NL_SET_ERR_MSG_ATTR(info->extack, token, "invalid token");
684                 return ret;
685         }
686
687         sk = (struct sock *)msk;
688
689         if (!mptcp_pm_is_userspace(msk)) {
690                 GENL_SET_ERR_MSG(info, "invalid request; userspace PM not selected");
691                 goto out;
692         }
693
694         ret = mptcp_pm_parse_entry(attr, info, false, &addr);
695         if (ret < 0)
696                 goto out;
697
698         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
699         if (!msg) {
700                 ret = -ENOMEM;
701                 goto out;
702         }
703
704         reply = genlmsg_put_reply(msg, info, &mptcp_genl_family, 0,
705                                   info->genlhdr->cmd);
706         if (!reply) {
707                 GENL_SET_ERR_MSG(info, "not enough space in Netlink message");
708                 ret = -EMSGSIZE;
709                 goto fail;
710         }
711
712         lock_sock(sk);
713         spin_lock_bh(&msk->pm.lock);
714         entry = mptcp_userspace_pm_lookup_addr_by_id(msk, addr.addr.id);
715         if (!entry) {
716                 GENL_SET_ERR_MSG(info, "address not found");
717                 ret = -EINVAL;
718                 goto unlock_fail;
719         }
720
721         ret = mptcp_nl_fill_addr(msg, entry);
722         if (ret)
723                 goto unlock_fail;
724
725         genlmsg_end(msg, reply);
726         ret = genlmsg_reply(msg, info);
727         spin_unlock_bh(&msk->pm.lock);
728         release_sock(sk);
729         sock_put(sk);
730         return ret;
731
732 unlock_fail:
733         spin_unlock_bh(&msk->pm.lock);
734         release_sock(sk);
735 fail:
736         nlmsg_free(msg);
737 out:
738         sock_put(sk);
739         return ret;
740 }
This page took 0.074905 seconds and 4 git commands to generate.