tnew - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 9aec88f29cf8145f887f31a4bfc7299f723b72e8
 (DIR) parent 9fe7e1a14c84bddc7bb0ec16ce23f44b5479ce94
 (HTM) Author: rsc <devnull@localhost>
       Date:   Sat, 31 Dec 2005 19:33:03 +0000
       
       new
       
       Diffstat:
         A src/libip/Darwin.c                  |       1 +
         A src/libip/FreeBSD.c                 |     144 +++++++++++++++++++++++++++++++
         A src/libip/Linux.c                   |     254 +++++++++++++++++++++++++++++++
         A src/libip/NetBSD.c                  |       1 +
         A src/libip/OpenBSD.c                 |       1 +
         A src/libip/SunOS.c                   |       1 +
         A src/libip/freeipifc.c               |      20 ++++++++++++++++++++
         M src/libip/mkfile                    |       4 ++--
         M src/libip/myetheraddr.c             |      51 +++++++++++--------------------
         M src/libip/myipaddr.c                |      30 +++++++++++++++++++++++++++---
         A src/libip/none.c                    |      24 ++++++++++++++++++++++++
         D src/libip/readipifc.c               |     194 ------------------------------
       
       12 files changed, 493 insertions(+), 232 deletions(-)
       ---
 (DIR) diff --git a/src/libip/Darwin.c b/src/libip/Darwin.c
       t@@ -0,0 +1 @@
       +#include "none.c"
 (DIR) diff --git a/src/libip/FreeBSD.c b/src/libip/FreeBSD.c
       t@@ -0,0 +1,144 @@
       +#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/module.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;
       +        int i, mib[6], n, alloc;
       +        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;
       +        
       +        if(sysctl(mib, 6, nil, &n, nil, 0) < 0)
       +                return nil;
       +        p = mallocz(n, 1);
       +        if(p == nil)
       +                return nil;
       +        if(sysctl(mib, 6, p, &n, nil, 0) < 0){
       +                free(p);
       +                return nil;
       +        }
       +        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;
       +
       +                while(p < ep){
       +                        ah = (struct ifa_msghdr*)p;
       +                        nmh = (struct if_msghdr*)p;
       +                        if(nmh->ifm_type != RTM_NEWADDR)
       +                                break;
       +                        p += nmh->ifm_msglen;
       +                        alloc = 0;
       +                        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_LINK && i == RTAX_IFA){
       +                                        struct sockaddr_dl *e;
       +                                        
       +                                        if(e->sdl_type == IFT_ETHER && e->sdl_alen == 6)
       +                                                memmove(ifc->ether, LLADDR(e), 6);
       +                                }
       +                                if(sa->sa_family != AF_INET)
       +                                        continue;
       +                                if(alloc == 0){
       +                                        alloc = 1;
       +                                        lifc = mallocz(sizeof *lifc, 1);
       +                                        *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;
       +                                }
       +                        }
       +                        maskip(lifc->ip, lifc->mask, lifc->net);
       +                }
       +        }
       +        return list;
       +}
 (DIR) diff --git a/src/libip/Linux.c b/src/libip/Linux.c
       t@@ -0,0 +1,254 @@
       +#include <u.h>
       +#include <sys/ioctl.h>
       +#include <sys/socket.h>
       +#include <netinet/in.h>
       +#include <arpa/inet.h>
       +#include <asm/types.h>
       +#include <net/if_arp.h>
       +#include <linux/netlink.h>
       +#include <linux/rtnetlink.h>
       +#include <net/if.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +/*
       + * Use netlink sockets to find interfaces.
       + * Thanks to Erik Quanstrom.
       + */
       +static int
       +netlinkrequest(int fd, int type, int (*fn)(struct nlmsghdr *h, Ipifc**, int), 
       +        Ipifc **ifc, int index)
       +{
       +        char buf[1024];
       +        int n;
       +        struct sockaddr_nl nl;
       +        struct {
       +                struct nlmsghdr nlh;
       +                struct rtgenmsg g;
       +        } req;
       +        struct nlmsghdr *h;
       +
       +        memset(&nl, 0, sizeof nl);
       +        nl.nl_family = AF_NETLINK;
       +
       +        memset(&req, 0, sizeof req);
       +        req.nlh.nlmsg_len = sizeof req;
       +        req.nlh.nlmsg_type = type;
       +        req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
       +        req.nlh.nlmsg_pid = 0;
       +        req.nlh.nlmsg_seq = 1;
       +        req.g.rtgen_family = AF_NETLINK;
       +
       +        if(sendto(fd, (void*)&req, sizeof req, 0, (struct sockaddr*)&nl, sizeof nl) < 0)
       +                return -1;
       +
       +        while((n=read(fd, buf, sizeof buf)) > 0){
       +                for(h=(struct nlmsghdr*)buf; NLMSG_OK(h, n); h = NLMSG_NEXT(h, n)){
       +                        if(h->nlmsg_type == NLMSG_DONE)
       +                                return 0;
       +                        if(h->nlmsg_type == NLMSG_ERROR){
       +                                werrstr("netlink error");
       +                                return -1;
       +                        }
       +                        if(fn(h, ifc, index) < 0)
       +                                return -1;
       +                }
       +        }
       +        werrstr("netlink error");
       +        return -1;
       +}
       +
       +static int
       +devsocket(void)
       +{
       +        /* we couldn't care less which one; just want to talk to the kernel! */
       +        static int dumb[3] = { AF_INET, AF_PACKET, AF_INET6 };
       +        int i, fd;
       +        
       +        for(i=0; i<nelem(dumb); i++)
       +                if((fd = socket(dumb[i], SOCK_DGRAM, 0)) >= 0)
       +                        return fd;
       +        return -1;
       +}
       +
       +static int
       +parsertattr(struct rtattr **dst, int ndst, struct nlmsghdr *h, int type, int skip)
       +{
       +        struct rtattr *src;
       +        int len;
       +        
       +        len = h->nlmsg_len - NLMSG_LENGTH(skip);
       +        if(len < 0 || h->nlmsg_type != type){
       +                werrstr("attrs too short");
       +                return -1;
       +        }
       +        src = (struct rtattr*)((char*)NLMSG_DATA(h) + NLMSG_ALIGN(skip));
       +
       +        memset(dst, 0, ndst*sizeof dst[0]);
       +        for(; RTA_OK(src, len); src = RTA_NEXT(src, len))
       +                if(src->rta_type < ndst)
       +                        dst[src->rta_type] = src;
       +        return 0;
       +}
       +
       +static void
       +rta2ip(int af, uchar *ip, struct rtattr *rta)
       +{
       +        memset(ip, 0, IPaddrlen);
       +        
       +        switch(af){
       +        case AF_INET:
       +                memmove(ip, v4prefix, IPv4off);
       +                memmove(ip+IPv4off, RTA_DATA(rta), IPv4addrlen);
       +                break;
       +        case AF_INET6:
       +                memmove(ip, RTA_DATA(rta), IPaddrlen);
       +                break;
       +        }
       +}
       +
       +static int
       +getlink(struct nlmsghdr *h, Ipifc **ipifclist, int index)
       +{
       +        char *p;
       +        int fd;
       +        struct rtattr *attr[IFLA_MAX+1];
       +        struct ifinfomsg *ifi;
       +        Ipifc *ifc;
       +        
       +        ifi = (struct ifinfomsg*)NLMSG_DATA(h);
       +        if(index >= 0 && ifi->ifi_index != index)
       +                return 0;
       +
       +        ifc = mallocz(sizeof *ifc, 1);
       +        if(ifc == nil)
       +                return -1;
       +        ifc->index = ifi->ifi_index;
       +
       +        while(*ipifclist)
       +                ipifclist = &(*ipifclist)->next;
       +        *ipifclist = ifc;
       +
       +        if(parsertattr(attr, nelem(attr), h, RTM_NEWLINK, sizeof(struct ifinfomsg)) < 0)
       +                return -1;
       +
       +        if(attr[IFLA_IFNAME])
       +                p = (char*)RTA_DATA(attr[IFLA_IFNAME]);
       +        else
       +                p = "nil";
       +        strecpy(ifc->dev, ifc->dev+sizeof ifc->dev, p);
       +
       +        if(attr[IFLA_MTU])
       +                ifc->mtu = *(int*)RTA_DATA(attr[IFLA_MTU]);
       +        
       +        if(attr[IFLA_STATS]){
       +                struct rtnl_link_stats *s;
       +
       +                s = RTA_DATA(attr[IFLA_STATS]);
       +                ifc->pktin = s->rx_packets;
       +                ifc->pktout = s->tx_packets;
       +                ifc->errin = s->rx_errors;
       +                ifc->errout = s->tx_errors;
       +        }
       +        
       +        if((fd = devsocket()) > 0){
       +                struct ifreq ifr;
       +
       +                memset(&ifr, 0, sizeof ifr);
       +                strncpy(ifr.ifr_name, p, IFNAMSIZ);
       +                ifr.ifr_mtu = 0;
       +                if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
       +                        ifc->rp.linkmtu = ifr.ifr_mtu;
       +
       +                memset(&ifr, 0, sizeof ifr);
       +                strncpy(ifr.ifr_name, p, IFNAMSIZ);
       +                if(ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0
       +                && ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER)
       +                        memmove(ifc->ether, ifr.ifr_hwaddr.sa_data, 6);
       +                
       +                close(fd);
       +        }
       +        return 0;
       +}
       +
       +static int
       +getaddr(struct nlmsghdr *h, Ipifc **ipifclist, int index)
       +{
       +        int mask;
       +        Ipifc *ifc;
       +        Iplifc *lifc, **l;
       +        struct ifaddrmsg *ifa;
       +        struct rtattr *attr[IFA_MAX+1];
       +        
       +        USED(index);
       +
       +        ifa = (struct ifaddrmsg*)NLMSG_DATA(h);
       +        for(ifc=*ipifclist; ifc; ifc=ifc->next)
       +                if(ifc->index == ifa->ifa_index)
       +                        break;
       +        if(ifc == nil)
       +                return 0;
       +        if(parsertattr(attr, nelem(attr), h, RTM_NEWADDR, sizeof(struct ifaddrmsg)) < 0)
       +                return -1;
       +        
       +        lifc = mallocz(sizeof *lifc, 1);
       +        if(lifc == nil)
       +                return -1;
       +        for(l=&ifc->lifc; *l; l=&(*l)->next)
       +                ;
       +        *l = lifc;
       +
       +        if(attr[IFA_ADDRESS] == nil)
       +                attr[IFA_ADDRESS] = attr[IFA_LOCAL];
       +        if(attr[IFA_ADDRESS] == nil)
       +                return 0;
       +
       +        rta2ip(ifa->ifa_family, lifc->ip, attr[IFA_ADDRESS]);
       +        
       +        mask = ifa->ifa_prefixlen/8;
       +        if(ifa->ifa_family == AF_INET)
       +                mask += IPv4off;
       +        memset(lifc->mask, 0xFF, mask);
       +        memmove(lifc->net, lifc->ip, mask);
       +        
       +        if(attr[IFA_CACHEINFO]){
       +                struct ifa_cacheinfo *ci;
       +
       +                ci = RTA_DATA(attr[IFA_CACHEINFO]);
       +                lifc->preflt = ci->ifa_prefered;
       +                lifc->validlt = ci->ifa_valid;
       +        }
       +        return 0;
       +}
       +
       +Ipifc*
       +readipifc(char *net, Ipifc *ifc, int index)
       +{
       +        int fd;
       +
       +        USED(net);
       +        freeipifc(ifc);
       +        ifc = nil;
       +        
       +        fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
       +        if(fd < 0)
       +                return nil;
       +        ifc = nil;
       +        if(netlinkrequest(fd, RTM_GETLINK, getlink, &ifc, index) < 0
       +        || netlinkrequest(fd, RTM_GETADDR, getaddr, &ifc, index) < 0){
       +                close(fd);
       +                freeipifc(ifc);
       +                return nil;
       +        }
       +        close(fd);
       +        return ifc;
       +}
       +
       +int
       +_myetheraddr(uchar *to, char *dev)
       +{
       +        int fd;
       +        struct ifreq ifr;
       +        
       +        return 0;
       +}
 (DIR) diff --git a/src/libip/NetBSD.c b/src/libip/NetBSD.c
       t@@ -0,0 +1 @@
       +#include "none.c"
 (DIR) diff --git a/src/libip/OpenBSD.c b/src/libip/OpenBSD.c
       t@@ -0,0 +1 @@
       +#include "none.c"
 (DIR) diff --git a/src/libip/SunOS.c b/src/libip/SunOS.c
       t@@ -0,0 +1 @@
       +#include "none.c"
 (DIR) diff --git a/src/libip/freeipifc.c b/src/libip/freeipifc.c
       t@@ -0,0 +1,20 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +void
       +freeipifc(Ipifc *i)
       +{
       +        Ipifc *next;
       +        Iplifc *l, *lnext;
       +
       +        for(; i; i=next){
       +                next = i->next;
       +                for(l=i->lifc; l; l=lnext){
       +                        lnext = l->next;
       +                        free(l);
       +                }
       +                free(i);
       +        }
       +}
       +
 (DIR) diff --git a/src/libip/mkfile b/src/libip/mkfile
       t@@ -5,14 +5,14 @@ OFILES=\
                bo.$O\
                classmask.$O\
                eipfmt.$O\
       +        freeipifc.$O\
                ipaux.$O\
       -        myetheraddr.$O\
                myipaddr.$O\
                parseether.$O\
                parseip.$O\
                ptclbsum.$O\
       -        readipifc.$O\
                udp.$O\
       +        $SYSNAME.$O\
        
        HFILES=\
                ip.h
 (DIR) diff --git a/src/libip/myetheraddr.c b/src/libip/myetheraddr.c
       t@@ -2,40 +2,25 @@
        #include <libc.h>
        #include <ip.h>
        
       +static char zea[6];
       +
        int
        myetheraddr(uchar *to, char *dev)
        {
       -        int n, fd;
       -        char buf[256], *ptr;
       -
       -        /* Make one exist */
       -        if(*dev == '/')
       -                sprint(buf, "%s/clone", dev);
       -        else
       -                sprint(buf, "/net/%s/clone", dev);
       -        fd = open(buf, ORDWR);
       -        if(fd >= 0)
       -                close(fd);
       -
       -        if(*dev == '/')
       -                sprint(buf, "%s/0/stats", dev);
       -        else
       -                sprint(buf, "/net/%s/0/stats", dev);
       -        fd = open(buf, OREAD);
       -        if(fd < 0)
       -                return -1;
       -
       -        n = read(fd, buf, sizeof(buf)-1);
       -        close(fd);
       -        if(n <= 0)
       -                return -1;
       -        buf[n] = 0;
       -
       -        ptr = strstr(buf, "addr: ");
       -        if(!ptr)
       -                return -1;
       -        ptr += 6;
       -
       -        parseether(to, ptr);
       -        return 0;
       +        Ipifc *ifclist, *ifc;
       +        
       +        ifclist = readipifc(nil, nil, -1);
       +        for(ifc=ifclist; ifc; ifc=ifc->next){
       +                if(dev && strcmp(ifc->dev) != 0)
       +                        continue;
       +                if(memcmp(zea, ifc->ether, 6) == 0)
       +                        continue;
       +                memmove(to, ifc->ether, 6);
       +                freeipifc(ifclist);
       +                return 0;
       +        }
       +        freeipifc(ifclist);
       +        werrstr("no ethernet devices");
       +        return -1;
        }
       +
 (DIR) diff --git a/src/libip/myipaddr.c b/src/libip/myipaddr.c
       t@@ -2,20 +2,44 @@
        #include <libc.h>
        #include <ip.h>
        
       +static uchar loopbacknet[IPaddrlen] = {
       +        0, 0, 0, 0,
       +        0, 0, 0, 0,
       +        0, 0, 0xff, 0xff,
       +        127, 0, 0, 0
       +};
       +static uchar loopbackmask[IPaddrlen] = {
       +        0xff, 0xff, 0xff, 0xff,
       +        0xff, 0xff, 0xff, 0xff,
       +        0xff, 0xff, 0xff, 0xff,
       +        0xff, 0, 0, 0
       +};
       +
       +// find first ip addr that isn't the friggin loopback address
       +// unless there are no others
        int
        myipaddr(uchar *ip, char *net)
        {
                Ipifc *nifc;
                Iplifc *lifc;
       -        static Ipifc *ifc;
       +        Ipifc *ifc;
       +        uchar mynet[IPaddrlen];
        
       -        ifc = readipifc(net, ifc, -1);
       +        ifc = readipifc(net, nil, -1);
                for(nifc = ifc; nifc; nifc = nifc->next)
       -                for(lifc = nifc->lifc; lifc; lifc = lifc->next)
       +                for(lifc = nifc->lifc; lifc; lifc = lifc->next){
       +                        maskip(lifc->ip, loopbackmask, mynet);
       +                        if(ipcmp(mynet, loopbacknet) == 0){
       +                                continue;
       +                        }
                                if(ipcmp(lifc->ip, IPnoaddr) != 0){
                                        ipmove(ip, lifc->ip);
       +                                freeipifc(ifc);
                                        return 0;
                                }
       +                }
                ipmove(ip, IPnoaddr);
       +        freeipifc(ifc);
                return -1;
        }
       +
 (DIR) diff --git a/src/libip/none.c b/src/libip/none.c
       t@@ -0,0 +1,24 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +Ipifc*
       +readipifc(char *net, Ipifc *ipifc, int index)
       +{
       +        USED(net);
       +        USED(ipifc);
       +        USED(index);
       +        
       +        werrstr("not implemented");
       +        return nil;
       +}
       +
       +int
       +myetheraddr(uchar *to, char *dev)
       +{
       +        USED(to);
       +        USED(dev);
       +
       +        werrstr("not implemented");
       +        return -1;
       +}
 (DIR) diff --git a/src/libip/readipifc.c b/src/libip/readipifc.c
       t@@ -1,194 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <ctype.h>
       -#include <ip.h>
       -
       -static Ipifc**
       -_readoldipifc(char *buf, Ipifc **l, int index)
       -{
       -        char *f[200];
       -        int i, n;
       -        Ipifc *ifc;
       -        Iplifc *lifc, **ll;
       -
       -        /* allocate new interface */
       -        *l = ifc = mallocz(sizeof(Ipifc), 1);
       -        if(ifc == nil)
       -                return l;
       -        l = &ifc->next;
       -        ifc->index = index;
       -
       -        n = tokenize(buf, f, nelem(f));
       -        if(n < 2)
       -                return l;
       -
       -        strncpy(ifc->dev, f[0], sizeof ifc->dev);
       -        ifc->dev[sizeof(ifc->dev) - 1] = 0;
       -        ifc->mtu = strtoul(f[1], nil, 10);
       -
       -        ll = &ifc->lifc;
       -        for(i = 2; n-i >= 7; i += 7){
       -                /* allocate new local address */
       -                *ll = lifc = mallocz(sizeof(Iplifc), 1);
       -                ll = &lifc->next;
       -
       -                parseip(lifc->ip, f[i]);
       -                parseipmask(lifc->mask, f[i+1]);
       -                parseip(lifc->net, f[i+2]);
       -                ifc->pktin = strtoul(f[i+3], nil, 10);
       -                ifc->pktout = strtoul(f[i+4], nil, 10);
       -                ifc->errin = strtoul(f[i+5], nil, 10);
       -                ifc->errout = strtoul(f[i+6], nil, 10);
       -        }
       -        return l;
       -}
       -
       -static char*
       -findfield(char *name, char **f, int n)
       -{
       -        int i;
       -
       -        for(i = 0; i < n-1; i++)
       -                if(strcmp(f[i], name) == 0)
       -                        return f[i+1];
       -        return "";
       -}
       -
       -static Ipifc**
       -_readipifc(char *file, Ipifc **l, int index)
       -{
       -        int i, n, fd, lines;
       -        char buf[4*1024];
       -        char *line[32];
       -        char *f[64];
       -        Ipifc *ifc;
       -        Iplifc *lifc, **ll;
       -
       -        /* read the file */
       -        fd = open(file, OREAD);
       -        if(fd < 0)
       -                return l;
       -        n = 0;
       -        while((i = read(fd, buf+n, sizeof(buf)-1-n)) > 0 && n < sizeof(buf) - 1)
       -                n += i;
       -        buf[n] = 0;
       -        close(fd);
       -
       -        if(strncmp(buf, "device", 6) != 0)
       -                return _readoldipifc(buf, l, index);
       -
       -        /* allocate new interface */
       -        *l = ifc = mallocz(sizeof(Ipifc), 1);
       -        if(ifc == nil)
       -                return l;
       -        l = &ifc->next;
       -        ifc->index = index;
       -
       -        lines = getfields(buf, line, nelem(line), 1, "\n");
       -
       -        /* pick off device specific info(first line) */
       -        n = tokenize(line[0], f, nelem(f));
       -        strncpy(ifc->dev, findfield("device", f, n), sizeof(ifc->dev));
       -        ifc->dev[sizeof(ifc->dev)-1] = 0;
       -        if(ifc->dev[0] == 0){
       -                free(ifc);
       -                return l;
       -        }
       -        ifc->mtu = strtoul(findfield("maxmtu", f, n), nil, 10);
       -        ifc->sendra6 = atoi(findfield("sendra", f, n));
       -        ifc->recvra6 = atoi(findfield("recvra", f, n));
       -        ifc->rp.mflag = atoi(findfield("mflag", f, n));
       -        ifc->rp.oflag = atoi(findfield("oflag", f, n));
       -        ifc->rp.maxraint = atoi(findfield("maxraint", f, n));
       -        ifc->rp.minraint = atoi(findfield("minraint", f, n));
       -        ifc->rp.linkmtu = atoi(findfield("linkmtu", f, n));
       -        ifc->rp.reachtime = atoi(findfield("reachtime", f, n));
       -        ifc->rp.rxmitra = atoi(findfield("rxmitra", f, n));
       -        ifc->rp.ttl = atoi(findfield("ttl", f, n));
       -        ifc->rp.routerlt = atoi(findfield("routerlt", f, n));
       -        ifc->pktin = strtoul(findfield("pktin", f, n), nil, 10);
       -        ifc->pktout = strtoul(findfield("pktout", f, n), nil, 10);
       -        ifc->errin = strtoul(findfield("errin", f, n), nil, 10);
       -        ifc->errout = strtoul(findfield("errout", f, n), nil, 10);
       -        
       -        /* now read the addresses */
       -        ll = &ifc->lifc;
       -        for(i = 1; i < lines; i++){
       -                n = tokenize(line[i], f, nelem(f));
       -                if(n < 5)
       -                        break;
       -
       -                /* allocate new local address */
       -                *ll = lifc = mallocz(sizeof(Iplifc), 1);
       -                ll = &lifc->next;
       -
       -                parseip(lifc->ip, f[0]);
       -                parseipmask(lifc->mask, f[1]);
       -                parseip(lifc->net, f[2]);
       -
       -                lifc->validlt = strtoul(f[3], nil, 10);
       -                lifc->preflt = strtoul(f[4], nil, 10);
       -        }
       -
       -        return l;
       -}
       -
       -static void
       -_freeifc(Ipifc *ifc)
       -{
       -        Ipifc *next;
       -        Iplifc *lnext, *lifc;
       -
       -        if(ifc == nil)
       -                return;
       -        for(; ifc; ifc = next){
       -                next = ifc->next;
       -                for(lifc = ifc->lifc; lifc; lifc = lnext){
       -                        lnext = lifc->next;
       -                        free(lifc);
       -                }
       -                free(ifc);
       -        }
       -}
       -
       -Ipifc*
       -readipifc(char *net, Ipifc *ifc, int index)
       -{
       -        int fd, i, n;
       -        Dir *dir;
       -        char directory[128];
       -        char buf[128];
       -        Ipifc **l;
       -
       -        _freeifc(ifc);
       -
       -        l = &ifc;
       -        ifc = nil;
       -
       -        if(net == 0)
       -                net = "/net";
       -        snprint(directory, sizeof(directory), "%s/ipifc", net);
       -
       -        if(index >= 0){
       -                snprint(buf, sizeof(buf), "%s/%d/status", directory, index);
       -                _readipifc(buf, l, index);
       -        } else {
       -                fd = open(directory, OREAD);
       -                if(fd < 0)
       -                        return nil;
       -                n = dirreadall(fd, &dir);
       -                close(fd);
       -        
       -                for(i = 0; i < n; i++){
       -                        if(strcmp(dir[i].name, "clone") == 0)
       -                                continue;
       -                        if(strcmp(dir[i].name, "stats") == 0)
       -                                continue;
       -                        snprint(buf, sizeof(buf), "%s/%s/status", directory, dir[i].name);
       -                        l = _readipifc(buf, l, atoi(dir[i].name));
       -                }
       -                free(dir);
       -        }
       -
       -        return ifc;
       -}