diff --git a/net/net-mtools/Makefile b/net/net-mtools/Makefile new file mode 100644 index 000000000..c19532616 --- /dev/null +++ b/net/net-mtools/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=net-mtools +PKG_VERSION:=2.3 +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL=https://github.com/troglobit/mtools +PKG_SOURCE_VERSION:=db665a4303c38cee908eba4dac50873c3f1d899c +PKG_MIRROR_HASH:=687e3743e46c8ddd23f03168b4021ed08b1a858b2a6743db3b62cb3d4c3592a0 + +include $(INCLUDE_DIR)/package.mk + +define Package/net-mtools + SECTION:=net + CATEGORY:=Network + TITLE:=Debug multicast setups with mtools (msend and mreceive) + URL:=https://github.com/troglobit/mtools +endef + +define Package/net-mtools/description + The tools msend and mreceive can be particulary useful + when debugging multicast setups. + + msend continuously sends UDP packets to the multicast + group specified by the -g and -p options. + + mreceive joins a multicast group specified by the -g and + -p options, then receives and displays the multicast + packets sent to this group:port combination by the msend + command. +endef + +define Package/net-mtools/install + $(INSTALL_DIR) $(1)/usr/sbin + $(CP) $(PKG_BUILD_DIR)/msend $(1)/usr/sbin/ + $(CP) $(PKG_BUILD_DIR)/mreceive $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,net-mtools)) diff --git a/net/net-mtools/patches/001-mreceive-refactor-multicast-joining-to-separate-func.patch b/net/net-mtools/patches/001-mreceive-refactor-multicast-joining-to-separate-func.patch new file mode 100644 index 000000000..db96daedf --- /dev/null +++ b/net/net-mtools/patches/001-mreceive-refactor-multicast-joining-to-separate-func.patch @@ -0,0 +1,66 @@ +From 0cfc04eac370ee33118e17a298d4739c94cacc73 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Tue, 19 Apr 2022 12:28:03 +0300 +Subject: [PATCH 1/6] mreceive: refactor multicast joining to separate function + +Signed-off-by: Vladimir Oltean +--- + mreceive.c | 33 ++++++++++++++++++--------------- + 1 file changed, 18 insertions(+), 15 deletions(-) + +--- a/mreceive.c ++++ b/mreceive.c +@@ -61,12 +61,27 @@ Usage: mreceive [-g GROUP] [-p PORT] [-i + -h Print the command usage.\n\n", VERSION); + } + ++static void igmp_join(int s, in_addr_t multiaddr, in_addr_t interface) ++{ ++ struct ip_mreq mreq; ++ int ret; ++ ++ mreq.imr_multiaddr.s_addr = multiaddr; ++ mreq.imr_interface.s_addr = interface; ++ ++ ret = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, ++ (char *)&mreq, sizeof(mreq)); ++ if (ret == SOCKET_ERROR) { ++ printf("setsockopt() IP_ADD_MEMBERSHIP failed.\n"); ++ exit(1); ++ } ++} ++ + int main(int argc, char *argv[]) + { + struct sockaddr_in stLocal, stFrom; + unsigned char achIn[BUFSIZE]; + int s, i; +- struct ip_mreq stMreq; + int iTmp, iRet; + int ipnum = 0; + int ii; +@@ -153,22 +168,10 @@ int main(int argc, char *argv[]) + + /* join the multicast group. */ + if (!ipnum) { /* single interface */ +- stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR); +- stMreq.imr_interface.s_addr = INADDR_ANY; +- iRet = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() IP_ADD_MEMBERSHIP failed.\n"); +- exit(1); +- } ++ igmp_join(s, inet_addr(TEST_ADDR), INADDR_ANY); + } else { + for (i = 0; i < ipnum; i++) { +- stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR); +- stMreq.imr_interface.s_addr = IP[i]; +- iRet = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() IP_ADD_MEMBERSHIP failed.\n"); +- exit(1); +- } ++ igmp_join(s, inet_addr(TEST_ADDR), IP[i]); + } + } + diff --git a/net/net-mtools/patches/002-mreceive-join-IGMP-group-by-interface.patch b/net/net-mtools/patches/002-mreceive-join-IGMP-group-by-interface.patch new file mode 100644 index 000000000..5959062f9 --- /dev/null +++ b/net/net-mtools/patches/002-mreceive-join-IGMP-group-by-interface.patch @@ -0,0 +1,113 @@ +From 65af96e0907ba9367aab9c1534b11c7f674c1e6a Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Tue, 19 Apr 2022 13:29:07 +0300 +Subject: [PATCH 2/6] mreceive: join IGMP group by interface + +mreceive uses the old-style struct ip_mreq for IP_ADD_MEMBERSHIP, which +takes the source address of the interface wishing to join. + +Since the IPV6_ADD_MEMBERSHIP variant only takes a struct ipv6_mreq +which contains the ifindex and not the source address, we need to add +support for that. + +In preparation for IPv6 support, add logic to join an IGMP group either +by source address or by interface name, whichever is specified. + +Signed-off-by: Vladimir Oltean +--- + mreceive.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 46 insertions(+), 5 deletions(-) + +--- a/mreceive.c ++++ b/mreceive.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -61,7 +62,7 @@ Usage: mreceive [-g GROUP] [-p PORT] [-i + -h Print the command usage.\n\n", VERSION); + } + +-static void igmp_join(int s, in_addr_t multiaddr, in_addr_t interface) ++static void igmp_join_by_saddr(int s, in_addr_t multiaddr, in_addr_t interface) + { + struct ip_mreq mreq; + int ret; +@@ -77,10 +78,34 @@ static void igmp_join(int s, in_addr_t m + } + } + ++static void igmp_join_by_if_name(int s, in_addr_t multicast, ++ const char *if_name) ++{ ++ struct ip_mreqn mreq = {}; ++ int if_index; ++ int ret; ++ ++ if_index = if_nametoindex(if_name); ++ if (!if_index) { ++ perror("if_nametoindex"); ++ exit(1); ++ } ++ ++ mreq.imr_multiaddr.s_addr = multicast; ++ mreq.imr_ifindex = if_index; ++ ++ ret = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); ++ if (ret) { ++ perror("setsockopt() IP_ADD_MEMBERSHIP"); ++ exit(1); ++ } ++} ++ + int main(int argc, char *argv[]) + { + struct sockaddr_in stLocal, stFrom; + unsigned char achIn[BUFSIZE]; ++ const char *if_name; + int s, i; + int iTmp, iRet; + int ipnum = 0; +@@ -131,6 +156,17 @@ int main(int argc, char *argv[]) + ii++; + ipnum++; + } ++ } else if (strcmp(argv[ii], "-I") == 0) { ++ ii++; ++ if (ii < argc) { ++ if (if_name) { ++ printf("Single interface expected\n"); ++ exit(1); ++ } ++ ++ if_name = argv[ii]; ++ ii++; ++ } + } else if (strcmp(argv[ii], "-n") == 0) { + ii++; + NUM = 1; +@@ -167,11 +203,16 @@ int main(int argc, char *argv[]) + } + + /* join the multicast group. */ +- if (!ipnum) { /* single interface */ +- igmp_join(s, inet_addr(TEST_ADDR), INADDR_ANY); ++ if (if_name) { ++ igmp_join_by_if_name(s, inet_addr(TEST_ADDR), if_name); + } else { +- for (i = 0; i < ipnum; i++) { +- igmp_join(s, inet_addr(TEST_ADDR), IP[i]); ++ if (!ipnum) { /* single interface */ ++ igmp_join_by_saddr(s, inet_addr(TEST_ADDR), INADDR_ANY); ++ } else { ++ for (i = 0; i < ipnum; i++) { ++ igmp_join_by_saddr(s, inet_addr(TEST_ADDR), ++ IP[i]); ++ } + } + } + diff --git a/net/net-mtools/patches/003-mreceive-support-IPv6.patch b/net/net-mtools/patches/003-mreceive-support-IPv6.patch new file mode 100644 index 000000000..cfd1ab2cf --- /dev/null +++ b/net/net-mtools/patches/003-mreceive-support-IPv6.patch @@ -0,0 +1,578 @@ +From cc7f68045e5f3cfc6c932996af784ab319951426 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Tue, 19 Apr 2022 13:29:20 +0300 +Subject: [PATCH 3/6] mreceive: support IPv6 + +Extend the mreceive program with a generalization of sockets, +addresses and socket options that covers both IPv4 and IPv6. + +Most of the lower-level implementation is moved to common.c and exported +through common.h such that it can be reused by msend at a later time. + +The makefile rule to link object files into executables is updated to +look at all specified objects rather than just the first, by using $^ +instead of $<. Otherwise, common.o would be ignored when linking +mreceive. + +Signed-off-by: Vladimir Oltean +--- + Makefile | 8 +- + common.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + common.h | 36 ++++++++ + mreceive.c | 142 ++++++++++------------------- + 4 files changed, 349 insertions(+), 98 deletions(-) + create mode 100644 common.c + create mode 100644 common.h + +--- a/Makefile ++++ b/Makefile +@@ -20,8 +20,8 @@ mandir = $(prefix)/share/man/man8 + # ttcp is currently not part of the distribution because its not tested + # yet. Please test and let me know at GitHub so I can include it! :) + EXEC := msend mreceive +-OBJS := $(EXEC:=.o) +-DEPS := $(EXEC:=.d) ++OBJS := msend.o mreceive.o common.o ++DEPS := msend.d mreceive.d common.d + MANS = $(addsuffix .8,$(EXEC)) + DISTFILES = README.md LICENSE.md + +@@ -33,10 +33,10 @@ all: $(EXEC) + + .o: + @printf " LINK $@\n" +- @$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $< $(LDLIBS$(LDLIBS-$(@))) ++ @$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@))) + + msend: msend.o +-mreceive: mreceive.o ++mreceive: mreceive.o common.o + ttcp: ttcp.o + + install: $(EXEC) +--- /dev/null ++++ b/common.c +@@ -0,0 +1,261 @@ ++/* ++ * common.c -- Common functions for mreceive.c and msend.c ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++ ++int ip_address_parse(const char *string, struct ip_address *ip) ++{ ++ int ret; ++ ++ ret = inet_pton(AF_INET6, string, &ip->addr6); ++ if (ret > 0) { ++ ip->family = AF_INET6; ++ } else { ++ ret = inet_pton(AF_INET, string, &ip->addr); ++ if (ret > 0) { ++ ip->family = AF_INET; ++ } else { ++ fprintf(stderr, "IP address %s not in known format\n", ++ string); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++int socket_create(struct sock *s, int family, int port) ++{ ++ struct sockaddr *serv_addr; ++ int sockopt = 1; ++ int fd, ret; ++ ++ memset(s, 0, sizeof(*s)); ++ ++ if (family == AF_INET) { ++ serv_addr = (struct sockaddr *)&s->udp4; ++ s->udp4.sin_addr.s_addr = htonl(INADDR_ANY); ++ s->udp4.sin_port = htons(port); ++ s->udp4.sin_family = AF_INET; ++ s->addr_size = sizeof(struct sockaddr_in); ++ } else { ++ serv_addr = (struct sockaddr *)&s->udp6; ++ s->udp6.sin6_addr = in6addr_any; ++ s->udp6.sin6_port = htons(port); ++ s->udp6.sin6_family = AF_INET6; ++ s->addr_size = sizeof(struct sockaddr_in6); ++ } ++ ++ fd = socket(family, SOCK_DGRAM, 0); ++ if (fd < 0) { ++ perror("socket"); ++ return fd; ++ } ++ ++ /* avoid EADDRINUSE error on bind() */ ++ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)); ++ if (ret) { ++ perror("setsockopt() SO_REUSEADDR"); ++ close(fd); ++ return ret; ++ } ++ ++ ret = bind(fd, serv_addr, s->addr_size); ++ if (ret) { ++ perror("bind"); ++ close(fd); ++ return ret; ++ } ++ ++ s->fd = fd; ++ ++ return 0; ++} ++ ++static int igmp_join_by_saddr(struct sock *s, const struct ip_address *mc, ++ struct ip_address *saddr) ++{ ++ struct ip_mreq mreq = {}; ++ int fd = s->fd; ++ int off = 0; ++ int ret; ++ ++ memcpy(&mreq.imr_multiaddr, &mc->addr, sizeof(struct in_addr)); ++ memcpy(&mreq.imr_interface.s_addr, &saddr->addr, ++ sizeof(struct in_addr)); ++ ++ ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); ++ if (ret) { ++ perror("setsockopt() IP_ADD_MEMBERSHIP"); ++ return -1; ++ } ++ ++ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &off, sizeof(int)); ++ if (ret) { ++ perror("setsockopt() IP_MULTICAST_LOOP"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int igmp_join_by_if_name(struct sock *s, const struct ip_address *mc, ++ const char *if_name) ++{ ++ struct ip_mreqn mreq = {}; ++ int fd = s->fd; ++ int if_index; ++ int off = 0; ++ int ret; ++ ++ if_index = if_nametoindex(if_name); ++ if (!if_index) { ++ perror("if_nametoindex"); ++ return -1; ++ } ++ ++ memcpy(&mreq.imr_multiaddr, &mc->addr, sizeof(struct in_addr)); ++ mreq.imr_ifindex = if_index; ++ ++ ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); ++ if (ret) { ++ perror("setsockopt() IP_ADD_MEMBERSHIP"); ++ return -1; ++ } ++ ++ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &off, sizeof(int)); ++ if (ret) { ++ perror("setsockopt() IP_MULTICAST_LOOP"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int mld_join(struct sock *s, const struct ip_address *mc, ++ const char *if_name) ++{ ++ struct ipv6_mreq mreq = {}; ++ int if_index, off = 0; ++ int fd = s->fd; ++ int ret; ++ ++ if_index = if_nametoindex(if_name); ++ if (!if_index) { ++ perror("if_nametoindex"); ++ return -1; ++ } ++ ++ memcpy(&mreq.ipv6mr_multiaddr, &mc->addr6, sizeof(struct in6_addr)); ++ mreq.ipv6mr_interface = if_index; ++ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, ++ sizeof(mreq)); ++ if (ret) { ++ perror("setsockopt IPV6_ADD_MEMBERSHIP"); ++ return -1; ++ } ++ ++ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, ++ sizeof(int)); ++ if (ret) { ++ perror("setsockopt IPV6_MULTICAST_LOOP"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int mc_join(struct sock *s, const struct ip_address *mc, const char *if_name, ++ int num_saddrs, struct ip_address *saddrs) ++{ ++ int i, ret; ++ ++ if (if_name) { ++ switch (mc->family) { ++ case AF_INET: ++ return igmp_join_by_if_name(s, mc, if_name); ++ case AF_INET6: ++ return mld_join(s, mc, if_name); ++ default: ++ return -1; ++ } ++ } ++ ++ if (!num_saddrs) { /* single interface */ ++ struct ip_address saddr = { ++ .family = AF_INET, ++ .addr.s_addr = INADDR_ANY, ++ }; ++ ++ return igmp_join_by_saddr(s, mc, &saddr); ++ } ++ ++ for (i = 0; i < num_saddrs; i++) { ++ ret = igmp_join_by_saddr(s, mc, &saddrs[i]); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int igmp_set_ttl(int fd, int ttl) ++{ ++ int ret; ++ ++ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(int)); ++ if (ret) ++ perror("setsockopt() IP_MULTICAST_TTL"); ++ ++ return ret; ++} ++ ++static int mld_set_hop_limit(int fd, int limit) ++{ ++ int ret; ++ ++ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &limit, ++ sizeof(int)); ++ if (ret) ++ perror("setsockopt() IPV6_MULTICAST_HOPS"); ++ ++ return ret; ++} ++ ++int mc_set_hop_limit(struct sock *s, int limit) ++{ ++ switch (s->addr_size) { ++ case sizeof(struct sockaddr_in): ++ return igmp_set_ttl(s->fd, limit); ++ case sizeof(struct sockaddr_in6): ++ return mld_set_hop_limit(s->fd, limit); ++ default: ++ return -1; ++ } ++} ++ ++int mc_recv(struct sock *s, void *buf, size_t len, struct sock *from) ++{ ++ from->addr_size = sizeof(struct sockaddr_in6); ++ ++ return recvfrom(s->fd, buf, len, 0, (struct sockaddr *)&(from->udp6), ++ &from->addr_size); ++} ++ ++int socket_get_port(const struct sock *s) ++{ ++ switch (s->addr_size) { ++ case sizeof(struct sockaddr_in): ++ return ntohs(s->udp4.sin_port); ++ case sizeof(struct sockaddr_in6): ++ return ntohs(s->udp6.sin6_port); ++ default: ++ return 0; ++ } ++} +--- /dev/null ++++ b/common.h +@@ -0,0 +1,36 @@ ++/* ++ * common.h -- Common header for mreceive.c and msend.c ++ */ ++#ifndef _COMMON_H ++#define _COMMON_H ++ ++#include ++#include ++#include ++ ++struct ip_address { ++ int family; ++ union { ++ struct in_addr addr; ++ struct in6_addr addr6; ++ }; ++}; ++ ++struct sock { ++ socklen_t addr_size; ++ union { ++ struct sockaddr_in udp4; ++ struct sockaddr_in6 udp6; ++ }; ++ int fd; ++}; ++ ++int ip_address_parse(const char *string, struct ip_address *ip); ++int socket_create(struct sock *s, int family, int port); ++int mc_join(struct sock *s, const struct ip_address *mc, const char *if_name, ++ int num_saddrs, struct ip_address *saddrs); ++int mc_set_hop_limit(struct sock *s, int limit); ++int mc_recv(struct sock *s, void *buf, size_t len, struct sock *from); ++int socket_get_port(const struct sock *s); ++ ++#endif +--- a/mreceive.c ++++ b/mreceive.c +@@ -28,6 +28,8 @@ + #include + #include + ++#include "common.h" ++ + #define TRUE 1 + #define FALSE 0 + #ifndef INVALID_SOCKET +@@ -43,7 +45,7 @@ + + char *TEST_ADDR = "224.1.1.1"; + int TEST_PORT = 4444; +-unsigned long IP[MAXIP]; ++struct ip_address IP[MAXIP]; + int NUM = 0; + + void printHelp(void) +@@ -62,52 +64,12 @@ Usage: mreceive [-g GROUP] [-p PORT] [-i + -h Print the command usage.\n\n", VERSION); + } + +-static void igmp_join_by_saddr(int s, in_addr_t multiaddr, in_addr_t interface) +-{ +- struct ip_mreq mreq; +- int ret; +- +- mreq.imr_multiaddr.s_addr = multiaddr; +- mreq.imr_interface.s_addr = interface; +- +- ret = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, +- (char *)&mreq, sizeof(mreq)); +- if (ret == SOCKET_ERROR) { +- printf("setsockopt() IP_ADD_MEMBERSHIP failed.\n"); +- exit(1); +- } +-} +- +-static void igmp_join_by_if_name(int s, in_addr_t multicast, +- const char *if_name) +-{ +- struct ip_mreqn mreq = {}; +- int if_index; +- int ret; +- +- if_index = if_nametoindex(if_name); +- if (!if_index) { +- perror("if_nametoindex"); +- exit(1); +- } +- +- mreq.imr_multiaddr.s_addr = multicast; +- mreq.imr_ifindex = if_index; +- +- ret = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); +- if (ret) { +- perror("setsockopt() IP_ADD_MEMBERSHIP"); +- exit(1); +- } +-} +- + int main(int argc, char *argv[]) + { +- struct sockaddr_in stLocal, stFrom; + unsigned char achIn[BUFSIZE]; +- const char *if_name; +- int s, i; +- int iTmp, iRet; ++ const char *if_name = NULL; ++ struct ip_address mc; ++ struct sock s, from; + int ipnum = 0; + int ii; + unsigned int numreceived; +@@ -116,6 +78,8 @@ int main(int argc, char *argv[]) + int starttime; + int curtime; + struct timeval tv; ++ int ret; ++ int i; + + /* + if( argc < 2 ) { +@@ -152,7 +116,10 @@ int main(int argc, char *argv[]) + } else if (strcmp(argv[ii], "-i") == 0) { + ii++; + if ((ii < argc) && !(strchr(argv[ii], '-'))) { +- IP[ipnum] = inet_addr(argv[ii]); ++ ret = ip_address_parse(argv[ii], &IP[ipnum]); ++ if (ret) ++ exit(1); ++ + ii++; + ipnum++; + } +@@ -177,73 +144,59 @@ int main(int argc, char *argv[]) + } + } + +- /* get a datagram socket */ +- s = socket(AF_INET, SOCK_DGRAM, 0); +- if (s == INVALID_SOCKET) { +- printf("socket() failed.\n"); ++ ret = ip_address_parse(TEST_ADDR, &mc); ++ if (ret) + exit(1); +- } + +- /* avoid EADDRINUSE error on bind() */ +- iTmp = TRUE; +- iRet = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&iTmp, sizeof(iTmp)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() SO_REUSEADDR failed.\n"); ++ if (mc.family == AF_INET6 && ipnum) { ++ printf("Joining IPv6 groups by source address not supported, use -I\n"); + exit(1); + } + +- /* name the socket */ +- stLocal.sin_family = AF_INET; +- stLocal.sin_addr.s_addr = htonl(INADDR_ANY); +- stLocal.sin_port = htons(TEST_PORT); +- iRet = bind(s, (struct sockaddr *)&stLocal, sizeof(stLocal)); +- if (iRet == SOCKET_ERROR) { +- printf("bind() failed.\n"); ++ if (mc.family == AF_INET6 && !if_name) { ++ printf("-I is mandatory with IPv6\n"); + exit(1); + } + +- /* join the multicast group. */ +- if (if_name) { +- igmp_join_by_if_name(s, inet_addr(TEST_ADDR), if_name); +- } else { +- if (!ipnum) { /* single interface */ +- igmp_join_by_saddr(s, inet_addr(TEST_ADDR), INADDR_ANY); +- } else { +- for (i = 0; i < ipnum; i++) { +- igmp_join_by_saddr(s, inet_addr(TEST_ADDR), +- IP[i]); +- } +- } +- } ++ /* get a datagram socket */ ++ ret = socket_create(&s, mc.family, TEST_PORT); ++ if (ret) ++ exit(1); + +- /* set TTL to traverse up to multiple routers */ +- iTmp = TTL_VALUE; +- iRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&iTmp, sizeof(iTmp)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() IP_MULTICAST_TTL failed.\n"); ++ /* join the multicast group. */ ++ ret = mc_join(&s, &mc, if_name, ipnum, IP); ++ if (ret) + exit(1); +- } + +- /* disable loopback */ +- /* iTmp = TRUE; */ +- iTmp = FALSE; +- iRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&iTmp, sizeof(iTmp)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() IP_MULTICAST_LOOP failed.\n"); ++ /* set TTL to traverse up to multiple routers */ ++ ret = mc_set_hop_limit(&s, TTL_VALUE); ++ if (ret) + exit(1); +- } + + printf("Now receiving from multicast group: %s\n", TEST_ADDR); + + for (i = 0;; i++) { +- socklen_t addr_size = sizeof(struct sockaddr_in); ++ char from_buf[INET6_ADDRSTRLEN]; + static int iCounter = 1; ++ const char *addr_str; + + /* receive from the multicast address */ + +- iRet = recvfrom(s, achIn, BUFSIZE, 0, (struct sockaddr *)&stFrom, &addr_size); +- if (iRet < 0) { +- printf("recvfrom() failed.\n"); ++ ret = mc_recv(&s, achIn, BUFSIZE, &from); ++ if (ret < 0) { ++ perror("recvfrom"); ++ exit(1); ++ } ++ ++ if (mc.family == AF_INET) { ++ addr_str = inet_ntop(AF_INET, &from.udp4.sin_addr, ++ from_buf, INET6_ADDRSTRLEN); ++ } else { ++ addr_str = inet_ntop(AF_INET6, &from.udp6.sin6_addr, ++ from_buf, INET6_ADDRSTRLEN); ++ } ++ if (!addr_str) { ++ perror("inet_ntop"); + exit(1); + } + +@@ -256,7 +209,8 @@ int main(int argc, char *argv[]) + numreceived = + (unsigned int)achIn[0] + ((unsigned int)(achIn[1]) << 8) + ((unsigned int)(achIn[2]) << 16) + + ((unsigned int)(achIn[3]) >> 24); +- fprintf(stdout, "%5d\t%s:%5d\t%d.%03d\t%5d\n", iCounter, inet_ntoa(stFrom.sin_addr), ntohs(stFrom.sin_port), ++ fprintf(stdout, "%5d\t%s:%5d\t%d.%03d\t%5d\n", iCounter, ++ from_buf, socket_get_port(&from), + curtime / 1000000, (curtime % 1000000) / 1000, numreceived); + fflush(stdout); + rcvCountNew = numreceived; +@@ -276,7 +230,7 @@ int main(int argc, char *argv[]) + rcvCountOld = rcvCountNew; + } else { + printf("Receive msg %d from %s:%d: %s\n", +- iCounter, inet_ntoa(stFrom.sin_addr), ntohs(stFrom.sin_port), achIn); ++ iCounter, from_buf, socket_get_port(&from), achIn); + } + iCounter++; + } diff --git a/net/net-mtools/patches/004-msend-support-IPv6.patch b/net/net-mtools/patches/004-msend-support-IPv6.patch new file mode 100644 index 000000000..84d517538 --- /dev/null +++ b/net/net-mtools/patches/004-msend-support-IPv6.patch @@ -0,0 +1,401 @@ +From 9aa908fc2dd84cfed151fa260b39465978079274 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Tue, 19 Apr 2022 19:28:59 +0300 +Subject: [PATCH 4/6] msend: support IPv6 + +Finish the conversion by updating msend to use the common procedures +that support IPv6. + +I've only tested this with a link-local source address. + +Signed-off-by: Vladimir Oltean +--- + Makefile | 2 +- + common.c | 62 +++++++++++++++++++++---- + common.h | 5 +- + mreceive.c | 2 +- + msend.c | 131 +++++++++++++++++++++++++++++------------------------ + 5 files changed, 132 insertions(+), 70 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -35,7 +35,7 @@ all: $(EXEC) + @printf " LINK $@\n" + @$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@))) + +-msend: msend.o ++msend: msend.o common.o + mreceive: mreceive.o common.o + ttcp: ttcp.o + +--- a/common.c ++++ b/common.c +@@ -30,7 +30,8 @@ int ip_address_parse(const char *string, + return 0; + } + +-int socket_create(struct sock *s, int family, int port) ++int socket_create(struct sock *s, int family, int port, ++ struct ip_address *saddr, const char *if_name) + { + struct sockaddr *serv_addr; + int sockopt = 1; +@@ -40,13 +41,16 @@ int socket_create(struct sock *s, int fa + + if (family == AF_INET) { + serv_addr = (struct sockaddr *)&s->udp4; +- s->udp4.sin_addr.s_addr = htonl(INADDR_ANY); ++ s->udp4.sin_addr = saddr ? saddr->addr : ++ (struct in_addr) { ++ .s_addr = htonl(INADDR_ANY), ++ }; + s->udp4.sin_port = htons(port); + s->udp4.sin_family = AF_INET; + s->addr_size = sizeof(struct sockaddr_in); + } else { + serv_addr = (struct sockaddr *)&s->udp6; +- s->udp6.sin6_addr = in6addr_any; ++ s->udp6.sin6_addr = saddr ? saddr->addr6 : in6addr_any; + s->udp6.sin6_port = htons(port); + s->udp6.sin6_family = AF_INET6; + s->addr_size = sizeof(struct sockaddr_in6); +@@ -66,11 +70,22 @@ int socket_create(struct sock *s, int fa + return ret; + } + +- ret = bind(fd, serv_addr, s->addr_size); +- if (ret) { +- perror("bind"); +- close(fd); +- return ret; ++ if (if_name) { ++ /* Bind to device, required for IPv6 link-local addresses */ ++ ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, if_name, ++ IFNAMSIZ - 1); ++ if (ret) { ++ perror("setsockopt() SO_BINDTODEVICE"); ++ close(fd); ++ return ret; ++ } ++ } else { ++ ret = bind(fd, serv_addr, s->addr_size); ++ if (ret) { ++ perror("bind"); ++ close(fd); ++ return ret; ++ } + } + + s->fd = fd; +@@ -248,6 +263,12 @@ int mc_recv(struct sock *s, void *buf, s + &from->addr_size); + } + ++int mc_send(struct sock *s, struct sock *to, void *buf, size_t len) ++{ ++ return sendto(s->fd, buf, len, 0, (struct sockaddr *)&(to->udp4), ++ s->addr_size); ++} ++ + int socket_get_port(const struct sock *s) + { + switch (s->addr_size) { +@@ -259,3 +280,28 @@ int socket_get_port(const struct sock *s + return 0; + } + } ++ ++int socket_set_loopback(struct sock *s, int loop) ++{ ++ int fd = s->fd; ++ int ret; ++ ++ switch (s->addr_size) { ++ case sizeof(struct sockaddr_in): ++ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, ++ sizeof(int)); ++ if (ret) ++ perror("setsockopt IP_MULTICAST_LOOP"); ++ break; ++ case sizeof(struct sockaddr_in6): ++ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, ++ sizeof(int)); ++ if (ret) ++ perror("setsockopt IPV6_MULTICAST_LOOP"); ++ break; ++ default: ++ return 0; ++ } ++ ++ return ret; ++} +--- a/common.h ++++ b/common.h +@@ -26,11 +26,14 @@ struct sock { + }; + + int ip_address_parse(const char *string, struct ip_address *ip); +-int socket_create(struct sock *s, int family, int port); ++int socket_create(struct sock *s, int family, int port, ++ struct ip_address *saddr, const char *if_name); + int mc_join(struct sock *s, const struct ip_address *mc, const char *if_name, + int num_saddrs, struct ip_address *saddrs); + int mc_set_hop_limit(struct sock *s, int limit); + int mc_recv(struct sock *s, void *buf, size_t len, struct sock *from); ++int mc_send(struct sock *s, struct sock *to, void *buf, size_t len); + int socket_get_port(const struct sock *s); ++int socket_set_loopback(struct sock *s, int loop); + + #endif +--- a/mreceive.c ++++ b/mreceive.c +@@ -159,7 +159,7 @@ int main(int argc, char *argv[]) + } + + /* get a datagram socket */ +- ret = socket_create(&s, mc.family, TEST_PORT); ++ ret = socket_create(&s, mc.family, TEST_PORT, NULL, NULL); + if (ret) + exit(1); + +--- a/msend.c ++++ b/msend.c +@@ -30,6 +30,8 @@ + #include + #include + ++#include "common.h" ++ + #define TRUE 1 + #define FALSE 0 + #ifndef INVALID_SOCKET +@@ -45,18 +47,16 @@ char *TEST_ADDR = "224.1.1.1"; + int TEST_PORT = 4444; + int TTL_VALUE = 1; + int SLEEP_TIME = 1000; +-unsigned long IP = INADDR_ANY; + int NUM = 0; + + int join_flag = 0; /* not join */ + + typedef struct timerhandler_s { +- int s; ++ struct sock *s; ++ struct sock *to; + char *achOut; + int len; + int n; +- struct sockaddr *stTo; +- int addr_size; + } timerhandler_t; + timerhandler_t handler_par; + void timerhandler(); +@@ -87,16 +87,15 @@ Usage: msend [-g GROUP] [-p PORT] [-joi + + int main(int argc, char *argv[]) + { +- struct sockaddr_in stLocal, stTo; ++ struct ip_address *saddr = NULL, mc; ++ struct sock s = {}, to = {}; ++ const char *if_name = NULL; + char achOut[BUFSIZE] = ""; +- int s, i; +- struct ip_mreq stMreq; +- int iTmp, iRet; + int ii = 1; +- int addr_size = sizeof(struct sockaddr_in); + struct itimerval times; + sigset_t sigset; + struct sigaction act; ++ int ret, i; + + if ((argc == 2) && (strcmp(argv[ii], "-v") == 0)) { + printf("msend version 2.2\n"); +@@ -126,7 +125,32 @@ int main(int argc, char *argv[]) + } else if (strcmp(argv[ii], "-i") == 0) { + ii++; + if ((ii < argc) && !(strchr(argv[ii], '-'))) { +- IP = inet_addr(argv[ii]); ++ if (saddr) { ++ printf("Single source address allowed\n"); ++ exit(1); ++ } ++ ++ saddr = calloc(1, sizeof(*saddr)); ++ if (!saddr) { ++ printf("Low memory\n"); ++ exit(1); ++ } ++ ++ ret = ip_address_parse(argv[ii], saddr); ++ if (ret) ++ exit(1); ++ ++ ii++; ++ } ++ } else if (strcmp(argv[ii], "-I") == 0) { ++ ii++; ++ if (ii < argc) { ++ if (if_name) { ++ printf("Single interface expected\n"); ++ exit(1); ++ } ++ ++ if_name = argv[ii]; + ii++; + } + } else if (strcmp(argv[ii], "-t") == 0) { +@@ -158,62 +182,50 @@ int main(int argc, char *argv[]) + } + } + +- /* get a datagram socket */ +- s = socket(AF_INET, SOCK_DGRAM, 0); +- if (s == INVALID_SOCKET) { +- printf("socket() failed.\n"); ++ ret = ip_address_parse(TEST_ADDR, &mc); ++ if (ret) + exit(1); +- } + +- /* avoid EADDRINUSE error on bind() */ +- iTmp = TRUE; +- iRet = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&iTmp, sizeof(iTmp)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() SO_REUSEADDR failed.\n"); ++ if (join_flag && mc.family == AF_INET6 && !if_name) { ++ printf("-I is mandatory when joining IPv6 group\n"); + exit(1); + } + +- /* name the socket */ +- stLocal.sin_family = AF_INET; +- stLocal.sin_addr.s_addr = IP; +- stLocal.sin_port = htons(TEST_PORT); +- iRet = bind(s, (struct sockaddr *)&stLocal, sizeof(stLocal)); +- if (iRet == SOCKET_ERROR) { +- printf("bind() failed.\n"); ++ /* get a datagram socket */ ++ ret = socket_create(&s, mc.family, TEST_PORT, saddr, if_name); ++ if (ret) + exit(1); +- } + + /* join the multicast group. */ +- stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR); +- stMreq.imr_interface.s_addr = IP; + if (join_flag == 1) { +- iRet = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() IP_ADD_MEMBERSHIP failed.\n"); ++ ret = mc_join(&s, &mc, if_name, 0, NULL); ++ if (ret) + exit(1); +- } + } + + /* set TTL to traverse up to multiple routers */ +- iTmp = TTL_VALUE; +- iRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&iTmp, sizeof(iTmp)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() IP_MULTICAST_TTL failed.\n"); ++ ret = mc_set_hop_limit(&s, TTL_VALUE); ++ if (ret) + exit(1); +- } + + /* enable loopback */ +- iTmp = TRUE; +- iRet = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&iTmp, sizeof(iTmp)); +- if (iRet == SOCKET_ERROR) { +- printf("setsockopt() IP_MULTICAST_LOOP failed.\n"); ++ ret = socket_set_loopback(&s, 1); ++ if (ret) + exit(1); +- } + + /* assign our destination address */ +- stTo.sin_family = AF_INET; +- stTo.sin_addr.s_addr = inet_addr(TEST_ADDR); +- stTo.sin_port = htons(TEST_PORT); ++ if (mc.family == AF_INET) { ++ to.udp4.sin_addr = mc.addr; ++ to.udp4.sin_port = htons(TEST_PORT); ++ to.udp4.sin_family = AF_INET; ++ to.addr_size = sizeof(struct sockaddr_in); ++ } else { ++ to.udp6.sin6_addr = mc.addr6; ++ to.udp6.sin6_port = htons(TEST_PORT); ++ to.udp6.sin6_family = AF_INET6; ++ to.addr_size = sizeof(struct sockaddr_in6); ++ } ++ + printf("Now sending to multicast group: %s\n", TEST_ADDR); + + SLEEP_TIME *= 1000; /* convert to microsecond */ +@@ -237,12 +249,11 @@ int main(int argc, char *argv[]) + times.it_interval.tv_usec = (long)(SLEEP_TIME % 1000000); + setitimer(ITIMER_REAL, ×, NULL); + +- handler_par.s = s; ++ handler_par.s = &s; ++ handler_par.to = &to; + handler_par.achOut = achOut; + handler_par.len = strlen(achOut) + 1; + handler_par.n = 0; +- handler_par.stTo = (struct sockaddr *)&stTo; +- handler_par.addr_size = addr_size; + + /* now wait for the alarms */ + sigemptyset(&sigset); +@@ -252,8 +263,6 @@ int main(int argc, char *argv[]) + return 0; + } else { + for (i = 0; i < 10; i++) { +- int addr_size = sizeof(struct sockaddr_in); +- + if (NUM) { + achOut[3] = (unsigned char)(i >> 24); + achOut[2] = (unsigned char)(i >> 16); +@@ -264,9 +273,10 @@ int main(int argc, char *argv[]) + printf("Send out msg %d to %s:%d: %s\n", i, TEST_ADDR, TEST_PORT, achOut); + } + +- iRet = sendto(s, achOut, (NUM ? 4 : strlen(achOut) + 1), 0, (struct sockaddr *)&stTo, addr_size); +- if (iRet < 0) { +- printf("sendto() failed.\n"); ++ ret = mc_send(&s, &to, achOut, ++ NUM ? 4 : strlen(achOut) + 1); ++ if (ret < 0) { ++ perror("sendto"); + exit(1); + } + } /* end for(;;) */ +@@ -277,8 +287,8 @@ int main(int argc, char *argv[]) + + void timerhandler(void) + { +- int iRet; + static int iCounter = 1; ++ int ret; + + if (NUM) { + handler_par.achOut = (char *)(&iCounter); +@@ -287,11 +297,14 @@ void timerhandler(void) + } else { + printf("Sending msg %d, TTL %d, to %s:%d: %s\n", iCounter, TTL_VALUE, TEST_ADDR, TEST_PORT, handler_par.achOut); + } +- iRet = sendto(handler_par.s, handler_par.achOut, handler_par.len, handler_par.n, handler_par.stTo, handler_par.addr_size); +- if (iRet < 0) { +- printf("sendto() failed.\n"); ++ ++ ret = mc_send(handler_par.s, handler_par.to, handler_par.achOut, ++ handler_par.len); ++ if (ret < 0) { ++ perror("sendto"); + exit(1); + } ++ + iCounter++; + return; + } diff --git a/net/net-mtools/patches/005-mreceive-msend-add-new-I-option-to-the-help-text.patch b/net/net-mtools/patches/005-mreceive-msend-add-new-I-option-to-the-help-text.patch new file mode 100644 index 000000000..73af1d14e --- /dev/null +++ b/net/net-mtools/patches/005-mreceive-msend-add-new-I-option-to-the-help-text.patch @@ -0,0 +1,33 @@ +From bf95bdeccab98cec77dc1b10bce0b215754e4e46 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Thu, 21 Apr 2022 16:45:08 +0300 +Subject: [PATCH 5/6] mreceive: msend: add new -I option to the help text + +Signed-off-by: Vladimir Oltean +--- + mreceive.c | 2 ++ + msend.c | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/mreceive.c ++++ b/mreceive.c +@@ -58,6 +58,8 @@ Usage: mreceive [-g GROUP] [-p PORT] [-i + -p PORT UDP port number used in the multicast packets. Default: 4444\n\ + -i ADDRESS IP addresses of one or more interfaces to listen for the given\n\ + multicast group. Default: the system default interface.\n\ ++ -I interface The interface on which to receive. Can be specified as an\n\ ++ alternative to -i.\n\ + -n Interpret the contents of the message as a number instead of\n\ + a string of characters. Use this with `msend -n`\n\ + -v Print version information.\n\ +--- a/msend.c ++++ b/msend.c +@@ -72,6 +72,8 @@ Usage: msend [-g GROUP] [-p PORT] [-joi + -p PORT UDP port number used in the multicast packets. Default: 4444\n\ + -i ADDRESS IP address of the interface to use to send the packets.\n\ + The default is to use the system default interface.\n\ ++ -I interface The interface on which to send. Can be specified as an\n\ ++ alternative to -i.\n\ + -join Multicast sender will join the multicast group.\n\ + By default a sender never joins the group.\n\ + -P PERIOD Interval in milliseconds between packets. Default 1000 msec\n\ diff --git a/net/net-mtools/patches/006-msend-send-a-limited-number-of-test-packets.patch b/net/net-mtools/patches/006-msend-send-a-limited-number-of-test-packets.patch new file mode 100644 index 000000000..8e8db738e --- /dev/null +++ b/net/net-mtools/patches/006-msend-send-a-limited-number-of-test-packets.patch @@ -0,0 +1,81 @@ +From 1013b0a83aef868e6cd33b2f467b9f886b41e7bc Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Fri, 22 Apr 2022 12:59:56 +0300 +Subject: [PATCH 6/6] msend: send a limited number of test packets + +For easier integration into a selftest framework, limit the amount of +packets that the program sends via a command-line argument. + +Signed-off-by: Vladimir Oltean +--- + msend.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +--- a/msend.c ++++ b/msend.c +@@ -56,7 +56,7 @@ typedef struct timerhandler_s { + struct sock *to; + char *achOut; + int len; +- int n; ++ int num_pkts; + } timerhandler_t; + timerhandler_t handler_par; + void timerhandler(); +@@ -82,6 +82,7 @@ Usage: msend [-g GROUP] [-p PORT] [-joi + the first router will drop the packets! Default: 1\n\ + -text \"text\" Specify a string to use as payload in the packets, also\n\ + displayed by the mreceive command. Default: empty\n\ ++ -c Number of packets to send. Default: send indefinitely\n\ + -n Encode -text argument as a number instead of a string.\n\ + -v Print version information.\n\ + -h Print the command usage.\n\n", VERSION); +@@ -97,6 +98,7 @@ int main(int argc, char *argv[]) + struct itimerval times; + sigset_t sigset; + struct sigaction act; ++ int num_pkts = 0; + int ret, i; + + if ((argc == 2) && (strcmp(argv[ii], "-v") == 0)) { +@@ -171,6 +173,12 @@ int main(int argc, char *argv[]) + ii++; + NUM = 1; + ii++; ++ } else if (strcmp(argv[ii], "-c") == 0) { ++ ii++; ++ if ((ii < argc) && !(strchr(argv[ii], '-'))) { ++ num_pkts = atoi(argv[ii]); ++ ii++; ++ } + } else if (strcmp(argv[ii], "-text") == 0) { + ii++; + if ((ii < argc) && !(strchr(argv[ii], '-'))) { +@@ -255,7 +263,7 @@ int main(int argc, char *argv[]) + handler_par.to = &to; + handler_par.achOut = achOut; + handler_par.len = strlen(achOut) + 1; +- handler_par.n = 0; ++ handler_par.num_pkts = num_pkts; + + /* now wait for the alarms */ + sigemptyset(&sigset); +@@ -264,7 +272,7 @@ int main(int argc, char *argv[]) + } + return 0; + } else { +- for (i = 0; i < 10; i++) { ++ for (i = 0; num_pkts && i < num_pkts; i++) { + if (NUM) { + achOut[3] = (unsigned char)(i >> 24); + achOut[2] = (unsigned char)(i >> 16); +@@ -307,6 +315,9 @@ void timerhandler(void) + exit(1); + } + ++ if (iCounter == handler_par.num_pkts) ++ exit(1); ++ + iCounter++; + return; + } diff --git a/net/net-mtools/patches/100-mreceive-msend-fix-wrong-version-in-v-output.patch b/net/net-mtools/patches/100-mreceive-msend-fix-wrong-version-in-v-output.patch new file mode 100644 index 000000000..2ba867745 --- /dev/null +++ b/net/net-mtools/patches/100-mreceive-msend-fix-wrong-version-in-v-output.patch @@ -0,0 +1,37 @@ +From e0c9115e1ceb6621d6c04ae8bfd423a0452fea9c Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 5 Jul 2023 11:03:40 +0200 +Subject: [PATCH] mreceive: msend: fix wrong version in -v output + +-v output was never changed to follow VERSION declared in Makefile and +was still hardcoded. Fix this to improve version output and align to -h +output. + +Signed-off-by: Christian Marangi +--- + mreceive.c | 2 +- + msend.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/mreceive.c ++++ b/mreceive.c +@@ -93,7 +93,7 @@ int main(int argc, char *argv[]) + ii = 1; + + if ((argc == 2) && (strcmp(argv[ii], "-v") == 0)) { +- printf("mreceive version 2.2\n"); ++ printf("mreceive version %s\n", VERSION); + return 0; + } + if ((argc == 2) && (strcmp(argv[ii], "-h") == 0)) { +--- a/msend.c ++++ b/msend.c +@@ -102,7 +102,7 @@ int main(int argc, char *argv[]) + int ret, i; + + if ((argc == 2) && (strcmp(argv[ii], "-v") == 0)) { +- printf("msend version 2.2\n"); ++ printf("msend version %s\n", VERSION); + return 0; + } + if ((argc == 2) && (strcmp(argv[ii], "-h") == 0)) { diff --git a/net/net-mtools/test.sh b/net/net-mtools/test.sh new file mode 100755 index 000000000..c32f76802 --- /dev/null +++ b/net/net-mtools/test.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +msend -v | grep "$2" +mreceive -v | grep "$2"