• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14554080340

19 Apr 2025 11:46AM UTC coverage: 72.101% (-0.03%) from 72.13%
14554080340

push

github

web-flow
Add two new paragraphs to coding style about header files (#37188)

296880 of 411754 relevant lines covered (72.1%)

687547.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.76
/src/basic/ether-addr-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <errno.h>
4
#include <inttypes.h>
5
#include <net/ethernet.h>
6
#include <stdio.h>
7
#include <sys/types.h>
8

9
#include "ether-addr-util.h"
10
#include "hexdecoct.h"
11
#include "log.h"
12
#include "macro.h"
13
#include "string-util.h"
14

15
char* hw_addr_to_string_full(
7,263✔
16
                const struct hw_addr_data *addr,
17
                HardwareAddressToStringFlags flags,
18
                char buffer[static HW_ADDR_TO_STRING_MAX]) {
19

20
        assert(addr);
7,263✔
21
        assert(buffer);
7,263✔
22
        assert(addr->length <= HW_ADDR_MAX_SIZE);
7,263✔
23

24
        for (size_t i = 0, j = 0; i < addr->length; i++) {
52,745✔
25
                buffer[j++] = hexchar(addr->bytes[i] >> 4);
45,482✔
26
                buffer[j++] = hexchar(addr->bytes[i] & 0x0f);
45,482✔
27
                if (!FLAGS_SET(flags, HW_ADDR_TO_STRING_NO_COLON))
45,482✔
28
                        buffer[j++] = ':';
45,452✔
29
        }
30

31
        buffer[addr->length == 0 || FLAGS_SET(flags, HW_ADDR_TO_STRING_NO_COLON) ?
7,263✔
32
               addr->length * 2 :
7,268✔
33
               addr->length * 3 - 1] = '\0';
7,258✔
34
        return buffer;
7,263✔
35
}
36

37
struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length) {
250✔
38
        assert(addr);
250✔
39
        assert(length <= HW_ADDR_MAX_SIZE);
250✔
40

41
        addr->length = length;
250✔
42
        memcpy_safe(addr->bytes, bytes, length);
250✔
43
        return addr;
250✔
44
}
45

46
int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b) {
12,230✔
47
        int r;
12,230✔
48

49
        assert(a);
12,230✔
50
        assert(b);
12,230✔
51

52
        r = CMP(a->length, b->length);
12,230✔
53
        if (r != 0)
9,243✔
54
                return r;
3,840✔
55

56
        return memcmp(a->bytes, b->bytes, a->length);
8,390✔
57
}
58

59
void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state) {
2,213✔
60
        assert(p);
2,213✔
61
        assert(state);
2,213✔
62

63
        siphash24_compress_typesafe(p->length, state);
2,213✔
64
        siphash24_compress_safe(p->bytes, p->length, state);
2,213✔
65
}
2,213✔
66

67
DEFINE_HASH_OPS(hw_addr_hash_ops, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare);
68
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(hw_addr_hash_ops_free, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare, free);
17✔
69

70
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
29✔
71
        assert(addr);
29✔
72
        assert(buffer);
29✔
73

74
        /* Like ether_ntoa() but uses %02x instead of %x to print
75
         * ethernet addresses, which makes them look less funny. Also,
76
         * doesn't use a static buffer. */
77

78
        sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
29✔
79
                addr->ether_addr_octet[0],
29✔
80
                addr->ether_addr_octet[1],
29✔
81
                addr->ether_addr_octet[2],
29✔
82
                addr->ether_addr_octet[3],
29✔
83
                addr->ether_addr_octet[4],
29✔
84
                addr->ether_addr_octet[5]);
29✔
85

86
        return buffer;
29✔
87
}
88

89
int ether_addr_to_string_alloc(const struct ether_addr *addr, char **ret) {
×
90
        char *buf;
×
91

92
        assert(addr);
×
93
        assert(ret);
×
94

95
        buf = new(char, ETHER_ADDR_TO_STRING_MAX);
×
96
        if (!buf)
×
97
                return -ENOMEM;
98

99
        ether_addr_to_string(addr, buf);
×
100

101
        *ret = buf;
×
102
        return 0;
×
103
}
104

105
int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b) {
12,069✔
106
        return memcmp(a, b, ETH_ALEN);
12,069✔
107
}
108

109
static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *state) {
37✔
110
        siphash24_compress_typesafe(*p, state);
37✔
111
}
37✔
112

113
DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare);
114
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(ether_addr_hash_ops_free, struct ether_addr, ether_addr_hash_func, ether_addr_compare, free);
3✔
115

116
static int parse_hw_addr_one_field(const char **s, char sep, size_t len, uint8_t *buf) {
3,862✔
117
        const char *hex = HEXDIGITS, *p;
3,862✔
118
        uint16_t data = 0;
3,862✔
119
        bool cont;
3,862✔
120

121
        assert(s);
3,862✔
122
        assert(*s);
3,862✔
123
        assert(IN_SET(len, 1, 2));
3,862✔
124
        assert(buf);
3,862✔
125

126
        p = *s;
127

128
        for (size_t i = 0; i < len * 2; i++) {
11,646✔
129
                const char *hexoff;
7,859✔
130
                size_t x;
7,859✔
131

132
                if (*p == '\0' || *p == sep) {
7,859✔
133
                        if (i == 0)
68✔
134
                                return -EINVAL;
135
                        break;
136
                }
137

138
                hexoff = strchr(hex, *p);
7,791✔
139
                if (!hexoff)
7,791✔
140
                        return -EINVAL;
141

142
                assert(hexoff >= hex);
7,784✔
143
                x = hexoff - hex;
7,784✔
144
                if (x >= 16)
7,784✔
145
                        x -= 6; /* A-F */
70✔
146

147
                assert(x < 16);
70✔
148
                data <<= 4;
7,784✔
149
                data += x;
7,784✔
150

151
                p++;
7,784✔
152
        }
153

154
        if (*p != '\0' && *p != sep)
3,847✔
155
                return -EINVAL;
156

157
        switch (len) {
3,834✔
158
        case 1:
3,741✔
159
                buf[0] = data;
3,741✔
160
                break;
3,741✔
161
        case 2:
93✔
162
                buf[0] = (data & 0xff00) >> 8;
93✔
163
                buf[1] = data & 0xff;
93✔
164
                break;
93✔
165
        default:
×
166
                assert_not_reached();
×
167
        }
168

169
        cont = *p == sep;
3,834✔
170
        *s = p + cont;
3,834✔
171
        return cont;
3,834✔
172
}
173

