diff options
Diffstat (limited to 'tipc/misc.c')
-rw-r--r-- | tipc/misc.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/tipc/misc.c b/tipc/misc.c new file mode 100644 index 0000000..32d4a5e --- /dev/null +++ b/tipc/misc.c @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * misc.c Miscellaneous TIPC helper functions. + * + * Authors: Richard Alpe <richard.alpe@ericsson.com> + */ + +#include <stdio.h> +#include <stdint.h> +#include <linux/tipc.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> +#include <errno.h> +#include "misc.h" + +#define IN_RANGE(val, low, high) ((val) <= (high) && (val) >= (low)) + +uint32_t str2addr(char *str) +{ + unsigned int z, c, n; + char dummy; + + if (sscanf(str, "%u.%u.%u%c", &z, &c, &n, &dummy) != 3) { + fprintf(stderr, "invalid network address, syntax: Z.C.N\n"); + return 0; + } + + if (IN_RANGE(z, 0, 255) && IN_RANGE(c, 0, 4095) && IN_RANGE(n, 0, 4095)) + return tipc_addr(z, c, n); + + fprintf(stderr, "invalid network address \"%s\"\n", str); + return 0; +} + +static int is_hex(char *arr, int last) +{ + int i; + + while (!arr[last]) + last--; + + for (i = 0; i <= last; i++) { + if (!IN_RANGE(arr[i], '0', '9') && + !IN_RANGE(arr[i], 'a', 'f') && + !IN_RANGE(arr[i], 'A', 'F')) + return 0; + } + return 1; +} + +static int is_name(char *arr, int last) +{ + int i; + char c; + + while (!arr[last]) + last--; + + if (last > 15) + return 0; + + for (i = 0; i <= last; i++) { + c = arr[i]; + if (!IN_RANGE(c, '0', '9') && !IN_RANGE(c, 'a', 'z') && + !IN_RANGE(c, 'A', 'Z') && c != '-' && c != '_' && + c != '.' && c != ':' && c != '@') + return 0; + } + return 1; +} + +int str2nodeid(char *str, uint8_t *id) +{ + int len = strlen(str); + int i; + + if (len > 32) + return -1; + + if (is_name(str, len - 1)) { + memcpy(id, str, len); + return 0; + } + if (!is_hex(str, len - 1)) + return -1; + + str[len] = '0'; + for (i = 0; i < 16; i++) { + if (sscanf(&str[2 * i], "%2hhx", &id[i]) != 1) + break; + } + return 0; +} + +int str2key(char *str, struct tipc_aead_key *key) +{ + int len = strlen(str); + int ishex = 0; + int i; + + /* Check if the input is a hex string (i.e. 0x...) */ + if (len > 2 && strncmp(str, "0x", 2) == 0) { + ishex = is_hex(str + 2, len - 2 - 1); + if (ishex) { + len -= 2; + str += 2; + } + } + + key->keylen = ishex ? (len + 1) / 2 : len; + if (key->keylen > TIPC_AEAD_KEYLEN_MAX) + return -1; + + /* Obtain key: */ + if (!ishex) { + memcpy(key->key, str, len); + } else { + /* Convert hex string to key */ + for (i = 0; i < key->keylen; i++) { + if (i == 0 && len % 2 != 0) { + if (sscanf(str, "%1hhx", &key->key[0]) != 1) + return -1; + str += 1; + continue; + } + if (sscanf(str, "%2hhx", &key->key[i]) != 1) + return -1; + str += 2; + } + } + + return 0; +} + +void nodeid2str(uint8_t *id, char *str) +{ + int i; + + if (is_name((char *)id, 15)) { + memcpy(str, id, 16); + return; + } + + for (i = 0; i < 16; i++) + sprintf(&str[2 * i], "%02x", id[i]); + + for (i = 31; str[i] == '0'; i--) + str[i] = 0; +} + +void hash2nodestr(uint32_t hash, char *str) +{ + struct tipc_sioc_nodeid_req nr = {}; + int sd; + + sd = socket(AF_TIPC, SOCK_RDM, 0); + if (sd < 0) { + fprintf(stderr, "opening TIPC socket: %s\n", strerror(errno)); + return; + } + nr.peer = hash; + if (!ioctl(sd, SIOCGETNODEID, &nr)) + nodeid2str((uint8_t *)nr.node_id, str); + close(sd); +} |