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 #include <limits.h> 10 11 #include <sys/socket.h> 12 #include <sys/types.h> 13 14 #include <arpa/inet.h> 15 #include <net/if.h> 16 17 #include <linux/rtnetlink.h> 18 #include <linux/genetlink.h> 19 20 #include "linux/mptcp.h" 21 22 #ifndef MPTCP_PM_NAME 23 #define MPTCP_PM_NAME "mptcp_pm" 24 #endif 25 26 static void syntax(char *argv[]) 27 { 28 fprintf(stderr, "%s add|get|set|del|flush|dump|accept [<args>]\n", argv[0]); 29 fprintf(stderr, "\tadd [flags signal|subflow|backup|fullmesh] [id <nr>] [dev <name>] <ip>\n"); 30 fprintf(stderr, "\tann <local-ip> id <local-id> token <token> [port <local-port>] [dev <name>]\n"); 31 fprintf(stderr, "\trem id <local-id> token <token>\n"); 32 fprintf(stderr, "\tdel <id> [<ip>]\n"); 33 fprintf(stderr, "\tget <id>\n"); 34 fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>]\n"); 35 fprintf(stderr, "\tflush\n"); 36 fprintf(stderr, "\tdump\n"); 37 fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n"); 38 exit(0); 39 } 40 41 static int init_genl_req(char *data, int family, int cmd, int version) 42 { 43 struct nlmsghdr *nh = (void *)data; 44 struct genlmsghdr *gh; 45 int off = 0; 46 47 nh->nlmsg_type = family; 48 nh->nlmsg_flags = NLM_F_REQUEST; 49 nh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); 50 off += NLMSG_ALIGN(sizeof(*nh)); 51 52 gh = (void *)(data + off); 53 gh->cmd = cmd; 54 gh->version = version; 55 off += NLMSG_ALIGN(sizeof(*gh)); 56 return off; 57 } 58 59 static void nl_error(struct nlmsghdr *nh) 60 { 61 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh); 62 int len = nh->nlmsg_len - sizeof(*nh); 63 uint32_t off; 64 65 if (len < sizeof(struct nlmsgerr)) 66 error(1, 0, "netlink error message truncated %d min %ld", len, 67 sizeof(struct nlmsgerr)); 68 69 if (!err->error) { 70 /* check messages from kernel */ 71 struct rtattr *attrs = (struct rtattr *)NLMSG_DATA(nh); 72 73 while (RTA_OK(attrs, len)) { 74 if (attrs->rta_type == NLMSGERR_ATTR_MSG) 75 fprintf(stderr, "netlink ext ack msg: %s\n", 76 (char *)RTA_DATA(attrs)); 77 if (attrs->rta_type == NLMSGERR_ATTR_OFFS) { 78 memcpy(&off, RTA_DATA(attrs), 4); 79 fprintf(stderr, "netlink err off %d\n", 80 (int)off); 81 } 82 attrs = RTA_NEXT(attrs, len); 83 } 84 } else { 85 fprintf(stderr, "netlink error %d", err->error); 86 } 87 } 88 89 /* do a netlink command and, if max > 0, fetch the reply */ 90 static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max) 91 { 92 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 93 socklen_t addr_len; 94 void *data = nh; 95 int rem, ret; 96 int err = 0; 97 98 nh->nlmsg_len = len; 99 ret = sendto(fd, data, len, 0, (void *)&nladdr, sizeof(nladdr)); 100 if (ret != len) 101 error(1, errno, "send netlink: %uB != %uB\n", ret, len); 102 if (max == 0) 103 return 0; 104 105 addr_len = sizeof(nladdr); 106 rem = ret = recvfrom(fd, data, max, 0, (void *)&nladdr, &addr_len); 107 if (ret < 0) 108 error(1, errno, "recv netlink: %uB\n", ret); 109 110 /* Beware: the NLMSG_NEXT macro updates the 'rem' argument */ 111 for (; NLMSG_OK(nh, rem); nh = NLMSG_NEXT(nh, rem)) { 112 if (nh->nlmsg_type == NLMSG_ERROR) { 113 nl_error(nh); 114 err = 1; 115 } 116 } 117 if (err) 118 error(1, 0, "bailing out due to netlink error[s]"); 119 return ret; 120 } 121 122 static int genl_parse_getfamily(struct nlmsghdr *nlh) 123 { 124 struct genlmsghdr *ghdr = NLMSG_DATA(nlh); 125 int len = nlh->nlmsg_len; 126 struct rtattr *attrs; 127 128 if (nlh->nlmsg_type != GENL_ID_CTRL) 129 error(1, errno, "Not a controller message, len=%d type=0x%x\n", 130 nlh->nlmsg_len, nlh->nlmsg_type); 131 132 len -= NLMSG_LENGTH(GENL_HDRLEN); 133 134 if (len < 0) 135 error(1, errno, "wrong controller message len %d\n", len); 136 137 if (ghdr->cmd != CTRL_CMD_NEWFAMILY) 138 error(1, errno, "Unknown controller command %d\n", ghdr->cmd); 139 140 attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); 141 while (RTA_OK(attrs, len)) { 142 if (attrs->rta_type == CTRL_ATTR_FAMILY_ID) 143 return *(__u16 *)RTA_DATA(attrs); 144 attrs = RTA_NEXT(attrs, len); 145 } 146 147 error(1, errno, "can't find CTRL_ATTR_FAMILY_ID attr"); 148 return -1; 149 } 150 151 static int resolve_mptcp_pm_netlink(int fd) 152 { 153 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 154 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 155 1024]; 156 struct nlmsghdr *nh; 157 struct rtattr *rta; 158 int namelen; 159 int off = 0; 160 161 memset(data, 0, sizeof(data)); 162 nh = (void *)data; 163 off = init_genl_req(data, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 0); 164 165 rta = (void *)(data + off); 166 namelen = strlen(MPTCP_PM_NAME) + 1; 167 rta->rta_type = CTRL_ATTR_FAMILY_NAME; 168 rta->rta_len = RTA_LENGTH(namelen); 169 memcpy(RTA_DATA(rta), MPTCP_PM_NAME, namelen); 170 off += NLMSG_ALIGN(rta->rta_len); 171 172 do_nl_req(fd, nh, off, sizeof(data)); 173 return genl_parse_getfamily((void *)data); 174 } 175 176 int remove_addr(int fd, int pm_family, int argc, char *argv[]) 177 { 178 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 179 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 180 1024]; 181 struct nlmsghdr *nh; 182 struct rtattr *rta; 183 u_int32_t token; 184 u_int8_t id; 185 int off = 0; 186 int arg; 187 188 memset(data, 0, sizeof(data)); 189 nh = (void *)data; 190 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_REMOVE, 191 MPTCP_PM_VER); 192 193 if (argc < 6) 194 syntax(argv); 195 196 for (arg = 2; arg < argc; arg++) { 197 if (!strcmp(argv[arg], "id")) { 198 if (++arg >= argc) 199 error(1, 0, " missing id value"); 200 201 id = atoi(argv[arg]); 202 rta = (void *)(data + off); 203 rta->rta_type = MPTCP_PM_ATTR_LOC_ID; 204 rta->rta_len = RTA_LENGTH(1); 205 memcpy(RTA_DATA(rta), &id, 1); 206 off += NLMSG_ALIGN(rta->rta_len); 207 } else if (!strcmp(argv[arg], "token")) { 208 if (++arg >= argc) 209 error(1, 0, " missing token value"); 210 211 token = atoi(argv[arg]); 212 rta = (void *)(data + off); 213 rta->rta_type = MPTCP_PM_ATTR_TOKEN; 214 rta->rta_len = RTA_LENGTH(4); 215 memcpy(RTA_DATA(rta), &token, 4); 216 off += NLMSG_ALIGN(rta->rta_len); 217 } else 218 error(1, 0, "unknown keyword %s", argv[arg]); 219 } 220 221 do_nl_req(fd, nh, off, 0); 222 return 0; 223 } 224 225 int announce_addr(int fd, int pm_family, int argc, char *argv[]) 226 { 227 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 228 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 229 1024]; 230 u_int32_t flags = MPTCP_PM_ADDR_FLAG_SIGNAL; 231 u_int32_t token = UINT_MAX; 232 struct rtattr *rta, *addr; 233 u_int32_t id = UINT_MAX; 234 struct nlmsghdr *nh; 235 u_int16_t family; 236 int addr_start; 237 int off = 0; 238 int arg; 239 240 memset(data, 0, sizeof(data)); 241 nh = (void *)data; 242 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ANNOUNCE, 243 MPTCP_PM_VER); 244 245 if (argc < 7) 246 syntax(argv); 247 248 /* local-ip header */ 249 addr_start = off; 250 addr = (void *)(data + off); 251 addr->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 252 addr->rta_len = RTA_LENGTH(0); 253 off += NLMSG_ALIGN(addr->rta_len); 254 255 /* local-ip data */ 256 /* record addr type */ 257 rta = (void *)(data + off); 258 if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) { 259 family = AF_INET; 260 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 261 rta->rta_len = RTA_LENGTH(4); 262 } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) { 263 family = AF_INET6; 264 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 265 rta->rta_len = RTA_LENGTH(16); 266 } else 267 error(1, errno, "can't parse ip %s", argv[2]); 268 off += NLMSG_ALIGN(rta->rta_len); 269 270 /* addr family */ 271 rta = (void *)(data + off); 272 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 273 rta->rta_len = RTA_LENGTH(2); 274 memcpy(RTA_DATA(rta), &family, 2); 275 off += NLMSG_ALIGN(rta->rta_len); 276 277 for (arg = 3; arg < argc; arg++) { 278 if (!strcmp(argv[arg], "id")) { 279 /* local-id */ 280 if (++arg >= argc) 281 error(1, 0, " missing id value"); 282 283 id = atoi(argv[arg]); 284 rta = (void *)(data + off); 285 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 286 rta->rta_len = RTA_LENGTH(1); 287 memcpy(RTA_DATA(rta), &id, 1); 288 off += NLMSG_ALIGN(rta->rta_len); 289 } else if (!strcmp(argv[arg], "dev")) { 290 /* for the if_index */ 291 int32_t ifindex; 292 293 if (++arg >= argc) 294 error(1, 0, " missing dev name"); 295 296 ifindex = if_nametoindex(argv[arg]); 297 if (!ifindex) 298 error(1, errno, "unknown device %s", argv[arg]); 299 300 rta = (void *)(data + off); 301 rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX; 302 rta->rta_len = RTA_LENGTH(4); 303 memcpy(RTA_DATA(rta), &ifindex, 4); 304 off += NLMSG_ALIGN(rta->rta_len); 305 } else if (!strcmp(argv[arg], "port")) { 306 /* local-port (optional) */ 307 u_int16_t port; 308 309 if (++arg >= argc) 310 error(1, 0, " missing port value"); 311 312 port = atoi(argv[arg]); 313 rta = (void *)(data + off); 314 rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 315 rta->rta_len = RTA_LENGTH(2); 316 memcpy(RTA_DATA(rta), &port, 2); 317 off += NLMSG_ALIGN(rta->rta_len); 318 } else if (!strcmp(argv[arg], "token")) { 319 /* MPTCP connection token */ 320 if (++arg >= argc) 321 error(1, 0, " missing token value"); 322 323 token = atoi(argv[arg]); 324 } else 325 error(1, 0, "unknown keyword %s", argv[arg]); 326 } 327 328 /* addr flags */ 329 rta = (void *)(data + off); 330 rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 331 rta->rta_len = RTA_LENGTH(4); 332 memcpy(RTA_DATA(rta), &flags, 4); 333 off += NLMSG_ALIGN(rta->rta_len); 334 335 addr->rta_len = off - addr_start; 336 337 if (id == UINT_MAX || token == UINT_MAX) 338 error(1, 0, " missing mandatory inputs"); 339 340 /* token */ 341 rta = (void *)(data + off); 342 rta->rta_type = MPTCP_PM_ATTR_TOKEN; 343 rta->rta_len = RTA_LENGTH(4); 344 memcpy(RTA_DATA(rta), &token, 4); 345 off += NLMSG_ALIGN(rta->rta_len); 346 347 do_nl_req(fd, nh, off, 0); 348 349 return 0; 350 } 351 352 int add_addr(int fd, int pm_family, int argc, char *argv[]) 353 { 354 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 355 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 356 1024]; 357 struct rtattr *rta, *nest; 358 struct nlmsghdr *nh; 359 u_int32_t flags = 0; 360 u_int16_t family; 361 int nest_start; 362 u_int8_t id; 363 int off = 0; 364 int arg; 365 366 memset(data, 0, sizeof(data)); 367 nh = (void *)data; 368 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_ADD_ADDR, 369 MPTCP_PM_VER); 370 371 if (argc < 3) 372 syntax(argv); 373 374 nest_start = off; 375 nest = (void *)(data + off); 376 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 377 nest->rta_len = RTA_LENGTH(0); 378 off += NLMSG_ALIGN(nest->rta_len); 379 380 /* addr data */ 381 rta = (void *)(data + off); 382 if (inet_pton(AF_INET, argv[2], RTA_DATA(rta))) { 383 family = AF_INET; 384 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 385 rta->rta_len = RTA_LENGTH(4); 386 } else if (inet_pton(AF_INET6, argv[2], RTA_DATA(rta))) { 387 family = AF_INET6; 388 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 389 rta->rta_len = RTA_LENGTH(16); 390 } else 391 error(1, errno, "can't parse ip %s", argv[2]); 392 off += NLMSG_ALIGN(rta->rta_len); 393 394 /* family */ 395 rta = (void *)(data + off); 396 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 397 rta->rta_len = RTA_LENGTH(2); 398 memcpy(RTA_DATA(rta), &family, 2); 399 off += NLMSG_ALIGN(rta->rta_len); 400 401 for (arg = 3; arg < argc; arg++) { 402 if (!strcmp(argv[arg], "flags")) { 403 char *tok, *str; 404 405 /* flags */ 406 if (++arg >= argc) 407 error(1, 0, " missing flags value"); 408 409 /* do not support flag list yet */ 410 for (str = argv[arg]; (tok = strtok(str, ",")); 411 str = NULL) { 412 if (!strcmp(tok, "subflow")) 413 flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW; 414 else if (!strcmp(tok, "signal")) 415 flags |= MPTCP_PM_ADDR_FLAG_SIGNAL; 416 else if (!strcmp(tok, "backup")) 417 flags |= MPTCP_PM_ADDR_FLAG_BACKUP; 418 else if (!strcmp(tok, "fullmesh")) 419 flags |= MPTCP_PM_ADDR_FLAG_FULLMESH; 420 else 421 error(1, errno, 422 "unknown flag %s", argv[arg]); 423 } 424 425 if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL && 426 flags & MPTCP_PM_ADDR_FLAG_FULLMESH) { 427 error(1, errno, "error flag fullmesh"); 428 } 429 430 rta = (void *)(data + off); 431 rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 432 rta->rta_len = RTA_LENGTH(4); 433 memcpy(RTA_DATA(rta), &flags, 4); 434 off += NLMSG_ALIGN(rta->rta_len); 435 } else if (!strcmp(argv[arg], "id")) { 436 if (++arg >= argc) 437 error(1, 0, " missing id value"); 438 439 id = atoi(argv[arg]); 440 rta = (void *)(data + off); 441 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 442 rta->rta_len = RTA_LENGTH(1); 443 memcpy(RTA_DATA(rta), &id, 1); 444 off += NLMSG_ALIGN(rta->rta_len); 445 } else if (!strcmp(argv[arg], "dev")) { 446 int32_t ifindex; 447 448 if (++arg >= argc) 449 error(1, 0, " missing dev name"); 450 451 ifindex = if_nametoindex(argv[arg]); 452 if (!ifindex) 453 error(1, errno, "unknown device %s", argv[arg]); 454 455 rta = (void *)(data + off); 456 rta->rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX; 457 rta->rta_len = RTA_LENGTH(4); 458 memcpy(RTA_DATA(rta), &ifindex, 4); 459 off += NLMSG_ALIGN(rta->rta_len); 460 } else if (!strcmp(argv[arg], "port")) { 461 u_int16_t port; 462 463 if (++arg >= argc) 464 error(1, 0, " missing port value"); 465 if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) 466 error(1, 0, " flags must be signal when using port"); 467 468 port = atoi(argv[arg]); 469 rta = (void *)(data + off); 470 rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 471 rta->rta_len = RTA_LENGTH(2); 472 memcpy(RTA_DATA(rta), &port, 2); 473 off += NLMSG_ALIGN(rta->rta_len); 474 } else 475 error(1, 0, "unknown keyword %s", argv[arg]); 476 } 477 nest->rta_len = off - nest_start; 478 479 do_nl_req(fd, nh, off, 0); 480 return 0; 481 } 482 483 int del_addr(int fd, int pm_family, int argc, char *argv[]) 484 { 485 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 486 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 487 1024]; 488 struct rtattr *rta, *nest; 489 struct nlmsghdr *nh; 490 u_int16_t family; 491 int nest_start; 492 u_int8_t id; 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_DEL_ADDR, 498 MPTCP_PM_VER); 499 500 /* the only argument is the address id (nonzero) */ 501 if (argc != 3 && argc != 4) 502 syntax(argv); 503 504 id = atoi(argv[2]); 505 /* zero id with the IP address */ 506 if (!id && argc != 4) 507 syntax(argv); 508 509 nest_start = off; 510 nest = (void *)(data + off); 511 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 512 nest->rta_len = RTA_LENGTH(0); 513 off += NLMSG_ALIGN(nest->rta_len); 514 515 /* build a dummy addr with only the ID set */ 516 rta = (void *)(data + off); 517 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 518 rta->rta_len = RTA_LENGTH(1); 519 memcpy(RTA_DATA(rta), &id, 1); 520 off += NLMSG_ALIGN(rta->rta_len); 521 522 if (!id) { 523 /* addr data */ 524 rta = (void *)(data + off); 525 if (inet_pton(AF_INET, argv[3], RTA_DATA(rta))) { 526 family = AF_INET; 527 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 528 rta->rta_len = RTA_LENGTH(4); 529 } else if (inet_pton(AF_INET6, argv[3], RTA_DATA(rta))) { 530 family = AF_INET6; 531 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 532 rta->rta_len = RTA_LENGTH(16); 533 } else { 534 error(1, errno, "can't parse ip %s", argv[3]); 535 } 536 off += NLMSG_ALIGN(rta->rta_len); 537 538 /* family */ 539 rta = (void *)(data + off); 540 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 541 rta->rta_len = RTA_LENGTH(2); 542 memcpy(RTA_DATA(rta), &family, 2); 543 off += NLMSG_ALIGN(rta->rta_len); 544 } 545 nest->rta_len = off - nest_start; 546 547 do_nl_req(fd, nh, off, 0); 548 return 0; 549 } 550 551 static void print_addr(struct rtattr *attrs, int len) 552 { 553 uint16_t family = 0; 554 uint16_t port = 0; 555 char str[1024]; 556 uint32_t flags; 557 uint8_t id; 558 559 while (RTA_OK(attrs, len)) { 560 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY) 561 memcpy(&family, RTA_DATA(attrs), 2); 562 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT) 563 memcpy(&port, RTA_DATA(attrs), 2); 564 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) { 565 if (family != AF_INET) 566 error(1, errno, "wrong IP (v4) for family %d", 567 family); 568 inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str)); 569 printf("%s", str); 570 if (port) 571 printf(" %d", port); 572 } 573 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) { 574 if (family != AF_INET6) 575 error(1, errno, "wrong IP (v6) for family %d", 576 family); 577 inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str)); 578 printf("%s", str); 579 if (port) 580 printf(" %d", port); 581 } 582 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) { 583 memcpy(&id, RTA_DATA(attrs), 1); 584 printf("id %d ", id); 585 } 586 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FLAGS) { 587 memcpy(&flags, RTA_DATA(attrs), 4); 588 589 printf("flags "); 590 if (flags & MPTCP_PM_ADDR_FLAG_SIGNAL) { 591 printf("signal"); 592 flags &= ~MPTCP_PM_ADDR_FLAG_SIGNAL; 593 if (flags) 594 printf(","); 595 } 596 597 if (flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { 598 printf("subflow"); 599 flags &= ~MPTCP_PM_ADDR_FLAG_SUBFLOW; 600 if (flags) 601 printf(","); 602 } 603 604 if (flags & MPTCP_PM_ADDR_FLAG_BACKUP) { 605 printf("backup"); 606 flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP; 607 if (flags) 608 printf(","); 609 } 610 611 if (flags & MPTCP_PM_ADDR_FLAG_FULLMESH) { 612 printf("fullmesh"); 613 flags &= ~MPTCP_PM_ADDR_FLAG_FULLMESH; 614 if (flags) 615 printf(","); 616 } 617 618 if (flags & MPTCP_PM_ADDR_FLAG_IMPLICIT) { 619 printf("implicit"); 620 flags &= ~MPTCP_PM_ADDR_FLAG_IMPLICIT; 621 if (flags) 622 printf(","); 623 } 624 625 /* bump unknown flags, if any */ 626 if (flags) 627 printf("0x%x", flags); 628 printf(" "); 629 } 630 if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_IF_IDX) { 631 char name[IF_NAMESIZE], *ret; 632 int32_t ifindex; 633 634 memcpy(&ifindex, RTA_DATA(attrs), 4); 635 ret = if_indextoname(ifindex, name); 636 if (ret) 637 printf("dev %s ", ret); 638 else 639 printf("dev unknown/%d", ifindex); 640 } 641 642 attrs = RTA_NEXT(attrs, len); 643 } 644 printf("\n"); 645 } 646 647 static void print_addrs(struct nlmsghdr *nh, int pm_family, int total_len) 648 { 649 struct rtattr *attrs; 650 651 for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) { 652 int len = nh->nlmsg_len; 653 654 if (nh->nlmsg_type == NLMSG_DONE) 655 break; 656 if (nh->nlmsg_type == NLMSG_ERROR) 657 nl_error(nh); 658 if (nh->nlmsg_type != pm_family) 659 continue; 660 661 len -= NLMSG_LENGTH(GENL_HDRLEN); 662 attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) + 663 GENL_HDRLEN); 664 while (RTA_OK(attrs, len)) { 665 if (attrs->rta_type == 666 (MPTCP_PM_ATTR_ADDR | NLA_F_NESTED)) 667 print_addr((void *)RTA_DATA(attrs), 668 attrs->rta_len); 669 attrs = RTA_NEXT(attrs, len); 670 } 671 } 672 } 673 674 int get_addr(int fd, int pm_family, int argc, char *argv[]) 675 { 676 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 677 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 678 1024]; 679 struct rtattr *rta, *nest; 680 struct nlmsghdr *nh; 681 int nest_start; 682 u_int8_t id; 683 int off = 0; 684 685 memset(data, 0, sizeof(data)); 686 nh = (void *)data; 687 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, 688 MPTCP_PM_VER); 689 690 /* the only argument is the address id */ 691 if (argc != 3) 692 syntax(argv); 693 694 id = atoi(argv[2]); 695 696 nest_start = off; 697 nest = (void *)(data + off); 698 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 699 nest->rta_len = RTA_LENGTH(0); 700 off += NLMSG_ALIGN(nest->rta_len); 701 702 /* build a dummy addr with only the ID set */ 703 rta = (void *)(data + off); 704 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 705 rta->rta_len = RTA_LENGTH(1); 706 memcpy(RTA_DATA(rta), &id, 1); 707 off += NLMSG_ALIGN(rta->rta_len); 708 nest->rta_len = off - nest_start; 709 710 print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); 711 return 0; 712 } 713 714 int dump_addrs(int fd, int pm_family, int argc, char *argv[]) 715 { 716 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 717 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 718 1024]; 719 pid_t pid = getpid(); 720 struct nlmsghdr *nh; 721 int off = 0; 722 723 memset(data, 0, sizeof(data)); 724 nh = (void *)data; 725 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_GET_ADDR, 726 MPTCP_PM_VER); 727 nh->nlmsg_flags |= NLM_F_DUMP; 728 nh->nlmsg_seq = 1; 729 nh->nlmsg_pid = pid; 730 nh->nlmsg_len = off; 731 732 print_addrs(nh, pm_family, do_nl_req(fd, nh, off, sizeof(data))); 733 return 0; 734 } 735 736 int flush_addrs(int fd, int pm_family, int argc, char *argv[]) 737 { 738 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 739 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 740 1024]; 741 struct nlmsghdr *nh; 742 int off = 0; 743 744 memset(data, 0, sizeof(data)); 745 nh = (void *)data; 746 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_FLUSH_ADDRS, 747 MPTCP_PM_VER); 748 749 do_nl_req(fd, nh, off, 0); 750 return 0; 751 } 752 753 static void print_limits(struct nlmsghdr *nh, int pm_family, int total_len) 754 { 755 struct rtattr *attrs; 756 uint32_t max; 757 758 for (; NLMSG_OK(nh, total_len); nh = NLMSG_NEXT(nh, total_len)) { 759 int len = nh->nlmsg_len; 760 761 if (nh->nlmsg_type == NLMSG_DONE) 762 break; 763 if (nh->nlmsg_type == NLMSG_ERROR) 764 nl_error(nh); 765 if (nh->nlmsg_type != pm_family) 766 continue; 767 768 len -= NLMSG_LENGTH(GENL_HDRLEN); 769 attrs = (struct rtattr *) ((char *) NLMSG_DATA(nh) + 770 GENL_HDRLEN); 771 while (RTA_OK(attrs, len)) { 772 int type = attrs->rta_type; 773 774 if (type != MPTCP_PM_ATTR_RCV_ADD_ADDRS && 775 type != MPTCP_PM_ATTR_SUBFLOWS) 776 goto next; 777 778 memcpy(&max, RTA_DATA(attrs), 4); 779 printf("%s %u\n", type == MPTCP_PM_ATTR_SUBFLOWS ? 780 "subflows" : "accept", max); 781 782 next: 783 attrs = RTA_NEXT(attrs, len); 784 } 785 } 786 } 787 788 int get_set_limits(int fd, int pm_family, int argc, char *argv[]) 789 { 790 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 791 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 792 1024]; 793 uint32_t rcv_addr = 0, subflows = 0; 794 int cmd, len = sizeof(data); 795 struct nlmsghdr *nh; 796 int off = 0; 797 798 /* limit */ 799 if (argc == 4) { 800 rcv_addr = atoi(argv[2]); 801 subflows = atoi(argv[3]); 802 cmd = MPTCP_PM_CMD_SET_LIMITS; 803 } else { 804 cmd = MPTCP_PM_CMD_GET_LIMITS; 805 } 806 807 memset(data, 0, sizeof(data)); 808 nh = (void *)data; 809 off = init_genl_req(data, pm_family, cmd, MPTCP_PM_VER); 810 811 /* limit */ 812 if (cmd == MPTCP_PM_CMD_SET_LIMITS) { 813 struct rtattr *rta = (void *)(data + off); 814 815 rta->rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS; 816 rta->rta_len = RTA_LENGTH(4); 817 memcpy(RTA_DATA(rta), &rcv_addr, 4); 818 off += NLMSG_ALIGN(rta->rta_len); 819 820 rta = (void *)(data + off); 821 rta->rta_type = MPTCP_PM_ATTR_SUBFLOWS; 822 rta->rta_len = RTA_LENGTH(4); 823 memcpy(RTA_DATA(rta), &subflows, 4); 824 off += NLMSG_ALIGN(rta->rta_len); 825 826 /* do not expect a reply */ 827 len = 0; 828 } 829 830 len = do_nl_req(fd, nh, off, len); 831 if (cmd == MPTCP_PM_CMD_GET_LIMITS) 832 print_limits(nh, pm_family, len); 833 return 0; 834 } 835 836 int set_flags(int fd, int pm_family, int argc, char *argv[]) 837 { 838 char data[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 839 NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 840 1024]; 841 struct rtattr *rta, *nest; 842 struct nlmsghdr *nh; 843 u_int32_t flags = 0; 844 u_int16_t family; 845 int nest_start; 846 int use_id = 0; 847 u_int8_t id; 848 int off = 0; 849 int arg = 2; 850 851 memset(data, 0, sizeof(data)); 852 nh = (void *)data; 853 off = init_genl_req(data, pm_family, MPTCP_PM_CMD_SET_FLAGS, 854 MPTCP_PM_VER); 855 856 if (argc < 3) 857 syntax(argv); 858 859 nest_start = off; 860 nest = (void *)(data + off); 861 nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR; 862 nest->rta_len = RTA_LENGTH(0); 863 off += NLMSG_ALIGN(nest->rta_len); 864 865 if (!strcmp(argv[arg], "id")) { 866 if (++arg >= argc) 867 error(1, 0, " missing id value"); 868 869 use_id = 1; 870 id = atoi(argv[arg]); 871 rta = (void *)(data + off); 872 rta->rta_type = MPTCP_PM_ADDR_ATTR_ID; 873 rta->rta_len = RTA_LENGTH(1); 874 memcpy(RTA_DATA(rta), &id, 1); 875 off += NLMSG_ALIGN(rta->rta_len); 876 } else { 877 /* addr data */ 878 rta = (void *)(data + off); 879 if (inet_pton(AF_INET, argv[arg], RTA_DATA(rta))) { 880 family = AF_INET; 881 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4; 882 rta->rta_len = RTA_LENGTH(4); 883 } else if (inet_pton(AF_INET6, argv[arg], RTA_DATA(rta))) { 884 family = AF_INET6; 885 rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6; 886 rta->rta_len = RTA_LENGTH(16); 887 } else { 888 error(1, errno, "can't parse ip %s", argv[arg]); 889 } 890 off += NLMSG_ALIGN(rta->rta_len); 891 892 /* family */ 893 rta = (void *)(data + off); 894 rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY; 895 rta->rta_len = RTA_LENGTH(2); 896 memcpy(RTA_DATA(rta), &family, 2); 897 off += NLMSG_ALIGN(rta->rta_len); 898 } 899 900 if (++arg >= argc) 901 error(1, 0, " missing flags keyword"); 902 903 for (; arg < argc; arg++) { 904 if (!strcmp(argv[arg], "flags")) { 905 char *tok, *str; 906 907 /* flags */ 908 if (++arg >= argc) 909 error(1, 0, " missing flags value"); 910 911 for (str = argv[arg]; (tok = strtok(str, ",")); 912 str = NULL) { 913 if (!strcmp(tok, "backup")) 914 flags |= MPTCP_PM_ADDR_FLAG_BACKUP; 915 else if (!strcmp(tok, "fullmesh")) 916 flags |= MPTCP_PM_ADDR_FLAG_FULLMESH; 917 else if (strcmp(tok, "nobackup") && 918 strcmp(tok, "nofullmesh")) 919 error(1, errno, 920 "unknown flag %s", argv[arg]); 921 } 922 923 rta = (void *)(data + off); 924 rta->rta_type = MPTCP_PM_ADDR_ATTR_FLAGS; 925 rta->rta_len = RTA_LENGTH(4); 926 memcpy(RTA_DATA(rta), &flags, 4); 927 off += NLMSG_ALIGN(rta->rta_len); 928 } else if (!strcmp(argv[arg], "port")) { 929 u_int16_t port; 930 931 if (use_id) 932 error(1, 0, " port can't be used with id"); 933 934 if (++arg >= argc) 935 error(1, 0, " missing port value"); 936 937 port = atoi(argv[arg]); 938 rta = (void *)(data + off); 939 rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT; 940 rta->rta_len = RTA_LENGTH(2); 941 memcpy(RTA_DATA(rta), &port, 2); 942 off += NLMSG_ALIGN(rta->rta_len); 943 } else { 944 error(1, 0, "unknown keyword %s", argv[arg]); 945 } 946 } 947 nest->rta_len = off - nest_start; 948 949 do_nl_req(fd, nh, off, 0); 950 return 0; 951 } 952 953 int main(int argc, char *argv[]) 954 { 955 int fd, pm_family; 956 957 if (argc < 2) 958 syntax(argv); 959 960 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 961 if (fd == -1) 962 error(1, errno, "socket netlink"); 963 964 pm_family = resolve_mptcp_pm_netlink(fd); 965 966 if (!strcmp(argv[1], "add")) 967 return add_addr(fd, pm_family, argc, argv); 968 else if (!strcmp(argv[1], "ann")) 969 return announce_addr(fd, pm_family, argc, argv); 970 else if (!strcmp(argv[1], "rem")) 971 return remove_addr(fd, pm_family, argc, argv); 972 else if (!strcmp(argv[1], "del")) 973 return del_addr(fd, pm_family, argc, argv); 974 else if (!strcmp(argv[1], "flush")) 975 return flush_addrs(fd, pm_family, argc, argv); 976 else if (!strcmp(argv[1], "get")) 977 return get_addr(fd, pm_family, argc, argv); 978 else if (!strcmp(argv[1], "dump")) 979 return dump_addrs(fd, pm_family, argc, argv); 980 else if (!strcmp(argv[1], "limits")) 981 return get_set_limits(fd, pm_family, argc, argv); 982 else if (!strcmp(argv[1], "set")) 983 return set_flags(fd, pm_family, argc, argv); 984 985 fprintf(stderr, "unknown sub-command: %s", argv[1]); 986 syntax(argv); 987 return 0; 988 } 989