tadd libip - 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 d7094239263eac816ebb3af32641079b7924c666
 (DIR) parent 99947423b136903263513b9022aab6586c8c6cc5
 (HTM) Author: rsc <devnull@localhost>
       Date:   Sun, 23 Nov 2003 18:23:20 +0000
       
       add libip
       
       Diffstat:
         A src/libip/bo.c                      |      44 +++++++++++++++++++++++++++++++
         A src/libip/classmask.c               |      25 +++++++++++++++++++++++++
         A src/libip/eipfmt.c                  |     109 +++++++++++++++++++++++++++++++
         A src/libip/equivip.c                 |      13 +++++++++++++
         A src/libip/ip.h                      |      77 +++++++++++++++++++++++++++++++
         A src/libip/ipaux.c                   |     102 +++++++++++++++++++++++++++++++
         A src/libip/myetheraddr.c             |      41 +++++++++++++++++++++++++++++++
         A src/libip/myipaddr.c                |      21 +++++++++++++++++++++
         A src/libip/parseether.c              |      25 +++++++++++++++++++++++++
         A src/libip/parseip.c                 |     135 +++++++++++++++++++++++++++++++
         A src/libip/ptclbsum.c                |      68 +++++++++++++++++++++++++++++++
         A src/libip/readipifc.c               |     194 ++++++++++++++++++++++++++++++
         A src/libip/testreadipifc.c           |      21 +++++++++++++++++++++
       
       13 files changed, 875 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/libip/bo.c b/src/libip/bo.c
       t@@ -0,0 +1,44 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +
       +void
       +hnputl(void *p, uint v)
       +{
       +        uchar *a;
       +
       +        a = p;
       +        a[0] = v>>24;
       +        a[1] = v>>16;
       +        a[2] = v>>8;
       +        a[3] = v;
       +}
       +
       +void
       +hnputs(void *p, ushort v)
       +{
       +        uchar *a;
       +
       +        a = p;
       +        a[0] = v>>8;
       +        a[1] = v;
       +}
       +
       +uint
       +nhgetl(void *p)
       +{
       +        uchar *a;
       +
       +        a = p;
       +        return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
       +}
       +
       +ushort
       +nhgets(void *p)
       +{
       +        uchar *a;
       +
       +        a = p;
       +        return (a[0]<<8)|(a[1]<<0);
       +}
 (DIR) diff --git a/src/libip/classmask.c b/src/libip/classmask.c
       t@@ -0,0 +1,25 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +uchar classmask[4][16] = {
       +        0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0x00,0x00,0x00,
       +        0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0x00,0x00,0x00,
       +        0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0x00,0x00,
       +        0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0x00,
       +};
       +
       +uchar*
       +defmask(uchar *ip)
       +{
       +        return classmask[ip[IPv4off]>>6];
       +}
       +
       +void
       +maskip(uchar *from, uchar *mask, uchar *to)
       +{
       +        int i;
       +
       +        for(i = 0; i < IPaddrlen; i++)
       +                to[i] = from[i] & mask[i];
       +}
 (DIR) diff --git a/src/libip/eipfmt.c b/src/libip/eipfmt.c
       t@@ -0,0 +1,109 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +enum
       +{
       +        Isprefix= 16,
       +};
       +
       +uchar prefixvals[256] =
       +{
       +[0x00] 0 | Isprefix,
       +[0x80] 1 | Isprefix,
       +[0xC0] 2 | Isprefix,
       +[0xE0] 3 | Isprefix,
       +[0xF0] 4 | Isprefix,
       +[0xF8] 5 | Isprefix,
       +[0xFC] 6 | Isprefix,
       +[0xFE] 7 | Isprefix,
       +[0xFF] 8 | Isprefix,
       +};
       +
       +int
       +eipfmt(Fmt *f)
       +{
       +        char buf[5*8];
       +        static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
       +        static char *ifmt = "%d.%d.%d.%d";
       +        uchar *p, ip[16];
       +        ulong *lp;
       +        ushort s;
       +        int i, j, n, eln, eli;
       +
       +        switch(f->r) {
       +        case 'E':                /* Ethernet address */
       +                p = va_arg(f->args, uchar*);
       +                snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
       +                return fmtstrcpy(f, buf);
       +
       +        case 'I':                /* Ip address */
       +                p = va_arg(f->args, uchar*);
       +common:
       +                if(memcmp(p, v4prefix, 12) == 0){
       +                        snprint(buf, sizeof buf, ifmt, p[12], p[13], p[14], p[15]);
       +                        return fmtstrcpy(f, buf);
       +                }
       +
       +                /* find longest elision */
       +                eln = eli = -1;
       +                for(i = 0; i < 16; i += 2){
       +                        for(j = i; j < 16; j += 2)
       +                                if(p[j] != 0 || p[j+1] != 0)
       +                                        break;
       +                        if(j > i && j - i > eln){
       +                                eli = i;
       +                                eln = j - i;
       +                        }
       +                }
       +
       +                /* print with possible elision */
       +                n = 0;
       +                for(i = 0; i < 16; i += 2){
       +                        if(i == eli){
       +                                n += sprint(buf+n, "::");
       +                                i += eln;
       +                                if(i >= 16)
       +                                        break;
       +                        } else if(i != 0)
       +                                n += sprint(buf+n, ":");
       +                        s = (p[i]<<8) + p[i+1];
       +                        n += sprint(buf+n, "%ux", s);
       +                }
       +                return fmtstrcpy(f, buf);
       +
       +        case 'i':                /* v6 address as 4 longs */
       +                lp = va_arg(f->args, ulong*);
       +                for(i = 0; i < 4; i++)
       +                        hnputl(ip+4*i, *lp++);
       +                p = ip;
       +                goto common;
       +
       +        case 'V':                /* v4 ip address */
       +                p = va_arg(f->args, uchar*);
       +                snprint(buf, sizeof buf, ifmt, p[0], p[1], p[2], p[3]);
       +                return fmtstrcpy(f, buf);
       +
       +        case 'M':                /* ip mask */
       +                p = va_arg(f->args, uchar*);
       +
       +                /* look for a prefix mask */
       +                for(i = 0; i < 16; i++)
       +                        if(p[i] != 0xff)
       +                                break;
       +                if(i < 16){
       +                        if((prefixvals[p[i]] & Isprefix) == 0)
       +                                goto common;
       +                        for(j = i+1; j < 16; j++)
       +                                if(p[j] != 0)
       +                                        goto common;
       +                        n = 8*i + (prefixvals[p[i]] & ~Isprefix);
       +                } else
       +                        n = 8*16;
       +
       +                /* got one, use /xx format */
       +                snprint(buf, sizeof buf, "/%d", n);
       +                return fmtstrcpy(f, buf);
       +        }
       +        return fmtstrcpy(f, "(eipfmt)");
       +}
 (DIR) diff --git a/src/libip/equivip.c b/src/libip/equivip.c
       t@@ -0,0 +1,13 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +equivip(uchar *a, uchar *b)
       +{
       +        int i;
       +
       +        for(i = 0; i < 4; i++)
       +                if(a[i] != b[i])
       +                        return 0;
       +        return 1;
       +}
 (DIR) diff --git a/src/libip/ip.h b/src/libip/ip.h
       t@@ -0,0 +1,77 @@
       +#pragma        src        "/sys/src/libip"
       +#pragma        lib        "libip.a"
       +
       +enum 
       +{
       +        IPaddrlen=        16,
       +        IPv4addrlen=        4,
       +        IPv4off=        12,
       +        IPllen=                4,
       +};
       +
       +/*
       + *  for reading /net/ipifc
       + */
       +typedef struct Ipifc Ipifc;
       +typedef struct Ipifcs Ipifcs;
       +
       +struct Ipifc
       +{
       +        char        dev[64];
       +        uchar        ip[IPaddrlen];
       +        uchar        mask[IPaddrlen];
       +        uchar        net[IPaddrlen];                /* ip & mask */
       +        Ipifc        *next;
       +};
       +
       +struct Ipifcs
       +{
       +        Ipifc *first;
       +        Ipifc *last;
       +};
       +
       +/*
       + *  user level udp headers
       + */
       +enum 
       +{
       +        Udphdrsize=        36,        /* size of a Udphdr */
       +};
       +
       +typedef struct Udphdr Udphdr;
       +struct Udphdr
       +{
       +        uchar        raddr[IPaddrlen];        /* remote address and port */
       +        uchar        laddr[IPaddrlen];        /* local address and port */
       +        uchar        rport[2];
       +        uchar        lport[2];
       +};
       +
       +uchar*        defmask(uchar*);
       +void        maskip(uchar*, uchar*, uchar*);
       +int        eipconv(va_list*, Fconv*);
       +ulong        parseip(uchar*, char*);
       +ulong        parseipmask(uchar*, char*);
       +int        parseether(uchar*, char*);
       +int        myipaddr(uchar*, char*);
       +int        myetheraddr(uchar*, char*);
       +
       +void        readipifc(char*, Ipifcs*);
       +
       +void        hnputl(void*, uint);
       +void        hnputs(void*, ushort);
       +uint        nhgetl(void*);
       +ushort        nhgets(void*);
       +
       +#define        ipcmp(x, y) memcmp(x, y, IPaddrlen)
       +#define        ipmove(x, y) memmove(x, y, IPaddrlen)
       +
       +extern uchar IPv4bcast[IPaddrlen];
       +extern uchar IPv4bcastobs[IPaddrlen];
       +extern uchar IPv4allsys[IPaddrlen];
       +extern uchar IPv4allrouter[IPaddrlen];
       +extern uchar IPnoaddr[IPaddrlen];
       +extern uchar v4prefix[IPaddrlen];
       +extern uchar IPallbits[IPaddrlen];
       +
       +#define CLASS(p) ((*(uchar*)(p))>>6)
 (DIR) diff --git a/src/libip/ipaux.c b/src/libip/ipaux.c
       t@@ -0,0 +1,102 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +/*
       + *  well known IP addresses
       + */
       +uchar IPv4bcast[IPaddrlen] = {
       +        0, 0, 0, 0,
       +        0, 0, 0, 0,
       +        0, 0, 0xff, 0xff,
       +        0xff, 0xff, 0xff, 0xff
       +};
       +uchar IPv4allsys[IPaddrlen] = {
       +        0, 0, 0, 0,
       +        0, 0, 0, 0,
       +        0, 0, 0xff, 0xff,
       +        0xe0, 0, 0, 0x01
       +};
       +uchar IPv4allrouter[IPaddrlen] = {
       +        0, 0, 0, 0,
       +        0, 0, 0, 0,
       +        0, 0, 0xff, 0xff,
       +        0xe0, 0, 0, 0x02
       +};
       +uchar IPallbits[IPaddrlen] = {
       +        0xff, 0xff, 0xff, 0xff,
       +        0xff, 0xff, 0xff, 0xff,
       +        0xff, 0xff, 0xff, 0xff,
       +        0xff, 0xff, 0xff, 0xff
       +};
       +uchar IPnoaddr[IPaddrlen];
       +
       +/*
       + *  prefix of all v4 addresses
       + */
       +uchar v4prefix[IPaddrlen] = {
       +        0, 0, 0, 0,
       +        0, 0, 0, 0,
       +        0, 0, 0xff, 0xff,
       +        0, 0, 0, 0
       +};
       +
       +int
       +isv4(uchar *ip)
       +{
       +        return memcmp(ip, v4prefix, IPv4off) == 0;
       +}
       +
       +/*
       + *  the following routines are unrolled with no memset's to speed
       + *  up the usual case
       + */
       +void
       +v4tov6(uchar *v6, uchar *v4)
       +{
       +        v6[0] = 0;
       +        v6[1] = 0;
       +        v6[2] = 0;
       +        v6[3] = 0;
       +        v6[4] = 0;
       +        v6[5] = 0;
       +        v6[6] = 0;
       +        v6[7] = 0;
       +        v6[8] = 0;
       +        v6[9] = 0;
       +        v6[10] = 0xff;
       +        v6[11] = 0xff;
       +        v6[12] = v4[0];
       +        v6[13] = v4[1];
       +        v6[14] = v4[2];
       +        v6[15] = v4[3];
       +}
       +
       +int
       +v6tov4(uchar *v4, uchar *v6)
       +{
       +        if(v6[0] == 0
       +        && v6[1] == 0
       +        && v6[2] == 0
       +        && v6[3] == 0
       +        && v6[4] == 0
       +        && v6[5] == 0
       +        && v6[6] == 0
       +        && v6[7] == 0
       +        && v6[8] == 0
       +        && v6[9] == 0
       +        && v6[10] == 0xff
       +        && v6[11] == 0xff)
       +        {
       +                v4[0] = v6[12];
       +                v4[1] = v6[13];
       +                v4[2] = v6[14];
       +                v4[3] = v6[15];
       +                return 0;
       +        } else {
       +                memset(v4, 0, 4);
       +                if(memcmp(v6, IPnoaddr, IPaddrlen) == 0)
       +                        return 0;
       +                return -1;
       +        }
       +}
 (DIR) diff --git a/src/libip/myetheraddr.c b/src/libip/myetheraddr.c
       t@@ -0,0 +1,41 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +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;
       +}
 (DIR) diff --git a/src/libip/myipaddr.c b/src/libip/myipaddr.c
       t@@ -0,0 +1,21 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +int
       +myipaddr(uchar *ip, char *net)
       +{
       +        Ipifc *nifc;
       +        Iplifc *lifc;
       +        static Ipifc *ifc;
       +
       +        ifc = readipifc(net, ifc, -1);
       +        for(nifc = ifc; nifc; nifc = nifc->next)
       +                for(lifc = nifc->lifc; lifc; lifc = lifc->next)
       +                        if(ipcmp(lifc->ip, IPnoaddr) != 0){
       +                                ipmove(ip, lifc->ip);
       +                                return 0;
       +                        }
       +        ipmove(ip, IPnoaddr);
       +        return -1;
       +}
 (DIR) diff --git a/src/libip/parseether.c b/src/libip/parseether.c
       t@@ -0,0 +1,25 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +int
       +parseether(uchar *to, char *from)
       +{
       +        char nip[4];
       +        char *p;
       +        int i;
       +
       +        p = from;
       +        for(i = 0; i < 6; i++){
       +                if(*p == 0)
       +                        return -1;
       +                nip[0] = *p++;
       +                if(*p == 0)
       +                        return -1;
       +                nip[1] = *p++;
       +                nip[2] = 0;
       +                to[i] = strtoul(nip, 0, 16);
       +                if(*p == ':')
       +                        p++;
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/libip/parseip.c b/src/libip/parseip.c
       t@@ -0,0 +1,135 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +char*
       +v4parseip(uchar *to, char *from)
       +{
       +        int i;
       +        char *p;
       +
       +        p = from;
       +        for(i = 0; i < 4 && *p; i++){
       +                to[i] = strtoul(p, &p, 0);
       +                if(*p == '.')
       +                        p++;
       +        }
       +        switch(CLASS(to)){
       +        case 0:        /* class A - 1 uchar net */
       +        case 1:
       +                if(i == 3){
       +                        to[3] = to[2];
       +                        to[2] = to[1];
       +                        to[1] = 0;
       +                } else if (i == 2){
       +                        to[3] = to[1];
       +                        to[1] = 0;
       +                }
       +                break;
       +        case 2:        /* class B - 2 uchar net */
       +                if(i == 3){
       +                        to[3] = to[2];
       +                        to[2] = 0;
       +                }
       +                break;
       +        }
       +        return p;
       +}
       +
       +ulong
       +parseip(uchar *to, char *from)
       +{
       +        int i, elipsis = 0, v4 = 1;
       +        ulong x;
       +        char *p, *op;
       +
       +        memset(to, 0, IPaddrlen);
       +        p = from;
       +        for(i = 0; i < 16 && *p; i+=2){
       +                op = p;
       +                x = strtoul(p, &p, 16);
       +                if(*p == '.' || (*p == 0 && i == 0)){
       +                        p = v4parseip(to+i, op);
       +                        i += 4;
       +                        break;
       +                }
       +                to[i] = x>>8;
       +                to[i+1] = x;
       +                if(*p == ':'){
       +                        v4 = 0;
       +                        if(*++p == ':'){
       +                                elipsis = i+2;
       +                                p++;
       +                        }
       +                }
       +        }
       +        if(i < 16){
       +                memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
       +                memset(&to[elipsis], 0, 16-i);
       +        }
       +        if(v4){
       +                to[10] = to[11] = 0xff;
       +                return nhgetl(to+12);
       +        } else
       +                return 6;
       +}
       +
       +/*
       + *  hack to allow ip v4 masks to be entered in the old
       + *  style
       + */
       +ulong
       +parseipmask(uchar *to, char *from)
       +{
       +        ulong x;
       +        int i;
       +        uchar *p;
       +
       +        if(*from == '/'){
       +                /* as a number of prefix bits */
       +                i = atoi(from+1);
       +                if(i < 0)
       +                        i = 0;
       +                if(i > 128)
       +                        i = 128;
       +                memset(to, 0, IPaddrlen);
       +                for(p = to; i >= 8; i -= 8)
       +                        *p++ = 0xff;
       +                if(i > 0)
       +                        *p = ~((1<<(8-i))-1);
       +                x = nhgetl(to+IPv4off);
       +        } else {
       +                /* as a straight bit mask */
       +                x = parseip(to, from);
       +                if(memcmp(to, v4prefix, IPv4off) == 0)
       +                        memset(to, 0xff, IPv4off);
       +        }
       +        return x;
       +}
       +
       +/*
       + *  parse a v4 ip address/mask in cidr format
       + */
       +char*
       +v4parsecidr(uchar *addr, uchar *mask, char *from)
       +{
       +        int i;
       +        char *p;
       +        uchar *a;
       +
       +        p = v4parseip(addr, from);
       +
       +        if(*p == '/'){
       +                /* as a number of prefix bits */
       +                i = strtoul(p+1, &p, 0);
       +                if(i > 32)
       +                        i = 32;
       +                memset(mask, 0, IPv4addrlen);
       +                for(a = mask; i >= 8; i -= 8)
       +                        *a++ = 0xff;
       +                if(i > 0)
       +                        *a = ~((1<<(8-i))-1);
       +        } else 
       +                memcpy(mask, defmask(addr), IPv4addrlen);
       +        return p;
       +}
 (DIR) diff --git a/src/libip/ptclbsum.c b/src/libip/ptclbsum.c
       t@@ -0,0 +1,68 @@
       +#include        <u.h>
       +#include        <libc.h>
       +#include        <ip.h>
       +
       +static        short        endian        = 1;
       +static        uchar*        aendian        = (uchar*)&endian;
       +#define        LITTLE        *aendian
       +
       +ushort
       +ptclbsum(uchar *addr, int len)
       +{
       +        ulong losum, hisum, mdsum, x;
       +        ulong t1, t2;
       +
       +        losum = 0;
       +        hisum = 0;
       +        mdsum = 0;
       +
       +        x = 0;
       +        if((ulong)addr & 1) {
       +                if(len) {
       +                        hisum += addr[0];
       +                        len--;
       +                        addr++;
       +                }
       +                x = 1;
       +        }
       +        while(len >= 16) {
       +                t1 = *(ushort*)(addr+0);
       +                t2 = *(ushort*)(addr+2);        mdsum += t1;
       +                t1 = *(ushort*)(addr+4);        mdsum += t2;
       +                t2 = *(ushort*)(addr+6);        mdsum += t1;
       +                t1 = *(ushort*)(addr+8);        mdsum += t2;
       +                t2 = *(ushort*)(addr+10);        mdsum += t1;
       +                t1 = *(ushort*)(addr+12);        mdsum += t2;
       +                t2 = *(ushort*)(addr+14);        mdsum += t1;
       +                mdsum += t2;
       +                len -= 16;
       +                addr += 16;
       +        }
       +        while(len >= 2) {
       +                mdsum += *(ushort*)addr;
       +                len -= 2;
       +                addr += 2;
       +        }
       +        if(x) {
       +                if(len)
       +                        losum += addr[0];
       +                if(LITTLE)
       +                        losum += mdsum;
       +                else
       +                        hisum += mdsum;
       +        } else {
       +                if(len)
       +                        hisum += addr[0];
       +                if(LITTLE)
       +                        hisum += mdsum;
       +                else
       +                        losum += mdsum;
       +        }
       +
       +        losum += hisum >> 8;
       +        losum += (hisum & 0xff) << 8;
       +        while(hisum = losum>>16)
       +                losum = hisum + (losum & 0xffff);
       +
       +        return losum & 0xffff;
       +}
 (DIR) diff --git a/src/libip/readipifc.c b/src/libip/readipifc.c
       t@@ -0,0 +1,194 @@
       +#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;
       +}
 (DIR) diff --git a/src/libip/testreadipifc.c b/src/libip/testreadipifc.c
       t@@ -0,0 +1,21 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <ip.h>
       +
       +void
       +main(void)
       +{
       +        Ipifc *ifc, *list;
       +        Iplifc *lifc;
       +        int i;
       +
       +        fmtinstall('I', eipfmt);
       +        fmtinstall('M', eipfmt);
       +
       +        list = readipifc("/net", nil, -1);
       +        for(ifc = list; ifc; ifc = ifc->next){
       +                print("ipifc %s %d\n", ifc->dev, ifc->mtu);
       +                for(lifc = ifc->lifc; lifc; lifc = lifc->next)
       +                        print("\t%I %M %I\n", lifc->ip, lifc->mask, lifc->net);
       +        }
       +}