Commit Diff


commit - 99947423b136903263513b9022aab6586c8c6cc5
commit + d7094239263eac816ebb3af32641079b7924c666
blob - /dev/null
blob + 54675d8cb7e0c51700c422cce7b0c6017c2d8ae4 (mode 644)
--- /dev/null
+++ src/libip/bo.c
@@ -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);
+}
blob - /dev/null
blob + 5932f878f0ed10027479542fbac99f6a88d22f34 (mode 644)
--- /dev/null
+++ src/libip/classmask.c
@@ -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];
+}
blob - /dev/null
blob + 8333225a5fa52e14630e47514a29ab26be06d132 (mode 644)
--- /dev/null
+++ 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 = "%.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)");
+}
blob - /dev/null
blob + 858bc1ca684a8d35e888578aa1df7c47764c19fb (mode 644)
--- /dev/null
+++ src/libip/equivip.c
@@ -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;
+}
blob - /dev/null
blob + aae565c0fc66ef9500b61fdfadc0810c2c4a28fd (mode 644)
--- /dev/null
+++ src/libip/ip.h
@@ -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)
blob - /dev/null
blob + 215b37ee94195b194df726d344a15902560fcb26 (mode 644)
--- /dev/null
+++ 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;
+	}
+}
blob - /dev/null
blob + d6995b7a0fa797cd5ce8c4b0b826c6b48d86e51a (mode 644)
--- /dev/null
+++ src/libip/myetheraddr.c
@@ -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;
+}
blob - /dev/null
blob + d9b692017ef9950cefd58f14c8959044e9625d9c (mode 644)
--- /dev/null
+++ src/libip/myipaddr.c
@@ -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;
+}
blob - /dev/null
blob + f199eb6f11cf7eb33aaad325143d69cbb71aba77 (mode 644)
--- /dev/null
+++ 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;
+}
blob - /dev/null
blob + c0dd55ccdc549f37abffb024b7926360873dbbe7 (mode 644)
--- /dev/null
+++ src/libip/parseip.c
@@ -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;
+}
blob - /dev/null
blob + d87815bce5fe02415748b98011da58bd533cb2a2 (mode 644)
--- /dev/null
+++ 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((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;
+}
blob - /dev/null
blob + b28b3b0cf7ad426450b0bf65bcf5298d34c5cb0d (mode 644)
--- /dev/null
+++ src/libip/readipifc.c
@@ -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;
+}
blob - /dev/null
blob + aa57120c8e938500322e8d07596ea6ade4bdbf8d (mode 644)
--- /dev/null
+++ 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);
+	}
+}