/* Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* get hardware address for an interface */ /* if there are many available, any non-zero one can be used */ #include "mysys_priv.h" #include "my_sys.h" #include #ifndef MAIN #ifdef __FreeBSD__ #include #include #include #include #include my_bool my_gethwaddr(uchar *to) { size_t len; char *buf, *next, *end; struct if_msghdr *ifm; struct sockaddr_dl *sdl; int res=1, mib[6]={CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0}; char zero_array[ETHER_ADDR_LEN] = {0}; if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) goto err; if (!(buf = alloca(len))) goto err; if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) goto err; end = buf + len; for (next = buf ; res && next < end ; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type == RTM_IFINFO) { sdl= (struct sockaddr_dl *)(ifm + 1); memcpy(to, LLADDR(sdl), ETHER_ADDR_LEN); res= memcmp(to, zero_array, ETHER_ADDR_LEN) ? 0 : 1; } } err: return res; } #elif __linux__ #include #include #include #define MAX_IFS 64 my_bool my_gethwaddr(uchar *to) { int fd= -1; int res= 1; struct ifreq ifr; struct ifreq ifs[MAX_IFS]; struct ifreq *ifri= NULL; struct ifreq *ifend= NULL; char zero_array[ETHER_ADDR_LEN] = {0}; struct ifconf ifc; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return 1; /* Retrieve interfaces */ ifc.ifc_len= sizeof(ifs); ifc.ifc_req= ifs; if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { close(fd); return 1; } /* Initialize out parameter */ memcpy(to, zero_array, ETHER_ADDR_LEN); /* Calculate first address after array */ ifend= ifs + (ifc.ifc_len / sizeof(struct ifreq)); /* Loop over all interfaces */ for (ifri= ifc.ifc_req; ifri < ifend; ifri++) { if (ifri->ifr_addr.sa_family == AF_INET) { /* Reset struct, copy interface name */ memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifri->ifr_name, sizeof(ifr.ifr_name)); /* Get HW address, break if not 0 */ if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) { memcpy(to, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); if (memcmp(to, zero_array, ETHER_ADDR_LEN)) { res= 0; break; } } } } close(fd); return res; } #elif defined(_WIN32) /* Workaround for BUG#32082 (Definition of VOID in my_global.h conflicts with windows headers) */ #ifdef VOID #undef VOID #define VOID void #endif #include /* The following typedef is for dynamically loading iphlpapi.dll / GetAdaptersAddresses. Dynamic loading is used because GetAdaptersAddresses is not available on Windows 2000 which MySQL still supports. Static linking would cause an unresolved export. */ typedef DWORD (WINAPI *pfnGetAdaptersAddresses)(IN ULONG Family, IN DWORD Flags,IN PVOID Reserved, OUT PIP_ADAPTER_ADDRESSES pAdapterAddresses, IN OUT PULONG pOutBufLen); /* my_gethwaddr - Windows version @brief Retrieve MAC address from network hardware @param[out] to MAC address exactly six bytes @return Operation status @retval 0 OK @retval <>0 FAILED */ my_bool my_gethwaddr(uchar *to) { PIP_ADAPTER_ADDRESSES pAdapterAddresses; PIP_ADAPTER_ADDRESSES pCurrAddresses; IP_ADAPTER_ADDRESSES adapterAddresses; ULONG address_len; my_bool return_val= 1; static pfnGetAdaptersAddresses fnGetAdaptersAddresses= (pfnGetAdaptersAddresses)-1; if(fnGetAdaptersAddresses == (pfnGetAdaptersAddresses)-1) { /* Get the function from the DLL */ fnGetAdaptersAddresses= (pfnGetAdaptersAddresses) GetProcAddress(LoadLibrary("iphlpapi.dll"), "GetAdaptersAddresses"); } if (!fnGetAdaptersAddresses) return 1; /* failed to get function */ address_len= sizeof (IP_ADAPTER_ADDRESSES); /* Get the required size for the address data. */ if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, &adapterAddresses, &address_len) == ERROR_BUFFER_OVERFLOW) { pAdapterAddresses= my_malloc(key_memory_win_IP_ADAPTER_ADDRESSES, address_len, 0); if (!pAdapterAddresses) return 1; /* error, alloc failed */ } else pAdapterAddresses= &adapterAddresses; /* one is enough don't alloc */ /* Get the hardware info. */ if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &address_len) == NO_ERROR) { pCurrAddresses= pAdapterAddresses; while (pCurrAddresses) { /* Look for ethernet cards. */ if (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD) { /* check for a good address */ if (pCurrAddresses->PhysicalAddressLength < 6) continue; /* bad address */ /* save 6 bytes of the address in the 'to' parameter */ memcpy(to, pCurrAddresses->PhysicalAddress, 6); /* Network card found, we're done. */ return_val= 0; break; } pCurrAddresses= pCurrAddresses->Next; } } /* Clean up memory allocation. */ if (pAdapterAddresses != &adapterAddresses) my_free(pAdapterAddresses); return return_val; } #else /* __FreeBSD__ || __linux__ || _WIN32 */ /* just fail */ my_bool my_gethwaddr(uchar *to MY_ATTRIBUTE((unused))) { return 1; } #endif #else /* MAIN */ int main(int argc MY_ATTRIBUTE((unused)),char **argv) { uchar mac[6]; uint i; MY_INIT(argv[0]); if (my_gethwaddr(mac)) { printf("my_gethwaddr failed with errno %d\n", errno); exit(1); } for (i=0; i < sizeof(mac); i++) { if (i) printf(":"); printf("%02x", mac[i]); } printf("\n"); return 0; } #endif