1 /*
2 * virmacaddr.c: MAC address handling
3 *
4 * Copyright (C) 2006-2013 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but 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
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23
24 #include "virmacaddr.h"
25 #include "virrandom.h"
26 #include "viralloc.h"
27
28 static const unsigned char virMacAddrBroadcastAddrRaw[VIR_MAC_BUFLEN] =
29 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
30
31 /* Compare two MAC addresses, ignoring differences in case,
32 * as well as leading zeros.
33 */
34 int
virMacAddrCompare(const char * p,const char * q)35 virMacAddrCompare(const char *p, const char *q)
36 {
37 unsigned char c, d;
38 do {
39 while (*p == '0' && g_ascii_isxdigit(p[1]))
40 ++p;
41 while (*q == '0' && g_ascii_isxdigit(q[1]))
42 ++q;
43 c = g_ascii_tolower(*p);
44 d = g_ascii_tolower(*q);
45
46 if (c == 0 || d == 0)
47 break;
48
49 ++p;
50 ++q;
51 } while (c == d);
52
53 if (UCHAR_MAX <= INT_MAX)
54 return c - d;
55
56 /* On machines where 'char' and 'int' are types of the same size, the
57 difference of two 'unsigned char' values - including the sign bit -
58 doesn't fit in an 'int'. */
59 return c > d ? 1 : c < d ? -1 : 0;
60 }
61
62 /**
63 * virMacAddrCmp:
64 * @mac1: pointer to 1st MAC address
65 * @mac2: pointer to 2nd MAC address
66 *
67 * Return 0 if MAC addresses are equal,
68 * < 0 if mac1 < mac2,
69 * > 0 if mac1 > mac2
70 */
71 int
virMacAddrCmp(const virMacAddr * mac1,const virMacAddr * mac2)72 virMacAddrCmp(const virMacAddr *mac1, const virMacAddr *mac2)
73 {
74 return memcmp(mac1->addr, mac2->addr, VIR_MAC_BUFLEN);
75 }
76
77 /**
78 * virMacAddrCmpRaw:
79 * @mac1: pointer to 1st MAC address
80 * @mac2: pointer to 2nd MAC address in plain buffer
81 *
82 * Return 0 if MAC addresses are equal,
83 * < 0 if mac1 < mac2,
84 * > 0 if mac1 > mac2
85 */
86 int
virMacAddrCmpRaw(const virMacAddr * mac1,const unsigned char mac2[VIR_MAC_BUFLEN])87 virMacAddrCmpRaw(const virMacAddr *mac1,
88 const unsigned char mac2[VIR_MAC_BUFLEN])
89 {
90 return memcmp(mac1->addr, mac2, VIR_MAC_BUFLEN);
91 }
92
93 /**
94 * virMacAddrSet
95 * @dst: pointer to destination
96 * @src: pointer to source
97 *
98 * Copy src to dst
99 */
100 void
virMacAddrSet(virMacAddr * dst,const virMacAddr * src)101 virMacAddrSet(virMacAddr *dst, const virMacAddr *src)
102 {
103 memcpy(dst, src, sizeof(*src));
104 }
105
106 /**
107 * virMacAddrSetRaw
108 * @dst: pointer to destination to hold MAC address
109 * @src: raw MAC address data
110 *
111 * Set the MAC address to the given value
112 */
113 void
virMacAddrSetRaw(virMacAddr * dst,const unsigned char src[VIR_MAC_BUFLEN])114 virMacAddrSetRaw(virMacAddr *dst, const unsigned char src[VIR_MAC_BUFLEN])
115 {
116 memcpy(dst->addr, src, VIR_MAC_BUFLEN);
117 }
118
119 /**
120 * virMacAddrGetRaw
121 * @src: pointer to MAC address
122 * @dst: pointer to raw memory to write MAC address into
123 *
124 * Copies the MAC address into raw memory
125 */
126 void
virMacAddrGetRaw(const virMacAddr * src,unsigned char dst[VIR_MAC_BUFLEN])127 virMacAddrGetRaw(const virMacAddr *src, unsigned char dst[VIR_MAC_BUFLEN])
128 {
129 memcpy(dst, src->addr, VIR_MAC_BUFLEN);
130 }
131
132 /**
133 * virMacAddrParse:
134 * @str: string representation of MAC address, e.g., "0:1E:FC:E:3a:CB"
135 * @addr: 6-byte MAC address
136 *
137 * Parse a MAC address
138 *
139 * Return 0 upon success, or -1 in case of error.
140 */
141 int
virMacAddrParse(const char * str,virMacAddr * addr)142 virMacAddrParse(const char* str, virMacAddr *addr)
143 {
144 size_t i;
145
146 errno = 0;
147 for (i = 0; i < VIR_MAC_BUFLEN; i++) {
148 char *end_ptr;
149 unsigned long result;
150
151 /* This is solely to avoid accepting the leading
152 * space or "+" that strtoul would otherwise accept.
153 */
154 if (!g_ascii_isxdigit(*str))
155 break;
156
157 result = strtoul(str, &end_ptr, 16); /* exempt from syntax-check */
158
159 if ((end_ptr - str) < 1 || 2 < (end_ptr - str) ||
160 (errno != 0) ||
161 (0xFF < result))
162 break;
163
164 addr->addr[i] = (unsigned char) result;
165
166 if ((i == 5) && (*end_ptr <= ' '))
167 return 0;
168 if (*end_ptr != ':')
169 break;
170
171 str = end_ptr + 1;
172 }
173
174 return -1;
175 }
176
177 /* virMacAddrFormat
178 * Converts the binary mac address in addr into a NULL-terminated
179 * character string in str. It is assumed that the memory pointed to
180 * by str is at least VIR_MAC_STRING_BUFLEN bytes long.
181 *
182 * Returns a pointer to the resulting character string.
183 */
184 const char *
virMacAddrFormat(const virMacAddr * addr,char * str)185 virMacAddrFormat(const virMacAddr *addr,
186 char *str)
187 {
188 g_snprintf(str, VIR_MAC_STRING_BUFLEN,
189 "%02x:%02x:%02x:%02x:%02x:%02x",
190 addr->addr[0], addr->addr[1], addr->addr[2],
191 addr->addr[3], addr->addr[4], addr->addr[5]);
192 str[VIR_MAC_STRING_BUFLEN-1] = '\0';
193 return str;
194 }
195
196 /**
197 * virMacAddrParseHex:
198 * @str: string hexadecimal representation of MAC address, e.g., "F801EFCE3aCB"
199 * @addr: 6-byte MAC address
200 *
201 * Parse the hexadecimal representation of a MAC address
202 *
203 * Return 0 upon success, or -1 in case of error.
204 */
205 int
virMacAddrParseHex(const char * str,virMacAddr * addr)206 virMacAddrParseHex(const char *str, virMacAddr *addr)
207 {
208 size_t i;
209
210 if (strspn(str, "0123456789abcdefABCDEF") != VIR_MAC_HEXLEN ||
211 str[VIR_MAC_HEXLEN])
212 return -1;
213
214 for (i = 0; i < VIR_MAC_BUFLEN; i++)
215 addr->addr[i] = (g_ascii_xdigit_value(str[2 * i]) << 4 |
216 g_ascii_xdigit_value(str[2 * i + 1]));
217 return 0;
218 }
219
virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN],virMacAddr * addr)220 void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN],
221 virMacAddr *addr)
222 {
223 addr->addr[0] = prefix[0];
224 addr->addr[1] = prefix[1];
225 addr->addr[2] = prefix[2];
226 addr->addr[3] = virRandomBits(8);
227 addr->addr[4] = virRandomBits(8);
228 addr->addr[5] = virRandomBits(8);
229 }
230
231 /* The low order bit of the first byte is the "multicast" bit. */
232 bool
virMacAddrIsMulticast(const virMacAddr * mac)233 virMacAddrIsMulticast(const virMacAddr *mac)
234 {
235 return !!(mac->addr[0] & 1);
236 }
237
238 bool
virMacAddrIsUnicast(const virMacAddr * mac)239 virMacAddrIsUnicast(const virMacAddr *mac)
240 {
241 return !(mac->addr[0] & 1);
242 }
243
244 bool
virMacAddrIsBroadcastRaw(const unsigned char s[VIR_MAC_BUFLEN])245 virMacAddrIsBroadcastRaw(const unsigned char s[VIR_MAC_BUFLEN])
246 {
247 return memcmp(virMacAddrBroadcastAddrRaw, s, sizeof(*s)) == 0;
248 }
249
250 void
virMacAddrFree(virMacAddr * addr)251 virMacAddrFree(virMacAddr *addr)
252 {
253 g_free(addr);
254 }
255