1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <errno.h>
4 #include <error.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9
10 #include <sys/socket.h>
11 #include <sys/types.h>
12
13 #include <arpa/inet.h>
14 #include <net/if.h>
15
16 #include <linux/rtnetlink.h>
17 #include <linux/genetlink.h>
18
19 #include "linux/mptcp.h"
20
21 #ifndef MPTCP_PM_NAME
22 #define MPTCP_PM_NAME "mptcp_pm"
23 #endif
24
syntax(char * argv[])25 static void syntax(char *argv[])
26 {
27 fprintf(stderr, "%s add|get|set|del|flush|dump|accept [<args>]\n", argv[0]);
28 fprintf(stderr, "\tadd [flags signal|subflow|backup|fullmesh] [id <nr>] [dev <name>] <ip>\n");
29 fprintf(stderr, "\tdel <id> [<ip>]\n");
30 fprintf(stderr, "\tget <id>\n");
31 fprintf(stderr, "\tset <ip> [flags backup|nobackup]\n");
32 fprintf(stderr, "\tflush\n");
33 fprintf(stderr, "\tdump\n");
34 fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n");
35 exit(0);
36 }
37
init_genl_req(char * data,int family,int cmd,int version)38 static int init_genl_req(char *data, int family, int cmd, int version)
39 {
40 struct nlmsghdr *nh = (void *)data;
41 struct genlmsghdr *gh;
42 int off = 0;
43
44 nh->nlmsg_type = family;
45 nh->nlmsg_flags = NLM_F_REQUEST;
46 nh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
47 off += NLMSG_ALIGN(sizeof(*nh));
48
49 gh = (void *)(data + off);
50 gh->cmd = cmd;
51 gh->version = version;
52 off += NLMSG_ALIGN(sizeof(*gh));
53 return off;
54 }
55
nl_error(struct nlmsghdr * nh)56 static void nl_error(struct nlmsghdr *nh)
57 {
58 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh);
59 int len = nh->nlmsg_len - sizeof(*nh);
60 uint32_t off;
61
62 if (len < sizeof(struct nlmsgerr))
63 error(1, 0, "netlink error message truncated %d min %ld", len,
64 sizeof(struct nlmsgerr));
65
66 if (!err->error) {
67 /* check messages from kernel */
68 struct rtattr *attrs = (struct rtattr *)NLMSG_DATA(nh);
69
70 while (RTA_OK(attrs, len)) {
71 if (attrs->rta_type == NLMSGERR_ATTR_MSG)
72 fprintf(stderr, "netlink ext ack msg: %s\n",
73 (char *)RTA_DATA(attrs));
74 if (attrs->rta_type == NLMSGERR_ATTR_OFFS) {
75 memcpy(&off, RTA_DATA(attrs), 4);
76 fprintf(stderr, "netlink err off %d\n",
77 (int)off);
78 }
79 attrs = RTA_NEXT(attrs, len);
80 }
81 } else {
82 fprintf(stderr, "netlink error %d", err->error);
83 }
84 }
85
86 /* do a netlink command and, if max > 0, fetch the reply */
do_nl_req(int fd,struct nlmsghdr * nh,int len,int max)87 static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max)
88 {
89 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
90 socklen_t addr_len;
91 void *data = nh;
92 int rem, ret;
93 int err = 0;
94
95 nh->nlmsg_len = len;
96 ret = sendto(fd, data, len, 0, (void *)&nladdr, sizeof(nladdr));
97 if (ret != len)
98 error(1, errno, "send netlink: %uB != %uB\n", ret, len);
99 if (max == 0)
100 return 0;
101
102 addr_len = sizeof(nladdr);
103 rem = ret = recvfrom(fd, data, max, 0, (void *)&nladdr, &addr_len);
104 if (ret < 0)
105 error(1, errno, "recv netlink: %uB\n", ret);
106
107 /* Beware: the NLMSG_NEXT macro updates the 'rem' argument */
108 for (; NLMSG_OK(nh, rem); nh = NLMSG_NEXT(nh, rem)) {
109 if (nh->nlmsg_type == NLMSG_ERROR) {
110 nl_error(nh);
111 err = 1;
112 }
113 }
114 if (err)
115 error(1, 0, "bailing out due to netlink error[s]");
116 return ret;
117 }
118
genl_parse_getfamily(struct nlmsghdr * nlh)119 static int genl_parse_getfamily(struct nlmsghdr *nlh)
120 {
121 struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
122 int len = nlh->nlmsg_len;
123 struct rtattr *attrs;
124
125 if (nlh->nlmsg_type != GENL_ID_CTRL)
126 error(1, errno, "Not a controller message, len=%d type=0x%x\n",
127 nlh->nlmsg_len, nlh->nlmsg_type);
128
129 len -= NLMSG_LENGTH(GENL_HDRLEN);
130
131 if (len < 0)
132 error(1, errno, "wrong controller message len %d\n", len);
133
134 if (ghdr->cmd != CTRL_CMD_NEWFAMILY)
135 error(1, errno, "Unknown controller command %d\n", ghdr->cmd);
136
137 attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
138 while (RTA_OK(attrs, len)) {
139 if (attrs->rta_type == CTRL_ATTR_FAMILY_ID)
140 return *(__u16 *)RTA_DATA(attrs);
141 attrs = RTA_NEXT(attrs, len);
142 }
143
144 error(1, errno, "can't find CTRL_ATTR_FAMILY_ID attr");
145 return -1;
146 }
147
resolve_mptcp_pm_netlink(int fd)148 static int resolve_mptcp_pm_netlink(int fd)
149 {
150 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
151 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
152 1024];
153 struct nlmsghdr *nh;
154 struct rtattr *rta;
155 int namelen;
156 int off = 0;
157
158 memset(data, 0, sizeof(data));
159 nh = (void *)data;
160 off = init_genl_req(data, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 0);
161
162 rta = (void *)(data + off);
163 namelen = strlen(MPTCP_PM_NAME) + 1;
164 rta->rta_type = CTRL_ATTR_FAMILY_NAME;
165 rta->rta_len = RTA_LENGTH(namelen);
166 memcpy(RTA_DATA(rta), MPTCP_PM_NAME, namelen);
167 off += NLMSG_ALIGN(rta->rta_len);
168
169 do_nl_req(fd, nh, off, sizeof(data));
170 return genl_parse_getfamily((void *)data);
171 }
172
add_addr(int fd,int pm_family,int argc,char * argv[])173 int add_addr(int fd, int pm_family, int argc, char *argv[])
174 {
175 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
176 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
177 1024];
178 struct rtattr *rta, *nest;
179 struct nlmsghdr *nh;
180 u_int32_t flags = 0;
181 u_int16_t family;
182 int nest_start;
183 u_int8_t id;
184 int off = 0;
185 int arg;
186
187 memset(data, 0, sizeof(data));
188 nh = (void *)data;
189 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ADD_ADDR,
190 MPTCP_PM_VER);
191
192 if (argc < 3)
193 syntax(argv);
194
195 nest_start = off;
196 nest = (void *)(data + off);
197 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
198 nest->rta_len = RTA_LENGTH(0);
199 off += NLMSG_ALIGN(nest->rta_len);
200
201 /* addr data */
202 rta = (void *)(data + off);
203 if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {
204 family = AF_INET;
205 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
206 rta->rta_len = RTA_LENGTH(4);
207 } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {
208 family = AF_INET6;
209 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
210 rta->rta_len = RTA_LENGTH(16);
211 } else
212 error(1, errno, "can't parse ip %s", argv[2]);
213 off += NLMSG_ALIGN(rta->rta_len);
214
215 /* family */
216 rta = (void *)(data + off);
217 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
218 rta->rta_len = RTA_LENGTH(2);
219 memcpy(RTA_DATA(rta), &family, 2);
220 off += NLMSG_ALIGN(rta->rta_len);
221
222 for (arg = 3; arg < argc; arg++) {
223 if (!strcmp(argv[arg], "flags")) {
224 char *tok, *str;
225
226 /* flags */
227 if (++arg >= argc)
228 error(1, 0, " missing flags value");
229
230 /* do not support flag list yet */
231 for (str = argv[arg]; (tok = strtok(str, ","));
232 str = NULL) {
233 if (!strcmp(tok, "subflow"))
234 flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW;
235 else if (!strcmp(tok, "signal"))
236 flags |= MPTCP_PM_ADDR_FLAG_SIGNAL;
237 else if (!strcmp(tok, "backup"))
238 flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
239 else if (!strcmp(tok, "fullmesh"))
240 flags |= MPTCP_PM_ADDR_FLAG_FULLMESH;
241 else
242 error(1, errno,
243 "unknown flag %s", argv[arg]);
244 }
245
246 if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL &&
247 flags & MPTCP_PM_ADDR_FLAG_FULLMESH) {
248 error(1, errno, "error flag fullmesh");
249 }
250
251 rta = (void *)(data + off);
252 rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
253 rta->rta_len = RTA_LENGTH(4);
254 memcpy(RTA_DATA(rta), &flags, 4);
255 off += NLMSG_ALIGN(rta->rta_len);
256 } else if (!strcmp(argv[arg], "id")) {
257 if (++arg >= argc)
258 error(1, 0, " missing id value");
259
260 id = atoi(argv[arg]);
261 rta = (void *)(data + off);
262 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
263 rta->rta_len = RTA_LENGTH(1);
264 memcpy(RTA_DATA(rta), &id, 1);
265 off += NLMSG_ALIGN(rta->rta_len);
266 } else if (!strcmp(argv[arg], "dev")) {
267 int32_t ifindex;
268
269 if (++arg >= argc)
270 error(1, 0, " missing dev name");
271
272 ifindex = if_nametoindex(argv[arg]);
273 if (!ifindex)
274 error(1, errno, "unknown device %s", argv[arg]);
275
276 rta = (void *)(data + off);
277 rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX;
278 rta->rta_len = RTA_LENGTH(4);
279 memcpy(RTA_DATA(rta), &ifindex, 4);
280 off += NLMSG_ALIGN(rta->rta_len);
281 } else if (!strcmp(argv[arg], "port")) {
282 u_int16_t port;
283
284 if (++arg >= argc)
285 error(1, 0, " missing port value");
286 if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
287 error(1, 0, " flags must be signal when using port");
288
289 port = atoi(argv[arg]);
290 rta = (void *)(data + off);
291 rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
292 rta->rta_len = RTA_LENGTH(2);
293 memcpy(RTA_DATA(rta), &port, 2);
294 off += NLMSG_ALIGN(rta->rta_len);
295 } else
296 error(1, 0, "unknown keyword %s", argv[arg]);
297 }
298 nest->rta_len = off - nest_start;
299
300 do_nl_req(fd, nh, off, 0);
301 return 0;
302 }
303
del_addr(int fd,int pm_family,int argc,char * argv[])304 int del_addr(int fd, int pm_family, int argc, char *argv[])
305 {
306 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
307 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
308 1024];
309 struct rtattr *rta, *nest;
310 struct nlmsghdr *nh;
311 u_int16_t family;
312 int nest_start;
313 u_int8_t id;
314 int off = 0;
315
316 memset(data, 0, sizeof(data));
317 nh = (void *)data;
318 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_DEL_ADDR,
319 MPTCP_PM_VER);
320
321 /* the only argument is the address id (nonzero) */
322 if (argc != 3 && argc != 4)
323 syntax(argv);
324
325 id = atoi(argv[2]);
326 /* zero id with the IP address */
327 if (!id && argc != 4)
328 syntax(argv);
329
330 nest_start = off;
331 nest = (void *)(data + off);
332 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
333 nest->rta_len = RTA_LENGTH(0);
334 off += NLMSG_ALIGN(nest->rta_len);
335
336 /* build a dummy addr with only the ID set */
337 rta = (void *)(data + off);
338 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
339 rta->rta_len = RTA_LENGTH(1);
340 memcpy(RTA_DATA(rta), &id, 1);
341 off += NLMSG_ALIGN(rta->rta_len);
342
343 if (!id) {
344 /* addr data */
345 rta = (void *)(data + off);
346 if (inet_pton(AF_INET, argv[3], RTA_DATA(rta))) {
347 family = AF_INET;
348 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
349 rta->rta_len = RTA_LENGTH(4);
350 } else if (inet_pton(AF_INET6, argv[3], RTA_DATA(rta))) {
351 family = AF_INET6;
352 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
353 rta->rta_len = RTA_LENGTH(16);
354 } else {
355 error(1, errno, "can't parse ip %s", argv[3]);
356 }
357 off += NLMSG_ALIGN(rta->rta_len);
358
359 /* family */
360 rta = (void *)(data + off);
361 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
362 rta->rta_len = RTA_LENGTH(2);
363 memcpy(RTA_DATA(rta), &family, 2);
364 off += NLMSG_ALIGN(rta->rta_len);
365 }
366 nest->rta_len = off - nest_start;
367
368 do_nl_req(fd, nh, off, 0);
369 return 0;
370 }
371
print_addr(struct rtattr * attrs,int len)372 static void print_addr(struct rtattr *attrs, int len)
373 {
374 uint16_t family = 0;
375 uint16_t port = 0;
376 char str[1024];
377 uint32_t flags;
378 uint8_t id;
379
380 while (RTA_OK(attrs, len)) {
381 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY)
382 memcpy(&family, RTA_DATA(attrs), 2);
383 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT)
384 memcpy(&port, RTA_DATA(attrs), 2);
385 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) {
386 if (family != AF_INET)
387 error(1, errno, "wrong IP (v4) for family %d",
388 family);
389 inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str));
390 printf("%s", str);
391 if (port)
392 printf(" %d", port);
393 }
394 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) {
395 if (family != AF_INET6)
396 error(1, errno, "wrong IP (v6) for family %d",
397 family);
398 inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str));
399 printf("%s", str);
400 if (port)
401 printf(" %d", port);
402 }
403 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) {
404 memcpy(&id, RTA_DATA(attrs), 1);
405 printf("id %d ", id);
406 }
407 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FLAGS) {
408 memcpy(&flags, RTA_DATA(attrs), 4);
409
410 printf("flags ");
411 if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
412 printf("signal");
413 flags &= ~MPTCP_PM_ADDR_FLAG_SIGNAL;
414 if (flags)
415 printf(",");
416 }
417
418 if (flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
419 printf("subflow");
420 flags &= ~MPTCP_PM_ADDR_FLAG_SUBFLOW;
421 if (flags)
422 printf(",");
423 }
424
425 if (flags & MPTCP_PM_ADDR_FLAG_BACKUP) {
426 printf("backup");
427 flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
428 if (flags)
429 printf(",");
430 }
431
432 if (flags & MPTCP_PM_ADDR_FLAG_FULLMESH) {
433 printf("fullmesh");
434 flags &= ~MPTCP_PM_ADDR_FLAG_FULLMESH;
435 if (flags)
436 printf(",");
437 }
438
439 /* bump unknown flags, if any */
440 if (flags)
441 printf("0x%x", flags);
442 printf(" ");
443 }
444 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) {
445 char name[IF_NAMESIZE], *ret;
446 int32_t ifindex;
447
448 memcpy(&ifindex, RTA_DATA(attrs), 4);
449 ret = if_indextoname(ifindex, name);
450 if (ret)
451 printf("dev %s ", ret);
452 else
453 printf("dev unknown/%d", ifindex);
454 }
455
456 attrs = RTA_NEXT(attrs, len);
457 }
458 printf("\n");
459 }
460
print_addrs(struct nlmsghdr * nh,int pm_family,int total_len)461 static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len)
462 {
463 struct rtattr *attrs;
464
465 for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {
466 int len = nh->nlmsg_len;
467
468 if (nh->nlmsg_type == NLMSG_DONE)
469 break;
470 if (nh->nlmsg_type == NLMSG_ERROR)
471 nl_error(nh);
472 if (nh->nlmsg_type != pm_family)
473 continue;
474
475 len -= NLMSG_LENGTH(GENL_HDRLEN);
476 attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +
477 GENL_HDRLEN);
478 while (RTA_OK(attrs, len)) {
479 if (attrs->rta_type ==
480 (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED))
481 print_addr((void *)RTA_DATA(attrs),
482 attrs->rta_len);
483 attrs = RTA_NEXT(attrs, len);
484 }
485 }
486 }
487
get_addr(int fd,int pm_family,int argc,char * argv[])488 int get_addr(int fd, int pm_family, int argc, char *argv[])
489 {
490 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
491 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
492 1024];
493 struct rtattr *rta, *nest;
494 struct nlmsghdr *nh;
495 int nest_start;
496 u_int8_t id;
497 int off = 0;
498
499 memset(data, 0, sizeof(data));
500 nh = (void *)data;
501 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
502 MPTCP_PM_VER);
503
504 /* the only argument is the address id */
505 if (argc != 3)
506 syntax(argv);
507
508 id = atoi(argv[2]);
509
510 nest_start = off;
511 nest = (void *)(data + off);
512 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
513 nest->rta_len = RTA_LENGTH(0);
514 off += NLMSG_ALIGN(nest->rta_len);
515
516 /* build a dummy addr with only the ID set */
517 rta = (void *)(data + off);
518 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID;
519 rta->rta_len = RTA_LENGTH(1);
520 memcpy(RTA_DATA(rta), &id, 1);
521 off += NLMSG_ALIGN(rta->rta_len);
522 nest->rta_len = off - nest_start;
523
524 print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
525 return 0;
526 }
527
dump_addrs(int fd,int pm_family,int argc,char * argv[])528 int dump_addrs(int fd, int pm_family, int argc, char *argv[])
529 {
530 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
531 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
532 1024];
533 pid_t pid = getpid();
534 struct nlmsghdr *nh;
535 int off = 0;
536
537 memset(data, 0, sizeof(data));
538 nh = (void *)data;
539 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR,
540 MPTCP_PM_VER);
541 nh->nlmsg_flags |= NLM_F_DUMP;
542 nh->nlmsg_seq = 1;
543 nh->nlmsg_pid = pid;
544 nh->nlmsg_len = off;
545
546 print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data)));
547 return 0;
548 }
549
flush_addrs(int fd,int pm_family,int argc,char * argv[])550 int flush_addrs(int fd, int pm_family, int argc, char *argv[])
551 {
552 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
553 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
554 1024];
555 struct nlmsghdr *nh;
556 int off = 0;
557
558 memset(data, 0, sizeof(data));
559 nh = (void *)data;
560 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_FLUSH_ADDRS,
561 MPTCP_PM_VER);
562
563 do_nl_req(fd, nh, off, 0);
564 return 0;
565 }
566
print_limits(struct nlmsghdr * nh,int pm_family,int total_len)567 static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len)
568 {
569 struct rtattr *attrs;
570 uint32_t max;
571
572 for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) {
573 int len = nh->nlmsg_len;
574
575 if (nh->nlmsg_type == NLMSG_DONE)
576 break;
577 if (nh->nlmsg_type == NLMSG_ERROR)
578 nl_error(nh);
579 if (nh->nlmsg_type != pm_family)
580 continue;
581
582 len -= NLMSG_LENGTH(GENL_HDRLEN);
583 attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) +
584 GENL_HDRLEN);
585 while (RTA_OK(attrs, len)) {
586 int type = attrs->rta_type;
587
588 if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS &&
589 type != MPTCP_PM_ATTR_SUBFLOWS)
590 goto next;
591
592 memcpy(&max, RTA_DATA(attrs), 4);
593 printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ?
594 "subflows" : "accept", max);
595
596 next:
597 attrs = RTA_NEXT(attrs, len);
598 }
599 }
600 }
601
get_set_limits(int fd,int pm_family,int argc,char * argv[])602 int get_set_limits(int fd, int pm_family, int argc, char *argv[])
603 {
604 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
605 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
606 1024];
607 uint32_t rcv_addr = 0, subflows = 0;
608 int cmd, len = sizeof(data);
609 struct nlmsghdr *nh;
610 int off = 0;
611
612 /* limit */
613 if (argc == 4) {
614 rcv_addr = atoi(argv[2]);
615 subflows = atoi(argv[3]);
616 cmd = MPTCP_PM_CMD_SET_LIMITS;
617 } else {
618 cmd = MPTCP_PM_CMD_GET_LIMITS;
619 }
620
621 memset(data, 0, sizeof(data));
622 nh = (void *)data;
623 off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER);
624
625 /* limit */
626 if (cmd == MPTCP_PM_CMD_SET_LIMITS) {
627 struct rtattr *rta = (void *)(data + off);
628
629 rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS;
630 rta->rta_len = RTA_LENGTH(4);
631 memcpy(RTA_DATA(rta), &rcv_addr, 4);
632 off += NLMSG_ALIGN(rta->rta_len);
633
634 rta = (void *)(data + off);
635 rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS;
636 rta->rta_len = RTA_LENGTH(4);
637 memcpy(RTA_DATA(rta), &subflows, 4);
638 off += NLMSG_ALIGN(rta->rta_len);
639
640 /* do not expect a reply */
641 len = 0;
642 }
643
644 len = do_nl_req(fd, nh, off, len);
645 if (cmd == MPTCP_PM_CMD_GET_LIMITS)
646 print_limits(nh, pm_family, len);
647 return 0;
648 }
649
set_flags(int fd,int pm_family,int argc,char * argv[])650 int set_flags(int fd, int pm_family, int argc, char *argv[])
651 {
652 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
653 NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
654 1024];
655 struct rtattr *rta, *nest;
656 struct nlmsghdr *nh;
657 u_int32_t flags = 0;
658 u_int16_t family;
659 int nest_start;
660 int off = 0;
661 int arg;
662
663 memset(data, 0, sizeof(data));
664 nh = (void *)data;
665 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS,
666 MPTCP_PM_VER);
667
668 if (argc < 3)
669 syntax(argv);
670
671 nest_start = off;
672 nest = (void *)(data + off);
673 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR;
674 nest->rta_len = RTA_LENGTH(0);
675 off += NLMSG_ALIGN(nest->rta_len);
676
677 /* addr data */
678 rta = (void *)(data + off);
679 if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) {
680 family = AF_INET;
681 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
682 rta->rta_len = RTA_LENGTH(4);
683 } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) {
684 family = AF_INET6;
685 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
686 rta->rta_len = RTA_LENGTH(16);
687 } else {
688 error(1, errno, "can't parse ip %s", argv[2]);
689 }
690 off += NLMSG_ALIGN(rta->rta_len);
691
692 /* family */
693 rta = (void *)(data + off);
694 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
695 rta->rta_len = RTA_LENGTH(2);
696 memcpy(RTA_DATA(rta), &family, 2);
697 off += NLMSG_ALIGN(rta->rta_len);
698
699 for (arg = 3; arg < argc; arg++) {
700 if (!strcmp(argv[arg], "flags")) {
701 char *tok, *str;
702
703 /* flags */
704 if (++arg >= argc)
705 error(1, 0, " missing flags value");
706
707 /* do not support flag list yet */
708 for (str = argv[arg]; (tok = strtok(str, ","));
709 str = NULL) {
710 if (!strcmp(tok, "backup"))
711 flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
712 else if (strcmp(tok, "nobackup"))
713 error(1, errno,
714 "unknown flag %s", argv[arg]);
715 }
716
717 rta = (void *)(data + off);
718 rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS;
719 rta->rta_len = RTA_LENGTH(4);
720 memcpy(RTA_DATA(rta), &flags, 4);
721 off += NLMSG_ALIGN(rta->rta_len);
722 } else {
723 error(1, 0, "unknown keyword %s", argv[arg]);
724 }
725 }
726 nest->rta_len = off - nest_start;
727
728 do_nl_req(fd, nh, off, 0);
729 return 0;
730 }
731
main(int argc,char * argv[])732 int main(int argc, char *argv[])
733 {
734 int fd, pm_family;
735
736 if (argc < 2)
737 syntax(argv);
738
739 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
740 if (fd == -1)
741 error(1, errno, "socket netlink");
742
743 pm_family = resolve_mptcp_pm_netlink(fd);
744
745 if (!strcmp(argv[1], "add"))
746 return add_addr(fd, pm_family, argc, argv);
747 else if (!strcmp(argv[1], "del"))
748 return del_addr(fd, pm_family, argc, argv);
749 else if (!strcmp(argv[1], "flush"))
750 return flush_addrs(fd, pm_family, argc, argv);
751 else if (!strcmp(argv[1], "get"))
752 return get_addr(fd, pm_family, argc, argv);
753 else if (!strcmp(argv[1], "dump"))
754 return dump_addrs(fd, pm_family, argc, argv);
755 else if (!strcmp(argv[1], "limits"))
756 return get_set_limits(fd, pm_family, argc, argv);
757 else if (!strcmp(argv[1], "set"))
758 return set_flags(fd, pm_family, argc, argv);
759
760 fprintf(stderr, "unknown sub-command: %s", argv[1]);
761 syntax(argv);
762 return 0;
763 }
764