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