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 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>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>]\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 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 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 */ 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 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 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 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 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 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 if (flags & MPTCP_PM_ADDR_FLAG_IMPLICIT) { 440 printf("implicit"); 441 flags &= ~MPTCP_PM_ADDR_FLAG_IMPLICIT; 442 if (flags) 443 printf(","); 444 } 445 446 /* bump unknown flags, if any */ 447 if (flags) 448 printf("0x%x", flags); 449 printf(" "); 450 } 451 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) { 452 char name[IF_NAMESIZE], *ret; 453 int32_t ifindex; 454 455 memcpy(&ifindex, RTA_DATA(attrs), 4); 456 ret = if_indextoname(ifindex, name); 457 if (ret) 458 printf("dev %s ", ret); 459 else 460 printf("dev unknown/%d", ifindex); 461 } 462 463 attrs = RTA_NEXT(attrs, len); 464 } 465 printf("\n"); 466 } 467 468 static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len) 469 { 470 struct rtattr *attrs; 471 472 for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) { 473 int len = nh->nlmsg_len; 474 475 if (nh->nlmsg_type == NLMSG_DONE) 476 break; 477 if (nh->nlmsg_type == NLMSG_ERROR) 478 nl_error(nh); 479 if (nh->nlmsg_type != pm_family) 480 continue; 481 482 len -= NLMSG_LENGTH(GENL_HDRLEN); 483 attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) + 484 GENL_HDRLEN); 485 while (RTA_OK(attrs, len)) { 486 if (attrs->rta_type == 487 (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED)) 488 print_addr((void *)RTA_DATA(attrs), 489 attrs->rta_len); 490 attrs = RTA_NEXT(attrs, len); 491 } 492 } 493 } 494 495 int get_addr(int fd, int pm_family, int argc, char *argv[]) 496 { 497 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 498 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 499 1024]; 500 struct rtattr *rta, *nest; 501 struct nlmsghdr *nh; 502 int nest_start; 503 u_int8_t id; 504 int off = 0; 505 506 memset(data, 0, sizeof(data)); 507 nh = (void *)data; 508 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, 509 MPTCP_PM_VER); 510 511 /* the only argument is the address id */ 512 if (argc != 3) 513 syntax(argv); 514 515 id = atoi(argv[2]); 516 517 nest_start = off; 518 nest = (void *)(data + off); 519 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 520 nest->rta_len = RTA_LENGTH(0); 521 off += NLMSG_ALIGN(nest->rta_len); 522 523 /* build a dummy addr with only the ID set */ 524 rta = (void *)(data + off); 525 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 526 rta->rta_len = RTA_LENGTH(1); 527 memcpy(RTA_DATA(rta), &id, 1); 528 off += NLMSG_ALIGN(rta->rta_len); 529 nest->rta_len = off - nest_start; 530 531 print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); 532 return 0; 533 } 534 535 int dump_addrs(int fd, int pm_family, int argc, char *argv[]) 536 { 537 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 538 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 539 1024]; 540 pid_t pid = getpid(); 541 struct nlmsghdr *nh; 542 int off = 0; 543 544 memset(data, 0, sizeof(data)); 545 nh = (void *)data; 546 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, 547 MPTCP_PM_VER); 548 nh->nlmsg_flags |= NLM_F_DUMP; 549 nh->nlmsg_seq = 1; 550 nh->nlmsg_pid = pid; 551 nh->nlmsg_len = off; 552 553 print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); 554 return 0; 555 } 556 557 int flush_addrs(int fd, int pm_family, int argc, char *argv[]) 558 { 559 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 560 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 561 1024]; 562 struct nlmsghdr *nh; 563 int off = 0; 564 565 memset(data, 0, sizeof(data)); 566 nh = (void *)data; 567 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_FLUSH_ADDRS, 568 MPTCP_PM_VER); 569 570 do_nl_req(fd, nh, off, 0); 571 return 0; 572 } 573 574 static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len) 575 { 576 struct rtattr *attrs; 577 uint32_t max; 578 579 for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) { 580 int len = nh->nlmsg_len; 581 582 if (nh->nlmsg_type == NLMSG_DONE) 583 break; 584 if (nh->nlmsg_type == NLMSG_ERROR) 585 nl_error(nh); 586 if (nh->nlmsg_type != pm_family) 587 continue; 588 589 len -= NLMSG_LENGTH(GENL_HDRLEN); 590 attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) + 591 GENL_HDRLEN); 592 while (RTA_OK(attrs, len)) { 593 int type = attrs->rta_type; 594 595 if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS && 596 type != MPTCP_PM_ATTR_SUBFLOWS) 597 goto next; 598 599 memcpy(&max, RTA_DATA(attrs), 4); 600 printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ? 601 "subflows" : "accept", max); 602 603 next: 604 attrs = RTA_NEXT(attrs, len); 605 } 606 } 607 } 608 609 int get_set_limits(int fd, int pm_family, int argc, char *argv[]) 610 { 611 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 612 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 613 1024]; 614 uint32_t rcv_addr = 0, subflows = 0; 615 int cmd, len = sizeof(data); 616 struct nlmsghdr *nh; 617 int off = 0; 618 619 /* limit */ 620 if (argc == 4) { 621 rcv_addr = atoi(argv[2]); 622 subflows = atoi(argv[3]); 623 cmd = MPTCP_PM_CMD_SET_LIMITS; 624 } else { 625 cmd = MPTCP_PM_CMD_GET_LIMITS; 626 } 627 628 memset(data, 0, sizeof(data)); 629 nh = (void *)data; 630 off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER); 631 632 /* limit */ 633 if (cmd == MPTCP_PM_CMD_SET_LIMITS) { 634 struct rtattr *rta = (void *)(data + off); 635 636 rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS; 637 rta->rta_len = RTA_LENGTH(4); 638 memcpy(RTA_DATA(rta), &rcv_addr, 4); 639 off += NLMSG_ALIGN(rta->rta_len); 640 641 rta = (void *)(data + off); 642 rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS; 643 rta->rta_len = RTA_LENGTH(4); 644 memcpy(RTA_DATA(rta), &subflows, 4); 645 off += NLMSG_ALIGN(rta->rta_len); 646 647 /* do not expect a reply */ 648 len = 0; 649 } 650 651 len = do_nl_req(fd, nh, off, len); 652 if (cmd == MPTCP_PM_CMD_GET_LIMITS) 653 print_limits(nh, pm_family, len); 654 return 0; 655 } 656 657 int set_flags(int fd, int pm_family, int argc, char *argv[]) 658 { 659 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 660 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 661 1024]; 662 struct rtattr *rta, *nest; 663 struct nlmsghdr *nh; 664 u_int32_t flags = 0; 665 u_int16_t family; 666 int nest_start; 667 int use_id = 0; 668 u_int8_t id; 669 int off = 0; 670 int arg = 2; 671 672 memset(data, 0, sizeof(data)); 673 nh = (void *)data; 674 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS, 675 MPTCP_PM_VER); 676 677 if (argc < 3) 678 syntax(argv); 679 680 nest_start = off; 681 nest = (void *)(data + off); 682 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 683 nest->rta_len = RTA_LENGTH(0); 684 off += NLMSG_ALIGN(nest->rta_len); 685 686 if (!strcmp(argv[arg], "id")) { 687 if (++arg >= argc) 688 error(1, 0, " missing id value"); 689 690 use_id = 1; 691 id = atoi(argv[arg]); 692 rta = (void *)(data + off); 693 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 694 rta->rta_len = RTA_LENGTH(1); 695 memcpy(RTA_DATA(rta), &id, 1); 696 off += NLMSG_ALIGN(rta->rta_len); 697 } else { 698 /* addr data */ 699 rta = (void *)(data + off); 700 if (inet_pton(AF_INET, argv[arg], RTA_DATA(rta))) { 701 family = AF_INET; 702 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 703 rta->rta_len = RTA_LENGTH(4); 704 } else if (inet_pton(AF_INET6, argv[arg], RTA_DATA(rta))) { 705 family = AF_INET6; 706 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 707 rta->rta_len = RTA_LENGTH(16); 708 } else { 709 error(1, errno, "can't parse ip %s", argv[arg]); 710 } 711 off += NLMSG_ALIGN(rta->rta_len); 712 713 /* family */ 714 rta = (void *)(data + off); 715 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 716 rta->rta_len = RTA_LENGTH(2); 717 memcpy(RTA_DATA(rta), &family, 2); 718 off += NLMSG_ALIGN(rta->rta_len); 719 } 720 721 if (++arg >= argc) 722 error(1, 0, " missing flags keyword"); 723 724 for (; arg < argc; arg++) { 725 if (!strcmp(argv[arg], "flags")) { 726 char *tok, *str; 727 728 /* flags */ 729 if (++arg >= argc) 730 error(1, 0, " missing flags value"); 731 732 for (str = argv[arg]; (tok = strtok(str, ",")); 733 str = NULL) { 734 if (!strcmp(tok, "backup")) 735 flags |= MPTCP_PM_ADDR_FLAG_BACKUP; 736 else if (!strcmp(tok, "fullmesh")) 737 flags |= MPTCP_PM_ADDR_FLAG_FULLMESH; 738 else if (strcmp(tok, "nobackup") && 739 strcmp(tok, "nofullmesh")) 740 error(1, errno, 741 "unknown flag %s", argv[arg]); 742 } 743 744 rta = (void *)(data + off); 745 rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 746 rta->rta_len = RTA_LENGTH(4); 747 memcpy(RTA_DATA(rta), &flags, 4); 748 off += NLMSG_ALIGN(rta->rta_len); 749 } else if (!strcmp(argv[arg], "port")) { 750 u_int16_t port; 751 752 if (use_id) 753 error(1, 0, " port can't be used with id"); 754 755 if (++arg >= argc) 756 error(1, 0, " missing port value"); 757 758 port = atoi(argv[arg]); 759 rta = (void *)(data + off); 760 rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 761 rta->rta_len = RTA_LENGTH(2); 762 memcpy(RTA_DATA(rta), &port, 2); 763 off += NLMSG_ALIGN(rta->rta_len); 764 } else { 765 error(1, 0, "unknown keyword %s", argv[arg]); 766 } 767 } 768 nest->rta_len = off - nest_start; 769 770 do_nl_req(fd, nh, off, 0); 771 return 0; 772 } 773 774 int main(int argc, char *argv[]) 775 { 776 int fd, pm_family; 777 778 if (argc < 2) 779 syntax(argv); 780 781 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 782 if (fd == -1) 783 error(1, errno, "socket netlink"); 784 785 pm_family = resolve_mptcp_pm_netlink(fd); 786 787 if (!strcmp(argv[1], "add")) 788 return add_addr(fd, pm_family, argc, argv); 789 else if (!strcmp(argv[1], "del")) 790 return del_addr(fd, pm_family, argc, argv); 791 else if (!strcmp(argv[1], "flush")) 792 return flush_addrs(fd, pm_family, argc, argv); 793 else if (!strcmp(argv[1], "get")) 794 return get_addr(fd, pm_family, argc, argv); 795 else if (!strcmp(argv[1], "dump")) 796 return dump_addrs(fd, pm_family, argc, argv); 797 else if (!strcmp(argv[1], "limits")) 798 return get_set_limits(fd, pm_family, argc, argv); 799 else if (!strcmp(argv[1], "set")) 800 return set_flags(fd, pm_family, argc, argv); 801 802 fprintf(stderr, "unknown sub-command: %s", argv[1]); 803 syntax(argv); 804 return 0; 805 } 806