144099b7bSPaul Traina /* 244099b7bSPaul Traina * getether.c : get the ethernet address of an interface 344099b7bSPaul Traina * 444099b7bSPaul Traina * All of this code is quite system-specific. As you may well 544099b7bSPaul Traina * guess, it took a good bit of detective work to figure out! 644099b7bSPaul Traina * 744099b7bSPaul Traina * If you figure out how to do this on another system, 844099b7bSPaul Traina * please let me know. <gwr@mc.com> 9148531efSWolfram Schneider * 107f3dea24SPeter Wemm * $FreeBSD$ 1144099b7bSPaul Traina */ 1244099b7bSPaul Traina 1344099b7bSPaul Traina #include <sys/types.h> 1444099b7bSPaul Traina #include <sys/socket.h> 1544099b7bSPaul Traina 16e08ac58bSPaul Traina #ifndef NO_UNISTD 17e08ac58bSPaul Traina #include <unistd.h> 18e08ac58bSPaul Traina #endif 19e08ac58bSPaul Traina 2044099b7bSPaul Traina #include <ctype.h> 211a37aa56SDavid E. O'Brien #include <paths.h> 227fe354baSIan Dowse #include <string.h> 2344099b7bSPaul Traina #include <syslog.h> 2444099b7bSPaul Traina 25e08ac58bSPaul Traina #include "getether.h" 2644099b7bSPaul Traina #include "report.h" 2744099b7bSPaul Traina #define EALEN 6 2844099b7bSPaul Traina 2944099b7bSPaul Traina #if defined(ultrix) || (defined(__osf__) && defined(__alpha)) 3044099b7bSPaul Traina /* 3144099b7bSPaul Traina * This is really easy on Ultrix! Thanks to 3244099b7bSPaul Traina * Harald Lundberg <hl@tekla.fi> for this code. 3344099b7bSPaul Traina * 3444099b7bSPaul Traina * The code here is not specific to the Alpha, but that was the 3544099b7bSPaul Traina * only symbol we could find to identify DEC's version of OSF. 3644099b7bSPaul Traina * (Perhaps we should just define DEC in the Makefile... -gwr) 3744099b7bSPaul Traina */ 3844099b7bSPaul Traina 3944099b7bSPaul Traina #include <sys/ioctl.h> 4044099b7bSPaul Traina #include <net/if.h> /* struct ifdevea */ 4144099b7bSPaul Traina 4244099b7bSPaul Traina getether(ifname, eap) 4344099b7bSPaul Traina char *ifname, *eap; 4444099b7bSPaul Traina { 4544099b7bSPaul Traina int rc = -1; 4644099b7bSPaul Traina int fd; 4744099b7bSPaul Traina struct ifdevea phys; 4844099b7bSPaul Traina bzero(&phys, sizeof(phys)); 4944099b7bSPaul Traina strcpy(phys.ifr_name, ifname); 5044099b7bSPaul Traina if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 5144099b7bSPaul Traina report(LOG_ERR, "getether: socket(INET,DGRAM) failed"); 5244099b7bSPaul Traina return -1; 5344099b7bSPaul Traina } 5444099b7bSPaul Traina if (ioctl(fd, SIOCRPHYSADDR, &phys) < 0) { 5544099b7bSPaul Traina report(LOG_ERR, "getether: ioctl SIOCRPHYSADDR failed"); 5644099b7bSPaul Traina } else { 5744099b7bSPaul Traina bcopy(&phys.current_pa[0], eap, EALEN); 5844099b7bSPaul Traina rc = 0; 5944099b7bSPaul Traina } 6044099b7bSPaul Traina close(fd); 6144099b7bSPaul Traina return rc; 6244099b7bSPaul Traina } 6344099b7bSPaul Traina 6444099b7bSPaul Traina #define GETETHER 6544099b7bSPaul Traina #endif /* ultrix|osf1 */ 6644099b7bSPaul Traina 6744099b7bSPaul Traina 6844099b7bSPaul Traina #ifdef SUNOS 6944099b7bSPaul Traina 7044099b7bSPaul Traina #include <sys/sockio.h> 7144099b7bSPaul Traina #include <sys/time.h> /* needed by net_if.h */ 7244099b7bSPaul Traina #include <net/nit_if.h> /* for NIOCBIND */ 7344099b7bSPaul Traina #include <net/if.h> /* for struct ifreq */ 7444099b7bSPaul Traina 7544099b7bSPaul Traina getether(ifname, eap) 7644099b7bSPaul Traina char *ifname; /* interface name from ifconfig structure */ 7744099b7bSPaul Traina char *eap; /* Ether address (output) */ 7844099b7bSPaul Traina { 7944099b7bSPaul Traina int rc = -1; 8044099b7bSPaul Traina 8144099b7bSPaul Traina struct ifreq ifrnit; 8244099b7bSPaul Traina int nit; 8344099b7bSPaul Traina 8444099b7bSPaul Traina bzero((char *) &ifrnit, sizeof(ifrnit)); 852386a44fSKris Kennaway strlcpy(&ifrnit.ifr_name[0], ifname, IFNAMSIZ); 8644099b7bSPaul Traina 8744099b7bSPaul Traina nit = open("/dev/nit", 0); 8844099b7bSPaul Traina if (nit < 0) { 8944099b7bSPaul Traina report(LOG_ERR, "getether: open /dev/nit: %s", 9044099b7bSPaul Traina get_errmsg()); 9144099b7bSPaul Traina return rc; 9244099b7bSPaul Traina } 9344099b7bSPaul Traina do { 9444099b7bSPaul Traina if (ioctl(nit, NIOCBIND, &ifrnit) < 0) { 9544099b7bSPaul Traina report(LOG_ERR, "getether: NIOCBIND on nit"); 9644099b7bSPaul Traina break; 9744099b7bSPaul Traina } 9844099b7bSPaul Traina if (ioctl(nit, SIOCGIFADDR, &ifrnit) < 0) { 9944099b7bSPaul Traina report(LOG_ERR, "getether: SIOCGIFADDR on nit"); 10044099b7bSPaul Traina break; 10144099b7bSPaul Traina } 10244099b7bSPaul Traina bcopy(&ifrnit.ifr_addr.sa_data[0], eap, EALEN); 10344099b7bSPaul Traina rc = 0; 10444099b7bSPaul Traina } while (0); 10544099b7bSPaul Traina close(nit); 10644099b7bSPaul Traina return rc; 10744099b7bSPaul Traina } 10844099b7bSPaul Traina 10944099b7bSPaul Traina #define GETETHER 11044099b7bSPaul Traina #endif /* SUNOS */ 11144099b7bSPaul Traina 11244099b7bSPaul Traina 113d1c0e759SPaul Traina #if defined(__FreeBSD__) || defined(__NetBSD__) 11444099b7bSPaul Traina /* Thanks to John Brezak <brezak@ch.hp.com> for this code. */ 11544099b7bSPaul Traina #include <sys/ioctl.h> 116628d2ac1SGarrett Wollman #include <sys/time.h> 11744099b7bSPaul Traina #include <net/if.h> 11844099b7bSPaul Traina #include <net/if_dl.h> 11944099b7bSPaul Traina #include <net/if_types.h> 12044099b7bSPaul Traina 1217fe354baSIan Dowse int 12244099b7bSPaul Traina getether(ifname, eap) 12344099b7bSPaul Traina char *ifname; /* interface name from ifconfig structure */ 12444099b7bSPaul Traina char *eap; /* Ether address (output) */ 12544099b7bSPaul Traina { 12644099b7bSPaul Traina int fd, rc = -1; 127*07ee9f80SPedro F. Giffuni int n; 1287fe354baSIan Dowse struct ifreq ibuf[16]; 12944099b7bSPaul Traina struct ifconf ifc; 130*07ee9f80SPedro F. Giffuni struct ifreq *ifrp, *ifend; 13144099b7bSPaul Traina 13244099b7bSPaul Traina /* Fetch the interface configuration */ 13344099b7bSPaul Traina fd = socket(AF_INET, SOCK_DGRAM, 0); 13444099b7bSPaul Traina if (fd < 0) { 13544099b7bSPaul Traina report(LOG_ERR, "getether: socket %s: %s", ifname, get_errmsg()); 13644099b7bSPaul Traina return (fd); 13744099b7bSPaul Traina } 13844099b7bSPaul Traina ifc.ifc_len = sizeof(ibuf); 13944099b7bSPaul Traina ifc.ifc_buf = (caddr_t) ibuf; 14044099b7bSPaul Traina if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) < 0 || 14144099b7bSPaul Traina ifc.ifc_len < sizeof(struct ifreq)) { 142be9efd56SKris Kennaway report(LOG_ERR, "getether: SIOCGIFCONF: %s", get_errmsg()); 14344099b7bSPaul Traina goto out; 14444099b7bSPaul Traina } 14544099b7bSPaul Traina /* Search interface configuration list for link layer address. */ 14644099b7bSPaul Traina ifrp = ibuf; 14744099b7bSPaul Traina ifend = (struct ifreq *) ((char *) ibuf + ifc.ifc_len); 14844099b7bSPaul Traina while (ifrp < ifend) { 14944099b7bSPaul Traina /* Look for interface */ 15044099b7bSPaul Traina if (strcmp(ifname, ifrp->ifr_name) == 0 && 15144099b7bSPaul Traina ifrp->ifr_addr.sa_family == AF_LINK && 15244099b7bSPaul Traina ((struct sockaddr_dl *) &ifrp->ifr_addr)->sdl_type == IFT_ETHER) { 15344099b7bSPaul Traina bcopy(LLADDR((struct sockaddr_dl *) &ifrp->ifr_addr), eap, EALEN); 15444099b7bSPaul Traina rc = 0; 15544099b7bSPaul Traina break; 15644099b7bSPaul Traina } 15744099b7bSPaul Traina /* Bump interface config pointer */ 15844099b7bSPaul Traina n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 15944099b7bSPaul Traina if (n < sizeof(*ifrp)) 16044099b7bSPaul Traina n = sizeof(*ifrp); 16144099b7bSPaul Traina ifrp = (struct ifreq *) ((char *) ifrp + n); 16244099b7bSPaul Traina } 16344099b7bSPaul Traina 16444099b7bSPaul Traina out: 16544099b7bSPaul Traina close(fd); 16644099b7bSPaul Traina return (rc); 16744099b7bSPaul Traina } 16844099b7bSPaul Traina 16944099b7bSPaul Traina #define GETETHER 17044099b7bSPaul Traina #endif /* __NetBSD__ */ 17144099b7bSPaul Traina 17244099b7bSPaul Traina 17344099b7bSPaul Traina #ifdef SVR4 17444099b7bSPaul Traina /* 17544099b7bSPaul Traina * This is for "Streams TCP/IP" by Lachman Associates. 17644099b7bSPaul Traina * They sure made this cumbersome! -gwr 17744099b7bSPaul Traina */ 17844099b7bSPaul Traina 17944099b7bSPaul Traina #include <sys/sockio.h> 18044099b7bSPaul Traina #include <sys/dlpi.h> 18144099b7bSPaul Traina #include <stropts.h> 182e08ac58bSPaul Traina #include <string.h> 18344099b7bSPaul Traina #ifndef NULL 18444099b7bSPaul Traina #define NULL 0 18544099b7bSPaul Traina #endif 18644099b7bSPaul Traina 187e08ac58bSPaul Traina int 18844099b7bSPaul Traina getether(ifname, eap) 18944099b7bSPaul Traina char *ifname; /* interface name from ifconfig structure */ 19044099b7bSPaul Traina char *eap; /* Ether address (output) */ 19144099b7bSPaul Traina { 19244099b7bSPaul Traina int rc = -1; 19344099b7bSPaul Traina char devname[32]; 19444099b7bSPaul Traina char tmpbuf[sizeof(union DL_primitives) + 16]; 19544099b7bSPaul Traina struct strbuf cbuf; 19644099b7bSPaul Traina int fd, flags; 19744099b7bSPaul Traina union DL_primitives *dlp; 19844099b7bSPaul Traina char *enaddr; 19944099b7bSPaul Traina int unit = -1; /* which unit to attach */ 20044099b7bSPaul Traina 2011a37aa56SDavid E. O'Brien snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, ifname); 20244099b7bSPaul Traina fd = open(devname, 2); 20344099b7bSPaul Traina if (fd < 0) { 20444099b7bSPaul Traina /* Try without the trailing digit. */ 20544099b7bSPaul Traina char *p = devname + 5; 20644099b7bSPaul Traina while (isalpha(*p)) 20744099b7bSPaul Traina p++; 20844099b7bSPaul Traina if (isdigit(*p)) { 20944099b7bSPaul Traina unit = *p - '0'; 21044099b7bSPaul Traina *p = '\0'; 21144099b7bSPaul Traina } 21244099b7bSPaul Traina fd = open(devname, 2); 21344099b7bSPaul Traina if (fd < 0) { 21444099b7bSPaul Traina report(LOG_ERR, "getether: open %s: %s", 21544099b7bSPaul Traina devname, get_errmsg()); 21644099b7bSPaul Traina return rc; 21744099b7bSPaul Traina } 21844099b7bSPaul Traina } 21944099b7bSPaul Traina #ifdef DL_ATTACH_REQ 22044099b7bSPaul Traina /* 22144099b7bSPaul Traina * If this is a "Style 2" DLPI, then we must "attach" first 22244099b7bSPaul Traina * to tell the driver which unit (board, port) we want. 22344099b7bSPaul Traina * For now, decide this based on the device name. 22444099b7bSPaul Traina * (Should do "info_req" and check dl_provider_style ...) 22544099b7bSPaul Traina */ 22644099b7bSPaul Traina if (unit >= 0) { 22744099b7bSPaul Traina memset(tmpbuf, 0, sizeof(tmpbuf)); 22844099b7bSPaul Traina dlp = (union DL_primitives *) tmpbuf; 22944099b7bSPaul Traina dlp->dl_primitive = DL_ATTACH_REQ; 23044099b7bSPaul Traina dlp->attach_req.dl_ppa = unit; 23144099b7bSPaul Traina cbuf.buf = tmpbuf; 23244099b7bSPaul Traina cbuf.len = DL_ATTACH_REQ_SIZE; 23344099b7bSPaul Traina if (putmsg(fd, &cbuf, NULL, 0) < 0) { 23444099b7bSPaul Traina report(LOG_ERR, "getether: attach: putmsg: %s", get_errmsg()); 23544099b7bSPaul Traina goto out; 23644099b7bSPaul Traina } 23744099b7bSPaul Traina /* Recv the ack. */ 23844099b7bSPaul Traina cbuf.buf = tmpbuf; 23944099b7bSPaul Traina cbuf.maxlen = sizeof(tmpbuf); 24044099b7bSPaul Traina flags = 0; 24144099b7bSPaul Traina if (getmsg(fd, &cbuf, NULL, &flags) < 0) { 24244099b7bSPaul Traina report(LOG_ERR, "getether: attach: getmsg: %s", get_errmsg()); 24344099b7bSPaul Traina goto out; 24444099b7bSPaul Traina } 24544099b7bSPaul Traina /* 24644099b7bSPaul Traina * Check the type, etc. 24744099b7bSPaul Traina */ 24844099b7bSPaul Traina if (dlp->dl_primitive == DL_ERROR_ACK) { 24944099b7bSPaul Traina report(LOG_ERR, "getether: attach: dlpi_errno=%d, unix_errno=%d", 25044099b7bSPaul Traina dlp->error_ack.dl_errno, 25144099b7bSPaul Traina dlp->error_ack.dl_unix_errno); 25244099b7bSPaul Traina goto out; 25344099b7bSPaul Traina } 25444099b7bSPaul Traina if (dlp->dl_primitive != DL_OK_ACK) { 25544099b7bSPaul Traina report(LOG_ERR, "getether: attach: not OK or ERROR"); 25644099b7bSPaul Traina goto out; 25744099b7bSPaul Traina } 25844099b7bSPaul Traina } /* unit >= 0 */ 25944099b7bSPaul Traina #endif /* DL_ATTACH_REQ */ 26044099b7bSPaul Traina 26144099b7bSPaul Traina /* 26244099b7bSPaul Traina * Get the Ethernet address the same way the ARP module 26344099b7bSPaul Traina * does when it is pushed onto a new stream (bind). 264d64ada50SJens Schweikhardt * One should instead be able just do a dl_info_req 26544099b7bSPaul Traina * but many drivers do not supply the hardware address 26644099b7bSPaul Traina * in the response to dl_info_req (they MUST supply it 26744099b7bSPaul Traina * for dl_bind_ack because the ARP module requires it). 26844099b7bSPaul Traina */ 26944099b7bSPaul Traina memset(tmpbuf, 0, sizeof(tmpbuf)); 27044099b7bSPaul Traina dlp = (union DL_primitives *) tmpbuf; 27144099b7bSPaul Traina dlp->dl_primitive = DL_BIND_REQ; 27244099b7bSPaul Traina dlp->bind_req.dl_sap = 0x8FF; /* XXX - Unused SAP */ 27344099b7bSPaul Traina cbuf.buf = tmpbuf; 27444099b7bSPaul Traina cbuf.len = DL_BIND_REQ_SIZE; 27544099b7bSPaul Traina if (putmsg(fd, &cbuf, NULL, 0) < 0) { 27644099b7bSPaul Traina report(LOG_ERR, "getether: bind: putmsg: %s", get_errmsg()); 27744099b7bSPaul Traina goto out; 27844099b7bSPaul Traina } 27944099b7bSPaul Traina /* Recv the ack. */ 28044099b7bSPaul Traina cbuf.buf = tmpbuf; 28144099b7bSPaul Traina cbuf.maxlen = sizeof(tmpbuf); 28244099b7bSPaul Traina flags = 0; 28344099b7bSPaul Traina if (getmsg(fd, &cbuf, NULL, &flags) < 0) { 28444099b7bSPaul Traina report(LOG_ERR, "getether: bind: getmsg: %s", get_errmsg()); 28544099b7bSPaul Traina goto out; 28644099b7bSPaul Traina } 28744099b7bSPaul Traina /* 28844099b7bSPaul Traina * Check the type, etc. 28944099b7bSPaul Traina */ 29044099b7bSPaul Traina if (dlp->dl_primitive == DL_ERROR_ACK) { 29144099b7bSPaul Traina report(LOG_ERR, "getether: bind: dlpi_errno=%d, unix_errno=%d", 29244099b7bSPaul Traina dlp->error_ack.dl_errno, 29344099b7bSPaul Traina dlp->error_ack.dl_unix_errno); 29444099b7bSPaul Traina goto out; 29544099b7bSPaul Traina } 29644099b7bSPaul Traina if (dlp->dl_primitive != DL_BIND_ACK) { 29744099b7bSPaul Traina report(LOG_ERR, "getether: bind: not OK or ERROR"); 29844099b7bSPaul Traina goto out; 29944099b7bSPaul Traina } 30044099b7bSPaul Traina if (dlp->bind_ack.dl_addr_offset == 0) { 30144099b7bSPaul Traina report(LOG_ERR, "getether: bind: ack has no address"); 30244099b7bSPaul Traina goto out; 30344099b7bSPaul Traina } 30444099b7bSPaul Traina if (dlp->bind_ack.dl_addr_length < EALEN) { 30544099b7bSPaul Traina report(LOG_ERR, "getether: bind: ack address truncated"); 30644099b7bSPaul Traina goto out; 30744099b7bSPaul Traina } 30844099b7bSPaul Traina /* 30944099b7bSPaul Traina * Copy the Ethernet address out of the message. 31044099b7bSPaul Traina */ 31144099b7bSPaul Traina enaddr = tmpbuf + dlp->bind_ack.dl_addr_offset; 31244099b7bSPaul Traina memcpy(eap, enaddr, EALEN); 31344099b7bSPaul Traina rc = 0; 31444099b7bSPaul Traina 31544099b7bSPaul Traina out: 31644099b7bSPaul Traina close(fd); 31744099b7bSPaul Traina return rc; 31844099b7bSPaul Traina } 31944099b7bSPaul Traina 32044099b7bSPaul Traina #define GETETHER 32144099b7bSPaul Traina #endif /* SVR4 */ 32244099b7bSPaul Traina 32344099b7bSPaul Traina 324e08ac58bSPaul Traina #ifdef __linux__ 32544099b7bSPaul Traina /* 32644099b7bSPaul Traina * This is really easy on Linux! This version (for linux) 327e08ac58bSPaul Traina * written by Nigel Metheringham <nigelm@ohm.york.ac.uk> and 328e08ac58bSPaul Traina * updated by Pauline Middelink <middelin@polyware.iaf.nl> 32944099b7bSPaul Traina * 33044099b7bSPaul Traina * The code is almost identical to the Ultrix code - however 33144099b7bSPaul Traina * the names are different to confuse the innocent :-) 33244099b7bSPaul Traina * Most of this code was stolen from the Ultrix bit above. 33344099b7bSPaul Traina */ 33444099b7bSPaul Traina 335e08ac58bSPaul Traina #include <memory.h> 33644099b7bSPaul Traina #include <sys/ioctl.h> 33744099b7bSPaul Traina #include <net/if.h> /* struct ifreq */ 338e08ac58bSPaul Traina #include <sys/socketio.h> /* Needed for IOCTL defs */ 33944099b7bSPaul Traina 340e08ac58bSPaul Traina int 34144099b7bSPaul Traina getether(ifname, eap) 34244099b7bSPaul Traina char *ifname, *eap; 34344099b7bSPaul Traina { 34444099b7bSPaul Traina int rc = -1; 34544099b7bSPaul Traina int fd; 34644099b7bSPaul Traina struct ifreq phys; 347e08ac58bSPaul Traina 348e08ac58bSPaul Traina memset(&phys, 0, sizeof(phys)); 34944099b7bSPaul Traina strcpy(phys.ifr_name, ifname); 35044099b7bSPaul Traina if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 35144099b7bSPaul Traina report(LOG_ERR, "getether: socket(INET,DGRAM) failed"); 35244099b7bSPaul Traina return -1; 35344099b7bSPaul Traina } 35444099b7bSPaul Traina if (ioctl(fd, SIOCGIFHWADDR, &phys) < 0) { 35544099b7bSPaul Traina report(LOG_ERR, "getether: ioctl SIOCGIFHWADDR failed"); 35644099b7bSPaul Traina } else { 357e08ac58bSPaul Traina memcpy(eap, &phys.ifr_hwaddr.sa_data, EALEN); 35844099b7bSPaul Traina rc = 0; 35944099b7bSPaul Traina } 36044099b7bSPaul Traina close(fd); 36144099b7bSPaul Traina return rc; 36244099b7bSPaul Traina } 36344099b7bSPaul Traina 36444099b7bSPaul Traina #define GETETHER 365e08ac58bSPaul Traina #endif /* __linux__ */ 36644099b7bSPaul Traina 36744099b7bSPaul Traina 36844099b7bSPaul Traina /* If we don't know how on this system, just return an error. */ 36944099b7bSPaul Traina #ifndef GETETHER 370e08ac58bSPaul Traina int 37144099b7bSPaul Traina getether(ifname, eap) 37244099b7bSPaul Traina char *ifname, *eap; 37344099b7bSPaul Traina { 37444099b7bSPaul Traina return -1; 37544099b7bSPaul Traina } 37644099b7bSPaul Traina 37744099b7bSPaul Traina #endif /* !GETETHER */ 37844099b7bSPaul Traina 37944099b7bSPaul Traina /* 38044099b7bSPaul Traina * Local Variables: 38144099b7bSPaul Traina * tab-width: 4 38244099b7bSPaul Traina * c-indent-level: 4 38344099b7bSPaul Traina * c-argdecl-indent: 4 38444099b7bSPaul Traina * c-continued-statement-offset: 4 38544099b7bSPaul Traina * c-continued-brace-offset: -4 38644099b7bSPaul Traina * c-label-offset: -4 38744099b7bSPaul Traina * c-brace-offset: 0 38844099b7bSPaul Traina * End: 38944099b7bSPaul Traina */ 390