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