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