]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - tipc/bearer.c
ll_map: Add function to remove link cache entry by index
[mirror_iproute2.git] / tipc / bearer.c
index 30b54d9fe24e9acc22e5d4025138c50a010da164..05dc84aa8dedebfc66ee068f3229a137543c7e57 100644 (file)
@@ -14,6 +14,7 @@
 #include <string.h>
 #include <netdb.h>
 #include <errno.h>
+#include <arpa/inet.h>
 
 #include <linux/tipc_netlink.h>
 #include <linux/tipc.h>
 #include "msg.h"
 #include "bearer.h"
 
+#define UDP_PROP_IP 1
+#define UDP_PROP_PORT 2
+
+struct cb_data {
+       int attr;
+       int prop;
+       struct nlmsghdr *nlh;
+};
+
 static void _print_bearer_opts(void)
 {
        fprintf(stderr,
-               "\nOPTIONS\n"
+               "OPTIONS\n"
                " priority              - Bearer link priority\n"
                " tolerance             - Bearer link tolerance\n"
-               " window                - Bearer link window\n");
+               " window                - Bearer link window\n"
+               " mtu                   - Bearer link mtu\n");
 }
 
-static void _print_bearer_media(void)
+void print_bearer_media(void)
 {
        fprintf(stderr,
                "\nMEDIA\n"
@@ -44,43 +55,30 @@ static void _print_bearer_media(void)
                " eth                   - Ethernet\n");
 }
 
-static void cmd_bearer_enable_l2_help(struct cmdl *cmdl)
+static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media)
 {
        fprintf(stderr,
-               "Usage: %s bearer enable media MEDIA device DEVICE [OPTIONS]\n"
+               "Usage: %s bearer enable media %s device DEVICE [OPTIONS]\n"
                "\nOPTIONS\n"
                " domain DOMAIN         - Discovery domain\n"
                " priority PRIORITY     - Bearer priority\n",
-               cmdl->argv[0]);
+               cmdl->argv[0], media);
 }
 
-static void cmd_bearer_enable_udp_help(struct cmdl *cmdl)
+static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media)
 {
        fprintf(stderr,
-               "Usage: %s bearer enable media udp name NAME localip IP [OPTIONS]\n"
-               "\nOPTIONS\n"
+               "Usage: %s bearer enable [OPTIONS] media %s name NAME localip IP [UDP OPTIONS]\n\n",
+               cmdl->argv[0], media);
+       fprintf(stderr,
+               "OPTIONS\n"
                " domain DOMAIN         - Discovery domain\n"
-               " priority PRIORITY     - Bearer priority\n"
+               " priority PRIORITY     - Bearer priority\n\n");
+       fprintf(stderr,
+               "UDP OPTIONS\n"
                " localport PORT        - Local UDP port (default 6118)\n"
                " remoteip IP           - Remote IP address\n"
-               " remoteport IP         - Remote UDP port (default 6118)\n",
-               cmdl->argv[0]);
-}
-
-static int enable_l2_bearer(struct nlmsghdr *nlh, struct opt *opts,
-                           struct cmdl *cmdl)
-{
-       struct opt *opt;
-       char id[TIPC_MAX_BEARER_NAME];
-
-       if (!(opt = get_opt(opts, "device"))) {
-               fprintf(stderr, "error: missing bearer device\n");
-               return -EINVAL;
-       }
-       snprintf(id, sizeof(id), "eth:%s", opt->val);
-       mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
-
-       return 0;
+               " remoteport PORT       - Remote UDP port (default 6118)\n");
 }
 
 static int get_netid_cb(const struct nlmsghdr *nlh, void *data)
@@ -123,8 +121,8 @@ static int generate_multicast(short af, char *buf, int bufsize)
        return 0;
 }
 
