1 /* 2 * bearer.c TIPC bearer functionality. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Richard Alpe <richard.alpe (at) ericsson.com> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <netdb.h> 16 #include <errno.h> 17 #include <arpa/inet.h> 18 19 #include <linux/tipc_netlink.h> 20 #include <linux/tipc.h> 21 #include <linux/genetlink.h> 22 23 #include <libmnl/libmnl.h> 24 #include <sys/socket.h> 25 26 #include "cmdl.h" 27 #include "msg.h" 28 #include "bearer.h" 29 30 #define UDP_PROP_IP 1 31 #define UDP_PROP_PORT 2 32 33 struct cb_data { 34 int attr; 35 int prop; 36 struct nlmsghdr *nlh; 37 }; 38 39 static void _print_bearer_opts(void) 40 { 41 fprintf(stderr, 42 "OPTIONS\n" 43 " priority - Bearer link priority\n" 44 " tolerance - Bearer link tolerance\n" 45 " window - Bearer link window\n"); 46 } 47 48 void print_bearer_media(void) 49 { 50 fprintf(stderr, 51 "\nMEDIA\n" 52 " udp - User Datagram Protocol\n" 53 " ib - Infiniband\n" 54 " eth - Ethernet\n"); 55 } 56 57 static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media) 58 { 59 fprintf(stderr, 60 "Usage: %s bearer enable media %s device DEVICE [OPTIONS]\n" 61 "\nOPTIONS\n" 62 " domain DOMAIN - Discovery domain\n" 63 " priority PRIORITY - Bearer priority\n", 64 cmdl->argv[0], media); 65 } 66 67 static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media) 68 { 69 fprintf(stderr, 70 "Usage: %s bearer enable [OPTIONS] media %s name NAME localip IP [UDP OPTIONS]\n\n", 71 cmdl->argv[0], media); 72 fprintf(stderr, 73 "OPTIONS\n" 74 " domain DOMAIN - Discovery domain\n" 75 " priority PRIORITY - Bearer priority\n\n"); 76 fprintf(stderr, 77 "UDP OPTIONS\n" 78 " localport PORT - Local UDP port (default 6118)\n" 79 " remoteip IP - Remote IP address\n" 80 " remoteport PORT - Remote UDP port (default 6118)\n"); 81 } 82 83 static int get_netid_cb(const struct nlmsghdr *nlh, void *data) 84 { 85 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 86 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 87 struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {}; 88 int *netid = (int*)data; 89 90 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 91 if (!info[TIPC_NLA_NET]) 92 return MNL_CB_ERROR; 93 mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs); 94 if (!attrs[TIPC_NLA_NET_ID]) 95 return MNL_CB_ERROR; 96 *netid = mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID]); 97 98 return MNL_CB_OK; 99 } 100 101 static int generate_multicast(short af, char *buf, int bufsize) 102 { 103 int netid; 104 char mnl_msg[MNL_SOCKET_BUFFER_SIZE]; 105 struct nlmsghdr *nlh; 106 107 if (!(nlh = msg_init(mnl_msg, TIPC_NL_NET_GET))) { 108 fprintf(stderr, "error, message initialization failed\n"); 109 return -1; 110 } 111 if (msg_dumpit(nlh, get_netid_cb, &netid)) { 112 fprintf(stderr, "error, failed to fetch TIPC network id from kernel\n"); 113 return -EINVAL; 114 } 115 if (af == AF_INET) 116 snprintf(buf, bufsize, "228.0.%u.%u", (netid>>8) & 0xFF, netid & 0xFF); 117 else 118 snprintf(buf, bufsize, "ff02::%u", netid); 119 120 return 0; 121 } 122 123 static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts, 124 struct cmdl *cmdl) 125 { 126 int err; 127 struct opt *opt; 128 struct nlattr *nest; 129 char buf[INET6_ADDRSTRLEN]; 130 char *locport = "6118"; 131 char *remport = "6118"; 132 char *locip = NULL; 133 char *remip = NULL; 134 struct addrinfo *loc = NULL; 135 struct addrinfo *rem = NULL; 136 struct addrinfo hints = { 137 .ai_family = AF_UNSPEC, 138 .ai_socktype = SOCK_DGRAM 139 }; 140 141 if (!(opt = get_opt(opts, "localip"))) { 142 fprintf(stderr, "error, udp bearer localip missing\n"); 143 cmd_bearer_enable_udp_help(cmdl, "udp"); 144 return -EINVAL; 145 } 146 locip = opt->val; 147 148 if ((opt = get_opt(opts, "remoteip"))) 149 remip = opt->val; 150 151 if ((opt = get_opt(opts, "localport"))) 152 locport = opt->val; 153 154 if ((opt = get_opt(opts, "remoteport"))) 155 remport = opt->val; 156 157 if ((err = getaddrinfo(locip, locport, &hints, &loc))) { 158 fprintf(stderr, "UDP local address error: %s\n", 159 gai_strerror(err)); 160 return err; 161 } 162 163 if (!remip) { 164 if (generate_multicast(loc->ai_family, buf, sizeof(buf))) { 165 fprintf(stderr, "Failed to generate multicast address\n"); 166 freeaddrinfo(loc); 167 return -EINVAL; 168 } 169 remip = buf; 170 } 171 172 if ((err = getaddrinfo(remip, remport, &hints, &rem))) { 173 fprintf(stderr, "UDP remote address error: %s\n", 174 gai_strerror(err)); 175 freeaddrinfo(loc); 176 return err; 177 } 178 179 if (rem->ai_family != loc->ai_family) { 180 fprintf(stderr, "UDP local and remote AF mismatch\n"); 181 freeaddrinfo(rem); 182 freeaddrinfo(loc); 183 return -EINVAL; 184 } 185 186 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS); 187 mnl_attr_put(nlh, TIPC_NLA_UDP_LOCAL, loc->ai_addrlen, loc->ai_addr); 188 mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, rem->ai_addrlen, rem->ai_addr); 189 mnl_attr_nest_end(nlh, nest); 190 191 freeaddrinfo(rem); 192 freeaddrinfo(loc); 193 194 return 0; 195 } 196 197 static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd, 198 struct cmdl *cmdl, struct opt *opts, 199 const struct tipc_sup_media *sup_media) 200 { 201 char bname[TIPC_MAX_BEARER_NAME]; 202 int err; 203 204 if ((err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, sup_media))) 205 return err; 206 207 mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, bname); 208 return 0; 209 } 210 211 int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl, 212 struct opt *opts, char *bname, 213 const struct tipc_sup_media *sup_media) 214 { 215 char *media; 216 char *identifier; 217 struct opt *opt; 218 const struct tipc_sup_media *entry; 219 220 221 if (!(opt = get_opt(opts, "media"))) { 222 if (help_flag) 223 (cmd->help)(cmdl); 224 else 225 fprintf(stderr, "error, missing bearer media\n"); 226 return -EINVAL; 227 } 228 media = opt->val; 229 230 for (entry = sup_media; entry->media; entry++) { 231 if (strcmp(entry->media, media)) 232 continue; 233 234 if (!(opt = get_opt(opts, entry->identifier))) { 235 if (help_flag) 236 (entry->help)(cmdl, media); 237 else 238 fprintf(stderr, "error, missing bearer %s\n", 239 entry->identifier); 240 return -EINVAL; 241 } 242 243 identifier = opt->val; 244 snprintf(bname, TIPC_MAX_BEARER_NAME, "%s:%s", media, identifier); 245 246 return 0; 247 } 248 249 fprintf(stderr, "error, invalid media type %s\n", media); 250 251 return -EINVAL; 252 } 253 254 static void cmd_bearer_add_udp_help(struct cmdl *cmdl, char *media) 255 { 256 fprintf(stderr, "Usage: %s bearer add media %s name NAME remoteip REMOTEIP\n\n", 257 cmdl->argv[0], media); 258 } 259 260 static void cmd_bearer_add_help(struct cmdl *cmdl) 261 { 262 fprintf(stderr, "Usage: %s bearer add media udp name NAME remoteip REMOTEIP\n", 263 cmdl->argv[0]); 264 } 265 266 static int udp_bearer_add(struct nlmsghdr *nlh, struct opt *opts, 267 struct cmdl *cmdl) 268 { 269 int err; 270 struct opt *opt; 271 struct nlattr *opts_nest; 272 char *remport = "6118"; 273 274 opts_nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS); 275 276 if ((opt = get_opt(opts, "remoteport"))) 277 remport = opt->val; 278 279 if ((opt = get_opt(opts, "remoteip"))) { 280 char *ip = opt->val; 281 struct addrinfo *addr = NULL; 282 struct addrinfo hints = { 283 .ai_family = AF_UNSPEC, 284 .ai_socktype = SOCK_DGRAM 285 }; 286 287 if ((err = getaddrinfo(ip, remport, &hints, &addr))) { 288 fprintf(stderr, "UDP address error: %s\n", 289 gai_strerror(err)); 290 freeaddrinfo(addr); 291 return err; 292 } 293 294 mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, addr->ai_addrlen, 295 addr->ai_addr); 296 freeaddrinfo(addr); 297 } else { 298 fprintf(stderr, "error, missing remoteip\n"); 299 return -EINVAL; 300 } 301 mnl_attr_nest_end(nlh, opts_nest); 302 303 return 0; 304 } 305 306 static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd, 307 struct cmdl *cmdl, void *data) 308 { 309 int err; 310 char *media; 311 char buf[MNL_SOCKET_BUFFER_SIZE]; 312 struct opt *opt; 313 struct nlattr *attrs; 314 struct opt opts[] = { 315 { "remoteip", OPT_KEYVAL, NULL }, 316 { "remoteport", OPT_KEYVAL, NULL }, 317 { "name", OPT_KEYVAL, NULL }, 318 { "media", OPT_KEYVAL, NULL }, 319 { NULL } 320 }; 321 const struct tipc_sup_media sup_media[] = { 322 { "udp", "name", cmd_bearer_add_udp_help}, 323 { NULL, }, 324 }; 325 326 /* Rewind optind to include media in the option list */ 327 cmdl->optind--; 328 if (parse_opts(opts, cmdl) < 0) 329 return -EINVAL; 330 331 if (!(opt = get_opt(opts, "media"))) { 332 fprintf(stderr, "error, missing media value\n"); 333 return -EINVAL; 334 } 335 media = opt->val; 336 337 if (strcmp(media, "udp") != 0) { 338 fprintf(stderr, "error, no \"%s\" media specific options available\n", 339 media); 340 return -EINVAL; 341 } 342 if (!(opt = get_opt(opts, "name"))) { 343 fprintf(stderr, "error, missing media name\n"); 344 return -EINVAL; 345 } 346 347 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ADD))) { 348 fprintf(stderr, "error, message initialisation failed\n"); 349 return -1; 350 } 351 352 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); 353 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); 354 if (err) 355 return err; 356 357 err = udp_bearer_add(nlh, opts, cmdl); 358 if (err) 359 return err; 360 361 mnl_attr_nest_end(nlh, attrs); 362 363 return msg_doit(nlh, NULL, NULL); 364 } 365 366 static int cmd_bearer_add(struct nlmsghdr *nlh, const struct cmd *cmd, 367 struct cmdl *cmdl, void *data) 368 { 369 const struct cmd cmds[] = { 370 { "media", cmd_bearer_add_media, cmd_bearer_add_help }, 371 { NULL } 372 }; 373 374 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 375 } 376 377 static void cmd_bearer_enable_help(struct cmdl *cmdl) 378 { 379 fprintf(stderr, 380 "Usage: %s bearer enable [OPTIONS] media MEDIA ARGS...\n\n" 381 "OPTIONS\n" 382 " domain DOMAIN - Discovery domain\n" 383 " priority PRIORITY - Bearer priority\n", 384 cmdl->argv[0]); 385 print_bearer_media(); 386 } 387 388 static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, 389 struct cmdl *cmdl, void *data) 390 { 391 int err; 392 struct opt *opt; 393 struct nlattr *nest; 394 char buf[MNL_SOCKET_BUFFER_SIZE]; 395 struct opt opts[] = { 396 { "device", OPT_KEYVAL, NULL }, 397 { "domain", OPT_KEYVAL, NULL }, 398 { "localip", OPT_KEYVAL, NULL }, 399 { "localport", OPT_KEYVAL, NULL }, 400 { "media", OPT_KEYVAL, NULL }, 401 { "name", OPT_KEYVAL, NULL }, 402 { "priority", OPT_KEYVAL, NULL }, 403 { "remoteip", OPT_KEYVAL, NULL }, 404 { "remoteport", OPT_KEYVAL, NULL }, 405 { NULL } 406 }; 407 struct tipc_sup_media sup_media[] = { 408 { "udp", "name", cmd_bearer_enable_udp_help}, 409 { "eth", "device", cmd_bearer_enable_l2_help }, 410 { "ib", "device", cmd_bearer_enable_l2_help }, 411 { NULL, }, 412 }; 413 414 if (parse_opts(opts, cmdl) < 0) { 415 if (help_flag) 416 (cmd->help)(cmdl); 417 return -EINVAL; 418 } 419 420 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ENABLE))) { 421 fprintf(stderr, "error: message initialisation failed\n"); 422 return -1; 423 } 424 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); 425 426 if ((opt = get_opt(opts, "domain"))) 427 mnl_attr_put_u32(nlh, TIPC_NLA_BEARER_DOMAIN, atoi(opt->val)); 428 429 if ((opt = get_opt(opts, "priority"))) { 430 struct nlattr *props; 431 432 props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP); 433 mnl_attr_put_u32(nlh, TIPC_NLA_PROP_PRIO, atoi(opt->val)); 434 mnl_attr_nest_end(nlh, props); 435 } 436 437 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); 438 if (err) 439 return err; 440 441 opt = get_opt(opts, "media"); 442 if (opt && strcmp(opt->val, "udp") == 0) { 443 err = nl_add_udp_enable_opts(nlh, opts, cmdl); 444 if (err) 445 return err; 446 } 447 mnl_attr_nest_end(nlh, nest); 448 449 return msg_doit(nlh, NULL, NULL); 450 } 451 452 static void cmd_bearer_disable_l2_help(struct cmdl *cmdl, char *media) 453 { 454 fprintf(stderr, "Usage: %s bearer disable media %s device DEVICE\n", 455 cmdl->argv[0], media); 456 } 457 458 static void cmd_bearer_disable_udp_help(struct cmdl *cmdl, char *media) 459 { 460 fprintf(stderr, "Usage: %s bearer disable media %s name NAME\n", 461 cmdl->argv[0], media); 462 } 463 464 static void cmd_bearer_disable_help(struct cmdl *cmdl) 465 { 466 fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n", 467 cmdl->argv[0]); 468 print_bearer_media(); 469 } 470 471 static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, 472 struct cmdl *cmdl, void *data) 473 { 474 int err; 475 char buf[MNL_SOCKET_BUFFER_SIZE]; 476 struct nlattr *nest; 477 struct opt opts[] = { 478 { "device", OPT_KEYVAL, NULL }, 479 { "name", OPT_KEYVAL, NULL }, 480 { "media", OPT_KEYVAL, NULL }, 481 { NULL } 482 }; 483 struct tipc_sup_media sup_media[] = { 484 { "udp", "name", cmd_bearer_disable_udp_help}, 485 { "eth", "device", cmd_bearer_disable_l2_help }, 486 { "ib", "device", cmd_bearer_disable_l2_help }, 487 { NULL, }, 488 }; 489 490 if (parse_opts(opts, cmdl) < 0) { 491 if (help_flag) 492 (cmd->help)(cmdl); 493 return -EINVAL; 494 } 495 496 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_DISABLE))) { 497 fprintf(stderr, "error, message initialisation failed\n"); 498 return -1; 499 } 500 501 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); 502 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); 503 if (err) 504 return err; 505 mnl_attr_nest_end(nlh, nest); 506 507 return msg_doit(nlh, NULL, NULL); 508 509 } 510 511 static void cmd_bearer_set_help(struct cmdl *cmdl) 512 { 513 fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n", 514 cmdl->argv[0]); 515 _print_bearer_opts(); 516 print_bearer_media(); 517 } 518 519 static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media) 520 { 521 fprintf(stderr, "Usage: %s bearer set OPTION media %s name NAME\n\n", 522 cmdl->argv[0], media); 523 _print_bearer_opts(); 524 } 525 526 static void cmd_bearer_set_l2_help(struct cmdl *cmdl, char *media) 527 { 528 fprintf(stderr, 529 "Usage: %s bearer set [OPTION]... media %s device DEVICE\n", 530 cmdl->argv[0], media); 531 _print_bearer_opts(); 532 } 533 534 static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, 535 struct cmdl *cmdl, void *data) 536 { 537 int err; 538 int val; 539 int prop; 540 char buf[MNL_SOCKET_BUFFER_SIZE]; 541 struct nlattr *props; 542 struct nlattr *attrs; 543 struct opt opts[] = { 544 { "device", OPT_KEYVAL, NULL }, 545 { "media", OPT_KEYVAL, NULL }, 546 { "name", OPT_KEYVAL, NULL }, 547 { NULL } 548 }; 549 struct tipc_sup_media sup_media[] = { 550 { "udp", "name", cmd_bearer_set_udp_help}, 551 { "eth", "device", cmd_bearer_set_l2_help }, 552 { "ib", "device", cmd_bearer_set_l2_help }, 553 { NULL, }, 554 }; 555 556 if (strcmp(cmd->cmd, "priority") == 0) 557 prop = TIPC_NLA_PROP_PRIO; 558 else if ((strcmp(cmd->cmd, "tolerance") == 0)) 559 prop = TIPC_NLA_PROP_TOL; 560 else if ((strcmp(cmd->cmd, "window") == 0)) 561 prop = TIPC_NLA_PROP_WIN; 562 else 563 return -EINVAL; 564 565 if (cmdl->optind >= cmdl->argc) { 566 fprintf(stderr, "error, missing value\n"); 567 return -EINVAL; 568 } 569 val = atoi(shift_cmdl(cmdl)); 570 571 if (parse_opts(opts, cmdl) < 0) 572 return -EINVAL; 573 574 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_SET))) { 575 fprintf(stderr, "error, message initialisation failed\n"); 576 return -1; 577 } 578 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); 579 580 props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP); 581 mnl_attr_put_u32(nlh, prop, val); 582 mnl_attr_nest_end(nlh, props); 583 584 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); 585 if (err) 586 return err; 587 588 mnl_attr_nest_end(nlh, attrs); 589 590 return msg_doit(nlh, NULL, NULL); 591 } 592 593 static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd, 594 struct cmdl *cmdl, void *data) 595 { 596 const struct cmd cmds[] = { 597 { "priority", cmd_bearer_set_prop, cmd_bearer_set_help }, 598 { "tolerance", cmd_bearer_set_prop, cmd_bearer_set_help }, 599 { "window", cmd_bearer_set_prop, cmd_bearer_set_help }, 600 { NULL } 601 }; 602 603 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 604 } 605 606 static void cmd_bearer_get_help(struct cmdl *cmdl) 607 { 608 fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n", 609 cmdl->argv[0]); 610 _print_bearer_opts(); 611 print_bearer_media(); 612 } 613 614 static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media) 615 { 616 fprintf(stderr, "Usage: %s bearer get [OPTION] media %s name NAME [UDP OPTIONS]\n\n", 617 cmdl->argv[0], media); 618 fprintf(stderr, 619 "UDP OPTIONS\n" 620 " remoteip - Remote ip address\n" 621 " remoteport - Remote port\n" 622 " localip - Local ip address\n" 623 " localport - Local port\n\n"); 624 _print_bearer_opts(); 625 } 626 627 static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media) 628 { 629 fprintf(stderr, 630 "Usage: %s bearer get OPTION media %s device DEVICE\n", 631 cmdl->argv[0], media); 632 _print_bearer_opts(); 633 } 634 635 636 static int bearer_dump_udp_cb(const struct nlmsghdr *nlh, void *data) 637 { 638 struct sockaddr_storage *addr; 639 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 640 struct nlattr *info[TIPC_NLA_UDP_MAX + 1] = {}; 641 642 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 643 644 if (!info[TIPC_NLA_UDP_REMOTE]) 645 return MNL_CB_ERROR; 646 647 addr = mnl_attr_get_payload(info[TIPC_NLA_UDP_REMOTE]); 648 649 if (addr->ss_family == AF_INET) { 650 struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr; 651 652 printf("%s\n", inet_ntoa(ipv4->sin_addr)); 653 } else if (addr->ss_family == AF_INET6) { 654 char straddr[INET6_ADDRSTRLEN]; 655 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr; 656 657 if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr, 658 sizeof(straddr))) { 659 fprintf(stderr, "error, parsing IPv6 addr\n"); 660 return MNL_CB_ERROR; 661 } 662 printf("%s\n", straddr); 663 664 } else { 665 return MNL_CB_ERROR; 666 } 667 668 return MNL_CB_OK; 669 } 670 671 static int bearer_get_udp_cb(const struct nlmsghdr *nlh, void *data) 672 { 673 struct cb_data *cb_data = (struct cb_data *) data; 674 struct sockaddr_storage *addr; 675 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 676 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 677 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {}; 678 struct nlattr *opts[TIPC_NLA_UDP_MAX + 1] = {}; 679 680 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 681 if (!info[TIPC_NLA_BEARER]) 682 return MNL_CB_ERROR; 683 684 mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs); 685 if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) 686 return MNL_CB_ERROR; 687 688 mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_UDP_OPTS], parse_attrs, opts); 689 if (!opts[TIPC_NLA_UDP_LOCAL]) 690 return MNL_CB_ERROR; 691 692 if ((cb_data->attr == TIPC_NLA_UDP_REMOTE) && 693 (cb_data->prop == UDP_PROP_IP) && 694 opts[TIPC_NLA_UDP_MULTI_REMOTEIP]) { 695 struct genlmsghdr *genl = mnl_nlmsg_get_payload(cb_data->nlh); 696 697 genl->cmd = TIPC_NL_UDP_GET_REMOTEIP; 698 return msg_dumpit(cb_data->nlh, bearer_dump_udp_cb, NULL); 699 } 700 701 addr = mnl_attr_get_payload(opts[cb_data->attr]); 702 703 if (addr->ss_family == AF_INET) { 704 struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr; 705 706 switch (cb_data->prop) { 707 case UDP_PROP_IP: 708 printf("%s\n", inet_ntoa(ipv4->sin_addr)); 709 break; 710 case UDP_PROP_PORT: 711 printf("%u\n", ntohs(ipv4->sin_port)); 712 break; 713 default: 714 return MNL_CB_ERROR; 715 } 716 717 } else if (addr->ss_family == AF_INET6) { 718 char straddr[INET6_ADDRSTRLEN]; 719 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr; 720 721 switch (cb_data->prop) { 722 case UDP_PROP_IP: 723 if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr, 724 sizeof(straddr))) { 725 fprintf(stderr, "error, parsing IPv6 addr\n"); 726 return MNL_CB_ERROR; 727 } 728 printf("%s\n", straddr); 729 break; 730 case UDP_PROP_PORT: 731 printf("%u\n", ntohs(ipv6->sin6_port)); 732 break; 733 default: 734 return MNL_CB_ERROR; 735 } 736 737 } else { 738 return MNL_CB_ERROR; 739 } 740 741 return MNL_CB_OK; 742 } 743 744 static int bearer_get_cb(const struct nlmsghdr *nlh, void *data) 745 { 746 int *prop = data; 747 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 748 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 749 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {}; 750 struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {}; 751 752 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 753 if (!info[TIPC_NLA_BEARER]) 754 return MNL_CB_ERROR; 755 756 mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs); 757 if (!attrs[TIPC_NLA_BEARER_PROP]) 758 return MNL_CB_ERROR; 759 760 mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_PROP], parse_attrs, props); 761 if (!props[*prop]) 762 return MNL_CB_ERROR; 763 764 printf("%u\n", mnl_attr_get_u32(props[*prop])); 765 766 return MNL_CB_OK; 767 } 768 769 static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd, 770 struct cmdl *cmdl, void *data) 771 { 772 int err; 773 char *media; 774 char buf[MNL_SOCKET_BUFFER_SIZE]; 775 struct opt *opt; 776 struct cb_data cb_data = {0}; 777 struct nlattr *attrs; 778 struct opt opts[] = { 779 { "localip", OPT_KEY, NULL }, 780 { "localport", OPT_KEY, NULL }, 781 { "remoteip", OPT_KEY, NULL }, 782 { "remoteport", OPT_KEY, NULL }, 783 { "name", OPT_KEYVAL, NULL }, 784 { "media", OPT_KEYVAL, NULL }, 785 { NULL } 786 }; 787 struct tipc_sup_media sup_media[] = { 788 { "udp", "name", cmd_bearer_get_udp_help}, 789 { NULL, }, 790 }; 791 792 /* Rewind optind to include media in the option list */ 793 cmdl->optind--; 794 if (parse_opts(opts, cmdl) < 0) 795 return -EINVAL; 796 797 if (!(opt = get_opt(opts, "media"))) { 798 fprintf(stderr, "error, missing media value\n"); 799 return -EINVAL; 800 } 801 media = opt->val; 802 803 if (help_flag) { 804 cmd_bearer_get_udp_help(cmdl, media); 805 return -EINVAL; 806 } 807 if (strcmp(media, "udp") != 0) { 808 fprintf(stderr, "error, no \"%s\" media specific options\n", media); 809 return -EINVAL; 810 } 811 if (!(opt = get_opt(opts, "name"))) { 812 fprintf(stderr, "error, missing media name\n"); 813 return -EINVAL; 814 } 815 816 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) { 817 fprintf(stderr, "error, message initialisation failed\n"); 818 return -1; 819 } 820 821 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); 822 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); 823 if (err) 824 return err; 825 mnl_attr_nest_end(nlh, attrs); 826 cb_data.nlh = nlh; 827 828 if (has_opt(opts, "localip")) { 829 cb_data.attr = TIPC_NLA_UDP_LOCAL; 830 cb_data.prop = UDP_PROP_IP; 831 return msg_doit(nlh, bearer_get_udp_cb, &cb_data); 832 } else if (has_opt(opts, "localport")) { 833 cb_data.attr = TIPC_NLA_UDP_LOCAL; 834 cb_data.prop = UDP_PROP_PORT; 835 return msg_doit(nlh, bearer_get_udp_cb, &cb_data); 836 } else if (has_opt(opts, "remoteip")) { 837 cb_data.attr = TIPC_NLA_UDP_REMOTE; 838 cb_data.prop = UDP_PROP_IP; 839 return msg_doit(nlh, bearer_get_udp_cb, &cb_data); 840 } else if (has_opt(opts, "remoteport")) { 841 cb_data.attr = TIPC_NLA_UDP_REMOTE; 842 cb_data.prop = UDP_PROP_PORT; 843 return msg_doit(nlh, bearer_get_udp_cb, &cb_data); 844 } 845 fprintf(stderr, "error, missing UDP option\n"); 846 return -EINVAL; 847 } 848 849 static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, 850 struct cmdl *cmdl, void *data) 851 { 852 int err; 853 int prop; 854 char buf[MNL_SOCKET_BUFFER_SIZE]; 855 struct nlattr *attrs; 856 struct opt opts[] = { 857 { "device", OPT_KEYVAL, NULL }, 858 { "media", OPT_KEYVAL, NULL }, 859 { "name", OPT_KEYVAL, NULL }, 860 { NULL } 861 }; 862 struct tipc_sup_media sup_media[] = { 863 { "udp", "name", cmd_bearer_get_udp_help}, 864 { "eth", "device", cmd_bearer_get_l2_help }, 865 { "ib", "device", cmd_bearer_get_l2_help }, 866 { NULL, }, 867 }; 868 869 if (help_flag) { 870 (cmd->help)(cmdl); 871 return -EINVAL; 872 } 873 874 if (strcmp(cmd->cmd, "priority") == 0) 875 prop = TIPC_NLA_PROP_PRIO; 876 else if ((strcmp(cmd->cmd, "tolerance") == 0)) 877 prop = TIPC_NLA_PROP_TOL; 878 else if ((strcmp(cmd->cmd, "window") == 0)) 879 prop = TIPC_NLA_PROP_WIN; 880 else 881 return -EINVAL; 882 883 if (parse_opts(opts, cmdl) < 0) 884 return -EINVAL; 885 886 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) { 887 fprintf(stderr, "error, message initialisation failed\n"); 888 return -1; 889 } 890 891 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); 892 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); 893 if (err) 894 return err; 895 mnl_attr_nest_end(nlh, attrs); 896 897 return msg_doit(nlh, bearer_get_cb, &prop); 898 } 899 900 static int cmd_bearer_get(struct nlmsghdr *nlh, const struct cmd *cmd, 901 struct cmdl *cmdl, void *data) 902 { 903 const struct cmd cmds[] = { 904 { "priority", cmd_bearer_get_prop, cmd_bearer_get_help }, 905 { "tolerance", cmd_bearer_get_prop, cmd_bearer_get_help }, 906 { "window", cmd_bearer_get_prop, cmd_bearer_get_help }, 907 { "media", cmd_bearer_get_media, cmd_bearer_get_help }, 908 { NULL } 909 }; 910 911 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 912 } 913 914 static int bearer_list_cb(const struct nlmsghdr *nlh, void *data) 915 { 916 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 917 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 918 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {}; 919 920 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 921 if (!info[TIPC_NLA_BEARER]) { 922 fprintf(stderr, "No bearer in netlink response\n"); 923 return MNL_CB_ERROR; 924 } 925 926 mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs); 927 if (!attrs[TIPC_NLA_BEARER_NAME]) { 928 fprintf(stderr, "Bearer name missing in netlink response\n"); 929 return MNL_CB_ERROR; 930 } 931 932 printf("%s\n", mnl_attr_get_str(attrs[TIPC_NLA_BEARER_NAME])); 933 934 return MNL_CB_OK; 935 } 936 937 static int cmd_bearer_list(struct nlmsghdr *nlh, const struct cmd *cmd, 938 struct cmdl *cmdl, void *data) 939 { 940 char buf[MNL_SOCKET_BUFFER_SIZE]; 941 942 if (help_flag) { 943 fprintf(stderr, "Usage: %s bearer list\n", cmdl->argv[0]); 944 return -EINVAL; 945 } 946 947 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) { 948 fprintf(stderr, "error, message initialisation failed\n"); 949 return -1; 950 } 951 952 return msg_dumpit(nlh, bearer_list_cb, NULL); 953 } 954 955 void cmd_bearer_help(struct cmdl *cmdl) 956 { 957 fprintf(stderr, 958 "Usage: %s bearer COMMAND [ARGS] ...\n" 959 "\n" 960 "COMMANDS\n" 961 " add - Add data to existing bearer\n" 962 " enable - Enable a bearer\n" 963 " disable - Disable a bearer\n" 964 " set - Set various bearer properties\n" 965 " get - Get various bearer properties\n" 966 " list - List bearers\n", cmdl->argv[0]); 967 } 968 969 int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, 970 void *data) 971 { 972 const struct cmd cmds[] = { 973 { "add", cmd_bearer_add, cmd_bearer_add_help }, 974 { "disable", cmd_bearer_disable, cmd_bearer_disable_help }, 975 { "enable", cmd_bearer_enable, cmd_bearer_enable_help }, 976 { "get", cmd_bearer_get, cmd_bearer_get_help }, 977 { "list", cmd_bearer_list, NULL }, 978 { "set", cmd_bearer_set, cmd_bearer_set_help }, 979 { NULL } 980 }; 981 982 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 983 } 984