diff --git a/Makefile b/Makefile index 5bc11477..5eddd504 100644 --- a/Makefile +++ b/Makefile @@ -40,9 +40,18 @@ DEFINES+=-DCONFDIR=\"$(CONFDIR)\" \ -DNETNS_RUN_DIR=\"$(NETNS_RUN_DIR)\" \ -DNETNS_ETC_DIR=\"$(NETNS_ETC_DIR)\" +#options for AX.25 +ADDLIB+=ax25_ntop.o + +#options for AX.25 +ADDLIB+=rose_ntop.o + #options for mpls ADDLIB+=mpls_ntop.o mpls_pton.o +#options for NETROM +ADDLIB+=netrom_ntop.o + CC := gcc HOSTCC ?= $(CC) DEFINES += -D_GNU_SOURCE diff --git a/include/utils.h b/include/utils.h index c9849461..b6c468e9 100644 --- a/include/utils.h +++ b/include/utils.h @@ -198,9 +198,15 @@ bool matches(const char *prefix, const char *string); int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits); int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta); +const char *ax25_ntop(int af, const void *addr, char *str, socklen_t len); + +const char *rose_ntop(int af, const void *addr, char *buf, socklen_t buflen); + const char *mpls_ntop(int af, const void *addr, char *str, size_t len); int mpls_pton(int af, const char *src, void *addr, size_t alen); +const char *netrom_ntop(int af, const void *addr, char *str, socklen_t len); + extern int __iproute2_hz_internal; int __get_hz(void); diff --git a/lib/ax25_ntop.c b/lib/ax25_ntop.c new file mode 100644 index 00000000..cfd0e04b --- /dev/null +++ b/lib/ax25_ntop.c @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#include +#include +#include + +#include "utils.h" + +const char *ax25_ntop1(const ax25_address *src, char *dst, socklen_t size); + +/* + * AX.25 addresses are based on Amateur radio callsigns followed by an SSID + * like XXXXXX-SS where the callsign consists of up to 6 ASCII characters + * which are either letters or digits and the SSID is a decimal number in the + * range 0..15. + * Amateur radio callsigns are assigned by a country's relevant authorities + * and are 3..6 characters though a few countries have assigned callsigns + * longer than that. AX.25 is not able to handle such longer callsigns. + * There are further restrictions on the format of valid callsigns by + * applicable national and international law. Linux doesn't need to care and + * will happily accept anything that consists of 6 ASCII characters in the + * range of A-Z and 0-9 for a callsign such as the default AX.25 MAC address + * LINUX-1 and the default broadcast address QST-0. + * The SSID is just a number and not encoded in ASCII digits. + * + * Being based on HDLC AX.25 encodes addresses by shifting them one bit left + * thus zeroing bit 0, the HDLC extension bit for all but the last bit of + * a packet's address field but for our purposes here we're not considering + * the HDLC extension bit that is it will always be zero. + * + * Linux' internal representation of AX.25 addresses in Linux is very similar + * to this on the on-air or on-the-wire format. The callsign is padded to + * 6 octets by adding spaces, followed by the SSID octet then all 7 octets + * are left-shifted by one bit. + * + * For example, for the address "LINUX-1" the callsign is LINUX and SSID is 1 + * the internal format is 98:92:9c:aa:b0:40:02. + */ + +const char *ax25_ntop1(const ax25_address *src, char *dst, socklen_t size) +{ + char c, *s; + int n; + + for (n = 0, s = dst; n < 6; n++) { + c = (src->ax25_call[n] >> 1) & 0x7f; + if (c != ' ') + *s++ = c; + } + + *s++ = '-'; + + n = ((src->ax25_call[6] >> 1) & 0x0f); + if (n > 9) { + *s++ = '1'; + n -= 10; + } + + *s++ = n + '0'; + *s++ = '\0'; + + if (*dst == '\0' || *dst == '-') { + dst[0] = '*'; + dst[1] = '\0'; + } + + return dst; +} + +const char *ax25_ntop(int af, const void *addr, char *buf, socklen_t buflen) +{ + switch (af) { + case AF_AX25: + errno = 0; + return ax25_ntop1((ax25_address *)addr, buf, buflen); + + default: + errno = EAFNOSUPPORT; + } + + return NULL; +} diff --git a/lib/ll_addr.c b/lib/ll_addr.c index 00b562ae..d6fd736b 100644 --- a/lib/ll_addr.c +++ b/lib/ll_addr.c @@ -39,6 +39,12 @@ const char *ll_addr_n2a(const unsigned char *addr, int alen, int type, if (alen == 16 && (type == ARPHRD_TUNNEL6 || type == ARPHRD_IP6GRE)) return inet_ntop(AF_INET6, addr, buf, blen); + if (alen == 7 && type == ARPHRD_AX25) + return ax25_ntop(AF_AX25, addr, buf, blen); + if (alen == 7 && type == ARPHRD_NETROM) + return netrom_ntop(AF_NETROM, addr, buf, blen); + if (alen == 5 && type == ARPHRD_ROSE) + return rose_ntop(AF_ROSE, addr, buf, blen); snprintf(buf, blen, "%02x", addr[0]); for (i = 1, l = 2; i < alen && l < blen; i++, l += 3) diff --git a/lib/netrom_ntop.c b/lib/netrom_ntop.c new file mode 100644 index 00000000..3dd6cb0b --- /dev/null +++ b/lib/netrom_ntop.c @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include + +#include "utils.h" + +const char *ax25_ntop1(const ax25_address *src, char *dst, socklen_t size); + +const char *netrom_ntop(int af, const void *addr, char *buf, socklen_t buflen) +{ + switch (af) { + case AF_NETROM: + errno = 0; + return ax25_ntop1((ax25_address *)addr, buf, buflen); + + default: + errno = EAFNOSUPPORT; + } + + return NULL; +} diff --git a/lib/rose_ntop.c b/lib/rose_ntop.c new file mode 100644 index 00000000..c9ba712c --- /dev/null +++ b/lib/rose_ntop.c @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" + +static const char *rose_ntop1(const rose_address *src, char *dst, + socklen_t size) +{ + char *p = dst; + int i; + + if (size < 10) + return NULL; + + for (i = 0; i < 5; i++) { + *p++ = '0' + ((src->rose_addr[i] >> 4) & 0xf); + *p++ = '0' + ((src->rose_addr[i] ) & 0xf); + } + + if (size == 10) + return dst; + + *p = '\0'; + + return dst; +} + +const char *rose_ntop(int af, const void *addr, char *buf, socklen_t buflen) +{ + switch (af) { + case AF_ROSE: + errno = 0; + return rose_ntop1((rose_address *)addr, buf, buflen); + + default: + errno = EAFNOSUPPORT; + } + + return NULL; +}