-static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts,
-                            struct cmdl *cmdl)
+static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts,
+                                 struct cmdl *cmdl)
 {
        int err;
        struct opt *opt;
@@ -134,7 +132,6 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts,
        char *remport = "6118";
        char *locip = NULL;
        char *remip = NULL;
-       char name[TIPC_MAX_BEARER_NAME];
        struct addrinfo *loc = NULL;
        struct addrinfo *rem = NULL;
        struct addrinfo hints = {
@@ -142,22 +139,9 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts,
                .ai_socktype = SOCK_DGRAM
        };
 
-       if (help_flag) {
-               cmd_bearer_enable_udp_help(cmdl);
-               /* TODO find a better error code? */
-               return -EINVAL;
-       }
-
-       if (!(opt = get_opt(opts, "name"))) {
-               fprintf(stderr, "error, udp bearer name missing\n");
-               cmd_bearer_enable_udp_help(cmdl);
-               return -EINVAL;
-       }
-       snprintf(name, sizeof(name), "udp:%s", opt->val);
-
        if (!(opt = get_opt(opts, "localip"))) {
                fprintf(stderr, "error, udp bearer localip missing\n");
-               cmd_bearer_enable_udp_help(cmdl);
+               cmd_bearer_enable_udp_help(cmdl, "udp");
                return -EINVAL;
        }
        locip = opt->val;
@@ -180,6 +164,7 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts,
        if (!remip) {
                if (generate_multicast(loc->ai_family, buf, sizeof(buf))) {
                        fprintf(stderr, "Failed to generate multicast address\n");
+                       freeaddrinfo(loc);
                        return -EINVAL;
                }
                remip = buf;
@@ -194,11 +179,11 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts,
 
        if (rem->ai_family != loc->ai_family) {
                fprintf(stderr, "UDP local and remote AF mismatch\n");
+               freeaddrinfo(rem);
+               freeaddrinfo(loc);
                return -EINVAL;
        }
 
-       mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, name);
-
        nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
        mnl_attr_put(nlh, TIPC_NLA_UDP_LOCAL, loc->ai_addrlen, loc->ai_addr);
        mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, rem->ai_addrlen, rem->ai_addr);
@@ -210,6 +195,194 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts,
        return 0;
 }
 