174
int parse_hw_addr_full(const char *s, size_t expected_len, struct hw_addr_data *ret) {
718✔
175
        size_t field_size, max_len, len = 0;
718✔
176
        uint8_t bytes[HW_ADDR_MAX_SIZE];
718✔
177
        char sep;
718✔
178
        int r;
718✔
179

180
        assert(s);
718✔
181
        assert(expected_len <= HW_ADDR_MAX_SIZE || expected_len == SIZE_MAX);
718✔
182
        assert(ret);
718✔
183

184
        /* This accepts the following formats:
185
         *
186
         * Dot separated 2 bytes format: xxyy.zzaa.bbcc
187
         * Colon separated 1 bytes format: xx:yy:zz:aa:bb:cc
188
         * Hyphen separated 1 bytes format: xx-yy-zz-aa-bb-cc
189
         *
190
         * Moreover, if expected_len == 0, 4, or 16, this also accepts:
191
         *
192
         * IPv4 format: used by IPv4 tunnel, e.g. ipgre
193
         * IPv6 format: used by IPv6 tunnel, e.g. ip6gre
194
         *
195
         * The expected_len argument controls the length of acceptable addresses:
196
         *
197
         * 0: accepts 4 (AF_INET), 16 (AF_INET6), 6 (ETH_ALEN), or 20 (INFINIBAND_ALEN).
198
         * SIZE_MAX: accepts arbitrary length, but at least one separator must be included.
199
         * Otherwise: accepts addresses with matching length.
200
         */
201

202
        if (IN_SET(expected_len, 0, sizeof(struct in_addr), sizeof(struct in6_addr))) {
718✔
203
                union in_addr_union a;
93✔
204
                int family;
93✔
205

206
                if (expected_len == 0)
93✔
207
                        r = in_addr_from_string_auto(s, &family, &a);
80✔
208
                else {
209
                        family = expected_len == sizeof(struct in_addr) ? AF_INET : AF_INET6;
13✔
210
                        r = in_addr_from_string(family, s, &a);
13✔
211
                }
212
                if (r >= 0) {
93✔
213
                        ret->length = FAMILY_ADDRESS_SIZE(family);
30✔
214
                        memcpy(ret->bytes, a.bytes, ret->length);
30✔
215
                        return 0;
30✔
216
                }
217
        }
218

219
        max_len =
1,376✔
220
                expected_len == 0 ? INFINIBAND_ALEN :
688✔
221
                expected_len == SIZE_MAX ? HW_ADDR_MAX_SIZE : expected_len;
627✔
222
        sep = s[strspn(s, HEXDIGITS)];
688✔
223

224
        if (sep == '.')
688✔
225
                field_size = 2;
226
        else if (IN_SET(sep, ':', '-'))
650✔
227
                field_size = 1;
228
        else
229
                return -EINVAL;
230

231
        if (max_len % field_size != 0)
677✔
232
                return -EINVAL;
233

234
        for (size_t i = 0; i < max_len / field_size; i++) {
3,870✔
235
                r = parse_hw_addr_one_field(&s, sep, field_size, bytes + i * field_size);
3,862✔
236
                if (r < 0)
3,862✔
237
                        return r;
238
                if (r == 0) {
3,834✔
239
                        len = (i + 1) * field_size;
641✔
240
                        break;
641✔
241
                }
242
        }
243

244
        if (len == 0)
649✔
245
                return -EINVAL;
246

247
        if (expected_len == 0) {
641✔
248
                if (!IN_SET(len, 4, 16, ETH_ALEN, INFINIBAND_ALEN))
61✔
249
                        return -EINVAL;
250
        } else if (expected_len != SIZE_MAX) {
580✔
251
                if (len != expected_len)
567✔
252
                        return -EINVAL;
253
        }
254

255
        ret->length = len;
630✔
256
        memcpy(ret->bytes, bytes, ret->length);
630✔
257
        return 0;
630✔
258
}
259

260
int parse_ether_addr(const char *s, struct ether_addr *ret) {
123✔
261
        struct hw_addr_data a;
123✔
262
        int r;
123✔
263

264
        assert(s);
123✔
265
        assert(ret);
123✔
266

267
        r = parse_hw_addr_full(s, ETH_ALEN, &a);
123✔
268
        if (r < 0)
123✔
269
                return r;
123✔
270

271
        *ret = a.ether;
85✔
272
        return 0;
85✔
273
}
274

275
void ether_addr_mark_random(struct ether_addr *addr) {
76✔
276
        assert(addr);
76✔
277

278
        /* see eth_random_addr in the kernel */
279
        addr->ether_addr_octet[0] &= 0xfe;        /* clear multicast bit */
76✔
280
        addr->ether_addr_octet[0] |= 0x02;        /* set local assignment bit (IEEE802) */
76✔
281
}
76✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc