Re(2): Ethernet address format question - part 2
Re(2): Ethernet address format question - part 2
- Subject: Re(2): Ethernet address format question - part 2
- From: "Peter Lovell" <email@hidden>
- Date: Thu, 2 Jun 2005 06:50:45 -0400
/* interface list routines */
//what follows is for *nix only, not win32
#ifndef WIN32
#include "/config.h" /* the configure script results */
#include <limits.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NET_IF_DL_H
#include <net/if_dl.h>
#endif
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <errno.h>
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
struct ifi_list* get_ifi_list(void)
{
struct ifi_list* ifi;
struct ifi_list* ifi_head = NULL;
struct ifi_list** ifi_pnext;
struct ifi_list ifi_zero; //prototype zero entry
struct ifi_list ifi_curr;
struct ifconf ifc;
struct ifreq* ifr;
struct ifreq ifr_work;
struct ifreq ifr_zero;
char* ifr_ptr; //important !! char*, not struct*
#ifdef SIOCGARP
struct arpreq arp_req;
#endif
int sd;
int oldsize;
int newsize;
int len;
char isAlias;
char* buf;
char* cptr;
char* temp;
int dp;
dp = 1 ;
memset( &ifi_zero, 0, sizeof(struct ifi_list) );
memset( &ifr_zero, 0, sizeof(struct ifreq) );
memset( &ifi_curr, 0, sizeof(struct ifi_list) );
sd = socket( AF_INET, SOCK_DGRAM, 0 );
if ( sd < 0 )
{
fprintf(stderr,"%s:%d ERROR: get_ifi_list failed to open socket,
errno = %d\n",__FILE__, __LINE__, errno );
return ifi_head; //return empty list if error
}
oldsize = 0;
newsize = 20 * sizeof(struct ifreq);
for ( ; ; )
{
buf = malloc( newsize );
if ( buf == NULL )
{
fprintf(stderr,"%s:%d ERROR: malloc failed, errno =
%d\n",__FILE__, __LINE__, errno );
return NULL; //return empty list if error
}
ifc.ifc_len = newsize;
ifc.ifc_buf = buf;
if ( ioctl( sd, SIOCGIFCONF, &ifc ) < 0 )
{
if ( errno != EINVAL || oldsize > 0 )
{
fprintf(stderr,"%s:%d ERROR: SIOCGIFCONF failed, errno =
%d\n",__FILE__, __LINE__, errno );
if ( buf != NULL )
free( buf);
return NULL; //return empty list if error
}
}
else // ioctl succeeded - do we have them all
{
if ( ifc.ifc_len == oldsize )
break; //same size means it was big enuff
}
//otherwise
oldsize = ifc.ifc_len;
newsize = 2 * oldsize;
free( buf );
}
if ( dp ) fprintf( stderr, "get_ifi_list: ifc.ifc_len %d\n", ifc.ifc_len);
// We have a buffer with all the interfaces
// Now walk the list and extract what we need
ifi_pnext = &ifi_head;
ifr_ptr = buf;
for ( ; ; )
{
// if this is out-of-range, i.e. we've done the final one,
// point at the zero entry to cause the final one to be added to
the list
if ( ifr_ptr >= buf + ifc.ifc_len )
ifr_ptr = (char*)&ifr_zero;
// Point at the current one, then calculate the pointer to the
next
ifr = (struct ifreq*)ifr_ptr;
#ifdef HAVE_SOCKADDR_SA_LEN
len = max( sizeof(struct sockaddr), ifr->ifr_addr.sa_len );
#else
switch ( ifr->ifr_addr.sa_family ) //otherwise size depends
upon family
{
#ifdef AF_INET6
case AF_INET6:
len = sizeof( struct sockaddr_in6 );
break;
#endif
case AF_INET:
default:
len = sizeof( struct sockaddr_in );
break;
}
#endif // HAVE_SOCKADDR_SA_LEN
if ( dp ) fprintf( stderr, "get_ifi_list: ifr 0x%p name %s sa_len %d\n",
ifr, ifr->ifr_name, len);
ifr_ptr += sizeof( ifr->ifr_name ) + len;
cptr = strchr( ifr->ifr_name, ':' );
isAlias = (cptr != NULL);
if ( cptr != NULL )
cptr = '\0'; // break an alias back to the parent
interface
if ( strcmp( ifr->ifr_name, ifi_curr.ifi_name ) != 0 ) //
different interface
{
if ( dp ) fprintf( stderr, "get_ifi_list: ifr 0x%p name %s oldname %s\n",
ifr, ifr->ifr_name, ifi_curr.ifi_name);
//this is a different interface, so save the existing entry
if appropriate
if ( strcmp( ifi_curr.ifi_name, "" ) != 0 ) //did we
actually have an entry - skip if not
{
// We do have a name, but what else
// If no IPv4 then try for it
#ifdef SIOCGIFADDR
if ( memcmp( &ifi_curr.ifi_v4addr, &ifi_zero.ifi_v4addr,
sizeof(ifi_curr.ifi_v4addr) ) == 0 )
{
if ( dp ) fprintf( stderr, "get_ifi_list: name %s try for IPv4\n",
ifi_curr.ifi_name);
strncpy(ifr_work.ifr_name, ifi_curr.ifi_name, IFNAMSIZ);
if ( ioctl(sd, SIOCGIFADDR, &ifr_work) >= 0 )
memcpy( &ifi_curr.ifi_v4addr, &(((struct
sockaddr_in*)&(ifr_work.ifr_addr))->sin_addr.s_addr), sizeof(struct
in_addr) );
}
#endif
// We have a name, but is there an enet address?
if ( memcmp( ifi_curr.ifi_haddr, ifi_zero.ifi_haddr,
sizeof(ifi_curr.ifi_haddr) ) == 0 )
{
if ( dp ) fprintf( stderr, "get_ifi_list: name %s try for enet\n",
ifi_curr.ifi_name);
// Lo - let me count the ways ....
// There are several ioctls for fetching the address
but we assume that
// if it's defined then it will work, and we don't
have to try the others
strncpy( ifr_work.ifr_name, ifi_curr.ifi_name, IFNAMSIZ );
#ifdef SIOCGIFHWADDR
if ( ioctl(sd, SIOCGIFHWADDR, &ifr_work) >= 0 )
memcpy( ifi_curr.ifi_haddr,
&ifr_work.ifr_hwaddr.sa_data, sizeof(ifi_curr.ifi_haddr) );
#elif defined SIOCGENADDR
if ( ioctl(sd, SIOCGENADDR, &ifr_work) >= 0 )
memcpy( ifi_curr.ifi_haddr, ifr_work.ifr_enaddr,
sizeof(ifi_curr.ifi_haddr) );
#endif
}
// If not but we do have IPv4 then try to get the enet from it
#ifdef SIOCGARP
if ( dp ) fprintf( stderr, "get_ifi_list: name %s try for enet from
IPv4\n", ifi_curr.ifi_name);
if ( (memcmp( ifi_curr.ifi_haddr, ifi_zero.ifi_haddr,
sizeof(ifi_curr.ifi_haddr) ) == 0) &&
(memcmp( &ifi_curr.ifi_v4addr, &ifi_zero.ifi_v4addr,
sizeof(ifi_curr.ifi_v4addr) ) != 0) )
{
memcpy( &arp_req.arp_pa, &ifi_curr.ifi_v4addr,
sizeof(struct sockaddr_in) );
if ( ioctl( sd, SIOCGARP, &arp_req ) >= 0 )
memcpy( ifi_curr.ifi_haddr,
arp_req.arp_ha.sa_data, ETHER_ADDR_LEN ); //assume ethernet for now
-- how to check??
}
#endif
if ( dp ) fprintf( stderr, "get_ifi_list: add name %s to list inet %x
haddr %x:%x:%x:%x:%x:%x\n", ifi_curr.ifi_name, ifi_curr.ifi_v4addr,
ifi_curr.ifi_haddr[0], ifi_curr.ifi_haddr[1], ifi_curr.ifi_haddr[2],
ifi_curr.ifi_haddr[3], ifi_curr.ifi_haddr[4], ifi_curr.ifi_haddr[5] );
if ( memcmp( ifi_curr.ifi_haddr, ifi_zero.ifi_haddr,
sizeof(ifi_curr.ifi_haddr) ) != 0)
{
//this has a name and enet address, so save it and
get ready for the next entry
temp = malloc( sizeof(ifi_curr) );
if ( temp == NULL )
{
fprintf(stderr,"%s:%d ERROR: malloc failed, errno
= %d\n",__FILE__, __LINE__, errno );
// ?? free some existing list??
return NULL; //return empty list if error
}
ifi = (struct ifi_list*)temp;
memcpy( ifi, &ifi_curr, sizeof(ifi_curr) );
*ifi_pnext = ifi;
ifi_pnext = &ifi->ifi_next;
}
}
memset( &ifi_curr, 0, sizeof(struct ifi_list) );
memcpy( ifi_curr.ifi_name, ifr->ifr_name,
sizeof(ifi_curr.ifi_name) );
}
if ( ifr == &ifr_zero )
break; //we're done
if ( isAlias )
continue; //we're not interested in aliases
#ifdef HAVE_SOCKADDR_DL_STRUCT
if ( ifr->ifr_addr.sa_family == AF_LINK /* or is equal to an
equivalent, for AIX I think */ )
{
if ( dp ) fprintf( stderr, "get_ifi_list: ifr 0x%p name %s try for
AF_LINK\n", ifr, ifr->ifr_name);
struct sockaddr_dl* sdl = (struct sockaddr_dl*) &ifr->ifr_addr;
// think about how to restrict this to just ethernet
if ( sdl->sdl_alen == ETHER_ADDR_LEN )
memcpy( ifi_curr.ifi_haddr, sdl->sdl_data + sdl-
>sdl_nlen, ETHER_ADDR_LEN );
}
#endif
if ( ifr->ifr_addr.sa_family == AF_INET )
{
memcpy( &ifi_curr.ifi_v4addr, &(((struct sockaddr_in*)&(ifr-
>ifr_addr))->sin_addr.s_addr), sizeof(struct in_addr) );
if ( dp ) fprintf( stderr, "get_ifi_list: ifr 0x%p name %s AF_INET %s\n",
ifr, ifr->ifr_name, inet_ntoa(((struct sockaddr_in*)&(ifr->ifr_addr))-
>sin_addr) );
}
}
return ifi_head;
}
#endif // WIN32
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden