Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */ 2 : 3 : #include <errno.h> 4 : #include <net/ethernet.h> 5 : #include <stdio.h> 6 : #include <sys/types.h> 7 : 8 : #include "ether-addr-util.h" 9 : #include "macro.h" 10 : #include "string-util.h" 11 : 12 4 : char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { 13 4 : assert(addr); 14 4 : assert(buffer); 15 : 16 : /* Like ether_ntoa() but uses %02x instead of %x to print 17 : * ethernet addresses, which makes them look less funny. Also, 18 : * doesn't use a static buffer. */ 19 : 20 24 : sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", 21 4 : addr->ether_addr_octet[0], 22 4 : addr->ether_addr_octet[1], 23 4 : addr->ether_addr_octet[2], 24 4 : addr->ether_addr_octet[3], 25 4 : addr->ether_addr_octet[4], 26 4 : addr->ether_addr_octet[5]); 27 : 28 4 : return buffer; 29 : } 30 : 31 75 : int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b) { 32 75 : return memcmp(a, b, ETH_ALEN); 33 : } 34 : 35 54 : static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *state) { 36 54 : siphash24_compress(p, sizeof(struct ether_addr), state); 37 54 : } 38 : 39 : DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare); 40 : 41 67 : int ether_addr_from_string(const char *s, struct ether_addr *ret) { 42 67 : size_t pos = 0, n, field; 43 67 : char sep = '\0'; 44 67 : const char *hex = HEXDIGITS, *hexoff; 45 : size_t x; 46 : bool touched; 47 : 48 : #define parse_fields(v) \ 49 : for (field = 0; field < ELEMENTSOF(v); field++) { \ 50 : touched = false; \ 51 : for (n = 0; n < (2 * sizeof(v[0])); n++) { \ 52 : if (s[pos] == '\0') \ 53 : break; \ 54 : hexoff = strchr(hex, s[pos]); \ 55 : if (!hexoff) \ 56 : break; \ 57 : assert(hexoff >= hex); \ 58 : x = hexoff - hex; \ 59 : if (x >= 16) \ 60 : x -= 6; /* A-F */ \ 61 : assert(x < 16); \ 62 : touched = true; \ 63 : v[field] <<= 4; \ 64 : v[field] += x; \ 65 : pos++; \ 66 : } \ 67 : if (!touched) \ 68 : return -EINVAL; \ 69 : if (field < (ELEMENTSOF(v)-1)) { \ 70 : if (s[pos] != sep) \ 71 : return -EINVAL; \ 72 : else \ 73 : pos++; \ 74 : } \ 75 : } 76 : 77 67 : assert(s); 78 67 : assert(ret); 79 : 80 67 : s += strspn(s, WHITESPACE); 81 67 : sep = s[strspn(s, hex)]; 82 : 83 67 : if (sep == '.') { 84 14 : uint16_t shorts[3] = { 0 }; 85 : 86 176 : parse_fields(shorts); 87 : 88 10 : if (s[pos] != '\0') 89 2 : return -EINVAL; 90 : 91 32 : for (n = 0; n < ELEMENTSOF(shorts); n++) { 92 24 : ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8); 93 24 : ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff); 94 : } 95 : 96 53 : } else if (IN_SET(sep, ':', '-')) { 97 45 : struct ether_addr out = ETHER_ADDR_NULL; 98 : 99 762 : parse_fields(out.ether_addr_octet); 100 : 101 35 : if (s[pos] != '\0') 102 9 : return -EINVAL; 103 : 104 182 : for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++) 105 156 : ret->ether_addr_octet[n] = out.ether_addr_octet[n]; 106 : 107 : } else 108 8 : return -EINVAL; 109 : 110 34 : return 0; 111 : }