virmacaddr.c 6.1 KB
Newer Older
1 2 3
/*
 * virmacaddr.c: MAC address handling
 *
4
 * Copyright (C) 2006-2013 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23 24 25 26
 */

#include <config.h>


#include "c-ctype.h"
#include "virmacaddr.h"
#include "virrandom.h"
27
#include "virutil.h"
28
#include "viralloc.h"
29

30 31 32
static const unsigned char virMacAddrBroadcastAddrRaw[VIR_MAC_BUFLEN] =
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/* Compare two MAC addresses, ignoring differences in case,
 * as well as leading zeros.
 */
int
virMacAddrCompare(const char *p, const char *q)
{
    unsigned char c, d;
    do {
        while (*p == '0' && c_isxdigit(p[1]))
            ++p;
        while (*q == '0' && c_isxdigit(q[1]))
            ++q;
        c = c_tolower(*p);
        d = c_tolower(*q);

        if (c == 0 || d == 0)
            break;

        ++p;
        ++q;
    } while (c == d);

    if (UCHAR_MAX <= INT_MAX)
        return c - d;

    /* On machines where 'char' and 'int' are types of the same size, the
       difference of two 'unsigned char' values - including the sign bit -
       doesn't fit in an 'int'.  */
61
    return c > d ? 1 : c < d ? -1 : 0;
62 63
}

64 65 66 67 68 69 70 71 72 73
/**
 * virMacAddrCmp:
 * @mac1: pointer to 1st MAC address
 * @mac2: pointer to 2nd MAC address
 *
 * Return 0 if MAC addresses are equal,
 * < 0 if mac1 < mac2,
 * > 0 if mac1 > mac2
 */
int
74
virMacAddrCmp(const virMacAddr *mac1, const virMacAddr *mac2)
75 76 77 78 79 80 81 82 83 84 85 86 87 88
{
    return memcmp(mac1->addr, mac2->addr, VIR_MAC_BUFLEN);
}

/**
 * virMacAddrCmpRaw:
 * @mac1: pointer to 1st MAC address
 * @mac2: pointer to 2nd MAC address in plain buffer
 *
 * Return 0 if MAC addresses are equal,
 * < 0 if mac1 < mac2,
 * > 0 if mac1 > mac2
 */
int
89
virMacAddrCmpRaw(const virMacAddr *mac1,
90 91 92 93 94 95 96 97 98 99 100 101 102
                 const unsigned char mac2[VIR_MAC_BUFLEN])
{
    return memcmp(mac1->addr, mac2, VIR_MAC_BUFLEN);
}

/**
 * virMacAddrSet
 * @dst: pointer to destination
 * @src: pointer to source
 *
 * Copy src to dst
 */
void
103
virMacAddrSet(virMacAddrPtr dst, const virMacAddr *src)
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
{
    memcpy(dst, src, sizeof(*src));
}

/**
 * virMacAddrSetRaw
 * @dst: pointer to destination to hold MAC address
 * @src: raw MAC address data
 *
 * Set the MAC address to the given value
 */
void
virMacAddrSetRaw(virMacAddrPtr dst, const unsigned char src[VIR_MAC_BUFLEN])
{
    memcpy(dst->addr, src, VIR_MAC_BUFLEN);
}

/**
 * virMacAddrGetRaw
 * @src: pointer to MAC address
 * @dst: pointer to raw memory to write MAC address into
 *
 * Copies the MAC address into raw memory
 */
void
129
virMacAddrGetRaw(const virMacAddr *src, unsigned char dst[VIR_MAC_BUFLEN])
130 131 132 133
{
    memcpy(dst, src->addr, VIR_MAC_BUFLEN);
}

134 135 136 137 138 139 140 141 142 143
/**
 * virMacAddrParse:
 * @str: string representation of MAC address, e.g., "0:1E:FC:E:3a:CB"
 * @addr: 6-byte MAC address
 *
 * Parse a MAC address
 *
 * Return 0 upon success, or -1 in case of error.
 */
