Often people are asking how to find out the MAC- (ethernet-, hardware-, ...) address from inside a C program.
Here are two solutions: The first one is a portable solution that uses the DLPI API. I compiled this example succesfull on HP-UX 10.20, AIX 4.2, and Solaris 2.6. The second one is an alternative method using system specific calls and works under Linux, HP-UX 10.20, and AIX 4.2.
/* * mac_addr_dlpi.c * * Return the MAC (ie, ethernet hardware) address by using the dlpi api. * * compile with: gcc -c -D "OS" mac_addr_dlpi.c * with "OS" is one of AIX, SunOS, HPUX */ /***********************************************************************/ /* this section defines a list of the dlpi capable devices * this depends on the operating system */ #undef DLPI_DEV #ifdef HPUX static char *dlpi_dev[] = {"/dev/dlpi", ""}; #define DLPI_DEV #endif #ifdef AIX static 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 char *dlpi_dev[] = {"/dev/eri", "/dev/hme", "/dev/ie", "/dev/le", ""}; #define DLPI_DEV #endif #ifndef DLPI_DEV static char *dlpi_dev[] = {"/dev/dlpi", ""}; /* unknown OS - hope that this will work ??? */ #define DLPI_DEV #endif /***********************************************************************/ /* * implementation */ #define INSAP 22 #define OUTSAP 24 #include <sys/types.h> #include <fcntl.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <ctype.h> #include <sys/stropts.h> #include <sys/poll.h> #include <sys/dlpi.h> #define bcopy(source, destination, length) memcpy(destination, source, length) #define AREA_SZ 5000 /*=* buffer length in bytes *=*/ 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}; #define GOT_CTRL 1 #define GOT_DATA 2 #define GOT_BOTH 3 #define GOT_INTR 4 #define GOT_ERR 128 /*=* get a message from a stream; return type of message *=*/ static int get_msg(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 check_ctrl(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 put_ctrl(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 put_both(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 dl_open(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; put_ctrl(*fd, sizeof(dl_attach_req_t), 0); get_msg(*fd); return check_ctrl(DL_OK_ACK); } /*=* send DL_BIND_REQ *=*/ static int dl_bind(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; put_ctrl(fd, sizeof(dl_bind_req_t), 0); get_msg(fd); if (GOT_ERR == check_ctrl(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 mac_addr_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 * */ long mac_addr_dlpi ( u_char *addr) { int fd; int ppa; u_char mac_addr[25]; int i; char **dev; for (dev = dlpi_dev; **dev != ''; ++dev) { for (ppa=0; ppa<10; ++ppa) { if (GOT_ERR != dl_open(*dev, ppa, &fd)) { if (GOT_ERR != dl_bind(fd, INSAP, mac_addr)) { bcopy( mac_addr, addr, 6); return 0; } } close(fd); } } return -1; } /***********************************************************************/ /* * Main (only for testing) */ #ifdef MAIN int main( int argc, char **argv) { long stat; int i; u_char addr[6]; stat = mac_addr_dlpi( 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
/* * mac_addr_sys.c * * Return the MAC (ie, ethernet hardware) address by using system specific * calls. * * compile with: gcc -c -D "OS" mac_addr_sys.c * with "OS" is one of Linux, AIX, HPUX */ #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #ifdef Linux #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <linux/if.h> #endif #ifdef HPUX #include <netio.h> #endif #ifdef AIX #include <sys/ndd_var.h> #include <sys/kinfo.h> #endif long mac_addr_sys ( u_char *addr) { /* 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 / 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; #endif /* implementation for HP-UX */ #ifdef HPUX #define LAN_DEV0 "/dev/lan0" int fd; struct fis iocnt_block; int i; char net_buf[sizeof(LAN_DEV0)+1]; char *p; (void)sprintf(net_buf, "%s", LAN_DEV0); p = net_buf + strlen(net_buf) - 1; /* * Get 802.3 address from card by opening the driver and interrogating it. */ for (i = 0; i < 10; i++, (*p)++) { if ((fd = open (net_buf, O_RDONLY)) != -1) { iocnt_block.reqtype = LOCAL_ADDRESS; ioctl (fd, NETSTAT, &iocnt_block); close (fd); if (iocnt_block.vtype == 6) break; } } if (fd == -1 || iocnt_block.vtype != 6) { return -1; } bcopy( &iocnt_block.value.s[0], addr, 6); return 0; #endif /* HPUX */ /* implementation for AIX */ #ifdef AIX int size; struct kinfo_ndd *nddp; size = getkerninfo(KINFO_NDD, 0, 0, 0); if (size <= 0) { return -1; } nddp = (struct kinfo_ndd *)malloc(size); if (!nddp) { return -1; } if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) { free(nddp); return -1; } bcopy(nddp->ndd_addr, addr, 6); free(nddp); return 0; #endif /* Not implemented platforms */ return -1; } /***********************************************************************/ /* * Main (only for testing) */ #ifdef MAIN int main( int argc, char **argv) { long stat; int i; u_char addr[6]; stat = mac_addr_sys( 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