+static char *cmd_get_media_type(const struct cmd *cmd, struct cmdl *cmdl,
+                               struct opt *opts)
+{
+       struct opt *opt = get_opt(opts, "media");
+
+       if (!opt) {
+               if (help_flag)
+                       (cmd->help)(cmdl);
+               else
+                       fprintf(stderr, "error, missing bearer media\n");
+               return NULL;
+       }
+       return opt->val;
+}
+
+static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd,
+                             struct cmdl *cmdl, struct opt *opts,
+                             const struct tipc_sup_media *sup_media)
+{
+       char bname[TIPC_MAX_BEARER_NAME];
+       int err;
+
+       if ((err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, sup_media)))
+               return err;
+
+       mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, bname);
+       return 0;
+}
+
+int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl,
+                              struct opt *opts, char *bname,
+                              const struct tipc_sup_media *sup_media)
+{
+       char *media;
+       char *identifier;
+       struct opt *opt;
+       const struct tipc_sup_media *entry;
+
+       if (!(media = cmd_get_media_type(cmd, cmdl, opts)))
+               return -EINVAL;
+
+       for (entry = sup_media; entry->media; entry++) {
+               if (strcmp(entry->media, media))
+                       continue;
+
+               if (!(opt = get_opt(opts, entry->identifier))) {
+                       if (help_flag)
+                               (entry->help)(cmdl, media);
+                       else
+                               fprintf(stderr, "error, missing bearer %s\n",
+                                       entry->identifier);
+                       return -EINVAL;
+               }
+
+               identifier = opt->val;
+               snprintf(bname, TIPC_MAX_BEARER_NAME, "%s:%s", media, identifier);
+
+               return 0;
+       }
+
+       fprintf(stderr, "error, invalid media type %s\n", media);
+
+       return -EINVAL;
+}
+
+static void cmd_bearer_add_udp_help(struct cmdl *cmdl, char *media)
+{
+       fprintf(stderr, "Usage: %s bearer add media %s name NAME remoteip REMOTEIP\n\n",
+               cmdl->argv[0], media);
+}
+
+static void cmd_bearer_add_help(struct cmdl *cmdl)
+{
+       fprintf(stderr, "Usage: %s bearer add media udp name NAME remoteip REMOTEIP\n",
+               cmdl->argv[0]);
+}
+
+static int udp_bearer_add(struct nlmsghdr *nlh, struct opt *opts,
+                         struct cmdl *cmdl)
+{
+       int err;
+       struct opt *opt;
+       struct nlattr *opts_nest;
+       char *remport = "6118";
+
+       opts_nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
+
+       if ((opt = get_opt(opts, "remoteport")))
+               remport = opt->val;
+
+       if ((opt = get_opt(opts, "remoteip"))) {
+               char *ip = opt->val;
+               struct addrinfo *addr = NULL;
+               struct addrinfo hints = {
+                       .ai_family = AF_UNSPEC,
+                       .ai_socktype = SOCK_DGRAM
+               };
+
+               if ((err = getaddrinfo(ip, remport, &hints, &addr))) {
+                       fprintf(stderr, "UDP address error: %s\n",
+                               gai_strerror(err));
+                       freeaddrinfo(addr);
+                       return err;
+               }
+
+               mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, addr->ai_addrlen,
+                            addr->ai_addr);
+               freeaddrinfo(addr);
+       } else {
+               fprintf(stderr, "error, missing remoteip\n");
+               return -EINVAL;
+       }
+       mnl_attr_nest_end(nlh, opts_nest);
+
+       return 0;
+}
+
+static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd,
+                               struct cmdl *cmdl, void *data)
+{
+       int err;
+       char *media;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct opt *opt;
+       struct nlattr *attrs;
+       struct opt opts[] = {
+               { "remoteip",           OPT_KEYVAL,     NULL },
+               { "remoteport",         OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { NULL }
+       };
+       const struct tipc_sup_media sup_media[] = {
+               { "udp",        "name",         cmd_bearer_add_udp_help},
+               { NULL, },
+       };
+
+       /* Rewind optind to include media in the option list */
+       cmdl->optind--;
+       if (parse_opts(opts, cmdl) < 0)
+               return -EINVAL;
+
+       if (!(opt = get_opt(opts, "media"))) {
+               fprintf(stderr, "error, missing media value\n");
+               return -EINVAL;
+       }
+       media = opt->val;
+
+       if (strcmp(media, "udp") != 0) {
+               fprintf(stderr, "error, no \"%s\" media specific options available\n",
+                       media);
+               return -EINVAL;
+       }
+       if (!(opt = get_opt(opts, "name"))) {
+               fprintf(stderr, "error, missing media name\n");
+               return -EINVAL;
+       }
+
+       if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ADD))) {
+               fprintf(stderr, "error, message initialisation failed\n");
+               return -1;
+       }
+
+       attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
+       err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+       if (err)
+               return err;
+
+       err = udp_bearer_add(nlh, opts, cmdl);
+       if (err)
+               return err;
+
+       mnl_attr_nest_end(nlh, attrs);
+
+       return msg_doit(nlh, NULL, NULL);
+}
+
+static int cmd_bearer_add(struct nlmsghdr *nlh, const struct cmd *cmd,
+                         struct cmdl *cmdl, void *data)
+{
+       const struct cmd cmds[] = {
+               { "media",      cmd_bearer_add_media,   cmd_bearer_add_help },
+               { NULL }
+       };
+
+       return run_cmd(nlh, cmd, cmds, cmdl, NULL);
+}
+
 static void cmd_bearer_enable_help(struct cmdl *cmdl)
 {
        fprintf(stderr,
@@ -218,7 +391,7 @@ static void cmd_bearer_enable_help(struct cmdl *cmdl)
                " domain DOMAIN         - Discovery domain\n"
                " priority PRIORITY     - Bearer priority\n",
                cmdl->argv[0]);
-       _print_bearer_media();
+       print_bearer_media();
 }
 
 static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
@@ -228,19 +401,24 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
        struct opt *opt;
        struct nlattr *nest;
        char buf[MNL_SOCKET_BUFFER_SIZE];
-       char *media;
        struct opt opts[] = {
-               { "device",             NULL },
-               { "domain",             NULL },
-               { "localip",            NULL },
-               { "localport",          NULL },
-               { "media",              NULL },
-               { "name",               NULL },
-               { "priority",           NULL },
-               { "remoteip",           NULL },
-               { "remoteport",         NULL },
+               { "device",             OPT_KEYVAL,     NULL },
+               { "domain",             OPT_KEYVAL,     NULL },
+               { "localip",            OPT_KEYVAL,     NULL },
+               { "localport",          OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
+               { "priority",           OPT_KEYVAL,     NULL },
+               { "remoteip",           OPT_KEYVAL,     NULL },
+               { "remoteport",         OPT_KEYVAL,     NULL },
                { NULL }
        };
+       struct tipc_sup_media sup_media[] = {
+               { "udp",        "name",         cmd_bearer_enable_udp_help},
+               { "eth",        "device",       cmd_bearer_enable_l2_help },
+               { "ib",         "device",       cmd_bearer_enable_l2_help },
+               { NULL, },
+       };
 
        if (parse_opts(opts, cmdl) < 0) {
                if (help_flag)
@@ -248,15 +426,6 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
                return -EINVAL;
        }
 
-       if (!(opt = get_opt(opts, "media"))) {
-               if (help_flag)
-                       (cmd->help)(cmdl);
-               else
-                       fprintf(stderr, "error, missing bearer media\n");
-               return -EINVAL;
-       }
-       media = opt->val;
-
        if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ENABLE))) {
                fprintf(stderr, "error: message initialisation failed\n");
                return -1;
@@ -274,95 +443,58 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
                mnl_attr_nest_end(nlh, props);
        }
 
