/** * @file macaddr.cpp * @author https://kldp.org/node/26319 * @brief getting mac address */ #include #include #include #include #include #include #ifndef WIN32 #include #include #ifndef _LINUX #include #include #else #ifdef _HAVE_STROPTS_H #include #endif #endif #else # pragma comment(lib, "iphlpapi.lib") #include #include #include #include #include #endif #include #include #ifdef _LINUX #include #include #include #include #include #endif #ifdef _HPUX #include #include #endif #ifdef _AIX #include #include /* in C++, 'getkerninfo()' function is not declared automatically. */ extern "C" int getkerninfo (int, char *, int *, int32long64_t); #endif #ifdef _SOLARIS #define BSD_COMP #include #include #include #include #include #include #include #include #include #include #include #include #endif #ifndef WIN32 #undef DLPI_DEV #ifdef HPUX static const char *dlpi_dev[] = {"/dev/dlpi", ""}; #define DLPI_DEV #endif #ifdef AIX static const char *dlpi_dev[] = {"/dev/dlpi/et", "/dev/dlpi/en", "/dev/dlpi/tr", "/dev/dlpi/fddi", ""}; #define DLPI_DEV /* AIX: remember to set up /etc/pse.conf or /etc/dlpi.conf */ #endif #ifdef SunOS static const char *dlpi_dev[] = {"/dev/hme", "/dev/ie", "/dev/le", "/dev/eri"}; #define DLPI_DEV #endif #if !defined(DLPI_DEV) && !defined(_LINUX) static const char *dlpi_dev[] = {"/dev/dlpi", ""}; /* unknown OS - hope that this will work ??? */ #define DLPI_DEV #endif /**********************************************************************/ /* * implementation */ #define INSAP 22 #define OUTSAP 24 #include #include #include #include #include #include #include #define bcopy(source, destination, length) memcpy(destination, source, length) #define AREA_SZ 5000 /*­=­* buffer length in bytes *­=­*/ #define GOT_CTRL 1 #define GOT_DATA 2 #define GOT_BOTH 3 #define GOT_INTR 4 #define GOT_ERR 128 #ifndef _LINUX static u_long ctl_area[AREA_SZ]; static u_long dat_area[AREA_SZ]; static struct strbuf ctl = {AREA_SZ, 0, (char *)ctl_area}; static struct strbuf dat = {AREA_SZ, 0, (char *)dat_area}; /*­=­* get a message from a stream; return type of message *­=­*/ static int GetMsg (int fd) { int flags = 0; int res, ret; ctl_area[0] = 0; dat_area[0] = 0; ret = 0; res = getmsg(fd, &ctl, &dat, &flags); if(res < 0) { if(errno == EINTR) { return(GOT_INTR); } else { return(GOT_ERR); } } if(ctl.len > 0) { ret |= GOT_CTRL; } if(dat.len > 0) { ret |= GOT_DATA; } return(ret); } /*­=­* verify that dl_primitive in ctl_area = prim *­=­*/ static int CheckCtrl (unsigned int prim) { dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area; if(err_ack->dl_primitive != prim) { return GOT_ERR; } return 0; } /*­=­* put a control message on a stream *­=­*/ static int PutCtrl (int fd, int len, int pri) { ctl.len = len; if(putmsg(fd, &ctl, 0, pri) < 0) { return GOT_ERR; } return 0; } /*­=­* put a control + data message on a stream *­=­*/ static int PutBoth (int fd, int clen, int dlen, int pri) { ctl.len = clen; dat.len = dlen; if(putmsg(fd, &ctl, &dat, pri) < 0) { return GOT_ERR; } return 0; } /*­=­* open file descriptor and attach *­=­*/ static int OpenDL (const char *dev, int ppa, int *fd) { dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area; if((*fd = open(dev, O_RDWR)) == -1) { return GOT_ERR; } attach_req->dl_primitive = DL_ATTACH_REQ; attach_req->dl_ppa = ppa; PutCtrl (*fd, sizeof(dl_attach_req_t), 0); GetMsg (*fd); return CheckCtrl (DL_OK_ACK); } /*­=­* send DL_BIND_REQ *­=­*/ static int BindDL (int fd, int sap, u_char *addr) { dl_bind_req_t *bind_req = (dl_bind_req_t *)ctl_area; dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)ctl_area; bind_req->dl_primitive = DL_BIND_REQ; bind_req->dl_sap = sap; bind_req->dl_max_conind = 1; bind_req->dl_service_mode = DL_CLDLS; bind_req->dl_conn_mgmt = 0; bind_req->dl_xidtest_flg = 0; PutCtrl (fd, sizeof(dl_bind_req_t), 0); GetMsg (fd); if (GOT_ERR == CheckCtrl (DL_BIND_ACK)) { return GOT_ERR; } bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, bind_ack->dl_addr_length); return 0; } /**********************************************************************/ /* * interface: * function DLPI - get the mac address of the "first" interface * * parameter: addr: an array of six bytes, has to be allocated by the caller * * return: 0 if OK, -1 if the address could not be determined * */ static long DLPI ( char *addr) { int fd; int ppa; u_char mac_addr[25]; const char **dev; for (dev = dlpi_dev; **dev != '\0'; ++dev) { for (ppa=0; ppa<10; ++ppa) { if (GOT_ERR != OpenDL (*dev, ppa, &fd)) { if (GOT_ERR != BindDL (fd, INSAP, mac_addr)) { bcopy( mac_addr, addr, 6); return 0; } } close(fd); } } return -1; } #endif //#ifndef _LINUX #endif //#ifndef WIN32 long GetMACAddress (char *addr) { #ifdef WIN32 IP_ADAPTER_INFO AdapterInfo[16]; // Allocate information // for up to 16 NICs DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer PIP_ADAPTER_INFO pAdapterInfo; DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo AdapterInfo, // [out] buffer to receive data &dwBufLen); // [in] size of receive data buffer assert(dwStatus == ERROR_SUCCESS); // Verify return value is // valid, no buffer overflow pAdapterInfo = AdapterInfo; // Contains pointer to // current adapter info do { // PrintMACaddress(pAdapterInfo->Address); // Print MAC address /* fprintf( stderr, "%02X %02X %02X %02X %02X %02X\n", pAdapterInfo->Address[0], pAdapterInfo->Address[1], pAdapterInfo->Address[2], pAdapterInfo->Address[3], pAdapterInfo->Address[4], pAdapterInfo->Address[5] ); // Print MAC address */ memcpy (addr, pAdapterInfo->Address, 6); if( addr[0] != '\0' || addr[1] != '\0' || addr[2] != '\0' || addr[3] != '\0' || addr[4] != '\0' || addr[5] != '\0' ) break; pAdapterInfo = pAdapterInfo->Next; // Progress through // linked list } while(pAdapterInfo); // Terminate if last adapter return 0; #else /* implementation for Linux */ #ifdef _LINUX struct ifreq ifr; struct ifreq *IFR; struct ifconf ifc; char buf[1024]; int s, i; int ok = 0; s = socket(AF_INET, SOCK_DGRAM, 0); if (s==-1) { return -1; } ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; ioctl(s, SIOCGIFCONF, &ifc); IFR = ifc.ifc_req; for (i = ifc.ifc_len / (int)sizeof(struct ifreq); --i >= 0; IFR++) { strcpy(ifr.ifr_name, IFR->ifr_name); if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) { if (! (ifr.ifr_flags & IFF_LOOPBACK)) { if (ioctl(s, SIOCGIFHWADDR, &ifr) == 0) { ok = 1; break; } } } } close(s); if (ok) { bcopy( ifr.ifr_hwaddr.sa_data, addr, 6); } else { return -1; } return 0; #else /* implementation for HP-UX */ #ifdef _HPUX return DLPI (addr); #endif /* HPUX */ /* implementation for AIX */ #ifdef _AIX int size; struct kinfo_ndd *nddp; size = getkerninfo(KINFO_NDD, 0, 0, 0); if (size <= 0) { goto DLPI; } nddp = (struct kinfo_ndd *)malloc(size); if (!nddp) { goto DLPI; } if (getkerninfo(KINFO_NDD, (char *)nddp, &size, 0) < 0) { free(nddp); goto DLPI; } bcopy(nddp->ndd_addr, addr, 6); free(nddp); return 0; #endif #ifdef _SOLARIS int sockfd; struct arpreq myarp; struct sockaddr_in *sin; struct utsname myname; struct hostent *hp; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd == -1) goto DLPI; if (uname(&myname) < 0) goto DLPI; if ((hp = gethostbyname(myname.nodename)) == NULL) goto DLPI; sin = (struct sockaddr_in *) &myarp.arp_pa; memset (sin, 0x00, sizeof(struct sockaddr_in)); memcpy (&sin->sin_addr, *hp->h_addr_list, sizeof(struct in_addr)); if (ioctl(sockfd, SIOCGARP, &myarp) != 0) goto DLPI; memcpy (addr, myarp.arp_ha.sa_data, 6); return 0; #endif DLPI: return DLPI (addr); #endif //#ifdef _LINUX #endif //#ifdef WIN32 } /***********************************************************************/ /* * Main (only for testing) */ #ifdef _MAC_TEST int main( int argc, char **argv) { long stat; int i; u_char addr[8] = {0,}; stat = GetMacAddress (addr); if (0 == stat) { printf( "MAC address = "); for (i=0; i<6; ++i) { printf("%2.2x", addr[i]); } printf( "\n"); } else { fprintf( stderr, "can't get MAC address\n"); exit( 1); } return 0; } #endif