1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include <net/ethernet.h>
9 #include "ether-addr-util.h"
10 #include "hexdecoct.h"
12 #include "string-util.h"
14 char *hw_addr_to_string_full(
15 const struct hw_addr_data
*addr
,
16 HardwareAddressToStringFlags flags
,
17 char buffer
[static HW_ADDR_TO_STRING_MAX
]) {
21 assert(addr
->length
<= HW_ADDR_MAX_SIZE
);
23 for (size_t i
= 0, j
= 0; i
< addr
->length
; i
++) {
24 buffer
[j
++] = hexchar(addr
->bytes
[i
] >> 4);
25 buffer
[j
++] = hexchar(addr
->bytes
[i
] & 0x0f);
26 if (!FLAGS_SET(flags
, HW_ADDR_TO_STRING_NO_COLON
))
30 buffer
[addr
->length
== 0 || FLAGS_SET(flags
, HW_ADDR_TO_STRING_NO_COLON
) ?
32 addr
->length
* 3 - 1] = '\0';
36 struct hw_addr_data
*hw_addr_set(struct hw_addr_data
*addr
, const uint8_t *bytes
, size_t length
) {
38 assert(length
<= HW_ADDR_MAX_SIZE
);
40 addr
->length
= length
;
41 memcpy_safe(addr
->bytes
, bytes
, length
);
45 int hw_addr_compare(const struct hw_addr_data
*a
, const struct hw_addr_data
*b
) {
51 r
= CMP(a
->length
, b
->length
);
55 return memcmp(a
->bytes
, b
->bytes
, a
->length
);
58 void hw_addr_hash_func(const struct hw_addr_data
*p
, struct siphash
*state
) {
62 siphash24_compress(&p
->length
, sizeof(p
->length
), state
);
63 siphash24_compress(p
->bytes
, p
->length
, state
);
66 DEFINE_HASH_OPS(hw_addr_hash_ops
, struct hw_addr_data
, hw_addr_hash_func
, hw_addr_compare
);
67 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(hw_addr_hash_ops_free
, struct hw_addr_data
, hw_addr_hash_func
, hw_addr_compare
, free
);
69 char* ether_addr_to_string(const struct ether_addr
*addr
, char buffer
[ETHER_ADDR_TO_STRING_MAX
]) {
73 /* Like ether_ntoa() but uses %02x instead of %x to print
74 * ethernet addresses, which makes them look less funny. Also,
75 * doesn't use a static buffer. */
77 sprintf(buffer
, "%02x:%02x:%02x:%02x:%02x:%02x",
78 addr
->ether_addr_octet
[0],
79 addr
->ether_addr_octet
[1],
80 addr
->ether_addr_octet
[2],
81 addr
->ether_addr_octet
[3],
82 addr
->ether_addr_octet
[4],
83 addr
->ether_addr_octet
[5]);
88 int ether_addr_to_string_alloc(const struct ether_addr
*addr
, char **ret
) {
94 buf
= new(char, ETHER_ADDR_TO_STRING_MAX
);
98 ether_addr_to_string(addr
, buf
);
104 int ether_addr_compare(const struct ether_addr
*a
, const struct ether_addr
*b
) {
105 return memcmp(a
, b
, ETH_ALEN
);
108 static void ether_addr_hash_func(const struct ether_addr
*p
, struct siphash
*state
) {
109 siphash24_compress(p
, sizeof(struct ether_addr
), state
);
112 DEFINE_HASH_OPS(ether_addr_hash_ops
, struct ether_addr
, ether_addr_hash_func
, ether_addr_compare
);
113 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(ether_addr_hash_ops_free
, struct ether_addr
, ether_addr_hash_func
, ether_addr_compare
, free
);
115 static int parse_hw_addr_one_field(const char **s
, char sep
, size_t len
, uint8_t *buf
) {
116 const char *hex
= HEXDIGITS
, *p
;
122 assert(IN_SET(len
, 1, 2));
127 for (size_t i
= 0; i
< len
* 2; i
++) {
131 if (*p
== '\0' || *p
== sep
) {
137 hexoff
= strchr(hex
, *p
);
141 assert(hexoff
>= hex
);
153 if (*p
!= '\0' && *p
!= sep
)
161 buf
[0] = (data
& 0xff00) >> 8;
162 buf
[1] = data
& 0xff;
165 assert_not_reached();
173 int parse_hw_addr_full(const char *s
, size_t expected_len
, struct hw_addr_data
*ret
) {
174 size_t field_size
, max_len
, len
= 0;
175 uint8_t bytes
[HW_ADDR_MAX_SIZE
];
180 assert(expected_len
<= HW_ADDR_MAX_SIZE
|| expected_len
== SIZE_MAX
);
183 /* This accepts the following formats:
185 * Dot separated 2 bytes format: xxyy.zzaa.bbcc
186 * Colon separated 1 bytes format: xx:yy:zz:aa:bb:cc
187 * Hyphen separated 1 bytes format: xx-yy-zz-aa-bb-cc
189 * Moreover, if expected_len == 0, 4, or 16, this also accepts:
191 * IPv4 format: used by IPv4 tunnel, e.g. ipgre
192 * IPv6 format: used by IPv6 tunnel, e.g. ip6gre
194 * The expected_len argument controls the length of acceptable addresses:
196 * 0: accepts 4 (AF_INET), 16 (AF_INET6), 6 (ETH_ALEN), or 20 (INFINIBAND_ALEN).
197 * SIZE_MAX: accepts arbitrary length, but at least one separator must be included.
198 * Otherwise: accepts addresses with matching length.
201 if (IN_SET(expected_len
, 0, sizeof(struct in_addr
), sizeof(struct in6_addr
))) {
202 union in_addr_union a
;
205 if (expected_len
== 0)
206 r
= in_addr_from_string_auto(s
, &family
, &a
);
208 family
= expected_len
== sizeof(struct in_addr
) ? AF_INET
: AF_INET6
;
209 r
= in_addr_from_string(family
, s
, &a
);
212 ret
->length
= FAMILY_ADDRESS_SIZE(family
);
213 memcpy(ret
->bytes
, a
.bytes
, ret
->length
);
219 expected_len
== 0 ? INFINIBAND_ALEN
:
220 expected_len
== SIZE_MAX
? HW_ADDR_MAX_SIZE
: expected_len
;
221 sep
= s
[strspn(s
, HEXDIGITS
)];
225 else if (IN_SET(sep
, ':', '-'))
230 if (max_len
% field_size
!= 0)
233 for (size_t i
= 0; i
< max_len
/ field_size
; i
++) {
234 r
= parse_hw_addr_one_field(&s
, sep
, field_size
, bytes
+ i
* field_size
);
238 len
= (i
+ 1) * field_size
;
246 if (expected_len
== 0) {
247 if (!IN_SET(len
, 4, 16, ETH_ALEN
, INFINIBAND_ALEN
))
249 } else if (expected_len
!= SIZE_MAX
) {
250 if (len
!= expected_len
)
255 memcpy(ret
->bytes
, bytes
, ret
->length
);
259 int parse_ether_addr(const char *s
, struct ether_addr
*ret
) {
260 struct hw_addr_data a
;
266 r
= parse_hw_addr_full(s
, ETH_ALEN
, &a
);