On Dec 30, 2010, at 5:00 PM, Mathew Rowley wrote: > I am trying to understand how to get the MAC address when a pcap_addr family > is of type AF_LINK.
...on OS X, which is relevant here. AF_LINK is a BSDism, and only OSes that inherit AF_LINK from whatever flavor of BSD introduced it support it - i.e., you can only do that on *BSD and OS X. Forget about it on other OSes. > It seems that the pacap_addr.sa_data should be of type (struct sockaddr_dl*) Yes. A sockaddr_dl is defined in OS X 10.6 as struct sockaddr_dl { u_char sdl_len; /* Total length of sockaddr */ u_char sdl_family; /* AF_LINK */ u_short sdl_index; /* if != 0, system given index for interface */ u_char sdl_type; /* interface type */ u_char sdl_nlen; /* interface name length, no trailing 0 reqd. */ u_char sdl_alen; /* link level address length */ u_char sdl_slen; /* link layer selector length */ char sdl_data[12]; /* minimum work area, can be larger; contains both if name and ll address */ #ifndef __APPLE__ /* For TokenRing */ u_short sdl_rcf; /* source routing control */ u_short sdl_route[16]; /* source routing information */ #endif }; > but then the sockaddr_dl sdl_alen is of variable size (I was expecting), You were expecting a fixed-length structure? As the above indicates, there's no reason to expect it to be fixed-length; as it says, sdl_data "contains both if name and ll address", with no guarantee that the interface name is fixed-length. Furthermore, there is no guarantee that the link-layer address is a 6-octet MAC address - a PPP interface would not have any link-layer address, and a FireWire interface would have an 8-octet link-layer address, not a 6-octet one. > and LLADDR doesnt help much. Any insight? Here is the sample code and output: > > OUTPUT: > link sdl_alen: 101 > mac : 64:ffffffb9:ffffffe8:ffffffb7:ffffffb8:06 OK, that's 64:b9:e8:b7:b8:06. "char" in "char sdl_data[12]" really means "byte", and, for the link-layer address, "byte" generally means "unsigned byte", and "char" is not an unsigned byte on most platforms - it's a *signed* byte on most platforms (and you're not using a Gould/SEL minicomputer, so you're on a platform where it's signed; maybe there are others where char is signed, but no modern UN*X platform has char as an unsigned type). I would treat the bytes pointed to by LLADDR(link) as "unsigned char". > if(a->addr->sa_family == AF_LINK && a->addr->sa_data != > NULL){ a->addr->sa_data will never be null - sa_data is an array member of "struct sockaddr", not a pointer, and the address of that array member can never be null. > // MAC ADDRESS > //struct sockaddr_dl *sdl = (struct sockaddr_dl > *) a->addr->sa_data; > link = (struct sockaddr_dl*)a->addr->sa_data; No, you want to do link = (struct sockaddr_dl *)(a->addr); a->addr points to a sockaddr structure of some sort. All sockaddr structures begin with the same fields, including the address family, with the same sizes; what follows it is address-family-dependent data. "struct sockaddr" is a template for all sockaddr structures; sa_family is the address family, and sa_data is the data. Other sockaddr structures overlay the *entire* structure; they also contain an address family field, followed by data. > char mac[link->sdl_alen]; > memcpy(mac, LLADDR(link), link->sdl_alen); > printf("link sdl_alen: %i\n", link->sdl_alen); > printf("mac : %02x:%02x:%02x:%02x:%02x:%02x\n", > mac[1], mac[2], mac[3], mac[4], mac[5], mac[6]); That will print garbage for a PPP interface, as sdl_alen is 0 for PPP interfaces, and will print only the first 6 octets of the address for a FireWire interface. Also, C arrays are zero-index, so that will not print the first octet of the address - and will print garbage as the last octet, *even for an 802.x MAC address*. You want to do if (link->sdl_alen != 0) { unsigned char *octetp; unsigned int i; char sep; printf("mac: "); sep = '\0'; octetp = (unsigned char *)LLADDR(link); for (i = 0; i < link->sdl_alen; i++) { if (sep != '\0') putchar(sep); printf("%02x", octetp[i]); sep = ':'; } putchar('\n'); } so that: 1) you don't print anything if the address is zero-length; 2) you print the exact number of octets there are in the address, even if it's less than or greater than 6; 3) you print the first octet.- This is the tcpdump-workers list. Visit https://cod.sandelman.ca/ to unsubscribe.