home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / bootpd-2.zip / GETETHER.C < prev    next >
C/C++ Source or Header  |  1995-02-15  |  9KB  |  384 lines

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