From af1a79cf490dc805be8b91d719a6aef4dc8fcf0d Mon Sep 17 00:00:00 2001 From: Kevin Adler Date: Thu, 8 Apr 2021 11:00:55 -0500 Subject: [PATCH] ibmi: Handle interface names longer than 10 chars IBM i interface names are based off the associated line description. Since line descriptions are objects, they have 10 character limit on their names. However, since IBM i 7.2 interface names may be up to 16 characters long if the interface is for a a VLAN (eg. MYETHLINE1.4094). To handle this, we must strip off a VLAN ID to get the actual line description name, since that's what the QDCRLIND API wants. One issue exists because line descriptions can contain periods and numbers; so for interface names less than 10 characters long ETH2.4 could be a line description name or it could be ETH2 with VLAN 4. We follow the method that the XPF ioctls use: try the interface name directly first and if an error occurs, try to strip off the VLAN ID. https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/ioctl.htm#unotes Fixes: https://github.com/libuv/libuv/issues/3062 PR-URL: https://github.com/libuv/libuv/pull/3144 Reviewed-By: Richard Lau --- src/unix/ibmi.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c index 96efc02b..8c6ae636 100644 --- a/src/unix/ibmi.c +++ b/src/unix/ibmi.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -166,7 +165,7 @@ static void iconv_a2e(const char* src, unsigned char dst[], size_t length) { srclen = strlen(src); if (srclen > length) - abort(); + srclen = length; for (i = 0; i < srclen; i++) dst[i] = a2e[src[i]]; /* padding the remaining part with spaces */ @@ -360,6 +359,10 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) { if (rc != 0) return rc; + if (err.bytes_available > 0) { + return -1; + } + /* convert ebcdic loca_adapter_address to ascii first */ iconv_e2a(rcvr.loca_adapter_address, mac_addr, sizeof(rcvr.loca_adapter_address)); @@ -443,9 +446,42 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0; if (!address->is_internal) { - int rc = get_ibmi_physical_address(address->name, &address->phys_addr); - if (rc != 0) - r = rc; + int rc = -1; + size_t name_len = strlen(address->name); + /* To get the associated MAC address, we must convert the address to a + * line description. Normally, the name field contains the line + * description name, but for VLANs it has the VLAN appended with a + * period. Since object names can also contain periods and numbers, there + * is no way to know if a returned name is for a VLAN or not. eg. + * *LIND ETH1.1 and *LIND ETH1, VLAN 1 both have the same name: ETH1.1 + * + * Instead, we apply the same heuristic used by some of the XPF ioctls: + * - names > 10 *must* contain a VLAN + * - assume names <= 10 do not contain a VLAN and try directly + * - if >10 or QDCRLIND returned an error, try to strip off a VLAN + * and try again + * - if we still get an error or couldn't find a period, leave the MAC as + * 00:00:00:00:00:00 + */ + if (name_len <= 10) { + /* Assume name does not contain a VLAN ID */ + rc = get_ibmi_physical_address(address->name, &address->phys_addr); + } + + if (name_len > 10 || rc != 0) { + /* The interface name must contain a VLAN ID suffix. Attempt to strip + * it off so we can get the line description to pass to QDCRLIND. + */ + char* temp_name = uv__strdup(address->name); + char* dot = strrchr(temp_name, '.'); + if (dot != NULL) { + *dot = '\0'; + if (strlen(temp_name) <= 10) { + rc = get_ibmi_physical_address(temp_name, &address->phys_addr); + } + } + uv__free(temp_name); + } } address++; @@ -498,4 +534,4 @@ int uv_get_process_title(char* buffer, size_t size) { } void uv__process_title_cleanup(void) { -} \ No newline at end of file +}