File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iftop / addrs_dlpi.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:57:34 2012 UTC (12 years, 3 months ago) by misho
Branches: iftop, MAIN
CVS tags: v1_0rc4, v0_17p0, v0_17, HEAD
iftop

    1: /*
    2:  * addrs_dlpi.c:
    3:  *
    4:  * Provides the get_addrs_dlpi() function for use on systems that require
    5:  * the use of the System V STREAMS DataLink Programming Interface for
    6:  * acquiring low-level ethernet information about interfaces.
    7:  *
    8:  * Like Solaris.
    9:  *
   10:  */
   11: 
   12: #include "config.h"
   13: 
   14: #ifdef HAVE_DLPI
   15: 
   16: #include <stdio.h>
   17: #include <stdlib.h>
   18: #include <errno.h>
   19: #include <unistd.h>
   20: #include <string.h>
   21: #include <fcntl.h>
   22: 
   23: #include <sys/types.h>
   24: #include <sys/sockio.h>
   25: #include <sys/ioctl.h>
   26: #include <sys/socket.h>
   27: #include <sys/dlpi.h>
   28: #include <net/if.h>
   29: 
   30: #include "dlcommon.h"
   31: 
   32: extern char *split_dname(char *device, int *unitp);
   33: extern char *strncpy2(char *dest, char *src, int n);
   34: extern char *strncat2(char *dest, char *src, int n);
   35: 
   36: /*
   37:  * This function identifies the IP address and ethernet address for the interface
   38:  * specified
   39:  *
   40:  * This function returns -1 on catastrophic failure, or a bitwise OR of the
   41:  * following values:
   42:  * XXX: change this to perfom "best effort" identification of addresses.
   43:  * Failure to find an address - for whatever reason - isn't fatal, just a
   44:  * nuisance.
   45:  *
   46:  * 1 - Was able to get the ethernet address
   47:  * 2 - Was able to get the IP address
   48:  *
   49:  * This function should return 3 if all information was found
   50:  */
   51: 
   52: int
   53: get_addrs_dlpi(char *interface, char if_hw_addr[], struct in_addr *if_ip_addr)
   54: {
   55:   int got_hw_addr = 0;
   56:   int got_ip_addr = 0;
   57: 
   58:   int fd;
   59:   long buf[MAXDLBUF];		/* long aligned */
   60:   union DL_primitives *dlp;
   61: 
   62:   char *cp;
   63:   int unit_num = 0;
   64:   int sap = 0;
   65: 
   66:   char *devname = NULL;
   67:   char *devname2 = NULL;
   68:   char fulldevpath[256];
   69: 
   70:   struct ifreq ifr = {};
   71: 
   72:   /* -- */
   73: 
   74:   memset(if_hw_addr, 0, 6);
   75: 
   76:   // we want to be able to process either a fully qualified /dev/ge0
   77:   // type interface definition, or just ge0.
   78: 
   79:   if (strncmp(interface, "/dev/", strlen("/dev/")) == 0) {
   80:     devname = interface + strlen("/dev/");
   81:   } else {
   82:     devname = interface;
   83:   }
   84: 
   85:   strncpy2(fulldevpath, "/dev/", sizeof(fulldevpath)-1);
   86:   cp = strncat2(fulldevpath, interface, sizeof(fulldevpath));
   87: 
   88:   if (strlen(cp) != 0) {
   89:     fprintf(stderr, "device name buffer overflow %s\n", fulldevpath);
   90:     return -1;
   91:   }
   92: 
   93:   fprintf(stderr,"interface: %s\n", devname);
   94: 
   95:   // on Solaris, even though we are wanting to talk to ethernet device
   96:   // ge0, we have to open /dev/ge, then bind to unit 0.  Dupe our
   97:   // full path, then identify and cut off the unit number
   98: 
   99:   devname2 = strdup(fulldevpath);
  100: 
  101:   cp = split_dname(devname2, &unit_num);
  102: 
  103:   if (cp == NULL) {
  104:     free(devname2);
  105:     goto get_ip_address;
  106:   } else {
  107:     *cp = '\0';			/* null terminate devname2 right before numeric extension */
  108:   }
  109: 
  110:   // devname2 should now be something akin to /dev/ge.  Try to open
  111:   // it, and if it fails, fall back to the full /dev/ge0.
  112: 
  113:   if ((fd = open(devname2, O_RDWR)) < 0) {
  114:     if (errno != ENOENT) {
  115:       fprintf(stderr, "Couldn't open %s\n", devname2);
  116:       free(devname2);
  117:       goto get_ip_address;
  118:     } else {
  119:       if ((fd = open(fulldevpath, O_RDWR)) < 0) {
  120: 	fprintf(stderr, "Couldn't open %s\n", fulldevpath);
  121: 	free(devname2);
  122: 	goto get_ip_address;
  123:       }
  124:     }
  125:   }
  126: 
  127:   free(devname2);
  128:   devname2 = NULL;
  129: 
  130:   /* Use the dlcommon functions to get access to the DLPI information for this
  131:    * interface.  All of these functions exit() out on failure
  132:    */
  133: 
  134:   dlp = (union DL_primitives*) buf;
  135: 
  136:   /*
  137:    * DLPI attach to our low-level device
  138:    */
  139: 
  140:   dlattachreq(fd, unit_num);
  141:   dlokack(fd, buf);
  142: 
  143:   /*
  144:    * DLPI bind
  145:    */
  146: 
  147:   dlbindreq(fd, sap, 0, DL_CLDLS, 0, 0);
  148:   dlbindack(fd, buf);
  149: 
  150:   /*
  151:    * DLPI DL_INFO_REQ
  152:    */
  153: 
  154:   dlinforeq(fd);
  155:   dlinfoack(fd, buf);
  156: 
  157:   /* 
  158:      printdlprim(dlp);  // uncomment this to dump out info from DLPI
  159:   */
  160: 
  161:   if (dlp->info_ack.dl_addr_length + dlp->info_ack.dl_sap_length == 6) {
  162:     memcpy(if_hw_addr, 
  163: 	   OFFADDR(dlp, dlp->info_ack.dl_addr_offset),
  164: 	   dlp->info_ack.dl_addr_length);
  165:     got_hw_addr = 1;
  166:   } else {
  167:     fprintf(stderr, "Error, bad length for hardware interface %s -- %d\n", 
  168: 	    interface,
  169: 	    dlp->info_ack.dl_addr_length);
  170:   }
  171: 
  172:   close(fd);
  173: 
  174:  get_ip_address:
  175: 
  176:   /* Get the IP address of the interface */
  177: 
  178: #ifdef SIOCGIFADDR
  179: 
  180:   fd = socket(PF_INET, SOCK_DGRAM, 0); /* any sort of IP socket will do */
  181: 
  182:   strncpy(ifr.ifr_name, interface, IFNAMSIZ);
  183: 
  184:   (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_INET;
  185: 
  186:   if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
  187:     fprintf(stderr, "Error getting IP address for interface: %s\n", "ge0"); 
  188:     perror("ioctl(SIOCGIFADDR)");
  189:   } else {
  190:     memcpy(if_ip_addr, &((*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr), sizeof(struct in_addr));
  191:     got_ip_addr = 2;
  192:   }
  193: #else
  194:   fprintf(stderr, "Cannot obtain IP address on this platform\n");
  195: #endif
  196: 
  197:   close(fd);
  198:   
  199:   return got_hw_addr + got_ip_addr;
  200: }
  201: 
  202: /*
  203:  * Split a device name into a device type name and a unit number;
  204:  * return the a pointer to the beginning of the unit number, which
  205:  * is the end of the device type name, and set "*unitp" to the unit
  206:  * number.
  207:  *
  208:  * Returns NULL on error, and fills "ebuf" with an error message.
  209:  */
  210: char *
  211: split_dname(char *device, int *unitp)
  212: {
  213:   char *cp;
  214:   char *eos;
  215:   int unit;
  216: 
  217:   /* -- */
  218: 
  219:   /*
  220:    * Look for a number at the end of the device name string.
  221:    */
  222: 
  223:   cp = device + strlen(device) - 1;
  224:   if (*cp < '0' || *cp > '9') {
  225:     fprintf(stderr, "%s missing unit number", device);
  226:     return (NULL);
  227:   }
  228:   
  229:   /* Digits at end of string are unit number */
  230:   while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9')
  231:     cp--;
  232:   
  233:   unit = (int) strtol(cp, &eos, 10);
  234:   if (*eos != '\0') {
  235:     fprintf(stderr, "%s bad unit number", device);
  236:     return (NULL);
  237:   }
  238:   *unitp = unit;
  239:   return (cp);
  240: }
  241: 
  242: /*------------------------------------------------------------------------------
  243:                                                                       strncpy2()
  244: 
  245: strncpy2() is like strncpy(), except that strncpy2() will always
  246: insure that the <dest> buffer is null terminated.  strncpy() will not
  247: NULL terminate the destination buffer if the <src> string is <n>
  248: characters long or longer, not counting the terminating NULL character.
  249: 
  250:       STRNCPY2() IS NOT A COMPATIBLE REPLACEMENT FOR STRNCPY()!!
  251: 
  252: There are two reasons to use strncpy2(). 
  253: 
  254: The first reason is to guarantee that <dest> buffer's bounds are not
  255: violated.  In this case, <n> should be the size of the <dest> buffer
  256: minus one.
  257: 
  258: i.e.,
  259: 
  260: char tempstring[MAXLINE];
  261: 
  262: strncpy2(tempstring, my_own_string, MAXLINE - 1);
  263: 
  264: The second reason is to copy a specific number of characters from
  265: <src> to <dest>.  In this case, <n> should be the number of characters
  266: you want to transfer, not including the terminating NULL character.
  267: 
  268: The following example copies "abc" into tempstring, and NULL
  269: terminates it.
  270: 
  271: char tempstring[MAXLINE];
  272: 
  273: strncpy2(tempstring, "abcdef123", 3);
  274: 
  275: strncpy2() returns a pointer to the first character in <src> that was
  276: not copied to <dest>.  If all of <src> was copied to <dest>,
  277: strncpy2() will return a pointer to the NULL character terminating the
  278: <src> string.
  279: 
  280: ------------------------------------------------------------------------------*/
  281: char *
  282: strncpy2(char *dest, char *src, int n)
  283: {
  284:   int
  285:     i = 0;
  286: 
  287:   char
  288:     *char_ptr;
  289: 
  290:   /* -- */
  291: 
  292:   if ((!dest) || (!src))
  293:     return(src);
  294: 
  295:   char_ptr = dest;
  296: 
  297:   while ((i++ < n) && *src)
  298:     *char_ptr++ = *src++;
  299: 
  300:   *char_ptr = '\0';
  301: 
  302:   return(src);
  303: }
  304: 
  305: /*------------------------------------------------------------------------------
  306:                                                                       strncat2()
  307: 
  308: Similar to strncat except that <n> is the size of the <dest> buffer
  309: (INCLUDING SPACE FOR THE TRAILING NULL CHAR), NOT the number of
  310: characters to add to the buffer.
  311: 
  312:       STRNCAT2() IS NOT A COMPATIBLE REPLACEMENT FOR STRNCAT()!
  313: 
  314: strncat2() always guarantees that the <dest> will be null terminated, and that
  315: the buffer limits will be honored.  strncat2() will not write even one
  316: byte beyond the end of the <dest> buffer.
  317: 
  318: strncat2() concatenates up to <n-1> - strlen(<dest>) characters from
  319: <src> to <dest>.
  320: 
  321: So if the <dest> buffer has a size of 20 bytes (including trailing NULL),
  322: and <dest> contains a 19 character string, nothing will be done to
  323: <dest>.
  324: 
  325: If the string in <dest> is longer than <n-1> characters upon entry to
  326: strncat2(), <dest> will be truncated after the <n-1>th character.
  327: 
  328: strncat2() returns a pointer to the first character in the src buffer that
  329: was not copied into dest.. so if strncat2() returns a non-zero character,
  330: string truncation occurred in the concat operation.
  331: 
  332: ------------------------------------------------------------------------------*/
  333: char *
  334: strncat2(char *dest, char *src, int n)
  335: {
  336:   int
  337:     i = 0;
  338: 
  339:   char
  340:     *dest_ptr,
  341:     *src_ptr;
  342: 
  343:   /* -- */
  344: 
  345:   if (!dest || !src)
  346:     return NULL;
  347: 
  348:   dest_ptr = dest;
  349:   src_ptr = src;
  350: 
  351:   /* i = 0 */
  352: 
  353:   while ((i < (n-1)) && *dest_ptr)
  354:     {
  355:       i++;
  356:       dest_ptr++;
  357:     }
  358: 
  359:   /* i is the number of characters in dest before the concatenation
  360:      operation.. a number between 0 and n-1 */
  361: 
  362:   while ((i++ < (n-1)) && *src_ptr)
  363:     *dest_ptr++ = *src_ptr++;
  364: 
  365:   /* i is the number of characters in dest after the concatenation
  366:      operation, or n if the concat operation got truncated.. a number
  367:      between 0 and n 
  368: 
  369:      We need to check src_ptr here because i will be equal to n if
  370:      <dest> was full before the concatenation operation started (which
  371:      effectively causes instant truncation even if the <src> string is
  372:      empty..
  373: 
  374:      We could just test src_ptr here, but that would report
  375:      a string truncation if <src> was empty, which we don't
  376:      necessarily want. */
  377: 
  378:   if ((i == n) && *src_ptr)
  379:     {
  380:       // we could log truncation here
  381:     }
  382: 
  383:   *dest_ptr = '\0';
  384: 
  385:   /* should point to a non-empty substring only if the concatenation
  386:      operation got truncated.
  387: 
  388:      If src_ptr points to an empty string, the operation always
  389:      succeeded, either due to an empty <src> or because of
  390:      sufficient room in <dest>. */
  391:      
  392:   return(src_ptr);
  393: }
  394: 
  395: #endif /* HAVE_DLPI */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>