-       if (strcmp(media, "udp") == 0) {
-               if (help_flag) {
-                       cmd_bearer_enable_udp_help(cmdl);
-                       return -EINVAL;
-               }
-               if ((err = enable_udp_bearer(nlh, opts, cmdl)))
-                       return err;
-       } else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
-               if (help_flag) {
-                       cmd_bearer_enable_l2_help(cmdl);
-                       return -EINVAL;
-               }
-               if ((err = enable_l2_bearer(nlh, opts, cmdl)))
+       err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+       if (err)
+               return err;
+
+       opt = get_opt(opts, "media");
+       if (opt && strcmp(opt->val, "udp") == 0) {
+               err = nl_add_udp_enable_opts(nlh, opts, cmdl);
+               if (err)
                        return err;
-       } else {
-               fprintf(stderr, "error, invalid media type \"%s\"\n", media);
-               return -EINVAL;
        }
-
        mnl_attr_nest_end(nlh, nest);
 
        return msg_doit(nlh, NULL, NULL);
 }
 
-static int add_l2_bearer(struct nlmsghdr *nlh, struct opt *opts)
-{
-       struct opt *opt;
-       char id[TIPC_MAX_BEARER_NAME];
-
-       if (!(opt = get_opt(opts, "device"))) {
-               fprintf(stderr, "error: missing bearer device\n");
-               return -EINVAL;
-       }
-       snprintf(id, sizeof(id), "eth:%s", opt->val);
-
-       mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
-
-       return 0;
-}
-
-static int add_udp_bearer(struct nlmsghdr *nlh, struct opt *opts)
-{
-       struct opt *opt;
-       char id[TIPC_MAX_BEARER_NAME];
-
-       if (!(opt = get_opt(opts, "name"))) {
-               fprintf(stderr, "error: missing bearer name\n");
-               return -EINVAL;
-       }
-       snprintf(id, sizeof(id), "udp:%s", opt->val);
-
-       mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
-
-       return 0;
-}
-
-static void cmd_bearer_disable_l2_help(struct cmdl *cmdl)
+static void cmd_bearer_disable_l2_help(struct cmdl *cmdl, char *media)
 {
-       fprintf(stderr, "Usage: %s bearer disable media udp device DEVICE\n",
-               cmdl->argv[0]);
+       fprintf(stderr, "Usage: %s bearer disable media %s device DEVICE\n",
+               cmdl->argv[0], media);
 }
 
-static void cmd_bearer_disable_udp_help(struct cmdl *cmdl)
+static void cmd_bearer_disable_udp_help(struct cmdl *cmdl, char *media)
 {
-       fprintf(stderr, "Usage: %s bearer disable media udp name NAME\n",
-               cmdl->argv[0]);
+       fprintf(stderr, "Usage: %s bearer disable media %s name NAME\n",
+               cmdl->argv[0], media);
 }
 
 static void cmd_bearer_disable_help(struct cmdl *cmdl)
 {
        fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n",
                cmdl->argv[0]);
