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