int
144
virMacAddrParse(const char* str, virMacAddrPtr addr)
145
{
146
    size_t i;
147 148 149 150 151 152 153 154 155 156 157 158

    errno = 0;
    for (i = 0; i < VIR_MAC_BUFLEN; i++) {
        char *end_ptr;
        unsigned long result;

        /* This is solely to avoid accepting the leading
         * space or "+" that strtoul would otherwise accept.
         */
        if (!c_isxdigit(*str))
            break;

E
Eric Blake 已提交
159
        result = strtoul(str, &end_ptr, 16); /* exempt from syntax-check */
160 161 162 163 164 165

        if ((end_ptr - str) < 1 || 2 < (end_ptr - str) ||
            (errno != 0) ||
            (0xFF < result))
            break;

166
        addr->addr[i] = (unsigned char) result;
167

168
        if ((i == 5) && (*end_ptr <= ' '))
169 170 171 172 173 174 175 176 177 178
            return 0;
        if (*end_ptr != ':')
            break;

        str = end_ptr + 1;
    }

    return -1;
}

179 180 181 182 183 184 185 186
/* virMacAddrFormat
 * Converts the binary mac address in addr into a NULL-terminated
 * character string in str. It is assumed that the memory pointed to
 * by str is at least VIR_MAC_STRING_BUFLEN bytes long.
 *
 * Returns a pointer to the resulting character string.
 */
const char *
187
virMacAddrFormat(const virMacAddr *addr,
188
                 char *str)
189 190
{
    snprintf(str, VIR_MAC_STRING_BUFLEN,
191
             "%02x:%02x:%02x:%02x:%02x:%02x",
192 193
             addr->addr[0], addr->addr[1], addr->addr[2],
             addr->addr[3], addr->addr[4], addr->addr[5]);
194
    str[VIR_MAC_STRING_BUFLEN-1] = '\0';
195
    return str;
196 197
}

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
/**
 * virMacAddrParseHex:
 * @str: string hexadecimal representation of MAC address, e.g., "F801EFCE3aCB"
 * @addr: 6-byte MAC address
 *
 * Parse the hexadecimal representation of a MAC address
 *
 * Return 0 upon success, or -1 in case of error.
 */
int
virMacAddrParseHex(const char *str, virMacAddrPtr addr)
{
    size_t i;

    if (strspn(str, "0123456789abcdefABCDEF") != VIR_MAC_HEXLEN ||
        str[VIR_MAC_HEXLEN])
        return -1;

    for (i = 0; i < VIR_MAC_BUFLEN; i++)
        addr->addr[i] = (virHexToBin(str[2 * i]) << 4 |
                         virHexToBin(str[2 * i + 1]));
    return 0;
}

222 223
void virMacAddrGenerate(const unsigned char prefix[VIR_MAC_PREFIX_BUFLEN],
                        virMacAddrPtr addr)
224
{
225 226 227 228 229 230
    addr->addr[0] = prefix[0];
    addr->addr[1] = prefix[1];
    addr->addr[2] = prefix[2];
    addr->addr[3] = virRandomBits(8);
    addr->addr[4] = virRandomBits(8);
    addr->addr[5] = virRandomBits(8);
231
}
232 233 234

/* The low order bit of the first byte is the "multicast" bit. */
bool
235
virMacAddrIsMulticast(const virMacAddr *mac)
236
{
237
    return !!(mac->addr[0] & 1);
238 239 240
}

bool
241
virMacAddrIsUnicast(const virMacAddr *mac)
242
{
243
    return !(mac->addr[0] & 1);
244
}
245 246 247 248 249 250

bool
virMacAddrIsBroadcastRaw(const unsigned char s[VIR_MAC_BUFLEN])
{
    return memcmp(virMacAddrBroadcastAddrRaw, s, sizeof(*s)) == 0;
}
251 252 253 254 255 256

void
virMacAddrFree(virMacAddrPtr addr)
{
    VIR_FREE(addr);
}