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> [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 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 /* 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 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 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 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 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 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 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 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 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