/* ******************************************************************** *
* ni_ifreq.c version 0.04 3-7-09 *
* *
* COPYRIGHT 2008-2009 Michael Robinton <michael@bizsystems.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of either: *
* *
* a) the GNU General Public License as published by the Free *
* Software Foundation; either version 2, or (at your option) any *
* later version, or *
* *
* b) the "Artistic License" which comes with this distribution. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either *
* the GNU General Public License or the Artistic License for more *
* details. *
* *
* You should have received a copy of the Artistic License with this *
* distribution, in the file named "Artistic". If not, I'll be glad *
* to provide one. *
* *
* You should also have received a copy of the GNU General Public *
* License along with this program in the file named "Copying". If not, *
* write to the *
* *
* Free Software Foundation, Inc. *
* 59 Temple Place, Suite 330 *
* Boston, MA 02111-1307, USA *
* *
* or visit their web page on the internet at: *
* *
* http://www.gnu.org/copyleft/gpl.html. *
* ******************************************************************** *
DESCRIPTION
Accessor functions for 'ifconf' and 'ifreq'
*
*/
/* for BSD flavors, consider using ifmib facility and struct if_data */
#include "localconf.h"
#ifdef HAVE_STRUCT_IFREQ
static void *
_ni_getifreqs(int fd, void * vifc)
{
int n,size;
struct ifconf * ifc = (struct ifconf *)vifc;
void * ifr;
bzero(ifc,sizeof(struct ifconf));
#ifdef SIOCGIFCOUNT
if (ioctl(fd, SIOCGIFCOUNT, ifc) != -1) {
size = ifc->ifc_len * sizeof(struct ifreq);
if (size > NI_IFREQ_MEM_MAX)
goto nifreq_nomem;
ifr = malloc(size);
if (ifr == NULL) {
nifreq_nomem:
errno = ENOMEM;
return NULL;
}
ifc->ifc_req = ifr;
ifc->ifc_len = size;
/* Solaris returns EINVAL for small buffer */
if (ioctl (fd, SIOCGIFCONF, ifc) < 0) {
free(ifr);
if (errno == EINVAL)
goto nifreq_iterate;
else
return NULL;
}
return ifr;
}
nifreq_iterate:
#endif
n = 2;
ifr = ifc->ifc_req;
while (1) {
ifr = realloc(ifr, n * PAGE_SIZE );
if (ifr == NULL) {
nifreq_mem_over:
free(ifc->ifc_req);
errno = ENOMEM;
return NULL;
}
ifc->ifc_req = ifr;
size = n * PAGE_SIZE;
if (size > NI_IFREQ_MEM_MAX)
goto nifreq_mem_over;
ifc->ifc_len = size;
if (ioctl( fd, SIOCGIFCONF, ifc ) < 0 && errno != EINVAL) {
free (ifr);
return NULL;
}
if (ifc->ifc_len < size - PAGE_SIZE) /* (n-1) * PAGE_SIZE */
break;
n *= 2;
}
return ifr;
}
/* print stuff of interest, return 0 on success else the errno */
int
ni_flav_ifreq_developer(void * ifcee)
{
/* ifcee unused */
int i, n, fd, inc, af, j;
unsigned short flags;
struct ifconf ifc;
struct nifreq *ifr, *lifr;
unsigned char * macp;
char namebuf[NI_MAXHOST];
#ifdef LOCAL_SIZEOF_SOCKADDR_DL
const struct sockaddr_dl * sdl;
#endif
#include "ni_IFF_inc.c"
if ((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
return errno;
if (_ni_getifreqs(fd,&ifc) == NULL) {
close(fd);
return errno;
}
ifr = (struct nifreq *)ifc.ifc_req;
lifr = (struct nifreq *)&(ifc.ifc_buf[ifc.ifc_len]);
/* while (ifr < lifr) { */
for(j = 0; j < ifc.ifc_len; j += inc) {
macp = NULL;
inc = ni_SIZEOF_ADDR_IFREQ((struct ifreq *)ifr,(&ifr->ni_saddr),sizeof(struct ifreq));
af = ifr->ni_saddr.sa_family;
printf("%s\t",ifr->ni_ifr_name);
if (af == AF_INET) {
if (ioctl(fd, SIOCGIFFLAGS,ifr) != -1) {
flags = ifr->ni_ushort;
printf("flags=%0x<",flags);
if (flags & IFF_UP)
printf("UP ");
else
printf("DOWN ");
n = sizeof(ni_iff_tab) / sizeof(ni_iff_t);
for (i=0;i<n;i++) {
if (flags & ni_iff_tab[i].iff_val)
printf("%s ",ni_iff_tab[i].iff_nam);
}
if (flags == 0)
printf(" ");
printf("\b> ");
}
if (ioctl(fd,SIOCGIFMETRIC,ifr) != -1 );
printf("metric %d ",ifr->ni_int);
#ifdef SIOCGIFMTU
if (ioctl(fd,SIOCGIFMTU,ifr) != -1 )
printf("mtu %d",ifr->ni_uint);
#elif defined SIOCGIFDATA
if (ioctl(fd,SIOCGIFDATA,ifr) != -1)
printf("mtu %d",((struct ifdata *)ifr->ni_data)->ifi_mtu;
#endif
printf("\n\t");
if (ioctl(fd,SIOCGIFADDR,ifr) != -1 ) {
#ifdef HAVE_GETNAMEINFO
if (getnameinfo(&ifr->ni_saddr,LOCAL_SIZEOF_SOCKADDR_IN,namebuf,NI_MAXHOST,NULL,0,NI_NUMERICHOST) != 0)
#endif
strcpy(namebuf,inet_ntoa(ifr->ni_sin.sin_addr));
printf("address %s\t",namebuf);
}
if (ioctl(fd,SIOCGIFNETMASK,ifr) != -1 )
printf("mask 0x%lx\t",(unsigned long)ntohl(ifr->ni_sin.sin_addr.s_addr));
if (ioctl(fd,SIOCGIFBRDADDR,ifr) != -1 )
printf("broadcast %s\t",inet_ntoa(ifr->ni_sin.sin_addr));
}
printf("\n\taf=%d sz=%d ",af,inc);
#if defined SIOCGIFHWADDR
if (ioctl(fd,SIOCGIFHWADDR,ifr) != -1 && NI_MAC_NOT_ZERO(&ifr->ni_saddr.sa_data))
macp = (unsigned char *)(&ifr->ni_saddr.sa_data);
#endif
#if defined SIOCGENADDR
if (ioctl(fd,SIOCGENADDR,ifr) != -1)
macp = (unsigned char *)(&ifr->ni_char);
#endif
if (macp != NULL)
NI_PRINT_MAC(macp);
printf("\n");
ifr = (struct nifreq *)(((char *)ifr) + inc);
}
close(fd);
free(ifc.ifc_req);
return 0;
}
static struct ni_ifconf_flavor ni_flavor_ifreq = {
.ni_type = NI_IFREQ,
#ifdef SIOCGIFINDEX
.siocgifindex = SIOCGIFINDEX,
#else
.siocgifindex = 0,
#endif
.siocsifaddr = SIOCSIFADDR,
.siocgifaddr = SIOCGIFADDR,
#ifdef SIOCDIFADDR
.siocdifaddr = SIOCDIFADDR,
# else
.siocdifaddr = 0,
#endif
#ifdef SIOCAIFADDR
.siocaifaddr = SIOCAIFADDR,
#else
.siocaifaddr = 0,
#endif
.siocsifdstaddr = SIOCSIFDSTADDR,
.siocgifdstaddr = SIOCGIFDSTADDR,
.siocsifflags = SIOCSIFFLAGS,
.siocgifflags = SIOCGIFFLAGS,
.siocsifmtu = SIOCSIFMTU,
.siocgifmtu = SIOCGIFMTU,
.siocsifbrdaddr = SIOCSIFBRDADDR,
.siocgifbrdaddr = SIOCGIFBRDADDR,
.siocsifnetmask = SIOCGIFNETMASK,
.siocgifnetmask = SIOCGIFNETMASK,
.siocsifmetric = SIOCSIFMETRIC,
.siocgifmetric = SIOCGIFMETRIC,
.ifr_offset = 0,
.gifaddrs = nifreq_gifaddrs,
.fifaddrs = ni_freeifaddrs,
.refreshifr = NULL,
.getifreqs = _ni_getifreqs,
.developer = ni_flav_ifreq_developer,
};
void
ni_ifreq_ctor()
{
ni_ifcf_register(&ni_flavor_ifreq);
}
#else
void
ni_ifreq_ctor()
{
return;
};
#endif /* have ifreq */