123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- /*
- * addrs_dlpi.c:
- *
- * Provides the get_addrs_dlpi() function for use on systems that require
- * the use of the System V STREAMS DataLink Programming Interface for
- * acquiring low-level ethernet information about interfaces.
- *
- * Like Solaris.
- *
- */
- #include "config.h"
- #ifdef HAVE_DLPI
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/sockio.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <sys/dlpi.h>
- #include <net/if.h>
- #include "dlcommon.h"
- extern char *split_dname(char *device, int *unitp);
- extern char *strncpy2(char *dest, char *src, int n);
- extern char *strncat2(char *dest, char *src, int n);
- /*
- * This function identifies the IP address and ethernet address for the interface
- * specified
- *
- * This function returns -1 on catastrophic failure, or a bitwise OR of the
- * following values:
- * XXX: change this to perfom "best effort" identification of addresses.
- * Failure to find an address - for whatever reason - isn't fatal, just a
- * nuisance.
- *
- * 1 - Was able to get the ethernet address
- * 2 - Was able to get the IP address
- *
- * This function should return 3 if all information was found
- */
- int
- get_addrs_dlpi(char *interface, char if_hw_addr[], struct in_addr *if_ip_addr)
- {
- int got_hw_addr = 0;
- int got_ip_addr = 0;
- int fd;
- long buf[MAXDLBUF]; /* long aligned */
- union DL_primitives *dlp;
- char *cp;
- int unit_num = 0;
- int sap = 0;
- char *devname = NULL;
- char *devname2 = NULL;
- char fulldevpath[256];
- struct ifreq ifr = {};
- /* -- */
- memset(if_hw_addr, 0, 6);
- // we want to be able to process either a fully qualified /dev/ge0
- // type interface definition, or just ge0.
- if (strncmp(interface, "/dev/", strlen("/dev/")) == 0) {
- devname = interface + strlen("/dev/");
- } else {
- devname = interface;
- }
- strncpy2(fulldevpath, "/dev/", sizeof(fulldevpath)-1);
- cp = strncat2(fulldevpath, interface, sizeof(fulldevpath));
- if (strlen(cp) != 0) {
- fprintf(stderr, "device name buffer overflow %s\n", fulldevpath);
- return -1;
- }
- fprintf(stderr,"interface: %s\n", devname);
- // on Solaris, even though we are wanting to talk to ethernet device
- // ge0, we have to open /dev/ge, then bind to unit 0. Dupe our
- // full path, then identify and cut off the unit number
- devname2 = strdup(fulldevpath);
- cp = split_dname(devname2, &unit_num);
- if (cp == NULL) {
- free(devname2);
- goto get_ip_address;
- } else {
- *cp = '\0'; /* null terminate devname2 right before numeric extension */
- }
- // devname2 should now be something akin to /dev/ge. Try to open
- // it, and if it fails, fall back to the full /dev/ge0.
- if ((fd = open(devname2, O_RDWR)) < 0) {
- if (errno != ENOENT) {
- fprintf(stderr, "Couldn't open %s\n", devname2);
- free(devname2);
- goto get_ip_address;
- } else {
- if ((fd = open(fulldevpath, O_RDWR)) < 0) {
- fprintf(stderr, "Couldn't open %s\n", fulldevpath);
- free(devname2);
- goto get_ip_address;
- }
- }
- }
- free(devname2);
- devname2 = NULL;
- /* Use the dlcommon functions to get access to the DLPI information for this
- * interface. All of these functions exit() out on failure
- */
- dlp = (union DL_primitives*) buf;
- /*
- * DLPI attach to our low-level device
- */
- dlattachreq(fd, unit_num);
- dlokack(fd, buf);
- /*
- * DLPI bind
- */
- dlbindreq(fd, sap, 0, DL_CLDLS, 0, 0);
- dlbindack(fd, buf);
- /*
- * DLPI DL_INFO_REQ
- */
- dlinforeq(fd);
- dlinfoack(fd, buf);
- /*
- printdlprim(dlp); // uncomment this to dump out info from DLPI
- */
- if (dlp->info_ack.dl_addr_length + dlp->info_ack.dl_sap_length == 6) {
- memcpy(if_hw_addr,
- OFFADDR(dlp, dlp->info_ack.dl_addr_offset),
- dlp->info_ack.dl_addr_length);
- got_hw_addr = 1;
- } else {
- fprintf(stderr, "Error, bad length for hardware interface %s -- %d\n",
- interface,
- dlp->info_ack.dl_addr_length);
- }
- close(fd);
- get_ip_address:
- /* Get the IP address of the interface */
- #ifdef SIOCGIFADDR
- fd = socket(PF_INET, SOCK_DGRAM, 0); /* any sort of IP socket will do */
- strncpy(ifr.ifr_name, interface, IFNAMSIZ);
- (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_INET;
- if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
- fprintf(stderr, "Error getting IP address for interface: %s\n", "ge0");
- perror("ioctl(SIOCGIFADDR)");
- } else {
- memcpy(if_ip_addr, &((*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr), sizeof(struct in_addr));
- got_ip_addr = 2;
- }
- #else
- fprintf(stderr, "Cannot obtain IP address on this platform\n");
- #endif
- close(fd);
-
- return got_hw_addr + got_ip_addr;
- }
- /*
- * Split a device name into a device type name and a unit number;
- * return the a pointer to the beginning of the unit number, which
- * is the end of the device type name, and set "*unitp" to the unit
- * number.
- *
- * Returns NULL on error, and fills "ebuf" with an error message.
- */
- char *
- split_dname(char *device, int *unitp)
- {
- char *cp;
- char *eos;
- int unit;
- /* -- */
- /*
- * Look for a number at the end of the device name string.
- */
- cp = device + strlen(device) - 1;
- if (*cp < '0' || *cp > '9') {
- fprintf(stderr, "%s missing unit number", device);
- return (NULL);
- }
-
- /* Digits at end of string are unit number */
- while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9')
- cp--;
-
- unit = (int) strtol(cp, &eos, 10);
- if (*eos != '\0') {
- fprintf(stderr, "%s bad unit number", device);
- return (NULL);
- }
- *unitp = unit;
- return (cp);
- }
- /*------------------------------------------------------------------------------
- strncpy2()
- strncpy2() is like strncpy(), except that strncpy2() will always
- insure that the <dest> buffer is null terminated. strncpy() will not
- NULL terminate the destination buffer if the <src> string is <n>
- characters long or longer, not counting the terminating NULL character.
- STRNCPY2() IS NOT A COMPATIBLE REPLACEMENT FOR STRNCPY()!!
- There are two reasons to use strncpy2().
- The first reason is to guarantee that <dest> buffer's bounds are not
- violated. In this case, <n> should be the size of the <dest> buffer
- minus one.
- i.e.,
- char tempstring[MAXLINE];
- strncpy2(tempstring, my_own_string, MAXLINE - 1);
- The second reason is to copy a specific number of characters from
- <src> to <dest>. In this case, <n> should be the number of characters
- you want to transfer, not including the terminating NULL character.
- The following example copies "abc" into tempstring, and NULL
- terminates it.
- char tempstring[MAXLINE];
- strncpy2(tempstring, "abcdef123", 3);
- strncpy2() returns a pointer to the first character in <src> that was
- not copied to <dest>. If all of <src> was copied to <dest>,
- strncpy2() will return a pointer to the NULL character terminating the
- <src> string.
- ------------------------------------------------------------------------------*/
- char *
- strncpy2(char *dest, char *src, int n)
- {
- int
- i = 0;
- char
- *char_ptr;
- /* -- */
- if ((!dest) || (!src))
- return(src);
- char_ptr = dest;
- while ((i++ < n) && *src)
- *char_ptr++ = *src++;
- *char_ptr = '\0';
- return(src);
- }
- /*------------------------------------------------------------------------------
- strncat2()
- Similar to strncat except that <n> is the size of the <dest> buffer
- (INCLUDING SPACE FOR THE TRAILING NULL CHAR), NOT the number of
- characters to add to the buffer.
- STRNCAT2() IS NOT A COMPATIBLE REPLACEMENT FOR STRNCAT()!
- strncat2() always guarantees that the <dest> will be null terminated, and that
- the buffer limits will be honored. strncat2() will not write even one
- byte beyond the end of the <dest> buffer.
- strncat2() concatenates up to <n-1> - strlen(<dest>) characters from
- <src> to <dest>.
- So if the <dest> buffer has a size of 20 bytes (including trailing NULL),
- and <dest> contains a 19 character string, nothing will be done to
- <dest>.
- If the string in <dest> is longer than <n-1> characters upon entry to
- strncat2(), <dest> will be truncated after the <n-1>th character.
- strncat2() returns a pointer to the first character in the src buffer that
- was not copied into dest.. so if strncat2() returns a non-zero character,
- string truncation occurred in the concat operation.
- ------------------------------------------------------------------------------*/
- char *
- strncat2(char *dest, char *src, int n)
- {
- int
- i = 0;
- char
- *dest_ptr,
- *src_ptr;
- /* -- */
- if (!dest || !src)
- return NULL;
- dest_ptr = dest;
- src_ptr = src;
- /* i = 0 */
- while ((i < (n-1)) && *dest_ptr)
- {
- i++;
- dest_ptr++;
- }
- /* i is the number of characters in dest before the concatenation
- operation.. a number between 0 and n-1 */
- while ((i++ < (n-1)) && *src_ptr)
- *dest_ptr++ = *src_ptr++;
- /* i is the number of characters in dest after the concatenation
- operation, or n if the concat operation got truncated.. a number
- between 0 and n
- We need to check src_ptr here because i will be equal to n if
- <dest> was full before the concatenation operation started (which
- effectively causes instant truncation even if the <src> string is
- empty..
- We could just test src_ptr here, but that would report
- a string truncation if <src> was empty, which we don't
- necessarily want. */
- if ((i == n) && *src_ptr)
- {
- // we could log truncation here
- }
- *dest_ptr = '\0';
- /* should point to a non-empty substring only if the concatenation
- operation got truncated.
- If src_ptr points to an empty string, the operation always
- succeeded, either due to an empty <src> or because of
- sufficient room in <dest>. */
-
- return(src_ptr);
- }
- #endif /* HAVE_DLPI */
|