-       _print_bearer_media();
+       print_bearer_media();
 }
 
 static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
                              struct cmdl *cmdl, void *data)
 {
        int err;
-       char *media;
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct nlattr *nest;
-       struct opt *opt;
        struct opt opts[] = {
-               { "device",             NULL },
-               { "name",               NULL },
-               { "media",              NULL },
+               { "device",             OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
                { NULL }
        };
+       struct tipc_sup_media sup_media[] = {
+               { "udp",        "name",         cmd_bearer_disable_udp_help},
+               { "eth",        "device",       cmd_bearer_disable_l2_help },
+               { "ib",         "device",       cmd_bearer_disable_l2_help },
+               { NULL, },
+       };
 
        if (parse_opts(opts, cmdl) < 0) {
                if (help_flag)
@@ -370,40 +502,15 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
                return -EINVAL;
        }
 
-       if (!(opt = get_opt(opts, "media"))) {
-               if (help_flag)
-                       (cmd->help)(cmdl);
-               else
-                       fprintf(stderr, "error, missing bearer media\n");
-               return -EINVAL;
-       }
-       media = opt->val;
-
        if (!(nlh = msg_init(buf, TIPC_NL_BEARER_DISABLE))) {
                fprintf(stderr, "error, message initialisation failed\n");
                return -1;
        }
 
        nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
-
-       if (strcmp(media, "udp") == 0) {
-               if (help_flag) {
-                       cmd_bearer_disable_udp_help(cmdl);
-                       return -EINVAL;
-               }
-               if ((err = add_udp_bearer(nlh, opts)))
-                       return err;
-       } else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
-               if (help_flag) {
-                       cmd_bearer_disable_l2_help(cmdl);
-                       return -EINVAL;
-               }
-               if ((err = add_l2_bearer(nlh, opts)))
-                       return err;
-       } else {
-               fprintf(stderr, "error, invalid media type \"%s\"\n", media);
-               return -EINVAL;
-       }
+       err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+       if (err)
+               return err;
        mnl_attr_nest_end(nlh, nest);
 
        return msg_doit(nlh, NULL, NULL);
@@ -415,13 +522,13 @@ static void cmd_bearer_set_help(struct cmdl *cmdl)
        fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n",
                cmdl->argv[0]);
        _print_bearer_opts();
-       _print_bearer_media();
+       print_bearer_media();
 }
 
-static void cmd_bearer_set_udp_help(struct cmdl *cmdl)
+static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media)
 {
-       fprintf(stderr, "Usage: %s bearer set OPTION media udp name NAME\n\n",
-               cmdl->argv[0]);
+       fprintf(stderr, "Usage: %s bearer set OPTION media %s name NAME\n\n",
+               cmdl->argv[0], media);
        _print_bearer_opts();
 }
 
@@ -434,22 +541,26 @@ static void cmd_bearer_set_l2_help(struct cmdl *cmdl, char *media)
 }
 
 static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
-                        struct cmdl *cmdl, void *data)
+                              struct cmdl *cmdl, void *data)
 {
        int err;
        int val;
        int prop;
-       char *media;
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct nlattr *props;
        struct nlattr *attrs;
-       struct opt *opt;
        struct opt opts[] = {
-               { "device",             NULL },
-               { "media",              NULL },
-               { "name",               NULL },
+               { "device",             OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
                { NULL }
        };
+       struct tipc_sup_media sup_media[] = {
+               { "udp",        "name",         cmd_bearer_set_udp_help},
+               { "eth",        "device",       cmd_bearer_set_l2_help },
+               { "ib",         "device",       cmd_bearer_set_l2_help },
+               { NULL, },
+       };
 
        if (strcmp(cmd->cmd, "priority") == 0)
                prop = TIPC_NLA_PROP_PRIO;
@@ -457,14 +568,11 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
                prop = TIPC_NLA_PROP_TOL;
        else if ((strcmp(cmd->cmd, "window") == 0))
                prop = TIPC_NLA_PROP_WIN;
+       else if ((strcmp(cmd->cmd, "mtu") == 0))
+               prop = TIPC_NLA_PROP_MTU;
        else
                return -EINVAL;
 
-       if (help_flag) {
-               (cmd->help)(cmdl);
-               return -EINVAL;
-       }
-
        if (cmdl->optind >= cmdl->argc) {
                fprintf(stderr, "error, missing value\n");
                return -EINVAL;
@@ -474,6 +582,17 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
        if (parse_opts(opts, cmdl) < 0)
                return -EINVAL;
 
+       if (prop == TIPC_NLA_PROP_MTU) {
+               char *media = cmd_get_media_type(cmd, cmdl, opts);
+
+               if (!media)
+                       return -EINVAL;
+               else if (strcmp(media, "udp")) {
+                       fprintf(stderr, "error, not supported for media\n");
+                       return -EINVAL;
+               }
+       }
+
        if (!(nlh = msg_init(buf, TIPC_NL_BEARER_SET))) {
                fprintf(stderr, "error, message initialisation failed\n");
                return -1;
@@ -484,30 +603,10 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
        mnl_attr_put_u32(nlh, prop, val);
        mnl_attr_nest_end(nlh, props);
 
-       if (!(opt = get_opt(opts, "media"))) {
-               fprintf(stderr, "error, missing media\n");
-               return -EINVAL;
-       }
-       media = opt->val;
+       err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+       if (err)
+               return err;
 
-       if (strcmp(media, "udp") == 0) {
-               if (help_flag) {
-                       cmd_bearer_set_udp_help(cmdl);
-                       return -EINVAL;
-               }
-               if ((err = add_udp_bearer(nlh, opts)))
-                       return err;
-       } else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
-               if (help_flag) {
-                       cmd_bearer_set_l2_help(cmdl, media);
-                       return -EINVAL;
-               }
-               if ((err = add_l2_bearer(nlh, opts)))
-                       return err;
-       } else {
-               fprintf(stderr, "error, invalid media type \"%s\"\n", media);
-               return -EINVAL;
-       }
        mnl_attr_nest_end(nlh, attrs);
 
        return msg_doit(nlh, NULL, NULL);
@@ -520,6 +619,7 @@ static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd,
                { "priority",   cmd_bearer_set_prop,    cmd_bearer_set_help },
                { "tolerance",  cmd_bearer_set_prop,    cmd_bearer_set_help },
                { "window",     cmd_bearer_set_prop,    cmd_bearer_set_help },
+               { "mtu",        cmd_bearer_set_prop,    cmd_bearer_set_help },
                { NULL }
        };
 
@@ -528,27 +628,142 @@ static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd,
 
 static void cmd_bearer_get_help(struct cmdl *cmdl)
 {
-       fprintf(stderr, "Usage: %s bearer get OPTION media MEDIA ARGS...\n",
+       fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n",
                cmdl->argv[0]);
        _print_bearer_opts();
-       _print_bearer_media();
+       print_bearer_media();
 }
 
-static void cmd_bearer_get_udp_help(struct cmdl *cmdl)
+static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media)
 {
-       fprintf(stderr, "Usage: %s bearer get OPTION media udp name NAME\n\n",
-               cmdl->argv[0]);
+       fprintf(stderr, "Usage: %s bearer get [OPTION] media %s name NAME [UDP OPTIONS]\n\n",
+               cmdl->argv[0], media);
+       fprintf(stderr,
+               "UDP OPTIONS\n"
+               " remoteip              - Remote ip address\n"
+               " remoteport            - Remote port\n"
+               " localip               - Local ip address\n"
+               " localport             - Local port\n\n");
        _print_bearer_opts();
 }
 
 static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media)
 {
        fprintf(stderr,
-               "Usage: %s bearer get [OPTION]... media %s device DEVICE\n",
+               "Usage: %s bearer get OPTION media %s device DEVICE\n",
                cmdl->argv[0], media);
        _print_bearer_opts();
 }
 
