Annotation of embedaddon/iftop/addrs_dlpi.c, revision 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>