Branch data 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 : 16 : char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
13 [ - + ]: 16 : assert(addr);
14 [ - + ]: 16 : 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 : 96 : sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
21 : 16 : addr->ether_addr_octet[0],
22 : 16 : addr->ether_addr_octet[1],
23 : 16 : addr->ether_addr_octet[2],
24 : 16 : addr->ether_addr_octet[3],
25 : 16 : addr->ether_addr_octet[4],
26 : 16 : addr->ether_addr_octet[5]);
27 : :
28 : 16 : return buffer;
29 : : }
30 : :
31 : 312 : int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b) {
32 : 312 : return memcmp(a, b, ETH_ALEN);
33 : : }
34 : :
35 : 216 : static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *state) {
36 : 216 : siphash24_compress(p, sizeof(struct ether_addr), state);
37 : 216 : }
38 : :
39 : : DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare);
40 : :
41 : 268 : int ether_addr_from_string(const char *s, struct ether_addr *ret) {
42 : 268 : size_t pos = 0, n, field;
43 : 268 : char sep = '\0';
44 : 268 : 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 [ - + ]: 268 : assert(s);
78 [ - + ]: 268 : assert(ret);
79 : :
80 : 268 : s += strspn(s, WHITESPACE);
81 : 268 : sep = s[strspn(s, hex)];
82 : :
83 [ + + ]: 268 : if (sep == '.') {
84 : 56 : uint16_t shorts[3] = { 0 };
85 : :
86 [ - + + + : 704 : parse_fields(shorts);
- + - + -
+ + + - +
+ + + + +
+ ]
87 : :
88 [ + + ]: 40 : if (s[pos] != '\0')
89 : 8 : return -EINVAL;
90 : :
91 [ + + ]: 128 : for (n = 0; n < ELEMENTSOF(shorts); n++) {
92 : 96 : ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
93 : 96 : ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
94 : : }
95 : :
96 [ + + + + ]: 212 : } else if (IN_SET(sep, ':', '-')) {
97 : 180 : struct ether_addr out = ETHER_ADDR_NULL;
98 : :
99 [ + + + + : 3048 : parse_fields(out.ether_addr_octet);
- + + + -
+ + + + +
+ + + + +
+ ]
100 : :
101 [ + + ]: 140 : if (s[pos] != '\0')
102 : 36 : return -EINVAL;
103 : :
104 [ + + ]: 728 : for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
105 : 624 : ret->ether_addr_octet[n] = out.ether_addr_octet[n];
106 : :
107 : : } else
108 : 32 : return -EINVAL;
109 : :
110 : 136 : return 0;
111 : : }
|