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