Annotation of embedaddon/iftop/addrs_dlpi.c, revision 1.1.1.1

1.1       misho       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>