xref: /inferno-os/appl/lib/ip.b (revision 3293d1240801e46dd9cc27f6ba1133bc2b1d22e1)
137da2899SCharles.Forsythimplement IP;
237da2899SCharles.Forsyth
337da2899SCharles.Forsyth#
437da2899SCharles.Forsyth# Copyright © 2003,2004 Vita Nuova Holdings Limited.  All rights reserved.
537da2899SCharles.Forsyth#
637da2899SCharles.Forsyth
737da2899SCharles.Forsythinclude "sys.m";
837da2899SCharles.Forsyth	sys: Sys;
937da2899SCharles.Forsyth
1037da2899SCharles.Forsythinclude "ip.m";
1137da2899SCharles.Forsyth
1237da2899SCharles.Forsythinit()
1337da2899SCharles.Forsyth{
1437da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
1537da2899SCharles.Forsyth	v4prefix = array[] of {
1637da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
1737da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
1837da2899SCharles.Forsyth		byte 0, byte 0, byte 16rFF, byte 16rFF,
1937da2899SCharles.Forsyth	};
2037da2899SCharles.Forsyth
2137da2899SCharles.Forsyth	v4bcast = IPaddr(array[] of {
2237da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
2337da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
2437da2899SCharles.Forsyth		byte 0, byte 0, byte 16rFF, byte 16rFF,
2537da2899SCharles.Forsyth		byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF,
2637da2899SCharles.Forsyth	});
2737da2899SCharles.Forsyth
2837da2899SCharles.Forsyth	v4allsys = IPaddr(array[] of {
2937da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
3037da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
3137da2899SCharles.Forsyth		byte 0, byte 0, byte 16rFF, byte 16rFF,
3237da2899SCharles.Forsyth		byte 16rE0, byte 0, byte 0, byte 16r01,
3337da2899SCharles.Forsyth	});
3437da2899SCharles.Forsyth
3537da2899SCharles.Forsyth	v4allrouter = IPaddr(array[] of {
3637da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
3737da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
3837da2899SCharles.Forsyth		byte 0, byte 0, byte 16rFF, byte 16rFF,
3937da2899SCharles.Forsyth		byte 16rE0, byte 0, byte 0, byte 16r02,
4037da2899SCharles.Forsyth	});
4137da2899SCharles.Forsyth
4237da2899SCharles.Forsyth	v4noaddr = IPaddr(array[] of {
4337da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
4437da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
4537da2899SCharles.Forsyth		byte 0, byte 0, byte 16rFF, byte 16rFF,
4637da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
4737da2899SCharles.Forsyth	});
4837da2899SCharles.Forsyth
4937da2899SCharles.Forsyth	selfv6 = IPaddr(array[] of {
5037da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
5137da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
5237da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
5337da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 1,
5437da2899SCharles.Forsyth	});
5537da2899SCharles.Forsyth
5637da2899SCharles.Forsyth	selfv4 = IPaddr(array[] of {
5737da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
5837da2899SCharles.Forsyth		byte 0, byte 0, byte 0, byte 0,
5937da2899SCharles.Forsyth		byte 0, byte 0, byte 16rFF, byte 16rFF,
6037da2899SCharles.Forsyth		byte 127, byte 0, byte 0, byte 1,
6137da2899SCharles.Forsyth	});
6237da2899SCharles.Forsyth
6337da2899SCharles.Forsyth	noaddr = IPaddr(array[] of {0 to IPaddrlen-1 => byte 0});
6437da2899SCharles.Forsyth	allbits = IPaddr(array[] of {0 to IPaddrlen-1 => byte 16rFF});
6537da2899SCharles.Forsyth}
6637da2899SCharles.Forsyth
6737da2899SCharles.ForsythIPaddr.newv6(a: array of byte): IPaddr
6837da2899SCharles.Forsyth{
69*3293d124Sforsyth	b := array[IPaddrlen] of byte;
7037da2899SCharles.Forsyth	b[0:] = a[0:IPaddrlen];
7137da2899SCharles.Forsyth	return IPaddr(b);
7237da2899SCharles.Forsyth}
7337da2899SCharles.Forsyth
7437da2899SCharles.ForsythIPaddr.newv4(a: array of byte): IPaddr
7537da2899SCharles.Forsyth{
7637da2899SCharles.Forsyth	b := array[IPaddrlen] of byte;
7737da2899SCharles.Forsyth	b[0:] = v4prefix;
7837da2899SCharles.Forsyth	b[IPv4off:] = a[0:IPv4addrlen];
7937da2899SCharles.Forsyth	return IPaddr(b);
8037da2899SCharles.Forsyth}
8137da2899SCharles.Forsyth
8237da2899SCharles.ForsythIPaddr.copy(ip: self IPaddr): IPaddr
8337da2899SCharles.Forsyth{
8437da2899SCharles.Forsyth	if(ip.a == nil)
8537da2899SCharles.Forsyth		return noaddr.copy();
86*3293d124Sforsyth	a := array[IPaddrlen] of byte;
8737da2899SCharles.Forsyth	a[0:] = ip.a;
8837da2899SCharles.Forsyth	return IPaddr(a);
8937da2899SCharles.Forsyth}
9037da2899SCharles.Forsyth
9137da2899SCharles.ForsythIPaddr.eq(ip: self IPaddr, v: IPaddr): int
9237da2899SCharles.Forsyth{
9337da2899SCharles.Forsyth	a := ip.a;
9437da2899SCharles.Forsyth	if(a == nil)
9537da2899SCharles.Forsyth		a = noaddr.a;
9637da2899SCharles.Forsyth	b := v.a;
9737da2899SCharles.Forsyth	if(b == nil)
9837da2899SCharles.Forsyth		b = noaddr.a;
9937da2899SCharles.Forsyth	for(i := 0; i < IPaddrlen; i++)
10037da2899SCharles.Forsyth		if(a[i] != b[i])
10137da2899SCharles.Forsyth			return 0;
10237da2899SCharles.Forsyth	return 1;
10337da2899SCharles.Forsyth}
10437da2899SCharles.Forsyth
10537da2899SCharles.ForsythIPaddr.mask(a1: self IPaddr, a2: IPaddr): IPaddr
10637da2899SCharles.Forsyth{
10737da2899SCharles.Forsyth	c := array[IPaddrlen] of byte;
10837da2899SCharles.Forsyth	for(i := 0; i < IPaddrlen; i++)
10937da2899SCharles.Forsyth		c[i] = a1.a[i] & a2.a[i];
11037da2899SCharles.Forsyth	return IPaddr(c);
11137da2899SCharles.Forsyth}
11237da2899SCharles.Forsyth
11337da2899SCharles.ForsythIPaddr.maskn(a1: self IPaddr, a2: IPaddr): IPaddr
11437da2899SCharles.Forsyth{
11537da2899SCharles.Forsyth	c := array[IPaddrlen] of byte;
11637da2899SCharles.Forsyth	for(i := 0; i < IPaddrlen; i++)
11737da2899SCharles.Forsyth		c[i] = a1.a[i] & ~a2.a[i];
11837da2899SCharles.Forsyth	return IPaddr(c);
11937da2899SCharles.Forsyth}
12037da2899SCharles.Forsyth
12137da2899SCharles.ForsythIPaddr.isv4(ip: self IPaddr): int
12237da2899SCharles.Forsyth{
12337da2899SCharles.Forsyth	for(i := 0; i < IPv4off; i++)
12437da2899SCharles.Forsyth		if(ip.a[i] != v4prefix[i])
12537da2899SCharles.Forsyth			return 0;
12637da2899SCharles.Forsyth	return 1;
12737da2899SCharles.Forsyth}
12837da2899SCharles.Forsyth
12937da2899SCharles.ForsythIPaddr.ismulticast(ip: self IPaddr): int
13037da2899SCharles.Forsyth{
13137da2899SCharles.Forsyth	if(ip.isv4()){
13237da2899SCharles.Forsyth		v := int ip.a[IPv4off];
13337da2899SCharles.Forsyth		return v >= 16rE0 && v < 16rF0 || ip.eq(v4bcast);	# rfc1112
13437da2899SCharles.Forsyth	}
13537da2899SCharles.Forsyth	return ip.a[0] == byte 16rFF;
13637da2899SCharles.Forsyth}
13737da2899SCharles.Forsyth
13837da2899SCharles.ForsythIPaddr.isvalid(ip: self IPaddr): int
13937da2899SCharles.Forsyth{
14037da2899SCharles.Forsyth	return !ip.eq(noaddr) && !ip.eq(v4noaddr);
14137da2899SCharles.Forsyth}
14237da2899SCharles.Forsyth
14337da2899SCharles.ForsythIPaddr.v4(ip: self IPaddr): array of byte
14437da2899SCharles.Forsyth{
14537da2899SCharles.Forsyth	if(!ip.isv4() && !ip.eq(noaddr))
14637da2899SCharles.Forsyth		return nil;
14737da2899SCharles.Forsyth	a := array[4] of byte;
14837da2899SCharles.Forsyth	for(i := 0; i < 4; i++)
14937da2899SCharles.Forsyth		a[i] = ip.a[IPv4off+i];
15037da2899SCharles.Forsyth	return a;
15137da2899SCharles.Forsyth}
15237da2899SCharles.Forsyth
15337da2899SCharles.ForsythIPaddr.v6(ip: self IPaddr): array of byte
15437da2899SCharles.Forsyth{
15537da2899SCharles.Forsyth	a := array[IPaddrlen] of byte;
15637da2899SCharles.Forsyth	a[0:] = ip.a;
15737da2899SCharles.Forsyth	return a;
15837da2899SCharles.Forsyth}
15937da2899SCharles.Forsyth
16037da2899SCharles.ForsythIPaddr.class(ip: self IPaddr): int
16137da2899SCharles.Forsyth{
16237da2899SCharles.Forsyth	if(!ip.isv4())
16337da2899SCharles.Forsyth		return 6;
16437da2899SCharles.Forsyth	return int ip.a[IPv4off]>>6;
16537da2899SCharles.Forsyth}
16637da2899SCharles.Forsyth
16737da2899SCharles.ForsythIPaddr.classmask(ip: self IPaddr): IPaddr
16837da2899SCharles.Forsyth{
16937da2899SCharles.Forsyth	m := allbits.copy();
17037da2899SCharles.Forsyth	if(!ip.isv4())
17137da2899SCharles.Forsyth		return m;
17237da2899SCharles.Forsyth	if((n := ip.class()) == 0)
17337da2899SCharles.Forsyth		n = 1;
17437da2899SCharles.Forsyth	for(i := IPaddrlen-4+n; i < IPaddrlen; i++)
17537da2899SCharles.Forsyth		m.a[i] = byte 0;
17637da2899SCharles.Forsyth	return m;
17737da2899SCharles.Forsyth}
17837da2899SCharles.Forsyth
17937da2899SCharles.Forsyth#
18037da2899SCharles.Forsyth# rfc2373
18137da2899SCharles.Forsyth#
18237da2899SCharles.Forsyth
18337da2899SCharles.ForsythIPaddr.parse(s: string): (int, IPaddr)
18437da2899SCharles.Forsyth{
18537da2899SCharles.Forsyth	a := noaddr.copy();
18637da2899SCharles.Forsyth	col := 0;
18737da2899SCharles.Forsyth	gap := 0;
18837da2899SCharles.Forsyth	for(i:=0; i<IPaddrlen && s != ""; i+=2){
18937da2899SCharles.Forsyth		c := 'x';
19037da2899SCharles.Forsyth		v := 0;
19137da2899SCharles.Forsyth		for(m := 0; m < len s && (c = s[m]) != '.' && c != ':'; m++){
19237da2899SCharles.Forsyth			d := 0;
19337da2899SCharles.Forsyth			if(c >= '0' && c <= '9')
19437da2899SCharles.Forsyth				d = c-'0';
19537da2899SCharles.Forsyth			else if(c >= 'a' && c <= 'f')
19637da2899SCharles.Forsyth				d = c-'a'+10;
19737da2899SCharles.Forsyth			else if(c >= 'A' && c <= 'F')
19837da2899SCharles.Forsyth				d = c-'A'+10;
19937da2899SCharles.Forsyth			else
20037da2899SCharles.Forsyth				return (-1, a);
20137da2899SCharles.Forsyth			v = (v<<4) | d;
20237da2899SCharles.Forsyth		}
20337da2899SCharles.Forsyth		if(c == '.'){
20437da2899SCharles.Forsyth			if(parseipv4(a.a[i:], s) < 0)
20537da2899SCharles.Forsyth				return (-1, noaddr.copy());
20637da2899SCharles.Forsyth			i += IPv4addrlen;
20737da2899SCharles.Forsyth			break;
20837da2899SCharles.Forsyth		}
20937da2899SCharles.Forsyth		if(v > 16rFFFF)
21037da2899SCharles.Forsyth			return (-1, a);
21137da2899SCharles.Forsyth		a.a[i] = byte (v>>8);
21237da2899SCharles.Forsyth		a.a[i+1] = byte v;
21337da2899SCharles.Forsyth		if(c == ':'){
21437da2899SCharles.Forsyth			col = 1;
21537da2899SCharles.Forsyth			if(++m < len s && s[m] == ':'){
21637da2899SCharles.Forsyth				if(gap > 0)
21737da2899SCharles.Forsyth					return (-1, a);
21837da2899SCharles.Forsyth				gap = i+2;
21937da2899SCharles.Forsyth				m++;
22037da2899SCharles.Forsyth			}
22137da2899SCharles.Forsyth		}
22237da2899SCharles.Forsyth		s = s[m:];
22337da2899SCharles.Forsyth	}
22437da2899SCharles.Forsyth	if(i < IPaddrlen){	# mind the gap
22537da2899SCharles.Forsyth		ns := i-gap;
22637da2899SCharles.Forsyth		for(j := 1; j <= ns; j++){
22737da2899SCharles.Forsyth			a.a[IPaddrlen-j] = a.a[i-j];
22837da2899SCharles.Forsyth			a.a[i-j] = byte 0;
22937da2899SCharles.Forsyth		}
23037da2899SCharles.Forsyth	}
23137da2899SCharles.Forsyth	if(!col)
23237da2899SCharles.Forsyth		a.a[0:] = v4prefix;
23337da2899SCharles.Forsyth	return (0, IPaddr(a));
23437da2899SCharles.Forsyth}
23537da2899SCharles.Forsyth
23637da2899SCharles.ForsythIPaddr.parsemask(s: string): (int, IPaddr)
23737da2899SCharles.Forsyth{
23837da2899SCharles.Forsyth	return parsemask(s, 128);
23937da2899SCharles.Forsyth}
24037da2899SCharles.Forsyth
24137da2899SCharles.ForsythIPaddr.parsecidr(s: string): (int, IPaddr, IPaddr)
24237da2899SCharles.Forsyth{
24337da2899SCharles.Forsyth	for(i := 0; i < len s && s[i] != '/'; i++)
24437da2899SCharles.Forsyth		;
24537da2899SCharles.Forsyth	(ok, a) := IPaddr.parse(s[0:i]);
24637da2899SCharles.Forsyth	if(i < len s){
24737da2899SCharles.Forsyth		(ok2, m) := IPaddr.parsemask(s[i:]);
24837da2899SCharles.Forsyth		if(ok < 0 || ok2 < 0)
24937da2899SCharles.Forsyth			return (-1, a, m);
25037da2899SCharles.Forsyth		return (0, a, m);
25137da2899SCharles.Forsyth	}
25237da2899SCharles.Forsyth	return (ok, a, allbits.copy());
25337da2899SCharles.Forsyth}
25437da2899SCharles.Forsyth
25537da2899SCharles.Forsythparseipv4(b: array of byte, s: string): int
25637da2899SCharles.Forsyth{
25737da2899SCharles.Forsyth	a := array[4] of {* => 0};
25837da2899SCharles.Forsyth	o := 0;
25937da2899SCharles.Forsyth	for(i := 0; i < 4 && o < len s; i++){
26037da2899SCharles.Forsyth		for(m := o; m < len s && (c := s[m]) != '.'; m++)
26137da2899SCharles.Forsyth			if(!(c >= '0' && c <= '9'))
26237da2899SCharles.Forsyth				return -1;
26337da2899SCharles.Forsyth		if(m == o)
26437da2899SCharles.Forsyth			return -1;
26537da2899SCharles.Forsyth		a[i] = int big s[o:m];
26637da2899SCharles.Forsyth		b[i] = byte a[i];
26737da2899SCharles.Forsyth		if(m < len s && s[m] == '.')
26837da2899SCharles.Forsyth			m++;
26937da2899SCharles.Forsyth		o = m;
27037da2899SCharles.Forsyth	}
27137da2899SCharles.Forsyth	case i {
27237da2899SCharles.Forsyth	1 =>		# 32 bit
27337da2899SCharles.Forsyth		b[0] = byte (a[0] >> 24);
27437da2899SCharles.Forsyth		b[1] = byte (a[0] >> 16);
27537da2899SCharles.Forsyth		b[2] = byte (a[0] >> 8);
27637da2899SCharles.Forsyth		b[3] = byte a[0];
27737da2899SCharles.Forsyth	2 =>
27837da2899SCharles.Forsyth		if(a[0] < 256){	# 8/24
27937da2899SCharles.Forsyth			b[0] = byte a[0];
28037da2899SCharles.Forsyth			b[1] = byte (a[1]>>16);
28137da2899SCharles.Forsyth			b[2] = byte (a[1]>>8);
28237da2899SCharles.Forsyth		}else if(a[0] < 65536){	# 16/16
28337da2899SCharles.Forsyth			b[0] = byte (a[0]>>8);
28437da2899SCharles.Forsyth			b[1] = byte a[0];
28537da2899SCharles.Forsyth			b[2] = byte (a[1]>>16);
28637da2899SCharles.Forsyth		}else{	# 24/8
28737da2899SCharles.Forsyth			b[0] = byte (a[0]>>16);
28837da2899SCharles.Forsyth			b[1] = byte (a[0]>>8);
28937da2899SCharles.Forsyth			b[2] = byte a[0];
29037da2899SCharles.Forsyth		}
29137da2899SCharles.Forsyth		b[3] = byte a[1];
29237da2899SCharles.Forsyth	3 =>		# 8/8/16
29337da2899SCharles.Forsyth		b[0] = byte a[0];
29437da2899SCharles.Forsyth		b[1] = byte a[1];
29537da2899SCharles.Forsyth		b[2] = byte (a[2]>>16);
29637da2899SCharles.Forsyth		b[3] = byte a[2];
29737da2899SCharles.Forsyth	}
29837da2899SCharles.Forsyth	return 0;
29937da2899SCharles.Forsyth}
30037da2899SCharles.Forsyth
30137da2899SCharles.Forsythparsemask(s: string, abits: int): (int, IPaddr)
30237da2899SCharles.Forsyth{
30337da2899SCharles.Forsyth	m := allbits.copy();
30437da2899SCharles.Forsyth	if(s == nil)
30537da2899SCharles.Forsyth		return (0, m);
30637da2899SCharles.Forsyth	if(s[0] != '/'){
30737da2899SCharles.Forsyth		(ok, a) := IPaddr.parse(s);
30837da2899SCharles.Forsyth		if(ok < 0)
30937da2899SCharles.Forsyth			return (0, m);
31037da2899SCharles.Forsyth		if(a.isv4())
31137da2899SCharles.Forsyth			a.a[0:] = m.a[0:IPv4off];
31237da2899SCharles.Forsyth		return (0, a);
31337da2899SCharles.Forsyth	}
31437da2899SCharles.Forsyth	if(len s == 1)
31537da2899SCharles.Forsyth		return (0, m);
31637da2899SCharles.Forsyth	nbit := int s[1:];
31737da2899SCharles.Forsyth	if(nbit < 0)
31837da2899SCharles.Forsyth		return (-1, m);
31937da2899SCharles.Forsyth	if(nbit > abits)
32037da2899SCharles.Forsyth		return (0, m);
32137da2899SCharles.Forsyth	nbit = abits-nbit;
32237da2899SCharles.Forsyth	i := IPaddrlen;
32337da2899SCharles.Forsyth	for(; nbit >= 8; nbit -= 8)
32437da2899SCharles.Forsyth		m.a[--i] = byte 0;
32537da2899SCharles.Forsyth	if(nbit > 0)
32637da2899SCharles.Forsyth		m.a[i-1] &= byte (~0<<nbit);
32737da2899SCharles.Forsyth	return (0, m);
32837da2899SCharles.Forsyth}
32937da2899SCharles.Forsyth
33037da2899SCharles.ForsythIPaddr.text(a: self IPaddr): string
33137da2899SCharles.Forsyth{
33237da2899SCharles.Forsyth	b := a.a;
33337da2899SCharles.Forsyth	if(b == nil)
33437da2899SCharles.Forsyth		return "::";
33537da2899SCharles.Forsyth	if(a.isv4())
33637da2899SCharles.Forsyth		return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]);
33737da2899SCharles.Forsyth	cs := -1;
33837da2899SCharles.Forsyth	nc := 0;
33937da2899SCharles.Forsyth	for(i:=0; i<IPaddrlen; i+=2)
34037da2899SCharles.Forsyth		if(int b[i] == 0 && int b[i+1] == 0){
34137da2899SCharles.Forsyth			for(j:=i+2; j<IPaddrlen; j+=2)
34237da2899SCharles.Forsyth				if(int b[j] != 0 || int b[j+1] != 0)
34337da2899SCharles.Forsyth					break;
34437da2899SCharles.Forsyth			if(j-i > nc){
34537da2899SCharles.Forsyth				nc = j-i;
34637da2899SCharles.Forsyth				cs = i;
34737da2899SCharles.Forsyth			}
34837da2899SCharles.Forsyth		}
34937da2899SCharles.Forsyth	if(nc <= 2)
35037da2899SCharles.Forsyth		cs = -1;
35137da2899SCharles.Forsyth	s := "";
35237da2899SCharles.Forsyth	for(i=0; i<IPaddrlen; ){
35337da2899SCharles.Forsyth		if(i == cs){
35437da2899SCharles.Forsyth			s += "::";
35537da2899SCharles.Forsyth			i += nc;
35637da2899SCharles.Forsyth		}else{
35737da2899SCharles.Forsyth			if(s != "" && s[len s-1]!=':')
35837da2899SCharles.Forsyth				s[len s] = ':';
35937da2899SCharles.Forsyth			v := (int a.a[i] << 8) | int a.a[i+1];
36037da2899SCharles.Forsyth			s += sys->sprint("%ux", v);
36137da2899SCharles.Forsyth			i += 2;
36237da2899SCharles.Forsyth		}
36337da2899SCharles.Forsyth	}
36437da2899SCharles.Forsyth	return s;
36537da2899SCharles.Forsyth}
36637da2899SCharles.Forsyth
36737da2899SCharles.ForsythIPaddr.masktext(a: self IPaddr): string
36837da2899SCharles.Forsyth{
36937da2899SCharles.Forsyth	b := a.a;
37037da2899SCharles.Forsyth	if(b == nil)
37137da2899SCharles.Forsyth		return "/0";
37237da2899SCharles.Forsyth	for(i:=0; i<IPaddrlen; i++)
37337da2899SCharles.Forsyth		if(i == IPv4off)
37437da2899SCharles.Forsyth			return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]);
37537da2899SCharles.Forsyth		else if(b[i] != byte 16rFF)
37637da2899SCharles.Forsyth			break;
37737da2899SCharles.Forsyth	for(j:=i+1; j<IPaddrlen; j++)
37837da2899SCharles.Forsyth		if(b[j] != byte 0)
37937da2899SCharles.Forsyth			return a.text();
38037da2899SCharles.Forsyth	nbit := 8*i;
38137da2899SCharles.Forsyth	if(i < IPaddrlen){
38237da2899SCharles.Forsyth		v := int b[i];
38337da2899SCharles.Forsyth		for(m := 16r80; m != 0; m >>= 1){
38437da2899SCharles.Forsyth			if((v & m) == 0)
38537da2899SCharles.Forsyth				break;
38637da2899SCharles.Forsyth			v &= ~m;
38737da2899SCharles.Forsyth			nbit++;
38837da2899SCharles.Forsyth		}
38937da2899SCharles.Forsyth		if(v != 0)
39037da2899SCharles.Forsyth			return a.text();
39137da2899SCharles.Forsyth	}
39237da2899SCharles.Forsyth	return sys->sprint("/%d", nbit);
39337da2899SCharles.Forsyth}
39437da2899SCharles.Forsyth
39537da2899SCharles.Forsythaddressesof(ifcs: list of ref Ipifc, all: int): list of IPaddr
39637da2899SCharles.Forsyth{
39737da2899SCharles.Forsyth	ra: list of IPaddr;
39837da2899SCharles.Forsyth	runi: list of IPaddr;
39937da2899SCharles.Forsyth	for(; ifcs != nil; ifcs = tl ifcs){
40037da2899SCharles.Forsyth		for(ifcas :=(hd ifcs).addrs; ifcs != nil; ifcs = tl ifcs){
40137da2899SCharles.Forsyth			a := (hd ifcas).ip;
40237da2899SCharles.Forsyth			if(all || !(a.eq(noaddr) || a.eq(v4noaddr))){	# ignore unspecified and loopback
40337da2899SCharles.Forsyth				if(a.ismulticast() || a.eq(selfv4) || a.eq(selfv6))
40437da2899SCharles.Forsyth					ra = a :: ra;
40537da2899SCharles.Forsyth				else
40637da2899SCharles.Forsyth					runi = a :: runi;
40737da2899SCharles.Forsyth			}
40837da2899SCharles.Forsyth		}
40937da2899SCharles.Forsyth	}
41037da2899SCharles.Forsyth	# unicast first, then others, both sets in order as found
41137da2899SCharles.Forsyth	# for ipv6, might want to give priority to unicast other than link- and site-local
41237da2899SCharles.Forsyth	al: list of IPaddr;
41337da2899SCharles.Forsyth	for(; ra != nil; ra = tl ra)
41437da2899SCharles.Forsyth		al = hd ra :: al;
41537da2899SCharles.Forsyth	for(; runi != nil; runi = tl runi)
41637da2899SCharles.Forsyth		al = hd runi :: al;
41737da2899SCharles.Forsyth	return al;
41837da2899SCharles.Forsyth}
41937da2899SCharles.Forsyth
42037da2899SCharles.Forsythinterfaceof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr)
42137da2899SCharles.Forsyth{
42237da2899SCharles.Forsyth	for(; l != nil; l = tl l){
42337da2899SCharles.Forsyth		ifc := hd l;
42437da2899SCharles.Forsyth		for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){
42537da2899SCharles.Forsyth			a := hd addrs;
42637da2899SCharles.Forsyth			if(ip.mask(a.mask).eq(a.net))
42737da2899SCharles.Forsyth				return (ifc, a);
42837da2899SCharles.Forsyth		}
42937da2899SCharles.Forsyth	}
43037da2899SCharles.Forsyth	return (nil, nil);
43137da2899SCharles.Forsyth}
43237da2899SCharles.Forsyth
43337da2899SCharles.Forsythownerof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr)
43437da2899SCharles.Forsyth{
43537da2899SCharles.Forsyth	for(; l != nil; l = tl l){
43637da2899SCharles.Forsyth		ifc := hd l;
43737da2899SCharles.Forsyth		for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){
43837da2899SCharles.Forsyth			a := hd addrs;
43937da2899SCharles.Forsyth			if(ip.eq(a.ip))
44037da2899SCharles.Forsyth				return (ifc, a);
44137da2899SCharles.Forsyth		}
44237da2899SCharles.Forsyth	}
44337da2899SCharles.Forsyth	return (nil, nil);
44437da2899SCharles.Forsyth}
44537da2899SCharles.Forsyth
44637da2899SCharles.Forsythreadipifc(net: string, index: int): (list of ref Ipifc, string)
44737da2899SCharles.Forsyth{
44837da2899SCharles.Forsyth	if(net == nil)
44937da2899SCharles.Forsyth		net = "/net";
45037da2899SCharles.Forsyth	if(index < 0){
45137da2899SCharles.Forsyth		ifcs: list of ref Ipifc;
45237da2899SCharles.Forsyth		dirfd := sys->open(net+"/ipifc", Sys->OREAD);
45337da2899SCharles.Forsyth		if(dirfd == nil)
45437da2899SCharles.Forsyth			return (nil, sys->sprint("%r"));
45537da2899SCharles.Forsyth		err: string;
45637da2899SCharles.Forsyth		for(;;){
45737da2899SCharles.Forsyth			(nd, dirs) := sys->dirread(dirfd);
45837da2899SCharles.Forsyth			if(nd <= 0){
45937da2899SCharles.Forsyth				if(nd < 0)
46037da2899SCharles.Forsyth					err = sys->sprint("%r");
46137da2899SCharles.Forsyth				break;
46237da2899SCharles.Forsyth			}
46337da2899SCharles.Forsyth			for(i:=0; i<nd; i++)
46437da2899SCharles.Forsyth				if((dn := dirs[i].name) != nil && dn[0]>='0' && dn[0]<='9'){
46537da2899SCharles.Forsyth					index = int dn;
46637da2899SCharles.Forsyth					ifc := readstatus(net+"/ipifc/"+dn+"/status", index);
46737da2899SCharles.Forsyth					if(ifc != nil)
46837da2899SCharles.Forsyth						ifcs = ifc :: ifcs;
46937da2899SCharles.Forsyth				}
47037da2899SCharles.Forsyth		}
47137da2899SCharles.Forsyth		l := ifcs;
47237da2899SCharles.Forsyth		for(ifcs = nil; l != nil; l = tl l)
47337da2899SCharles.Forsyth			ifcs = hd l :: ifcs;
47437da2899SCharles.Forsyth		return (ifcs, err);
47537da2899SCharles.Forsyth	}
47637da2899SCharles.Forsyth	ifc := readstatus(net+"/ipifc/"+string index+"/status", index);
47737da2899SCharles.Forsyth	if(ifc == nil)
47837da2899SCharles.Forsyth		return (nil, sys->sprint("%r"));
47937da2899SCharles.Forsyth	return (ifc :: nil, nil);
48037da2899SCharles.Forsyth}
48137da2899SCharles.Forsyth
48237da2899SCharles.Forsyth#
48337da2899SCharles.Forsyth# return data structure containing values read from status file:
48437da2899SCharles.Forsyth#
48537da2899SCharles.Forsyth# device /net/ether0 maxtu 1514 sendra 0 recvra 0 mflag 0 oflag 0 maxraint 600000 minraint 200000 linkmtu 0 reachtime 0 rxmitra 0 ttl 255 routerlt 1800000 pktin 47609 pktout 42322 errin 0 errout 0
48637da2899SCharles.Forsyth#	144.32.112.83 /119 144.32.112.0 4294967295   4294967295
48737da2899SCharles.Forsyth#		...
48837da2899SCharles.Forsyth#
48937da2899SCharles.Forsyth
49037da2899SCharles.Forsythreadstatus(file: string, index: int): ref Ipifc
49137da2899SCharles.Forsyth{
49237da2899SCharles.Forsyth	fd := sys->open(file, Sys->OREAD);
49337da2899SCharles.Forsyth	if(fd == nil)
49437da2899SCharles.Forsyth		return nil;
49537da2899SCharles.Forsyth	contents := slurp(fd);
49637da2899SCharles.Forsyth	fd = nil;
49737da2899SCharles.Forsyth	(nline, lines) := sys->tokenize(contents, "\n");
49837da2899SCharles.Forsyth	if(nline <= 0){
49937da2899SCharles.Forsyth		sys->werrstr("unexpected ipifc status file format");
50037da2899SCharles.Forsyth		return nil;
50137da2899SCharles.Forsyth	}
50237da2899SCharles.Forsyth	(nil, details) := sys->tokenize(hd lines, " \t\n");
50337da2899SCharles.Forsyth	lines = tl lines;
50437da2899SCharles.Forsyth	ifc := ref Ipifc;
50537da2899SCharles.Forsyth	ifc.index = index;
50637da2899SCharles.Forsyth	ifc.dev = valof(details, "device");
50737da2899SCharles.Forsyth	ifc.mtu = int valof(details, "maxtu");
50837da2899SCharles.Forsyth	ifc.pktin = big valof(details, "pktin");
50937da2899SCharles.Forsyth	ifc.pktout = big valof(details, "pktout");
51037da2899SCharles.Forsyth	ifc.errin = big valof(details, "errin");
51137da2899SCharles.Forsyth	ifc.errout = big valof(details, "errout");
51237da2899SCharles.Forsyth	ifc.sendra = int valof(details, "sendra");
51337da2899SCharles.Forsyth	ifc.recvra = int valof(details, "recvra");
51437da2899SCharles.Forsyth	ifc.rp.mflag = int valof(details, "mflag");
51537da2899SCharles.Forsyth	ifc.rp.oflag = int valof(details, "oflag");
51637da2899SCharles.Forsyth	ifc.rp.maxraint = int valof(details, "maxraint");
51737da2899SCharles.Forsyth	ifc.rp.minraint = int valof(details, "minraint");
51837da2899SCharles.Forsyth	ifc.rp.linkmtu = int valof(details, "linkmtu");
51937da2899SCharles.Forsyth	ifc.rp.reachtime = int valof(details, "reachtime");
52037da2899SCharles.Forsyth	ifc.rp.rxmitra = int valof(details, "rxmitra");
52137da2899SCharles.Forsyth	ifc.rp.ttl = int valof(details, "ttl");
52237da2899SCharles.Forsyth	ifc.rp.routerlt = int valof(details, "routerlt");
52337da2899SCharles.Forsyth	addrs: list of ref Ifcaddr;
52437da2899SCharles.Forsyth	for(; lines != nil; lines = tl lines){
52537da2899SCharles.Forsyth		(nf, fields) := sys->tokenize(hd lines, " \t\n");
52637da2899SCharles.Forsyth		if(nf >= 3){
52737da2899SCharles.Forsyth			addr := ref Ifcaddr;
52837da2899SCharles.Forsyth			(nil, addr.ip) = IPaddr.parse(hd fields); fields = tl fields;
52937da2899SCharles.Forsyth			(nil, addr.mask) = IPaddr.parsemask(hd fields); fields = tl fields;
53037da2899SCharles.Forsyth			(nil, addr.net) = IPaddr.parse(hd fields); fields = tl fields;
53137da2899SCharles.Forsyth			if(nf >= 5){
53237da2899SCharles.Forsyth				addr.preflt = big hd fields; fields = tl fields;
53337da2899SCharles.Forsyth				addr.validlt = big hd fields; fields = tl fields;
53437da2899SCharles.Forsyth			}else{
53537da2899SCharles.Forsyth				addr.preflt = big 0;
53637da2899SCharles.Forsyth				addr.validlt = big 0;
53737da2899SCharles.Forsyth			}
53837da2899SCharles.Forsyth			addrs = addr :: addrs;
53937da2899SCharles.Forsyth		}
54037da2899SCharles.Forsyth	}
54137da2899SCharles.Forsyth	for(; addrs != nil; addrs = tl addrs)
54237da2899SCharles.Forsyth		ifc.addrs = hd addrs :: ifc.addrs;
54337da2899SCharles.Forsyth	return ifc;
54437da2899SCharles.Forsyth}
54537da2899SCharles.Forsyth
54637da2899SCharles.Forsythslurp(fd: ref Sys->FD): string
54737da2899SCharles.Forsyth{
54837da2899SCharles.Forsyth	buf := array[2048] of byte;
54937da2899SCharles.Forsyth	s := "";
55037da2899SCharles.Forsyth	while((n := sys->read(fd, buf, len buf)) > 0)
55137da2899SCharles.Forsyth		s += string buf[0:n];
55237da2899SCharles.Forsyth	return s;
55337da2899SCharles.Forsyth}
55437da2899SCharles.Forsyth
55537da2899SCharles.Forsythvalof(l: list of string, attr: string): string
55637da2899SCharles.Forsyth{
55737da2899SCharles.Forsyth	while(l != nil){
55837da2899SCharles.Forsyth		label := hd l;
55937da2899SCharles.Forsyth		l = tl l;
56037da2899SCharles.Forsyth		if(label == attr){
56137da2899SCharles.Forsyth			if(l == nil)
56237da2899SCharles.Forsyth				return nil;
56337da2899SCharles.Forsyth			return hd l;
56437da2899SCharles.Forsyth		}
56537da2899SCharles.Forsyth		if(l != nil)
56637da2899SCharles.Forsyth			l = tl l;
56737da2899SCharles.Forsyth	}
56837da2899SCharles.Forsyth	return nil;
56937da2899SCharles.Forsyth}
57037da2899SCharles.Forsyth
57137da2899SCharles.ForsythUdphdr.new(): ref Udphdr
57237da2899SCharles.Forsyth{
57337da2899SCharles.Forsyth	return ref Udphdr(noaddr, noaddr, noaddr, 0, 0);
57437da2899SCharles.Forsyth}
57537da2899SCharles.Forsyth
57637da2899SCharles.ForsythUdphdr.unpack(a: array of byte, n: int): ref Udphdr
57737da2899SCharles.Forsyth{
57837da2899SCharles.Forsyth	case n {
57937da2899SCharles.Forsyth	Udp4hdrlen =>
58037da2899SCharles.Forsyth		u := ref Udphdr;
58137da2899SCharles.Forsyth		u.raddr = IPaddr.newv4(a[0:]);
58237da2899SCharles.Forsyth		u.laddr = IPaddr.newv4(a[IPv4addrlen:]);
58337da2899SCharles.Forsyth		u.rport = get2(a, 2*IPv4addrlen);
58437da2899SCharles.Forsyth		u.lport = get2(a, 2*IPv4addrlen+2);
58537da2899SCharles.Forsyth		u.ifcaddr = u.laddr.copy();
58637da2899SCharles.Forsyth		return u;
58737da2899SCharles.Forsyth	OUdphdrlen =>
58837da2899SCharles.Forsyth		u := ref Udphdr;
58937da2899SCharles.Forsyth		u.raddr = IPaddr.newv6(a[0:]);
59037da2899SCharles.Forsyth		u.laddr = IPaddr.newv6(a[IPaddrlen:]);
59137da2899SCharles.Forsyth		u.rport = get2(a, 2*IPaddrlen);
59237da2899SCharles.Forsyth		u.lport = get2(a, 2*IPaddrlen+2);
59337da2899SCharles.Forsyth		u.ifcaddr = u.laddr.copy();
59437da2899SCharles.Forsyth		return u;
59537da2899SCharles.Forsyth	Udphdrlen =>
59637da2899SCharles.Forsyth		u := ref Udphdr;
59737da2899SCharles.Forsyth		u.raddr = IPaddr.newv6(a[0:]);
59837da2899SCharles.Forsyth		u.laddr = IPaddr.newv6(a[IPaddrlen:]);
59937da2899SCharles.Forsyth		u.ifcaddr = IPaddr.newv6(a[2*IPaddrlen:]);
60037da2899SCharles.Forsyth		u.rport = get2(a, 3*IPaddrlen);
60137da2899SCharles.Forsyth		u.lport = get2(a, 3*IPaddrlen+2);
60237da2899SCharles.Forsyth		return u;
60337da2899SCharles.Forsyth	* =>
60437da2899SCharles.Forsyth		raise "Udphdr.unpack: bad length";
60537da2899SCharles.Forsyth	}
60637da2899SCharles.Forsyth}
60737da2899SCharles.Forsyth
60837da2899SCharles.ForsythUdphdr.pack(u: self ref Udphdr, a: array of byte, n: int)
60937da2899SCharles.Forsyth{
61037da2899SCharles.Forsyth	case n {
61137da2899SCharles.Forsyth	Udp4hdrlen =>
61237da2899SCharles.Forsyth		a[0:] = u.raddr.v4();
61337da2899SCharles.Forsyth		a[IPv4addrlen:] = u.laddr.v4();
61437da2899SCharles.Forsyth		put2(a, 2*IPv4addrlen, u.rport);
61537da2899SCharles.Forsyth		put2(a, 2*IPv4addrlen+2, u.lport);
61637da2899SCharles.Forsyth	OUdphdrlen =>
61737da2899SCharles.Forsyth		a[0:] = u.raddr.v6();
61837da2899SCharles.Forsyth		a[IPaddrlen:] = u.laddr.v6();
61937da2899SCharles.Forsyth		put2(a, 2*IPaddrlen, u.rport);
62037da2899SCharles.Forsyth		put2(a, 2*IPaddrlen+2, u.lport);
62137da2899SCharles.Forsyth	Udphdrlen =>
62237da2899SCharles.Forsyth		a[0:] = u.raddr.v6();
62337da2899SCharles.Forsyth		a[IPaddrlen:] = u.laddr.v6();
62437da2899SCharles.Forsyth		a[2*IPaddrlen:] = u.ifcaddr.v6();
62537da2899SCharles.Forsyth		put2(a, 3*IPaddrlen, u.rport);
62637da2899SCharles.Forsyth		put2(a, 3*IPaddrlen+2, u.lport);
62737da2899SCharles.Forsyth	* =>
62837da2899SCharles.Forsyth		raise "Udphdr.pack: bad length";
62937da2899SCharles.Forsyth	}
63037da2899SCharles.Forsyth}
63137da2899SCharles.Forsyth
63237da2899SCharles.Forsythget2(a: array of byte, o: int): int
63337da2899SCharles.Forsyth{
63437da2899SCharles.Forsyth	return (int a[o] << 8) | int a[o+1];
63537da2899SCharles.Forsyth}
63637da2899SCharles.Forsyth
63737da2899SCharles.Forsythput2(a: array of byte, o: int, val: int): int
63837da2899SCharles.Forsyth{
63937da2899SCharles.Forsyth	a[o] = byte (val>>8);
64037da2899SCharles.Forsyth	a[o+1] = byte val;
64137da2899SCharles.Forsyth	return o+2;
64237da2899SCharles.Forsyth}
64337da2899SCharles.Forsyth
64437da2899SCharles.Forsythget4(a: array of byte, o: int): int
64537da2899SCharles.Forsyth{
64637da2899SCharles.Forsyth	return (((((int a[o] << 8)| int a[o+1]) << 8) | int a[o+2]) << 8) | int a[o+3];
64737da2899SCharles.Forsyth}
64837da2899SCharles.Forsyth
64937da2899SCharles.Forsythput4(a: array of byte, o: int, val: int): int
65037da2899SCharles.Forsyth{
65137da2899SCharles.Forsyth	a[o] = byte (val>>24);
65237da2899SCharles.Forsyth	a[o+1] = byte (val>>16);
65337da2899SCharles.Forsyth	a[o+2] = byte (val>>8);
65437da2899SCharles.Forsyth	a[o+3] = byte val;
65537da2899SCharles.Forsyth	return o+4;
65637da2899SCharles.Forsyth}
657