File:  [DragonFly] / src / libexec / bootpd / getether.c
Revision 1.2: download - view: text, annotated - select for diffs
Tue Jun 17 04:27:07 2003 UTC (10 years, 10 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids.  Most
ids have been removed from !lint sections and moved into comment sections.

    1: /*
    2:  * getether.c : get the ethernet address of an interface
    3:  *
    4:  * All of this code is quite system-specific.  As you may well
    5:  * guess, it took a good bit of detective work to figure out!
    6:  *
    7:  * If you figure out how to do this on another system,
    8:  * please let me know.  <gwr@mc.com>
    9:  *
   10:  * $FreeBSD: src/libexec/bootpd/getether.c,v 1.9.2.3 2003/02/15 05:36:01 kris Exp $
   11:  * $DragonFly: src/libexec/bootpd/getether.c,v 1.2 2003/06/17 04:27:07 dillon Exp $
   12:  */
   13: 
   14: #include <sys/types.h>
   15: #include <sys/socket.h>
   16: 
   17: #ifndef	NO_UNISTD
   18: #include <unistd.h>
   19: #endif
   20: 
   21: #include <ctype.h>
   22: #include <paths.h>
   23: #include <string.h>
   24: #include <syslog.h>
   25: 
   26: #include "getether.h"
   27: #include "report.h"
   28: #define EALEN 6
   29: 
   30: #if defined(ultrix) || (defined(__osf__) && defined(__alpha))
   31: /*
   32:  * This is really easy on Ultrix!  Thanks to
   33:  * Harald Lundberg <hl@tekla.fi> for this code.
   34:  *
   35:  * The code here is not specific to the Alpha, but that was the
   36:  * only symbol we could find to identify DEC's version of OSF.
   37:  * (Perhaps we should just define DEC in the Makefile... -gwr)
   38:  */
   39: 
   40: #include <sys/ioctl.h>
   41: #include <net/if.h>				/* struct ifdevea */
   42: 
   43: getether(ifname, eap)
   44: 	char *ifname, *eap;
   45: {
   46: 	int rc = -1;
   47: 	int fd;
   48: 	struct ifdevea phys;
   49: 	bzero(&phys, sizeof(phys));
   50: 	strcpy(phys.ifr_name, ifname);
   51: 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
   52: 		report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
   53: 		return -1;
   54: 	}
   55: 	if (ioctl(fd, SIOCRPHYSADDR, &phys) < 0) {
   56: 		report(LOG_ERR, "getether: ioctl SIOCRPHYSADDR failed");
   57: 	} else {
   58: 		bcopy(&phys.current_pa[0], eap, EALEN);
   59: 		rc = 0;
   60: 	}
   61: 	close(fd);
   62: 	return rc;
   63: }
   64: 
   65: #define	GETETHER
   66: #endif /* ultrix|osf1 */
   67: 
   68: 
   69: #ifdef	SUNOS
   70: 
   71: #include <sys/sockio.h>
   72: #include <sys/time.h>			/* needed by net_if.h */
   73: #include <net/nit_if.h>			/* for NIOCBIND */
   74: #include <net/if.h>				/* for struct ifreq */
   75: 
   76: getether(ifname, eap)
   77: 	char *ifname;				/* interface name from ifconfig structure */
   78: 	char *eap;					/* Ether address (output) */
   79: {
   80: 	int rc = -1;
   81: 
   82: 	struct ifreq ifrnit;
   83: 	int nit;
   84: 
   85: 	bzero((char *) &ifrnit, sizeof(ifrnit));
   86: 	strncpy(&ifrnit.ifr_name[0], ifname, IFNAMSIZ);
   87: 
   88: 	nit = open("/dev/nit", 0);
   89: 	if (nit < 0) {
   90: 		report(LOG_ERR, "getether: open /dev/nit: %s",
   91: 			   get_errmsg());
   92: 		return rc;
   93: 	}
   94: 	do {
   95: 		if (ioctl(nit, NIOCBIND, &ifrnit) < 0) {
   96: 			report(LOG_ERR, "getether: NIOCBIND on nit");
   97: 			break;
   98: 		}
   99: 		if (ioctl(nit, SIOCGIFADDR, &ifrnit) < 0) {
  100: 			report(LOG_ERR, "getether: SIOCGIFADDR on nit");
  101: 			break;
  102: 		}
  103: 		bcopy(&ifrnit.ifr_addr.sa_data[0], eap, EALEN);
  104: 		rc = 0;
  105: 	} while (0);
  106: 	close(nit);
  107: 	return rc;
  108: }
  109: 
  110: #define	GETETHER
  111: #endif /* SUNOS */
  112: 
  113: 
  114: #if defined(__FreeBSD__) || defined(__NetBSD__)
  115: /* Thanks to John Brezak <brezak@ch.hp.com> for this code. */
  116: #include <sys/ioctl.h>
  117: #include <sys/time.h>
  118: #include <net/if.h>
  119: #include <net/if_dl.h>
  120: #include <net/if_types.h>
  121: 
  122: int
  123: getether(ifname, eap)
  124: 	char *ifname;				/* interface name from ifconfig structure */
  125: 	char *eap;					/* Ether address (output) */
  126: {
  127: 	int fd, rc = -1;
  128: 	register int n;
  129: 	struct ifreq ibuf[16];
  130: 	struct ifconf ifc;
  131: 	register struct ifreq *ifrp, *ifend;
  132: 
  133: 	/* Fetch the interface configuration */
  134: 	fd = socket(AF_INET, SOCK_DGRAM, 0);
  135: 	if (fd < 0) {
  136: 		report(LOG_ERR, "getether: socket %s: %s", ifname, get_errmsg());
  137: 		return (fd);
  138: 	}
  139: 	ifc.ifc_len = sizeof(ibuf);
  140: 	ifc.ifc_buf = (caddr_t) ibuf;
  141: 	if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) < 0 ||
  142: 		ifc.ifc_len < sizeof(struct ifreq)) {
  143: 		report(LOG_ERR, "getether: SIOCGIFCONF: %s", get_errmsg());
  144: 		goto out;
  145: 	}
  146: 	/* Search interface configuration list for link layer address. */
  147: 	ifrp = ibuf;
  148: 	ifend = (struct ifreq *) ((char *) ibuf + ifc.ifc_len);
  149: 	while (ifrp < ifend) {
  150: 		/* Look for interface */
  151: 		if (strcmp(ifname, ifrp->ifr_name) == 0 &&
  152: 			ifrp->ifr_addr.sa_family == AF_LINK &&
  153: 		((struct sockaddr_dl *) &ifrp->ifr_addr)->sdl_type == IFT_ETHER) {
  154: 			bcopy(LLADDR((struct sockaddr_dl *) &ifrp->ifr_addr), eap, EALEN);
  155: 			rc = 0;
  156: 			break;
  157: 		}
  158: 		/* Bump interface config pointer */
  159: 		n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
  160: 		if (n < sizeof(*ifrp))
  161: 			n = sizeof(*ifrp);
  162: 		ifrp = (struct ifreq *) ((char *) ifrp + n);
  163: 	}
  164: 
  165:   out:
  166: 	close(fd);
  167: 	return (rc);
  168: }
  169: 
  170: #define	GETETHER
  171: #endif /* __NetBSD__ */
  172: 
  173: 
  174: #ifdef	SVR4
  175: /*
  176:  * This is for "Streams TCP/IP" by Lachman Associates.
  177:  * They sure made this cumbersome!  -gwr
  178:  */
  179: 
  180: #include <sys/sockio.h>
  181: #include <sys/dlpi.h>
  182: #include <stropts.h>
  183: #include <string.h>
  184: #ifndef NULL
  185: #define NULL 0
  186: #endif
  187: 
  188: int
  189: getether(ifname, eap)
  190: 	char *ifname;				/* interface name from ifconfig structure */
  191: 	char *eap;					/* Ether address (output) */
  192: {
  193: 	int rc = -1;
  194: 	char devname[32];
  195: 	char tmpbuf[sizeof(union DL_primitives) + 16];
  196: 	struct strbuf cbuf;
  197: 	int fd, flags;
  198: 	union DL_primitives *dlp;
  199: 	char *enaddr;
  200: 	int unit = -1;				/* which unit to attach */
  201: 
  202: 	snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, ifname);
  203: 	fd = open(devname, 2);
  204: 	if (fd < 0) {
  205: 		/* Try without the trailing digit. */
  206: 		char *p = devname + 5;
  207: 		while (isalpha(*p))
  208: 			p++;
  209: 		if (isdigit(*p)) {
  210: 			unit = *p - '0';
  211: 			*p = '\0';
  212: 		}
  213: 		fd = open(devname, 2);
  214: 		if (fd < 0) {
  215: 			report(LOG_ERR, "getether: open %s: %s",
  216: 				   devname, get_errmsg());
  217: 			return rc;
  218: 		}
  219: 	}
  220: #ifdef	DL_ATTACH_REQ
  221: 	/*
  222: 	 * If this is a "Style 2" DLPI, then we must "attach" first
  223: 	 * to tell the driver which unit (board, port) we want.
  224: 	 * For now, decide this based on the device name.
  225: 	 * (Should do "info_req" and check dl_provider_style ...)
  226: 	 */
  227: 	if (unit >= 0) {
  228: 		memset(tmpbuf, 0, sizeof(tmpbuf));
  229: 		dlp = (union DL_primitives *) tmpbuf;
  230: 		dlp->dl_primitive = DL_ATTACH_REQ;
  231: 		dlp->attach_req.dl_ppa = unit;
  232: 		cbuf.buf = tmpbuf;
  233: 		cbuf.len = DL_ATTACH_REQ_SIZE;
  234: 		if (putmsg(fd, &cbuf, NULL, 0) < 0) {
  235: 			report(LOG_ERR, "getether: attach: putmsg: %s", get_errmsg());
  236: 			goto out;
  237: 		}
  238: 		/* Recv the ack. */
  239: 		cbuf.buf = tmpbuf;
  240: 		cbuf.maxlen = sizeof(tmpbuf);
  241: 		flags = 0;
  242: 		if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
  243: 			report(LOG_ERR, "getether: attach: getmsg: %s", get_errmsg());
  244: 			goto out;
  245: 		}
  246: 		/*
  247: 		 * Check the type, etc.
  248: 		 */
  249: 		if (dlp->dl_primitive == DL_ERROR_ACK) {
  250: 			report(LOG_ERR, "getether: attach: dlpi_errno=%d, unix_errno=%d",
  251: 				   dlp->error_ack.dl_errno,
  252: 				   dlp->error_ack.dl_unix_errno);
  253: 			goto out;
  254: 		}
  255: 		if (dlp->dl_primitive != DL_OK_ACK) {
  256: 			report(LOG_ERR, "getether: attach: not OK or ERROR");
  257: 			goto out;
  258: 		}
  259: 	} /* unit >= 0 */
  260: #endif	/* DL_ATTACH_REQ */
  261: 
  262: 	/*
  263: 	 * Get the Ethernet address the same way the ARP module
  264: 	 * does when it is pushed onto a new stream (bind).
  265: 	 * One should instead be able just do an dl_info_req
  266: 	 * but many drivers do not supply the hardware address
  267: 	 * in the response to dl_info_req (they MUST supply it
  268: 	 * for dl_bind_ack because the ARP module requires it).
  269: 	 */
  270: 	memset(tmpbuf, 0, sizeof(tmpbuf));
  271: 	dlp = (union DL_primitives *) tmpbuf;
  272: 	dlp->dl_primitive = DL_BIND_REQ;
  273: 	dlp->bind_req.dl_sap = 0x8FF;	/* XXX - Unused SAP */
  274: 	cbuf.buf = tmpbuf;
  275: 	cbuf.len = DL_BIND_REQ_SIZE;
  276: 	if (putmsg(fd, &cbuf, NULL, 0) < 0) {
  277: 		report(LOG_ERR, "getether: bind: putmsg: %s", get_errmsg());
  278: 		goto out;
  279: 	}
  280: 	/* Recv the ack. */
  281: 	cbuf.buf = tmpbuf;
  282: 	cbuf.maxlen = sizeof(tmpbuf);
  283: 	flags = 0;
  284: 	if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
  285: 		report(LOG_ERR, "getether: bind: getmsg: %s", get_errmsg());
  286: 		goto out;
  287: 	}
  288: 	/*
  289: 	 * Check the type, etc.
  290: 	 */
  291: 	if (dlp->dl_primitive == DL_ERROR_ACK) {
  292: 		report(LOG_ERR, "getether: bind: dlpi_errno=%d, unix_errno=%d",
  293: 			   dlp->error_ack.dl_errno,
  294: 			   dlp->error_ack.dl_unix_errno);
  295: 		goto out;
  296: 	}
  297: 	if (dlp->dl_primitive != DL_BIND_ACK) {
  298: 		report(LOG_ERR, "getether: bind: not OK or ERROR");
  299: 		goto out;
  300: 	}
  301: 	if (dlp->bind_ack.dl_addr_offset == 0) {
  302: 		report(LOG_ERR, "getether: bind: ack has no address");
  303: 		goto out;
  304: 	}
  305: 	if (dlp->bind_ack.dl_addr_length < EALEN) {
  306: 		report(LOG_ERR, "getether: bind: ack address truncated");
  307: 		goto out;
  308: 	}
  309: 	/*
  310: 	 * Copy the Ethernet address out of the message.
  311: 	 */
  312: 	enaddr = tmpbuf + dlp->bind_ack.dl_addr_offset;
  313: 	memcpy(eap, enaddr, EALEN);
  314: 	rc = 0;
  315: 
  316:   out:
  317: 	close(fd);
  318: 	return rc;
  319: }
  320: 
  321: #define	GETETHER
  322: #endif /* SVR4 */
  323: 
  324: 
  325: #ifdef	__linux__
  326: /*
  327:  * This is really easy on Linux!  This version (for linux)
  328:  * written by Nigel Metheringham <nigelm@ohm.york.ac.uk> and
  329:  * updated by Pauline Middelink <middelin@polyware.iaf.nl>
  330:  *
  331:  * The code is almost identical to the Ultrix code - however
  332:  * the names are different to confuse the innocent :-)
  333:  * Most of this code was stolen from the Ultrix bit above.
  334:  */
  335: 
  336: #include <memory.h>
  337: #include <sys/ioctl.h>
  338: #include <net/if.h>	       	/* struct ifreq */
  339: #include <sys/socketio.h>	/* Needed for IOCTL defs */
  340: 
  341: int
  342: getether(ifname, eap)
  343: 	char *ifname, *eap;
  344: {
  345: 	int rc = -1;
  346: 	int fd;
  347: 	struct ifreq phys;
  348: 
  349: 	memset(&phys, 0, sizeof(phys));
  350: 	strcpy(phys.ifr_name, ifname);
  351: 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  352: 		report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
  353: 		return -1;
  354: 	}
  355: 	if (ioctl(fd, SIOCGIFHWADDR, &phys) < 0) {
  356: 		report(LOG_ERR, "getether: ioctl SIOCGIFHWADDR failed");
  357: 	} else {
  358: 		memcpy(eap, &phys.ifr_hwaddr.sa_data, EALEN);
  359: 		rc = 0;
  360: 	}
  361: 	close(fd);
  362: 	return rc;
  363: }
  364: 
  365: #define	GETETHER
  366: #endif	/* __linux__ */
  367: 
  368: 
  369: /* If we don't know how on this system, just return an error. */
  370: #ifndef	GETETHER
  371: int
  372: getether(ifname, eap)
  373: 	char *ifname, *eap;
  374: {
  375: 	return -1;
  376: }
  377: 
  378: #endif /* !GETETHER */
  379: 
  380: /*
  381:  * Local Variables:
  382:  * tab-width: 4
  383:  * c-indent-level: 4
  384:  * c-argdecl-indent: 4
  385:  * c-continued-statement-offset: 4
  386:  * c-continued-brace-offset: -4
  387:  * c-label-offset: -4
  388:  * c-brace-offset: 0
  389:  * End:
  390:  */