+
+static int bearer_dump_udp_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct sockaddr_storage *addr;
+       struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+       struct nlattr *info[TIPC_NLA_UDP_MAX + 1] = {};
+
+       mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+
+       if (!info[TIPC_NLA_UDP_REMOTE])
+               return MNL_CB_ERROR;
+
+       addr = mnl_attr_get_payload(info[TIPC_NLA_UDP_REMOTE]);
+
+       if (addr->ss_family == AF_INET) {
+               struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr;
+
+               printf("%s\n", inet_ntoa(ipv4->sin_addr));
+       } else if (addr->ss_family == AF_INET6) {
+               char straddr[INET6_ADDRSTRLEN];
+               struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr;
+
+               if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr,
+                              sizeof(straddr))) {
+                       fprintf(stderr, "error, parsing IPv6 addr\n");
+                       return MNL_CB_ERROR;
+               }
+               printf("%s\n", straddr);
+
+       } else {
+               return MNL_CB_ERROR;
+       }
+
+       return MNL_CB_OK;
+}
+
+static int bearer_get_udp_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct cb_data *cb_data = (struct cb_data *) data;
+       struct sockaddr_storage *addr;
+       struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+       struct nlattr *info[TIPC_NLA_MAX + 1] = {};
+       struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
+       struct nlattr *opts[TIPC_NLA_UDP_MAX + 1] = {};
+
+       mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
+       if (!info[TIPC_NLA_BEARER])
+               return MNL_CB_ERROR;
+
+       mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
+       if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
+               return MNL_CB_ERROR;
+
+       mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_UDP_OPTS], parse_attrs, opts);
+       if (!opts[TIPC_NLA_UDP_LOCAL])
+               return MNL_CB_ERROR;
+
+       if ((cb_data->attr == TIPC_NLA_UDP_REMOTE) &&
+           (cb_data->prop == UDP_PROP_IP) &&
+           opts[TIPC_NLA_UDP_MULTI_REMOTEIP]) {
+               struct genlmsghdr *genl = mnl_nlmsg_get_payload(cb_data->nlh);
+
+               genl->cmd = TIPC_NL_UDP_GET_REMOTEIP;
+               return msg_dumpit(cb_data->nlh, bearer_dump_udp_cb, NULL);
+       }
+
+       addr = mnl_attr_get_payload(opts[cb_data->attr]);
+
+       if (addr->ss_family == AF_INET) {
+               struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr;
+
+               switch (cb_data->prop) {
+               case UDP_PROP_IP:
+                       printf("%s\n", inet_ntoa(ipv4->sin_addr));
+                       break;
+               case UDP_PROP_PORT:
+                       printf("%u\n", ntohs(ipv4->sin_port));
+                       break;
+               default:
+                       return MNL_CB_ERROR;
+               }
+
+       } else if (addr->ss_family == AF_INET6) {
+               char straddr[INET6_ADDRSTRLEN];
+               struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr;
+
+               switch (cb_data->prop) {
+               case UDP_PROP_IP:
+                       if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr,
+                                      sizeof(straddr))) {
+                               fprintf(stderr, "error, parsing IPv6 addr\n");
+                               return MNL_CB_ERROR;
+                       }
+                       printf("%s\n", straddr);
+                       break;
+               case UDP_PROP_PORT:
+                       printf("%u\n", ntohs(ipv6->sin6_port));
+                       break;
+               default:
+                       return MNL_CB_ERROR;
+               }
+
+       } else {
+               return MNL_CB_ERROR;
+       }
+
+       return MNL_CB_OK;
+}
+
 static int bearer_get_cb(const struct nlmsghdr *nlh, void *data)
 {
        int *prop = data;
@@ -574,21 +789,110 @@ static int bearer_get_cb(const struct nlmsghdr *nlh, void *data)
        return MNL_CB_OK;
 }
 
