summaryrefslogtreecommitdiff
path: root/sys/src/libip
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libip
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libip')
-rwxr-xr-xsys/src/libip/bo.c77
-rwxr-xr-xsys/src/libip/classmask.c86
-rwxr-xr-xsys/src/libip/eipfmt.c109
-rwxr-xr-xsys/src/libip/equivip.c25
-rwxr-xr-xsys/src/libip/ipaux.c102
-rwxr-xr-xsys/src/libip/mkfile26
-rwxr-xr-xsys/src/libip/myetheraddr.c28
-rwxr-xr-xsys/src/libip/myipaddr.c42
-rwxr-xr-xsys/src/libip/parseether.c25
-rwxr-xr-xsys/src/libip/parseip.c184
-rwxr-xr-xsys/src/libip/ptclbsum.c68
-rwxr-xr-xsys/src/libip/readipifc.c201
-rwxr-xr-xsys/src/libip/testreadipifc.c21
13 files changed, 994 insertions, 0 deletions
diff --git a/sys/src/libip/bo.c b/sys/src/libip/bo.c
new file mode 100755
index 000000000..95fc5f8de
--- /dev/null
+++ b/sys/src/libip/bo.c
@@ -0,0 +1,77 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+void
+hnputv(void *p, uvlong v)
+{
+ uchar *a;
+
+ a = p;
+ a[0] = v>>56;
+ a[1] = v>>48;
+ a[2] = v>>40;
+ a[3] = v>>32;
+ a[4] = v>>24;
+ a[5] = v>>16;
+ a[6] = v>>8;
+ a[7] = v;
+}
+
+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;
+}
+
+uvlong
+nhgetv(void *p)
+{
+ uchar *a;
+ uvlong v;
+
+ a = p;
+ v = (uvlong)a[0]<<56;
+ v |= (uvlong)a[1]<<48;
+ v |= (uvlong)a[2]<<40;
+ v |= (uvlong)a[3]<<32;
+ v |= a[4]<<24;
+ v |= a[5]<<16;
+ v |= a[6]<<8;
+ v |= a[7]<<0;
+ return 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);
+}
diff --git a/sys/src/libip/classmask.c b/sys/src/libip/classmask.c
new file mode 100755
index 000000000..1e41681f4
--- /dev/null
+++ b/sys/src/libip/classmask.c
@@ -0,0 +1,86 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+static 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,
+};
+
+static uchar v6loopback[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x01
+};
+
+static uchar v6linklocal[IPaddrlen] = {
+ 0xfe, 0x80, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+static uchar v6linklocalmask[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+static int v6llpreflen = 8; /* link-local prefix length in bytes */
+
+static uchar v6multicast[IPaddrlen] = {
+ 0xff, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+static uchar v6multicastmask[IPaddrlen] = {
+ 0xff, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+static int v6mcpreflen = 1; /* multicast prefix length */
+
+static uchar v6solicitednode[IPaddrlen] = {
+ 0xff, 0x02, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x01,
+ 0xff, 0, 0, 0
+};
+static uchar v6solicitednodemask[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0, 0x0, 0x0
+};
+static int v6snpreflen = 13;
+
+uchar*
+defmask(uchar *ip)
+{
+ if(isv4(ip))
+ return classmask[ip[IPv4off]>>6];
+ else {
+ if(ipcmp(ip, v6loopback) == 0)
+ return IPallbits;
+ else if(memcmp(ip, v6linklocal, v6llpreflen) == 0)
+ return v6linklocalmask;
+ else if(memcmp(ip, v6solicitednode, v6snpreflen) == 0)
+ return v6solicitednodemask;
+ else if(memcmp(ip, v6multicast, v6mcpreflen) == 0)
+ return v6multicastmask;
+ return IPallbits;
+ }
+}
+
+void
+maskip(uchar *from, uchar *mask, uchar *to)
+{
+ int i;
+
+ for(i = 0; i < IPaddrlen; i++)
+ to[i] = from[i] & mask[i];
+}
diff --git a/sys/src/libip/eipfmt.c b/sys/src/libip/eipfmt.c
new file mode 100755
index 000000000..ee04c5de8
--- /dev/null
+++ b/sys/src/libip/eipfmt.c
@@ -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 = "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux";
+ 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)");
+}
diff --git a/sys/src/libip/equivip.c b/sys/src/libip/equivip.c
new file mode 100755
index 000000000..020da8e65
--- /dev/null
+++ b/sys/src/libip/equivip.c
@@ -0,0 +1,25 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+int
+equivip4(uchar *a, uchar *b)
+{
+ int i;
+
+ for(i = 0; i < 4; i++)
+ if(a[i] != b[i])
+ return 0;
+ return 1;
+}
+
+int
+equivip6(uchar *a, uchar *b)
+{
+ int i;
+
+ for(i = 0; i < IPaddrlen; i++)
+ if(a[i] != b[i])
+ return 0;
+ return 1;
+}
diff --git a/sys/src/libip/ipaux.c b/sys/src/libip/ipaux.c
new file mode 100755
index 000000000..215b37ee9
--- /dev/null
+++ b/sys/src/libip/ipaux.c
@@ -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;
+ }
+}
diff --git a/sys/src/libip/mkfile b/sys/src/libip/mkfile
new file mode 100755
index 000000000..5a63a01a7
--- /dev/null
+++ b/sys/src/libip/mkfile
@@ -0,0 +1,26 @@
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libip.a
+OFILES=\
+ eipfmt.$O\
+ equivip.$O\
+ parseip.$O\
+ parseether.$O\
+ myetheraddr.$O\
+ myipaddr.$O\
+ classmask.$O\
+ bo.$O\
+ readipifc.$O\
+ ipaux.$O\
+ ptclbsum.$O\
+
+HFILES=\
+ /sys/include/ip.h
+
+UPDATE=\
+ mkfile\
+ $HFILES\
+ ${OFILES:%.$O=%.c}\
+ ${LIB:/$objtype/%=/386/%}\
+
+</sys/src/cmd/mksyslib
diff --git a/sys/src/libip/myetheraddr.c b/sys/src/libip/myetheraddr.c
new file mode 100755
index 000000000..34506fa06
--- /dev/null
+++ b/sys/src/libip/myetheraddr.c
@@ -0,0 +1,28 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+int
+myetheraddr(uchar *to, char *dev)
+{
+ int n, fd;
+ char buf[256];
+
+ if(*dev == '/')
+ sprint(buf, "%s/addr", dev);
+ else
+ sprint(buf, "/net/%s/addr", 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;
+
+ parseether(to, buf);
+ return 0;
+}
diff --git a/sys/src/libip/myipaddr.c b/sys/src/libip/myipaddr.c
new file mode 100755
index 000000000..e1a2773bd
--- /dev/null
+++ b/sys/src/libip/myipaddr.c
@@ -0,0 +1,42 @@
+#include <u.h>
+#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;
+ uchar mynet[IPaddrlen];
+
+ ifc = readipifc(net, ifc, -1);
+ for(nifc = ifc; nifc; nifc = nifc->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);
+ return 0;
+ }
+ }
+ ipmove(ip, IPnoaddr);
+ return -1;
+}
diff --git a/sys/src/libip/parseether.c b/sys/src/libip/parseether.c
new file mode 100755
index 000000000..f199eb6f1
--- /dev/null
+++ b/sys/src/libip/parseether.c
@@ -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;
+}
diff --git a/sys/src/libip/parseip.c b/sys/src/libip/parseip.c
new file mode 100755
index 000000000..7856b4a6c
--- /dev/null
+++ b/sys/src/libip/parseip.c
@@ -0,0 +1,184 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.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;
+}
+
+static int
+ipcharok(int c)
+{
+ return c == '.' || c == ':' || isascii(c) && isxdigit(c);
+}
+
+static int
+delimchar(int c)
+{
+ if(c == '\0')
+ return 1;
+ if(c == '.' || c == ':' || isascii(c) && isalnum(c))
+ return 0;
+ return 1;
+}
+
+/*
+ * `from' may contain an address followed by other characters,
+ * at least in /boot, so we permit whitespace (and more) after the address.
+ * we do ensure that "delete" cannot be parsed as "de::".
+ *
+ * some callers don't check the return value for errors, so
+ * set `to' to something distinctive in the case of a parse error.
+ */
+vlong
+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 < IPaddrlen && ipcharok(*p); i+=2){
+ op = p;
+ x = strtoul(p, &p, 16);
+ if(*p == '.' || (*p == 0 && i == 0)){ /* ends with v4? */
+ p = v4parseip(to+i, op);
+ i += 4;
+ break;
+ }
+ /* v6: at most 4 hex digits, followed by colon or delim */
+ if(x != (ushort)x || *p != ':' && !delimchar(*p)) {
+ memset(to, 0, IPaddrlen);
+ return -1; /* parse error */
+ }
+ to[i] = x>>8;
+ to[i+1] = x;
+ if(*p == ':'){
+ v4 = 0;
+ if(*++p == ':'){ /* :: is elided zero short(s) */
+ if (elipsis) {
+ memset(to, 0, IPaddrlen);
+ return -1; /* second :: */
+ }
+ elipsis = i+2;
+ p++;
+ }
+ } else if (p == op) /* strtoul made no progress? */
+ break;
+ }
+ if (p == from || !delimchar(*p)) {
+ memset(to, 0, IPaddrlen);
+ return -1; /* parse error */
+ }
+ if(i < IPaddrlen){
+ memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis);
+ memset(&to[elipsis], 0, IPaddrlen-i);
+ }
+ if(v4){
+ to[10] = to[11] = 0xff;
+ return nhgetl(to + IPv4off);
+ } else
+ return 6;
+}
+
+/*
+ * hack to allow ip v4 masks to be entered in the old
+ * style
+ */
+vlong
+parseipmask(uchar *to, char *from)
+{
+ int i, w;
+ vlong x;
+ uchar *p;
+
+ if(*from == '/'){
+ /* as a number of prefix bits */
+ i = atoi(from+1);
+ if(i < 0)
+ i = 0;
+ if(i > 128)
+ i = 128;
+ w = i;
+ 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);
+ /*
+ * identify as ipv6 if the mask is inexpressible as a v4 mask
+ * (because it has too few mask bits). Arguably, we could
+ * always return 6 here.
+ */
+ if (w < 8*(IPaddrlen-IPv4addrlen))
+ return 6;
+ } else {
+ /* as a straight v4 bit mask */
+ x = parseip(to, from);
+ if (x != -1)
+ x = (ulong)nhgetl(to + IPv4off);
+ 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;
+}
diff --git a/sys/src/libip/ptclbsum.c b/sys/src/libip/ptclbsum.c
new file mode 100755
index 000000000..b3dcb5359
--- /dev/null
+++ b/sys/src/libip/ptclbsum.c
@@ -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((uintptr)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;
+}
diff --git a/sys/src/libip/readipifc.c b/sys/src/libip/readipifc.c
new file mode 100755
index 000000000..8169a14eb
--- /dev/null
+++ b/sys/src/libip/readipifc.c
@@ -0,0 +1,201 @@
+#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, **l0;
+ 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);
+ /* ignore ifcs with no associated device */
+ if(strncmp(buf+6, " ", 2) == 0)
+ return l;
+ /* allocate new interface */
+ *l = ifc = mallocz(sizeof(Ipifc), 1);
+ if(ifc == nil)
+ return l;
+ l0 = 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));
+ if(n%2 != 0)
+ goto lose;
+ strncpy(ifc->dev, findfield("device", f, n), sizeof(ifc->dev));
+ ifc->dev[sizeof(ifc->dev)-1] = 0;
+ if(ifc->dev[0] == 0){
+lose:
+ free(ifc);
+ *l0 = nil;
+ return l;
+ }
+ ifc->mtu = strtoul(findfield("maxtu", 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;
+}
diff --git a/sys/src/libip/testreadipifc.c b/sys/src/libip/testreadipifc.c
new file mode 100755
index 000000000..aa57120c8
--- /dev/null
+++ b/sys/src/libip/testreadipifc.c
@@ -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);
+ }
+}