Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/* Multipath TCP
3 *
4 * Copyright (c) 2020, Red Hat, Inc.
5 */
6
7#define pr_fmt(fmt) "MPTCP: " fmt
8
9#include "protocol.h"
10#include "mptcp_pm_gen.h"
11
12#define MPTCP_PM_CMD_GRP_OFFSET 0
13#define MPTCP_PM_EV_GRP_OFFSET 1
14
15static const struct genl_multicast_group mptcp_pm_mcgrps[] = {
16 [MPTCP_PM_CMD_GRP_OFFSET] = { .name = MPTCP_PM_CMD_GRP_NAME, },
17 [MPTCP_PM_EV_GRP_OFFSET] = { .name = MPTCP_PM_EV_GRP_NAME,
18 .flags = GENL_MCAST_CAP_NET_ADMIN,
19 },
20};
21
22static int mptcp_pm_family_to_addr(int family)
23{
24#if IS_ENABLED(CONFIG_MPTCP_IPV6)
25 if (family == AF_INET6)
26 return MPTCP_PM_ADDR_ATTR_ADDR6;
27#endif
28 return MPTCP_PM_ADDR_ATTR_ADDR4;
29}
30
31static int mptcp_pm_parse_pm_addr_attr(struct nlattr *tb[],
32 const struct nlattr *attr,
33 struct genl_info *info,
34 struct mptcp_addr_info *addr,
35 bool require_family)
36{
37 int err, addr_addr;
38
39 if (!attr) {
40 GENL_SET_ERR_MSG(info, "missing address info");
41 return -EINVAL;
42 }
43
44 /* no validation needed - was already done via nested policy */
45 err = nla_parse_nested_deprecated(tb, MPTCP_PM_ADDR_ATTR_MAX, attr,
46 mptcp_pm_address_nl_policy, info->extack);
47 if (err)
48 return err;
49
50 if (tb[MPTCP_PM_ADDR_ATTR_ID])
51 addr->id = nla_get_u8(tb[MPTCP_PM_ADDR_ATTR_ID]);
52
53 if (!tb[MPTCP_PM_ADDR_ATTR_FAMILY]) {
54 if (!require_family)
55 return 0;
56
57 NL_SET_ERR_MSG_ATTR(info->extack, attr,
58 "missing family");
59 return -EINVAL;
60 }
61
62 addr->family = nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_FAMILY]);
63 if (addr->family != AF_INET
64#if IS_ENABLED(CONFIG_MPTCP_IPV6)
65 && addr->family != AF_INET6
66#endif
67 ) {
68 NL_SET_ERR_MSG_ATTR(info->extack, attr,
69 "unknown address family");
70 return -EINVAL;
71 }
72 addr_addr = mptcp_pm_family_to_addr(addr->family);
73 if (!tb[addr_addr]) {
74 NL_SET_ERR_MSG_ATTR(info->extack, attr,
75 "missing address data");
76 return -EINVAL;
77 }
78
79#if IS_ENABLED(CONFIG_MPTCP_IPV6)
80 if (addr->family == AF_INET6)
81 addr->addr6 = nla_get_in6_addr(tb[addr_addr]);
82 else
83#endif
84 addr->addr.s_addr = nla_get_in_addr(tb[addr_addr]);
85
86 if (tb[MPTCP_PM_ADDR_ATTR_PORT])
87 addr->port = htons(nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]));
88
89 return 0;
90}
91
92int mptcp_pm_parse_addr(struct nlattr *attr, struct genl_info *info,
93 struct mptcp_addr_info *addr)
94{
95 struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
96
97 memset(addr, 0, sizeof(*addr));
98
99 return mptcp_pm_parse_pm_addr_attr(tb, attr, info, addr, true);
100}
101
102int mptcp_pm_parse_entry(struct nlattr *attr, struct genl_info *info,
103 bool require_family,
104 struct mptcp_pm_addr_entry *entry)
105{
106 struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
107 int err;
108
109 memset(entry, 0, sizeof(*entry));
110
111 err = mptcp_pm_parse_pm_addr_attr(tb, attr, info, &entry->addr, require_family);
112 if (err)
113 return err;
114
115 if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX]) {
116 s32 val = nla_get_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]);
117
118 entry->ifindex = val;
119 }
120
121 if (tb[MPTCP_PM_ADDR_ATTR_FLAGS])
122 entry->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]) &
123 MPTCP_PM_ADDR_FLAGS_MASK;
124
125 if (tb[MPTCP_PM_ADDR_ATTR_PORT])
126 entry->addr.port = htons(nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]));
127
128 return 0;
129}
130
131static int mptcp_nl_fill_addr(struct sk_buff *skb,
132 struct mptcp_pm_addr_entry *entry)
133{
134 struct mptcp_addr_info *addr = &entry->addr;
135 struct nlattr *attr;
136
137 attr = nla_nest_start(skb, MPTCP_PM_ATTR_ADDR);
138 if (!attr)
139 return -EMSGSIZE;
140
141 if (nla_put_u16(skb, MPTCP_PM_ADDR_ATTR_FAMILY, addr->family))
142 goto nla_put_failure;
143 if (nla_put_u16(skb, MPTCP_PM_ADDR_ATTR_PORT, ntohs(addr->port)))
144 goto nla_put_failure;
145 if (nla_put_u8(skb, MPTCP_PM_ADDR_ATTR_ID, addr->id))
146 goto nla_put_failure;
147 if (nla_put_u32(skb, MPTCP_PM_ADDR_ATTR_FLAGS, entry->flags))
148 goto nla_put_failure;
149 if (entry->ifindex &&
150 nla_put_s32(skb, MPTCP_PM_ADDR_ATTR_IF_IDX, entry->ifindex))
151 goto nla_put_failure;
152
153 if (addr->family == AF_INET &&
154 nla_put_in_addr(skb, MPTCP_PM_ADDR_ATTR_ADDR4,
155 addr->addr.s_addr))
156 goto nla_put_failure;
157#if IS_ENABLED(CONFIG_MPTCP_IPV6)
158 else if (addr->family == AF_INET6 &&
159 nla_put_in6_addr(skb, MPTCP_PM_ADDR_ATTR_ADDR6, &addr->addr6))
160 goto nla_put_failure;
161#endif
162 nla_nest_end(skb, attr);
163 return 0;
164
165nla_put_failure:
166 nla_nest_cancel(skb, attr);
167 return -EMSGSIZE;
168}
169
170static int mptcp_pm_get_addr(u8 id, struct mptcp_pm_addr_entry *addr,
171 struct genl_info *info)
172{
173 if (info->attrs[MPTCP_PM_ATTR_TOKEN])
174 return mptcp_userspace_pm_get_addr(id, addr, info);
175 return mptcp_pm_nl_get_addr(id, addr, info);
176}
177
178int mptcp_pm_nl_get_addr_doit(struct sk_buff *skb, struct genl_info *info)
179{
180 struct mptcp_pm_addr_entry addr;
181 struct nlattr *attr;
182 struct sk_buff *msg;
183 void *reply;
184 int ret;
185
186 if (GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ENDPOINT_ADDR))
187 return -EINVAL;
188
189 attr = info->attrs[MPTCP_PM_ENDPOINT_ADDR];
190 ret = mptcp_pm_parse_entry(attr, info, false, &addr);
191 if (ret < 0)
192 return ret;
193
194 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
195 if (!msg)
196 return -ENOMEM;
197
198 reply = genlmsg_put_reply(msg, info, &mptcp_genl_family, 0,
199 info->genlhdr->cmd);
200 if (!reply) {
201 GENL_SET_ERR_MSG(info, "not enough space in Netlink message");
202 ret = -EMSGSIZE;
203 goto fail;
204 }
205
206 ret = mptcp_pm_get_addr(addr.addr.id, &addr, info);
207 if (ret) {
208 NL_SET_ERR_MSG_ATTR(info->extack, attr, "address not found");
209 goto fail;
210 }
211
212 ret = mptcp_nl_fill_addr(msg, &addr);
213 if (ret)
214 goto fail;
215
216 genlmsg_end(msg, reply);
217 ret = genlmsg_reply(msg, info);
218 return ret;
219
220fail:
221 nlmsg_free(msg);
222 return ret;
223}
224
225int mptcp_pm_genl_fill_addr(struct sk_buff *msg,
226 struct netlink_callback *cb,
227 struct mptcp_pm_addr_entry *entry)
228{
229 void *hdr;
230
231 hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid,
232 cb->nlh->nlmsg_seq, &mptcp_genl_family,
233 NLM_F_MULTI, MPTCP_PM_CMD_GET_ADDR);
234 if (!hdr)
235 return -EINVAL;
236
237 if (mptcp_nl_fill_addr(msg, entry) < 0) {
238 genlmsg_cancel(msg, hdr);
239 return -EINVAL;
240 }
241
242 genlmsg_end(msg, hdr);
243 return 0;
244}
245
246static int mptcp_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb)
247{
248 const struct genl_info *info = genl_info_dump(cb);
249
250 if (info->attrs[MPTCP_PM_ATTR_TOKEN])
251 return mptcp_userspace_pm_dump_addr(msg, cb);
252 return mptcp_pm_nl_dump_addr(msg, cb);
253}
254
255int mptcp_pm_nl_get_addr_dumpit(struct sk_buff *msg,
256 struct netlink_callback *cb)
257{
258 return mptcp_pm_dump_addr(msg, cb);
259}
260
261static int mptcp_pm_set_flags(struct genl_info *info)
262{
263 struct mptcp_pm_addr_entry loc = { .addr = { .family = AF_UNSPEC }, };
264 struct nlattr *attr_loc;
265 int ret = -EINVAL;
266
267 if (GENL_REQ_ATTR_CHECK(info, MPTCP_PM_ATTR_ADDR))
268 return ret;
269
270 attr_loc = info->attrs[MPTCP_PM_ATTR_ADDR];
271 ret = mptcp_pm_parse_entry(attr_loc, info, false, &loc);
272 if (ret < 0)
273 return ret;
274
275 if (info->attrs[MPTCP_PM_ATTR_TOKEN])
276 return mptcp_userspace_pm_set_flags(&loc, info);
277 return mptcp_pm_nl_set_flags(&loc, info);
278}
279
280int mptcp_pm_nl_set_flags_doit(struct sk_buff *skb, struct genl_info *info)
281{
282 return mptcp_pm_set_flags(info);
283}
284
285static void mptcp_nl_mcast_send(struct net *net, struct sk_buff *nlskb, gfp_t gfp)
286{
287 genlmsg_multicast_netns(&mptcp_genl_family, net,
288 nlskb, 0, MPTCP_PM_EV_GRP_OFFSET, gfp);
289}
290
291bool mptcp_userspace_pm_active(const struct mptcp_sock *msk)
292{
293 return genl_has_listeners(&mptcp_genl_family,
294 sock_net((const struct sock *)msk),
295 MPTCP_PM_EV_GRP_OFFSET);
296}
297
298static int mptcp_event_add_subflow(struct sk_buff *skb, const struct sock *ssk)
299{
300 const struct inet_sock *issk = inet_sk(ssk);
301 const struct mptcp_subflow_context *sf;
302
303 if (nla_put_u16(skb, MPTCP_ATTR_FAMILY, ssk->sk_family))
304 return -EMSGSIZE;
305
306 switch (ssk->sk_family) {
307 case AF_INET:
308 if (nla_put_in_addr(skb, MPTCP_ATTR_SADDR4, issk->inet_saddr))
309 return -EMSGSIZE;
310 if (nla_put_in_addr(skb, MPTCP_ATTR_DADDR4, issk->inet_daddr))
311 return -EMSGSIZE;
312 break;
313#if IS_ENABLED(CONFIG_MPTCP_IPV6)
314 case AF_INET6: {
315 if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &issk->pinet6->saddr))
316 return -EMSGSIZE;
317 if (nla_put_in6_addr(skb, MPTCP_ATTR_DADDR6, &ssk->sk_v6_daddr))
318 return -EMSGSIZE;
319 break;
320 }
321#endif
322 default:
323 WARN_ON_ONCE(1);
324 return -EMSGSIZE;
325 }
326
327 if (nla_put_be16(skb, MPTCP_ATTR_SPORT, issk->inet_sport))
328 return -EMSGSIZE;
329 if (nla_put_be16(skb, MPTCP_ATTR_DPORT, issk->inet_dport))
330 return -EMSGSIZE;
331
332 sf = mptcp_subflow_ctx(ssk);
333 if (WARN_ON_ONCE(!sf))
334 return -EINVAL;
335
336 if (nla_put_u8(skb, MPTCP_ATTR_LOC_ID, subflow_get_local_id(sf)))
337 return -EMSGSIZE;
338
339 if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, sf->remote_id))
340 return -EMSGSIZE;
341
342 return 0;
343}
344
345static int mptcp_event_put_token_and_ssk(struct sk_buff *skb,
346 const struct mptcp_sock *msk,
347 const struct sock *ssk)
348{
349 const struct sock *sk = (const struct sock *)msk;
350 const struct mptcp_subflow_context *sf;
351 u8 sk_err;
352
353 if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)))
354 return -EMSGSIZE;
355
356 if (mptcp_event_add_subflow(skb, ssk))
357 return -EMSGSIZE;
358
359 sf = mptcp_subflow_ctx(ssk);
360 if (WARN_ON_ONCE(!sf))
361 return -EINVAL;
362
363 if (nla_put_u8(skb, MPTCP_ATTR_BACKUP, sf->backup))
364 return -EMSGSIZE;
365
366 if (ssk->sk_bound_dev_if &&
367 nla_put_s32(skb, MPTCP_ATTR_IF_IDX, ssk->sk_bound_dev_if))
368 return -EMSGSIZE;
369
370 sk_err = READ_ONCE(ssk->sk_err);
371 if (sk_err && sk->sk_state == TCP_ESTABLISHED &&
372 nla_put_u8(skb, MPTCP_ATTR_ERROR, sk_err))
373 return -EMSGSIZE;
374
375 return 0;
376}
377
378static int mptcp_event_sub_established(struct sk_buff *skb,
379 const struct mptcp_sock *msk,
380 const struct sock *ssk)
381{
382 return mptcp_event_put_token_and_ssk(skb, msk, ssk);
383}
384
385static int mptcp_event_sub_closed(struct sk_buff *skb,
386 const struct mptcp_sock *msk,
387 const struct sock *ssk)
388{
389 const struct mptcp_subflow_context *sf;
390
391 if (mptcp_event_put_token_and_ssk(skb, msk, ssk))
392 return -EMSGSIZE;
393
394 sf = mptcp_subflow_ctx(ssk);
395 if (!sf->reset_seen)
396 return 0;
397
398 if (nla_put_u32(skb, MPTCP_ATTR_RESET_REASON, sf->reset_reason))
399 return -EMSGSIZE;
400
401 if (nla_put_u32(skb, MPTCP_ATTR_RESET_FLAGS, sf->reset_transient))
402 return -EMSGSIZE;
403
404 return 0;
405}
406
407static int mptcp_event_created(struct sk_buff *skb,
408 const struct mptcp_sock *msk,
409 const struct sock *ssk)
410{
411 int err = nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token));
412 u16 flags = 0;
413
414 if (err)
415 return err;
416
417 if (READ_ONCE(msk->pm.server_side)) {
418 flags |= MPTCP_PM_EV_FLAG_SERVER_SIDE;
419
420 /* Deprecated, and only set when it is the server side */
421 if (nla_put_u8(skb, MPTCP_ATTR_SERVER_SIDE, 1))
422 return -EMSGSIZE;
423 }
424
425 if (READ_ONCE(msk->pm.remote_deny_join_id0))
426 flags |= MPTCP_PM_EV_FLAG_DENY_JOIN_ID0;
427
428 if (flags && nla_put_u16(skb, MPTCP_ATTR_FLAGS, flags))
429 return -EMSGSIZE;
430
431 return mptcp_event_add_subflow(skb, ssk);
432}
433
434void mptcp_event_addr_removed(const struct mptcp_sock *msk, uint8_t id)
435{
436 struct net *net = sock_net((const struct sock *)msk);
437 struct nlmsghdr *nlh;
438 struct sk_buff *skb;
439
440 if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
441 return;
442
443 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
444 if (!skb)
445 return;
446
447 nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0, MPTCP_EVENT_REMOVED);
448 if (!nlh)
449 goto nla_put_failure;
450
451 if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)))
452 goto nla_put_failure;
453
454 if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, id))
455 goto nla_put_failure;
456
457 genlmsg_end(skb, nlh);
458 mptcp_nl_mcast_send(net, skb, GFP_ATOMIC);
459 return;
460
461nla_put_failure:
462 nlmsg_free(skb);
463}
464
465void mptcp_event_addr_announced(const struct sock *ssk,
466 const struct mptcp_addr_info *info)
467{
468 struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
469 struct mptcp_sock *msk = mptcp_sk(subflow->conn);
470 struct net *net = sock_net(ssk);
471 struct nlmsghdr *nlh;
472 struct sk_buff *skb;
473
474 if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
475 return;
476
477 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
478 if (!skb)
479 return;
480
481 nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0,
482 MPTCP_EVENT_ANNOUNCED);
483 if (!nlh)
484 goto nla_put_failure;
485
486 if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)))
487 goto nla_put_failure;
488
489 if (nla_put_u8(skb, MPTCP_ATTR_REM_ID, info->id))
490 goto nla_put_failure;
491
492 if (nla_put_be16(skb, MPTCP_ATTR_DPORT,
493 info->port == 0 ?
494 inet_sk(ssk)->inet_dport :
495 info->port))
496 goto nla_put_failure;
497
498 switch (info->family) {
499 case AF_INET:
500 if (nla_put_in_addr(skb, MPTCP_ATTR_DADDR4, info->addr.s_addr))
501 goto nla_put_failure;
502 break;
503#if IS_ENABLED(CONFIG_MPTCP_IPV6)
504 case AF_INET6:
505 if (nla_put_in6_addr(skb, MPTCP_ATTR_DADDR6, &info->addr6))
506 goto nla_put_failure;
507 break;
508#endif
509 default:
510 WARN_ON_ONCE(1);
511 goto nla_put_failure;
512 }
513
514 genlmsg_end(skb, nlh);
515 mptcp_nl_mcast_send(net, skb, GFP_ATOMIC);
516 return;
517
518nla_put_failure:
519 nlmsg_free(skb);
520}
521
522void mptcp_event_pm_listener(const struct sock *ssk,
523 enum mptcp_event_type event)
524{
525 const struct inet_sock *issk = inet_sk(ssk);
526 struct net *net = sock_net(ssk);
527 struct nlmsghdr *nlh;
528 struct sk_buff *skb;
529
530 if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
531 return;
532
533 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
534 if (!skb)
535 return;
536
537 nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0, event);
538 if (!nlh)
539 goto nla_put_failure;
540
541 if (nla_put_u16(skb, MPTCP_ATTR_FAMILY, ssk->sk_family))
542 goto nla_put_failure;
543
544 if (nla_put_be16(skb, MPTCP_ATTR_SPORT, issk->inet_sport))
545 goto nla_put_failure;
546
547 switch (ssk->sk_family) {
548 case AF_INET:
549 if (nla_put_in_addr(skb, MPTCP_ATTR_SADDR4, issk->inet_saddr))
550 goto nla_put_failure;
551 break;
552#if IS_ENABLED(CONFIG_MPTCP_IPV6)
553 case AF_INET6: {
554 if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &issk->pinet6->saddr))
555 goto nla_put_failure;
556 break;
557 }
558#endif
559 default:
560 WARN_ON_ONCE(1);
561 goto nla_put_failure;
562 }
563
564 genlmsg_end(skb, nlh);
565 mptcp_nl_mcast_send(net, skb, GFP_KERNEL);
566 return;
567
568nla_put_failure:
569 nlmsg_free(skb);
570}
571
572void mptcp_event(enum mptcp_event_type type, const struct mptcp_sock *msk,
573 const struct sock *ssk, gfp_t gfp)
574{
575 struct net *net = sock_net((const struct sock *)msk);
576 struct nlmsghdr *nlh;
577 struct sk_buff *skb;
578
579 if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
580 return;
581
582 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
583 if (!skb)
584 return;
585
586 nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0, type);
587 if (!nlh)
588 goto nla_put_failure;
589
590 switch (type) {
591 case MPTCP_EVENT_UNSPEC:
592 WARN_ON_ONCE(1);
593 break;
594 case MPTCP_EVENT_CREATED:
595 case MPTCP_EVENT_ESTABLISHED:
596 if (mptcp_event_created(skb, msk, ssk) < 0)
597 goto nla_put_failure;
598 break;
599 case MPTCP_EVENT_CLOSED:
600 if (nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)) < 0)
601 goto nla_put_failure;
602 break;
603 case MPTCP_EVENT_ANNOUNCED:
604 case MPTCP_EVENT_REMOVED:
605 /* call mptcp_event_addr_announced()/removed instead */
606 WARN_ON_ONCE(1);
607 break;
608 case MPTCP_EVENT_SUB_ESTABLISHED:
609 case MPTCP_EVENT_SUB_PRIORITY:
610 if (mptcp_event_sub_established(skb, msk, ssk) < 0)
611 goto nla_put_failure;
612 break;
613 case MPTCP_EVENT_SUB_CLOSED:
614 if (mptcp_event_sub_closed(skb, msk, ssk) < 0)
615 goto nla_put_failure;
616 break;
617 case MPTCP_EVENT_LISTENER_CREATED:
618 case MPTCP_EVENT_LISTENER_CLOSED:
619 break;
620 }
621
622 genlmsg_end(skb, nlh);
623 mptcp_nl_mcast_send(net, skb, gfp);
624 return;
625
626nla_put_failure:
627 nlmsg_free(skb);
628}
629
630struct genl_family mptcp_genl_family __ro_after_init = {
631 .name = MPTCP_PM_NAME,
632 .version = MPTCP_PM_VER,
633 .netnsok = true,
634 .module = THIS_MODULE,
635 .ops = mptcp_pm_nl_ops,
636 .n_ops = ARRAY_SIZE(mptcp_pm_nl_ops),
637 .resv_start_op = MPTCP_PM_CMD_SUBFLOW_DESTROY + 1,
638 .mcgrps = mptcp_pm_mcgrps,
639 .n_mcgrps = ARRAY_SIZE(mptcp_pm_mcgrps),
640};
641
642void __init mptcp_pm_nl_init(void)
643{
644 if (genl_register_family(&mptcp_genl_family))
645 panic("Failed to register MPTCP PM netlink family\n");
646}