+static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd,
+                               struct cmdl *cmdl, void *data)
+{
+       int err;
+       char *media;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct opt *opt;
+       struct cb_data cb_data = {0};
+       struct nlattr *attrs;
+       struct opt opts[] = {
+               { "localip",            OPT_KEY,        NULL },
+               { "localport",          OPT_KEY,        NULL },
+               { "remoteip",           OPT_KEY,        NULL },
+               { "remoteport",         OPT_KEY,        NULL },
+               { "name",               OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { NULL }
+       };
+       struct tipc_sup_media sup_media[] = {
+               { "udp",        "name",         cmd_bearer_get_udp_help},
+               { NULL, },
+       };
+
+       /* Rewind optind to include media in the option list */
+       cmdl->optind--;
+       if (parse_opts(opts, cmdl) < 0)
+               return -EINVAL;
+
+       if (!(opt = get_opt(opts, "media"))) {
+               fprintf(stderr, "error, missing media value\n");
+               return -EINVAL;
+       }
+       media = opt->val;
+
+       if (help_flag) {
+               cmd_bearer_get_udp_help(cmdl, media);
+               return -EINVAL;
+       }
+       if (strcmp(media, "udp") != 0) {
+               fprintf(stderr, "error, no \"%s\" media specific options\n", media);
+               return -EINVAL;
+       }
+       if (!(opt = get_opt(opts, "name"))) {
+               fprintf(stderr, "error, missing media name\n");
+               return -EINVAL;
+       }
+
+       if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
+               fprintf(stderr, "error, message initialisation failed\n");
+               return -1;
+       }
+
+       attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
+       err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+       if (err)
+               return err;
+       mnl_attr_nest_end(nlh, attrs);
+       cb_data.nlh = nlh;
+
+       if (has_opt(opts, "localip")) {
+               cb_data.attr = TIPC_NLA_UDP_LOCAL;
+               cb_data.prop = UDP_PROP_IP;
+               return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+       } else if (has_opt(opts, "localport")) {
+               cb_data.attr = TIPC_NLA_UDP_LOCAL;
+               cb_data.prop = UDP_PROP_PORT;
+               return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+       } else if (has_opt(opts, "remoteip")) {
+               cb_data.attr = TIPC_NLA_UDP_REMOTE;
+               cb_data.prop = UDP_PROP_IP;
+               return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+       } else if (has_opt(opts, "remoteport")) {
+               cb_data.attr = TIPC_NLA_UDP_REMOTE;
+               cb_data.prop = UDP_PROP_PORT;
+               return msg_doit(nlh, bearer_get_udp_cb, &cb_data);
+       }
+       fprintf(stderr, "error, missing UDP option\n");
+       return -EINVAL;
+}
+
 static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
                               struct cmdl *cmdl, void *data)
 {
        int err;
        int prop;
-       char *media;
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct nlattr *attrs;
-       struct opt *opt;
        struct opt opts[] = {
-               { "device",             NULL },
-               { "media",              NULL },
-               { "name",               NULL },
+               { "device",             OPT_KEYVAL,     NULL },
+               { "media",              OPT_KEYVAL,     NULL },
+               { "name",               OPT_KEYVAL,     NULL },
                { NULL }
        };
+       struct tipc_sup_media sup_media[] = {
+               { "udp",        "name",         cmd_bearer_get_udp_help},
+               { "eth",        "device",       cmd_bearer_get_l2_help },
+               { "ib",         "device",       cmd_bearer_get_l2_help },
+               { NULL, },
+       };
+
+       if (help_flag) {
+               (cmd->help)(cmdl);
+               return -EINVAL;
+       }
 
        if (strcmp(cmd->cmd, "priority") == 0)
                prop = TIPC_NLA_PROP_PRIO;
@@ -596,47 +900,34 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
                prop = TIPC_NLA_PROP_TOL;
        else if ((strcmp(cmd->cmd, "window") == 0))
                prop = TIPC_NLA_PROP_WIN;
+       else if ((strcmp(cmd->cmd, "mtu") == 0))
+               prop = TIPC_NLA_PROP_MTU;
        else
                return -EINVAL;
 
-       if (help_flag) {
-               (cmd->help)(cmdl);
-               return -EINVAL;
-       }
-
        if (parse_opts(opts, cmdl) < 0)
                return -EINVAL;
 
+       if (prop == TIPC_NLA_PROP_MTU) {
+               char *media = cmd_get_media_type(cmd, cmdl, opts);
+
+               if (!media)
+                       return -EINVAL;
+               else if (strcmp(media, "udp")) {
+                       fprintf(stderr, "error, not supported for media\n");
+                       return -EINVAL;
+               }
+       }
+
        if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
                fprintf(stderr, "error, message initialisation failed\n");
                return -1;
        }
 
