1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stdbool.h> 6 7 #include <rte_ether.h> 8 #include <rte_errno.h> 9 10 void 11 rte_eth_random_addr(uint8_t *addr) 12 { 13 uint64_t rand = rte_rand(); 14 uint8_t *p = (uint8_t *)&rand; 15 16 rte_memcpy(addr, p, RTE_ETHER_ADDR_LEN); 17 addr[0] &= (uint8_t)~RTE_ETHER_GROUP_ADDR; /* clear multicast bit */ 18 addr[0] |= RTE_ETHER_LOCAL_ADMIN_ADDR; /* set local assignment bit */ 19 } 20 21 void 22 rte_ether_format_addr(char *buf, uint16_t size, 23 const struct rte_ether_addr *eth_addr) 24 { 25 snprintf(buf, size, RTE_ETHER_ADDR_PRT_FMT, 26 RTE_ETHER_ADDR_BYTES(eth_addr)); 27 } 28 29 static int8_t get_xdigit(char ch) 30 { 31 if (ch >= '0' && ch <= '9') 32 return ch - '0'; 33 if (ch >= 'a' && ch <= 'f') 34 return ch - 'a' + 10; 35 if (ch >= 'A' && ch <= 'F') 36 return ch - 'A' + 10; 37 return -1; 38 } 39 40 /* Convert 00:11:22:33:44:55 to ethernet address */ 41 static bool get_ether_addr6(const char *s0, struct rte_ether_addr *ea, 42 const char sep) 43 { 44 const char *s = s0; 45 int i; 46 47 for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) { 48 int8_t x; 49 50 x = get_xdigit(*s++); 51 if (x < 0) 52 return false; /* not a hex digit */ 53 54 ea->addr_bytes[i] = x; 55 if (*s != sep && *s != '\0') { 56 x = get_xdigit(*s++); 57 if (x < 0) 58 return false; /* not a hex digit */ 59 ea->addr_bytes[i] <<= 4; 60 ea->addr_bytes[i] |= x; 61 } 62 63 if (i < RTE_ETHER_ADDR_LEN - 1 && 64 *s++ != sep) 65 return false; /* premature end of string */ 66 } 67 68 /* return true if no trailing characters */ 69 return *s == '\0'; 70 } 71 72 /* Convert 0011:2233:4455 to ethernet address */ 73 static bool get_ether_addr3(const char *s, struct rte_ether_addr *ea, 74 const char sep) 75 { 76 int i, j; 77 78 for (i = 0; i < RTE_ETHER_ADDR_LEN; i += 2) { 79 uint16_t w = 0; 80 81 for (j = 0; j < 4; j++) { 82 int8_t x; 83 84 x = get_xdigit(*s++); 85 if (x < 0) 86 return false; /* not a hex digit */ 87 w = (w << 4) | x; 88 } 89 90 ea->addr_bytes[i] = w >> 8; 91 ea->addr_bytes[i + 1] = w & 0xff; 92 93 if (i < RTE_ETHER_ADDR_LEN - 2 && 94 *s++ != sep) 95 return false; 96 } 97 98 return *s == '\0'; 99 } 100 101 /* 102 * Scan input to see if separated by dash, colon or period 103 * Returns separator and number of matches 104 * If separators are mixed will return 105 */ 106 static unsigned int get_ether_sep(const char *s, char *sep) 107 { 108 static const char separators[] = "-:."; 109 unsigned int count = 0; 110 const char *cp; 111 112 cp = strpbrk(s, separators); 113 if (cp == NULL) 114 return 0; /* no separator found */ 115 116 *sep = *cp; /* return the separator */ 117 do { 118 ++count; 119 /* find next instance of separator */ 120 cp = strchr(cp + 1, *sep); 121 } while (cp != NULL); 122 123 return count; 124 } 125 126 /* 127 * Be liberal in accepting a wide variety of notational formats 128 * for MAC address including: 129 * - Linux format six groups of hexadecimal digits separated by colon 130 * - Windows format six groups separated by hyphen 131 * - two groups hexadecimal digits 132 */ 133 int 134 rte_ether_unformat_addr(const char *s, struct rte_ether_addr *ea) 135 { 136 unsigned int count; 137 char sep = '\0'; 138 139 count = get_ether_sep(s, &sep); 140 switch (count) { 141 case 5: /* i.e 01:23:45:67:89:AB */ 142 if (get_ether_addr6(s, ea, sep)) 143 return 0; 144 break; 145 case 2: /* i.e 0123.4567.89AB */ 146 if (get_ether_addr3(s, ea, sep)) 147 return 0; 148 break; 149 default: 150 break; 151 } 152 153 rte_errno = EINVAL; 154 return -1; 155 } 156