Topic
  • 1 reply
  • Latest Post - ‏2011-11-25T06:04:06Z by SystemAdmin
SystemAdmin
SystemAdmin
549 Posts

Pinned topic Problem using ioctl (SIOCGIFCONF and SIOCGARP)

‏2011-10-29T18:32:37Z |
I am writing some portable code to print Interface, its IP address, and its MAC (Hardware) address. It is working on three platforms (viz, Linux, Solaris and HP-UX). However, it is creating problems on AIX.

The code is as follows:


#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <net/if_arp.h> #include <arpa/inet.h> #ifdef __sunos__ #include <sys/sockio.h> #endif   #define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof sa.sin_port])   #

if defined(__AIX) || defined(_AIX) #define MAX(x,y) ((x) > (y) ? (x) : (y)) #define SIZE(p) MAX((p).sa_len, sizeof(p)) #

else #define IFRSIZE   ((

int)(size * sizeof (struct ifreq))) #endif     

int main () 
{ unsigned 

char             *u = NULL; 

int                 sockfd; 

int                    size = 1; struct ifreq          *ifr; struct ifconf             ifc; struct sockaddr_in sa; struct arpreq               arp; 

char                      macStr[128]; 

if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) 
{ printf (
"Error: Unable to open socket.\n"); exit (1); 
}   #

if defined(__AIX__) || defined(_AIX) 

if (ioctl (sockfd, SIOCGSIZIFCONF, &size) == -1) 
{ perror(
"Error getting size of interface :"); exit (1); 
} ifc.ifc_req = (struct ifreq *) malloc (size); ifc.ifc_len = size;   

if (ioctl(sockfd, SIOCGIFCONF, &ifc)) 
{ printf (
"Error: ioctl SIOCFIFCONF.\n"); exit (1); 
} #

else ifc.ifc_len = IFRSIZE; ifc.ifc_req = NULL; 

do 
{ ++size; 
/* realloc buffer size until no overflow occurs  */ 

if (NULL == (ifc.ifc_req = (struct ifreq*)realloc(ifc.ifc_req, IFRSIZE))) 
{ printf (
"Error: Unable to allocate mememory.\n"); exit (1); 
} ifc.ifc_len = IFRSIZE; 

if (ioctl(sockfd, SIOCGIFCONF, &ifc)) 
{ printf (
"Error: ioctl SIOCFIFCONF.\n"); exit (1); 
} 
} 

while (IFRSIZE <= ifc.ifc_len); #endif ifr = ifc.ifc_req; 

while ((

char *) ifr < (

char *) ifc.ifc_req + ifc.ifc_len) 
{ printf(
"Interface:  %s\n", ifr->ifr_name); printf(
"IP Address: %s\n", inet_ntoa(inaddrr(ifr_addr.sa_data)));     u = NULL; #

if defined(__linux__) || defined(linux) 

if (0 == ioctl(sockfd, SIOCGIFHWADDR, ifr)) u = (unsigned 

char *) &ifr->ifr_addr.sa_data; 

else 
{ #endif arp.arp_pa = ifr->ifr_addr; 

if (0 == ioctl (sockfd, SIOCGARP, &arp)) u = (unsigned 

char *) arp.arp_ha.sa_data; 

else perror (
"Error during ioctl"); #

if defined(__linux__) || defined(linux) 
} #endif   memset (macStr, 0, sizeof (macStr)); 

if (u && u[0] + u[1] + u[2] + u[3] + u[4] + u[5]) 
{ sprintf (macStr, 
"%2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2X", u[0], u[1], u[2], u[3], u[4], u[5]); printf (
"HW Address: %s", macStr); 
}   printf(
"\n");     #

if defined(__AIX) || defined(_AIX) ifr = ((

char *) ifr + sizeof(ifr->ifr_name) + SIZE(ifr->ifr_addr)); #

else ++ifr; #endif 
} close(sockfd); 
}


Now the problem is that when I try to execute the executable after compiling, the following output is produced:


$ ./ifconfig-a-AIX Interface:  en0 IP Address: 6.3.6.0 Error during ioctl: Invalid argument   Interface:  en0 IP Address: 10.20.21.139 Error during ioctl: No such device or address   Interface:  lo0 IP Address: 24.3.0.0 Error during ioctl: Invalid argument   Interface:  lo0 IP Address: 127.0.0.1 Error during ioctl: No such device or address   Interface:  lo0 IP Address: 0.0.0.0 Error during ioctl: Invalid argument


However, the ifconfig -a output is as follows:


$ ifconfig -a en0: flags=7e080863,10<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64BIT,CHECKSUM_OFFLOAD,CHECKSUM_SUPPORT,PSEG> inet 10.20.21.139 netmask 0xffffff00 broadcast 10.20.21.255 lo0: flags=e08084b<UP,BROADCAST,LOOPBACK,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64BIT> inet 127.0.0.1 netmask 0xff000000 broadcast 127.255.255.255 inet6 ::1/0 tcp_sendspace 65536 tcp_recvspace 65536


The question is what I am doing wrong?
Why is my executable giving me duplicate entries for devices?
Also, why MAC address is not shown for any of the entries?
Thanks for any help.
Updated on 2011-11-25T06:04:06Z at 2011-11-25T06:04:06Z by SystemAdmin
  • SystemAdmin
    SystemAdmin
    549 Posts

    Re: Problem using ioctl (SIOCGIFCONF and SIOCGARP)

    ‏2011-11-25T06:04:06Z  
    You can add the following lines within the while (for AIX) to skip the duplicate entries for an interface.
    if (ifr->ifr_addr.sa_family != AF_INET) {
    ifr = ((char *) ifr + sizeof(ifr->ifr_name) + SIZE(ifr->ifr_addr));
    continue;
    }

    As you can see from if.h, ifreq contains a union and hence multiple entries exist for an interface in the returned ifreq.

    MAC address can be retrieved from entstat (for ent0, layer 2) not from ifconfig (en0, layer 3).