-       if (!(opt = get_opt(opts, "media"))) {
-               fprintf(stderr, "error, missing media\n");
-               return -EINVAL;
-       }
-       media = opt->val;
-
        attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
-       if (strcmp(media, "udp") == 0) {
-               if (help_flag) {
-                       cmd_bearer_get_udp_help(cmdl);
-                       return -EINVAL;
-               }
-               if ((err = add_udp_bearer(nlh, opts)))
-                       return err;
-       } else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) {
-               if (help_flag) {
-                       cmd_bearer_get_l2_help(cmdl, media);
-                       return -EINVAL;
-               }
-               if ((err = add_l2_bearer(nlh, opts)))
-                       return err;
-       } else {
-               fprintf(stderr, "error, invalid media type \"%s\"\n", media);
-               return -EINVAL;
-       }
+       err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
+       if (err)
+               return err;
        mnl_attr_nest_end(nlh, attrs);
 
        return msg_doit(nlh, bearer_get_cb, &prop);
@@ -649,6 +940,8 @@ static int cmd_bearer_get(struct nlmsghdr *nlh, const struct cmd *cmd,
                { "priority",   cmd_bearer_get_prop,    cmd_bearer_get_help },
                { "tolerance",  cmd_bearer_get_prop,    cmd_bearer_get_help },
                { "window",     cmd_bearer_get_prop,    cmd_bearer_get_help },
+               { "mtu",        cmd_bearer_get_prop,    cmd_bearer_get_help },
+               { "media",      cmd_bearer_get_media,   cmd_bearer_get_help },
                { NULL }
        };
 
@@ -702,6 +995,7 @@ void cmd_bearer_help(struct cmdl *cmdl)
                "Usage: %s bearer COMMAND [ARGS] ...\n"
                "\n"
                "COMMANDS\n"
+               " add                   - Add data to existing bearer\n"
                " enable                - Enable a bearer\n"
                " disable               - Disable a bearer\n"
                " set                   - Set various bearer properties\n"
@@ -713,6 +1007,7 @@ int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
               void *data)
 {
        const struct cmd cmds[] = {
+               { "add",        cmd_bearer_add,         cmd_bearer_add_help },
                { "disable",    cmd_bearer_disable,     cmd_bearer_disable_help },
                { "enable",     cmd_bearer_enable,      cmd_bearer_enable_help },
                { "get",        cmd_bearer_get,         cmd_bearer_get_help },