blob: 9bf2db0c22d2b7b1f996df09b031335b90f60379 [file] [log] [blame]
#include <u.h>
/* #include <everything_but_the_kitchen_sink.h> */
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <libc.h>
#include <ip.h>
static void
sockaddr2ip(uchar *ip, struct sockaddr *sa)
{
struct sockaddr_in *sin;
sin = (struct sockaddr_in*)sa;
memmove(ip, v4prefix, IPaddrlen);
memmove(ip+IPv4off, &sin->sin_addr, 4);
}
Ipifc*
readipifc(char *net, Ipifc *ifc, int index)
{
char *p, *ep, *q, *bp;
int i, mib[6];
size_t n;
Ipifc *list, **last;
Iplifc *lifc, **lastlifc;
struct if_msghdr *mh, *nmh;
struct ifa_msghdr *ah;
struct sockaddr *sa;
struct sockaddr_dl *sdl;
uchar ip[IPaddrlen];
USED(net);
free(ifc);
ifc = nil;
list = nil;
last = &list;
/*
* Does not handle IPv6 yet.
*/
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
n = 0;
if(sysctl(mib, 6, nil, &n, nil, 0) < 0)
return nil;
bp = mallocz(n, 1);
if(bp == nil)
return nil;
if(sysctl(mib, 6, bp, &n, nil, 0) < 0){
free(bp);
return nil;
}
p = bp;
ep = p+n;
while(p < ep){
mh = (struct if_msghdr*)p;
p += mh->ifm_msglen;
if(mh->ifm_type != RTM_IFINFO)
continue;
ifc = mallocz(sizeof *ifc, 1);
if(ifc == nil)
break;
*last = ifc;
last = &ifc->next;
sdl = (struct sockaddr_dl*)(mh+1);
n = sdl->sdl_nlen;
if(n >= sizeof ifc->dev)
n = sizeof ifc->dev - 1;
memmove(ifc->dev, sdl->sdl_data, n);
ifc->dev[n] = 0;
ifc->rp.linkmtu = mh->ifm_data.ifi_mtu;
lastlifc = &ifc->lifc;
if(sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == 6)
memmove(ifc->ether, LLADDR(sdl), 6);
while(p < ep){
ah = (struct ifa_msghdr*)p;
nmh = (struct if_msghdr*)p;
if(nmh->ifm_type != RTM_NEWADDR)
break;
p += nmh->ifm_msglen;
lifc = nil;
for(i=0, q=(char*)(ah+1); i<RTAX_MAX && q<p; i++){
if(!(ah->ifam_addrs & (1<<i)))
continue;
sa = (struct sockaddr*)q;
q += (sa->sa_len+sizeof(long)-1) & ~(sizeof(long)-1);
if(sa->sa_family != AF_INET)
continue;
if(lifc == nil){
lifc = mallocz(sizeof *lifc, 1);
if(lifc == nil)
continue;
*lastlifc = lifc;
lastlifc = &lifc->next;
}
sockaddr2ip(ip, sa);
switch(i){
case RTAX_IFA:
ipmove(lifc->ip, ip);
break;
case RTAX_NETMASK:
memset(ip, 0xFF, IPv4off);
ipmove(lifc->mask, ip);
break;
case RTAX_BRD:
if(mh->ifm_flags & IFF_POINTOPOINT)
/* ipmove(lifc->remote, ip) */ ;
if(mh->ifm_flags & IFF_BROADCAST)
/* ipmove(lifc->bcast, ip) */ ;
break;
case RTAX_GATEWAY:
break;
case RTAX_DST:
break;
}
}
if(lifc)
maskip(lifc->ip, lifc->mask, lifc->net);
}
}
free(bp);
return list;
}