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