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] [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 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 240 error(1, errno, 241 "unknown flag %s", argv[arg]); 242 } 243 244 rta = (void *)(data + off); 245 rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 246 rta->rta_len = RTA_LENGTH(4); 247 memcpy(RTA_DATA(rta), &flags, 4); 248 off += NLMSG_ALIGN(rta->rta_len); 249 } else if (!strcmp(argv[arg], "id")) { 250 if (++arg >= argc) 251 error(1, 0, " missing id value"); 252 253 id = atoi(argv[arg]); 254 rta = (void *)(data + off); 255 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 256 rta->rta_len = RTA_LENGTH(1); 257 memcpy(RTA_DATA(rta), &id, 1); 258 off += NLMSG_ALIGN(rta->rta_len); 259 } else if (!strcmp(argv[arg], "dev")) { 260 int32_t ifindex; 261 262 if (++arg >= argc) 263 error(1, 0, " missing dev name"); 264 265 ifindex = if_nametoindex(argv[arg]); 266 if (!ifindex) 267 error(1, errno, "unknown device %s", argv[arg]); 268 269 rta = (void *)(data + off); 270 rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX; 271 rta->rta_len = RTA_LENGTH(4); 272 memcpy(RTA_DATA(rta), &ifindex, 4); 273 off += NLMSG_ALIGN(rta->rta_len); 274 } else if (!strcmp(argv[arg], "port")) { 275 u_int16_t port; 276 277 if (++arg >= argc) 278 error(1, 0, " missing port value"); 279 if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) 280 error(1, 0, " flags must be signal when using port"); 281 282 port = atoi(argv[arg]); 283 rta = (void *)(data + off); 284 rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 285 rta->rta_len = RTA_LENGTH(2); 286 memcpy(RTA_DATA(rta), &port, 2); 287 off += NLMSG_ALIGN(rta->rta_len); 288 } else 289 error(1, 0, "unknown keyword %s", argv[arg]); 290 } 291 nest->rta_len = off - nest_start; 292 293 do_nl_req(fd, nh, off, 0); 294 return 0; 295 } 296 297 int del_addr(int fd, int pm_family, int argc, char *argv[]) 298 { 299 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 300 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 301 1024]; 302 struct rtattr *rta, *nest; 303 struct nlmsghdr *nh; 304 u_int16_t family; 305 int nest_start; 306 u_int8_t id; 307 int off = 0; 308 309 memset(data, 0, sizeof(data)); 310 nh = (void *)data; 311 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_DEL_ADDR, 312 MPTCP_PM_VER); 313 314 /* the only argument is the address id (nonzero) */ 315 if (argc != 3 && argc != 4) 316 syntax(argv); 317 318 id = atoi(argv[2]); 319 /* zero id with the IP address */ 320 if (!id && argc != 4) 321 syntax(argv); 322 323 nest_start = off; 324 nest = (void *)(data + off); 325 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 326 nest->rta_len = RTA_LENGTH(0); 327 off += NLMSG_ALIGN(nest->rta_len); 328 329 /* build a dummy addr with only the ID set */ 330 rta = (void *)(data + off); 331 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 332 rta->rta_len = RTA_LENGTH(1); 333 memcpy(RTA_DATA(rta), &id, 1); 334 off += NLMSG_ALIGN(rta->rta_len); 335 336 if (!id) { 337 /* addr data */ 338 rta = (void *)(data + off); 339 if (inet_pton(AF_INET, argv[3], RTA_DATA(rta))) { 340 family = AF_INET; 341 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 342 rta->rta_len = RTA_LENGTH(4); 343 } else if (inet_pton(AF_INET6, argv[3], RTA_DATA(rta))) { 344 family = AF_INET6; 345 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 346 rta->rta_len = RTA_LENGTH(16); 347 } else { 348 error(1, errno, "can't parse ip %s", argv[3]); 349 } 350 off += NLMSG_ALIGN(rta->rta_len); 351 352 /* family */ 353 rta = (void *)(data + off); 354 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 355 rta->rta_len = RTA_LENGTH(2); 356 memcpy(RTA_DATA(rta), &family, 2); 357 off += NLMSG_ALIGN(rta->rta_len); 358 } 359 nest->rta_len = off - nest_start; 360 361 do_nl_req(fd, nh, off, 0); 362 return 0; 363 } 364 365 static void print_addr(struct rtattr *attrs, int len) 366 { 367 uint16_t family = 0; 368 uint16_t port = 0; 369 char str[1024]; 370 uint32_t flags; 371 uint8_t id; 372 373 while (RTA_OK(attrs, len)) { 374 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY) 375 memcpy(&family, RTA_DATA(attrs), 2); 376 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT) 377 memcpy(&port, RTA_DATA(attrs), 2); 378 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) { 379 if (family != AF_INET) 380 error(1, errno, "wrong IP (v4) for family %d", 381 family); 382 inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str)); 383 printf("%s", str); 384 if (port) 385 printf(" %d", port); 386 } 387 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) { 388 if (family != AF_INET6) 389 error(1, errno, "wrong IP (v6) for family %d", 390 family); 391 inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str)); 392 printf("%s", str); 393 if (port) 394 printf(" %d", port); 395 } 396 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) { 397 memcpy(&id, RTA_DATA(attrs), 1); 398 printf("id %d ", id); 399 } 400 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FLAGS) { 401 memcpy(&flags, RTA_DATA(attrs), 4); 402 403 printf("flags "); 404 if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL) { 405 printf("signal"); 406 flags &= ~MPTCP_PM_ADDR_FLAG_SIGNAL; 407 if (flags) 408 printf(","); 409 } 410 411 if (flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { 412 printf("subflow"); 413 flags &= ~MPTCP_PM_ADDR_FLAG_SUBFLOW; 414 if (flags) 415 printf(","); 416 } 417 418 if (flags & MPTCP_PM_ADDR_FLAG_BACKUP) { 419 printf("backup"); 420 flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP; 421 if (flags) 422 printf(","); 423 } 424 425 /* bump unknown flags, if any */ 426 if (flags) 427 printf("0x%x", flags); 428 printf(" "); 429 } 430 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) { 431 char name[IF_NAMESIZE], *ret; 432 int32_t ifindex; 433 434 memcpy(&ifindex, RTA_DATA(attrs), 4); 435 ret = if_indextoname(ifindex, name); 436 if (ret) 437 printf("dev %s ", ret); 438 else 439 printf("dev unknown/%d", ifindex); 440 } 441 442 attrs = RTA_NEXT(attrs, len); 443 } 444 printf("\n"); 445 } 446 447 static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len) 448 { 449 struct rtattr *attrs; 450 451 for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) { 452 int len = nh->nlmsg_len; 453 454 if (nh->nlmsg_type == NLMSG_DONE) 455 break; 456 if (nh->nlmsg_type == NLMSG_ERROR) 457 nl_error(nh); 458 if (nh->nlmsg_type != pm_family) 459 continue; 460 461 len -= NLMSG_LENGTH(GENL_HDRLEN); 462 attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) + 463 GENL_HDRLEN); 464 while (RTA_OK(attrs, len)) { 465 if (attrs->rta_type == 466 (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED)) 467 print_addr((void *)RTA_DATA(attrs), 468 attrs->rta_len); 469 attrs = RTA_NEXT(attrs, len); 470 } 471 } 472 } 473 474 int get_addr(int fd, int pm_family, int argc, char *argv[]) 475 { 476 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 477 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 478 1024]; 479 struct rtattr *rta, *nest; 480 struct nlmsghdr *nh; 481 int nest_start; 482 u_int8_t id; 483 int off = 0; 484 485 memset(data, 0, sizeof(data)); 486 nh = (void *)data; 487 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, 488 MPTCP_PM_VER); 489 490 /* the only argument is the address id */ 491 if (argc != 3) 492 syntax(argv); 493 494 id = atoi(argv[2]); 495 496 nest_start = off; 497 nest = (void *)(data + off); 498 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 499 nest->rta_len = RTA_LENGTH(0); 500 off += NLMSG_ALIGN(nest->rta_len); 501 502 /* build a dummy addr with only the ID set */ 503 rta = (void *)(data + off); 504 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 505 rta->rta_len = RTA_LENGTH(1); 506 memcpy(RTA_DATA(rta), &id, 1); 507 off += NLMSG_ALIGN(rta->rta_len); 508 nest->rta_len = off - nest_start; 509 510 print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); 511 return 0; 512 } 513 514 int dump_addrs(int fd, int pm_family, int argc, char *argv[]) 515 { 516 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 517 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 518 1024]; 519 pid_t pid = getpid(); 520 struct nlmsghdr *nh; 521 int off = 0; 522 523 memset(data, 0, sizeof(data)); 524 nh = (void *)data; 525 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, 526 MPTCP_PM_VER); 527 nh->nlmsg_flags |= NLM_F_DUMP; 528 nh->nlmsg_seq = 1; 529 nh->nlmsg_pid = pid; 530 nh->nlmsg_len = off; 531 532 print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); 533 return 0; 534 } 535 536 int flush_addrs(int fd, int pm_family, int argc, char *argv[]) 537 { 538 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 539 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 540 1024]; 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_FLUSH_ADDRS, 547 MPTCP_PM_VER); 548 549 do_nl_req(fd, nh, off, 0); 550 return 0; 551 } 552 553 static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len) 554 { 555 struct rtattr *attrs; 556 uint32_t max; 557 558 for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) { 559 int len = nh->nlmsg_len; 560 561 if (nh->nlmsg_type == NLMSG_DONE) 562 break; 563 if (nh->nlmsg_type == NLMSG_ERROR) 564 nl_error(nh); 565 if (nh->nlmsg_type != pm_family) 566 continue; 567 568 len -= NLMSG_LENGTH(GENL_HDRLEN); 569 attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) + 570 GENL_HDRLEN); 571 while (RTA_OK(attrs, len)) { 572 int type = attrs->rta_type; 573 574 if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS && 575 type != MPTCP_PM_ATTR_SUBFLOWS) 576 goto next; 577 578 memcpy(&max, RTA_DATA(attrs), 4); 579 printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ? 580 "subflows" : "accept", max); 581 582 next: 583 attrs = RTA_NEXT(attrs, len); 584 } 585 } 586 } 587 588 int get_set_limits(int fd, int pm_family, int argc, char *argv[]) 589 { 590 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 591 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 592 1024]; 593 uint32_t rcv_addr = 0, subflows = 0; 594 int cmd, len = sizeof(data); 595 struct nlmsghdr *nh; 596 int off = 0; 597 598 /* limit */ 599 if (argc == 4) { 600 rcv_addr = atoi(argv[2]); 601 subflows = atoi(argv[3]); 602 cmd = MPTCP_PM_CMD_SET_LIMITS; 603 } else { 604 cmd = MPTCP_PM_CMD_GET_LIMITS; 605 } 606 607 memset(data, 0, sizeof(data)); 608 nh = (void *)data; 609 off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER); 610 611 /* limit */ 612 if (cmd == MPTCP_PM_CMD_SET_LIMITS) { 613 struct rtattr *rta = (void *)(data + off); 614 615 rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS; 616 rta->rta_len = RTA_LENGTH(4); 617 memcpy(RTA_DATA(rta), &rcv_addr, 4); 618 off += NLMSG_ALIGN(rta->rta_len); 619 620 rta = (void *)(data + off); 621 rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS; 622 rta->rta_len = RTA_LENGTH(4); 623 memcpy(RTA_DATA(rta), &subflows, 4); 624 off += NLMSG_ALIGN(rta->rta_len); 625 626 /* do not expect a reply */ 627 len = 0; 628 } 629 630 len = do_nl_req(fd, nh, off, len); 631 if (cmd == MPTCP_PM_CMD_GET_LIMITS) 632 print_limits(nh, pm_family, len); 633 return 0; 634 } 635 636 int set_flags(int fd, int pm_family, int argc, char *argv[]) 637 { 638 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 639 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 640 1024]; 641 struct rtattr *rta, *nest; 642 struct nlmsghdr *nh; 643 u_int32_t flags = 0; 644 u_int16_t family; 645 int nest_start; 646 int off = 0; 647 int arg; 648 649 memset(data, 0, sizeof(data)); 650 nh = (void *)data; 651 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS, 652 MPTCP_PM_VER); 653 654 if (argc < 3) 655 syntax(argv); 656 657 nest_start = off; 658 nest = (void *)(data + off); 659 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 660 nest->rta_len = RTA_LENGTH(0); 661 off += NLMSG_ALIGN(nest->rta_len); 662 663 /* addr data */ 664 rta = (void *)(data + off); 665 if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) { 666 family = AF_INET; 667 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 668 rta->rta_len = RTA_LENGTH(4); 669 } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) { 670 family = AF_INET6; 671 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 672 rta->rta_len = RTA_LENGTH(16); 673 } else { 674 error(1, errno, "can't parse ip %s", argv[2]); 675 } 676 off += NLMSG_ALIGN(rta->rta_len); 677 678 /* family */ 679 rta = (void *)(data + off); 680 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 681 rta->rta_len = RTA_LENGTH(2); 682 memcpy(RTA_DATA(rta), &family, 2); 683 off += NLMSG_ALIGN(rta->rta_len); 684 685 for (arg = 3; arg < argc; arg++) { 686 if (!strcmp(argv[arg], "flags")) { 687 char *tok, *str; 688 689 /* flags */ 690 if (++arg >= argc) 691 error(1, 0, " missing flags value"); 692 693 /* do not support flag list yet */ 694 for (str = argv[arg]; (tok = strtok(str, ",")); 695 str = NULL) { 696 if (!strcmp(tok, "backup")) 697 flags |= MPTCP_PM_ADDR_FLAG_BACKUP; 698 else if (strcmp(tok, "nobackup")) 699 error(1, errno, 700 "unknown flag %s", argv[arg]); 701 } 702 703 rta = (void *)(data + off); 704 rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 705 rta->rta_len = RTA_LENGTH(4); 706 memcpy(RTA_DATA(rta), &flags, 4); 707 off += NLMSG_ALIGN(rta->rta_len); 708 } else { 709 error(1, 0, "unknown keyword %s", argv[arg]); 710 } 711 } 712 nest->rta_len = off - nest_start; 713 714 do_nl_req(fd, nh, off, 0); 715 return 0; 716 } 717 718 int main(int argc, char *argv[]) 719 { 720 int fd, pm_family; 721 722 if (argc < 2) 723 syntax(argv); 724 725 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 726 if (fd == -1) 727 error(1, errno, "socket netlink"); 728 729 pm_family = resolve_mptcp_pm_netlink(fd); 730 731 if (!strcmp(argv[1], "add")) 732 return add_addr(fd, pm_family, argc, argv); 733 else if (!strcmp(argv[1], "del")) 734 return del_addr(fd, pm_family, argc, argv); 735 else if (!strcmp(argv[1], "flush")) 736 return flush_addrs(fd, pm_family, argc, argv); 737 else if (!strcmp(argv[1], "get")) 738 return get_addr(fd, pm_family, argc, argv); 739 else if (!strcmp(argv[1], "dump")) 740 return dump_addrs(fd, pm_family, argc, argv); 741 else if (!strcmp(argv[1], "limits")) 742 return get_set_limits(fd, pm_family, argc, argv); 743 else if (!strcmp(argv[1], "set")) 744 return set_flags(fd, pm_family, argc, argv); 745 746 fprintf(stderr, "unknown sub-command: %s", argv[1]); 747 syntax(argv); 748 return 0; 749 } 750