diff --git a/tipc/bearer.c b/tipc/bearer.c index 1f3a4d44..4470819e 100644 --- a/tipc/bearer.c +++ b/tipc/bearer.c @@ -19,10 +19,12 @@ #include #include #include +#include #include #include +#include "utils.h" #include "cmdl.h" #include "msg.h" #include "bearer.h" @@ -68,7 +70,7 @@ static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media) static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media) { fprintf(stderr, - "Usage: %s bearer enable [OPTIONS] media %s name NAME localip IP [UDP OPTIONS]\n\n" + "Usage: %s bearer enable [OPTIONS] media %s name NAME [localip IP|device DEVICE] [UDP OPTIONS]\n\n" "OPTIONS\n" " domain DOMAIN - Discovery domain\n" " priority PRIORITY - Bearer priority\n\n" @@ -119,6 +121,76 @@ static int generate_multicast(short af, char *buf, int bufsize) return 0; } +static struct ifreq ifr; +static int nl_dump_req_filter(struct nlmsghdr *nlh, int reqlen) +{ + struct ifaddrmsg *ifa = NLMSG_DATA(nlh); + + ifa->ifa_index = ifr.ifr_ifindex; + + return 0; +} + +static int nl_dump_addr_filter(struct nlmsghdr *nlh, void *arg) +{ + struct ifaddrmsg *ifa = NLMSG_DATA(nlh); + char *r_addr = (char *)arg; + int len = nlh->nlmsg_len; + struct rtattr *addr_attr; + + if (ifr.ifr_ifindex != ifa->ifa_index) + return 0; + + if (strlen(r_addr) > 0) + return 0; + + addr_attr = parse_rtattr_one(IFA_ADDRESS, IFA_RTA(ifa), + len - NLMSG_LENGTH(sizeof(*ifa))); + if (!addr_attr) + return 0; + + if (ifa->ifa_family == AF_INET) { + struct sockaddr_in ip4addr; + memcpy(&ip4addr.sin_addr, RTA_DATA(addr_attr), + sizeof(struct in_addr)); + inet_ntop(AF_INET, &ip4addr.sin_addr, r_addr, + INET_ADDRSTRLEN); + } else if (ifa->ifa_family == AF_INET6) { + struct sockaddr_in6 ip6addr; + memcpy(&ip6addr.sin6_addr, RTA_DATA(addr_attr), + sizeof(struct in6_addr)); + inet_ntop(AF_INET6, &ip6addr.sin6_addr, r_addr, + INET6_ADDRSTRLEN); + } + return 0; +} + +static int cmd_bearer_validate_and_get_addr(const char *name, char *r_addr) +{ + struct rtnl_handle rth = { .fd = -1 }; + int err = -1; + + memset(&ifr, 0, sizeof(ifr)); + if (!name || !r_addr || get_ifname(ifr.ifr_name, name)) + return err; + + ifr.ifr_ifindex = ll_name_to_index(ifr.ifr_name); + if (!ifr.ifr_ifindex) + return err; + + /* remove from cache */ + ll_drop_by_index(ifr.ifr_ifindex); + + if ((err = rtnl_open(&rth, 0)) < 0) + return err; + + if ((err = rtnl_addrdump_req(&rth, AF_UNSPEC, nl_dump_req_filter)) > 0) + err = rtnl_dump_filter(&rth, nl_dump_addr_filter, r_addr); + + rtnl_close(&rth); + return err; +} + static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts, struct cmdl *cmdl) { @@ -136,13 +208,25 @@ static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts, .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM }; + char addr[INET6_ADDRSTRLEN] = {0}; - if (!(opt = get_opt(opts, "localip"))) { - fprintf(stderr, "error, udp bearer localip missing\n"); - cmd_bearer_enable_udp_help(cmdl, "udp"); + opt = get_opt(opts, "device"); + if (opt && cmd_bearer_validate_and_get_addr(opt->val, addr) < 0) { + fprintf(stderr, "error, no device name available\n"); return -EINVAL; } - locip = opt->val; + + if (strlen(addr) > 0) { + locip = addr; + } else { + opt = get_opt(opts, "localip"); + if (!opt) { + fprintf(stderr, "error, udp bearer localip/device missing\n"); + cmd_bearer_enable_udp_help(cmdl, "udp"); + return -EINVAL; + } + locip = opt->val; + } if ((opt = get_opt(opts, "remoteip"))) remip = opt->val;