]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/ether-addr-util.c
Merge pull request #3235 from dkg/hwaddr-cleanup
[thirdparty/systemd.git] / src / basic / ether-addr-util.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2014 Tom Gundersen
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <net/ethernet.h>
21 #include <stdio.h>
22 #include <sys/types.h>
23
24 #include "ether-addr-util.h"
25 #include "macro.h"
26 #include "string-util.h"
27
28 char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
29 assert(addr);
30 assert(buffer);
31
32 /* Like ether_ntoa() but uses %02x instead of %x to print
33 * ethernet addresses, which makes them look less funny. Also,
34 * doesn't use a static buffer. */
35
36 sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
37 addr->ether_addr_octet[0],
38 addr->ether_addr_octet[1],
39 addr->ether_addr_octet[2],
40 addr->ether_addr_octet[3],
41 addr->ether_addr_octet[4],
42 addr->ether_addr_octet[5]);
43
44 return buffer;
45 }
46
47 bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
48 assert(a);
49 assert(b);
50
51 return a->ether_addr_octet[0] == b->ether_addr_octet[0] &&
52 a->ether_addr_octet[1] == b->ether_addr_octet[1] &&
53 a->ether_addr_octet[2] == b->ether_addr_octet[2] &&
54 a->ether_addr_octet[3] == b->ether_addr_octet[3] &&
55 a->ether_addr_octet[4] == b->ether_addr_octet[4] &&
56 a->ether_addr_octet[5] == b->ether_addr_octet[5];
57 }
58
59 int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset) {
60 size_t pos = 0, n, field;
61 char sep = '\0';
62 const char *hex = HEXDIGITS, *hexoff;
63 size_t x;
64 bool touched;
65
66 #define parse_fields(v) \
67 for (field = 0; field < ELEMENTSOF(v); field++) { \
68 touched = false; \
69 for (n = 0; n < (2 * sizeof(v[0])); n++) { \
70 if (s[pos] == '\0') \
71 break; \
72 hexoff = strchr(hex, s[pos]); \
73 if (hexoff == NULL) \
74 break; \
75 assert(hexoff >= hex); \
76 x = hexoff - hex; \
77 if (x >= 16) \
78 x -= 6; /* A-F */ \
79 assert(x < 16); \
80 touched = true; \
81 v[field] <<= 4; \
82 v[field] += x; \
83 pos++; \
84 } \
85 if (!touched) \
86 return -EINVAL; \
87 if (field < (ELEMENTSOF(v)-1)) { \
88 if (s[pos] != sep) \
89 return -EINVAL; \
90 else \
91 pos++; \
92 } \
93 }
94
95 assert(s);
96 assert(ret);
97
98 sep = s[strspn(s, hex)];
99 if (sep == '\n')
100 return -EINVAL;
101 if (strchr(":.-", sep) == NULL)
102 return -EINVAL;
103
104 if (sep == '.') {
105 uint16_t shorts[3] = { 0 };
106
107 parse_fields(shorts);
108
109 for (n = 0; n < ELEMENTSOF(shorts); n++) {
110 ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
111 ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
112 }
113 } else {
114 struct ether_addr out = { .ether_addr_octet = { 0 } };
115
116 parse_fields(out.ether_addr_octet);
117
118 for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
119 ret->ether_addr_octet[n] = out.ether_addr_octet[n];
120 }
121
122 if (offset)
123 *offset = pos;
124 return 0;
125 }