xref: /plan9-contrib/sys/src/9k/ip/ipaux.c (revision af94aef917f4ab0b0d706f43dac2fd4a78640131)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier #include	"ip.h"
89ef1f84bSDavid du Colombier #include	"ipv6.h"
99ef1f84bSDavid du Colombier 
109ef1f84bSDavid du Colombier char *v6hdrtypes[Maxhdrtype] =
119ef1f84bSDavid du Colombier {
129ef1f84bSDavid du Colombier 	[HBH]		"HopbyHop",
139ef1f84bSDavid du Colombier 	[ICMP]		"ICMP",
149ef1f84bSDavid du Colombier 	[IGMP]		"IGMP",
159ef1f84bSDavid du Colombier 	[GGP]		"GGP",
169ef1f84bSDavid du Colombier 	[IPINIP]	"IP",
179ef1f84bSDavid du Colombier 	[ST]		"ST",
189ef1f84bSDavid du Colombier 	[TCP]		"TCP",
199ef1f84bSDavid du Colombier 	[UDP]		"UDP",
209ef1f84bSDavid du Colombier 	[ISO_TP4]	"ISO_TP4",
219ef1f84bSDavid du Colombier 	[RH]		"Routinghdr",
229ef1f84bSDavid du Colombier 	[FH]		"Fraghdr",
239ef1f84bSDavid du Colombier 	[IDRP]		"IDRP",
249ef1f84bSDavid du Colombier 	[RSVP]		"RSVP",
259ef1f84bSDavid du Colombier 	[AH]		"Authhdr",
269ef1f84bSDavid du Colombier 	[ESP]		"ESP",
279ef1f84bSDavid du Colombier 	[ICMPv6]	"ICMPv6",
289ef1f84bSDavid du Colombier 	[NNH]		"Nonexthdr",
299ef1f84bSDavid du Colombier 	[ISO_IP]	"ISO_IP",
309ef1f84bSDavid du Colombier 	[IGRP]		"IGRP",
319ef1f84bSDavid du Colombier 	[OSPF]		"OSPF",
329ef1f84bSDavid du Colombier };
339ef1f84bSDavid du Colombier 
349ef1f84bSDavid du Colombier /*
359ef1f84bSDavid du Colombier  *  well known IPv6 addresses
369ef1f84bSDavid du Colombier  */
379ef1f84bSDavid du Colombier uchar v6Unspecified[IPaddrlen] = {
389ef1f84bSDavid du Colombier 	0, 0, 0, 0,
399ef1f84bSDavid du Colombier 	0, 0, 0, 0,
409ef1f84bSDavid du Colombier 	0, 0, 0, 0,
419ef1f84bSDavid du Colombier 	0, 0, 0, 0
429ef1f84bSDavid du Colombier };
439ef1f84bSDavid du Colombier uchar v6loopback[IPaddrlen] = {
449ef1f84bSDavid du Colombier 	0, 0, 0, 0,
459ef1f84bSDavid du Colombier 	0, 0, 0, 0,
469ef1f84bSDavid du Colombier 	0, 0, 0, 0,
479ef1f84bSDavid du Colombier 	0, 0, 0, 0x01
489ef1f84bSDavid du Colombier };
499ef1f84bSDavid du Colombier 
509ef1f84bSDavid du Colombier uchar v6linklocal[IPaddrlen] = {
519ef1f84bSDavid du Colombier 	0xfe, 0x80, 0, 0,
529ef1f84bSDavid du Colombier 	0, 0, 0, 0,
539ef1f84bSDavid du Colombier 	0, 0, 0, 0,
549ef1f84bSDavid du Colombier 	0, 0, 0, 0
559ef1f84bSDavid du Colombier };
569ef1f84bSDavid du Colombier uchar v6linklocalmask[IPaddrlen] = {
579ef1f84bSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
589ef1f84bSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
599ef1f84bSDavid du Colombier 	0, 0, 0, 0,
609ef1f84bSDavid du Colombier 	0, 0, 0, 0
619ef1f84bSDavid du Colombier };
629ef1f84bSDavid du Colombier int v6llpreflen = 8;	/* link-local prefix length in bytes */
639ef1f84bSDavid du Colombier 
649ef1f84bSDavid du Colombier uchar v6multicast[IPaddrlen] = {
659ef1f84bSDavid du Colombier 	0xff, 0, 0, 0,
669ef1f84bSDavid du Colombier 	0, 0, 0, 0,
679ef1f84bSDavid du Colombier 	0, 0, 0, 0,
689ef1f84bSDavid du Colombier 	0, 0, 0, 0
699ef1f84bSDavid du Colombier };
709ef1f84bSDavid du Colombier uchar v6multicastmask[IPaddrlen] = {
719ef1f84bSDavid du Colombier 	0xff, 0, 0, 0,
729ef1f84bSDavid du Colombier 	0, 0, 0, 0,
739ef1f84bSDavid du Colombier 	0, 0, 0, 0,
749ef1f84bSDavid du Colombier 	0, 0, 0, 0
759ef1f84bSDavid du Colombier };
769ef1f84bSDavid du Colombier int v6mcpreflen = 1;	/* multicast prefix length */
779ef1f84bSDavid du Colombier 
789ef1f84bSDavid du Colombier uchar v6allnodesN[IPaddrlen] = {
799ef1f84bSDavid du Colombier 	0xff, 0x01, 0, 0,
809ef1f84bSDavid du Colombier 	0, 0, 0, 0,
819ef1f84bSDavid du Colombier 	0, 0, 0, 0,
829ef1f84bSDavid du Colombier 	0, 0, 0, 0x01
839ef1f84bSDavid du Colombier };
849ef1f84bSDavid du Colombier uchar v6allroutersN[IPaddrlen] = {
859ef1f84bSDavid du Colombier 	0xff, 0x01, 0, 0,
869ef1f84bSDavid du Colombier 	0, 0, 0, 0,
879ef1f84bSDavid du Colombier 	0, 0, 0, 0,
889ef1f84bSDavid du Colombier 	0, 0, 0, 0x02
899ef1f84bSDavid du Colombier };
909ef1f84bSDavid du Colombier uchar v6allnodesNmask[IPaddrlen] = {
919ef1f84bSDavid du Colombier 	0xff, 0xff, 0, 0,
929ef1f84bSDavid du Colombier 	0, 0, 0, 0,
939ef1f84bSDavid du Colombier 	0, 0, 0, 0,
949ef1f84bSDavid du Colombier 	0, 0, 0, 0
959ef1f84bSDavid du Colombier };
969ef1f84bSDavid du Colombier int v6aNpreflen = 2;	/* all nodes (N) prefix */
979ef1f84bSDavid du Colombier 
989ef1f84bSDavid du Colombier uchar v6allnodesL[IPaddrlen] = {
999ef1f84bSDavid du Colombier 	0xff, 0x02, 0, 0,
1009ef1f84bSDavid du Colombier 	0, 0, 0, 0,
1019ef1f84bSDavid du Colombier 	0, 0, 0, 0,
1029ef1f84bSDavid du Colombier 	0, 0, 0, 0x01
1039ef1f84bSDavid du Colombier };
1049ef1f84bSDavid du Colombier uchar v6allroutersL[IPaddrlen] = {
1059ef1f84bSDavid du Colombier 	0xff, 0x02, 0, 0,
1069ef1f84bSDavid du Colombier 	0, 0, 0, 0,
1079ef1f84bSDavid du Colombier 	0, 0, 0, 0,
1089ef1f84bSDavid du Colombier 	0, 0, 0, 0x02
1099ef1f84bSDavid du Colombier };
1109ef1f84bSDavid du Colombier uchar v6allnodesLmask[IPaddrlen] = {
1119ef1f84bSDavid du Colombier 	0xff, 0xff, 0, 0,
1129ef1f84bSDavid du Colombier 	0, 0, 0, 0,
1139ef1f84bSDavid du Colombier 	0, 0, 0, 0,
1149ef1f84bSDavid du Colombier 	0, 0, 0, 0
1159ef1f84bSDavid du Colombier };
1169ef1f84bSDavid du Colombier int v6aLpreflen = 2;	/* all nodes (L) prefix */
1179ef1f84bSDavid du Colombier 
1189ef1f84bSDavid du Colombier uchar v6solicitednode[IPaddrlen] = {
1199ef1f84bSDavid du Colombier 	0xff, 0x02, 0, 0,
1209ef1f84bSDavid du Colombier 	0, 0, 0, 0,
1219ef1f84bSDavid du Colombier 	0, 0, 0, 0x01,
1229ef1f84bSDavid du Colombier 	0xff, 0, 0, 0
1239ef1f84bSDavid du Colombier };
1249ef1f84bSDavid du Colombier uchar v6solicitednodemask[IPaddrlen] = {
1259ef1f84bSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
1269ef1f84bSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
1279ef1f84bSDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
1289ef1f84bSDavid du Colombier 	0xff, 0x0, 0x0, 0x0
1299ef1f84bSDavid du Colombier };
1309ef1f84bSDavid du Colombier int v6snpreflen = 13;
1319ef1f84bSDavid du Colombier 
1329ef1f84bSDavid du Colombier ushort
ptclcsum(Block * bp,int offset,int len)1339ef1f84bSDavid du Colombier ptclcsum(Block *bp, int offset, int len)
1349ef1f84bSDavid du Colombier {
1359ef1f84bSDavid du Colombier 	uchar *addr;
1369ef1f84bSDavid du Colombier 	ulong losum, hisum;
1379ef1f84bSDavid du Colombier 	ushort csum;
1389ef1f84bSDavid du Colombier 	int odd, blocklen, x;
1399ef1f84bSDavid du Colombier 
1409ef1f84bSDavid du Colombier 	/* Correct to front of data area */
1419ef1f84bSDavid du Colombier 	while(bp != nil && offset && offset >= BLEN(bp)) {
1429ef1f84bSDavid du Colombier 		offset -= BLEN(bp);
1439ef1f84bSDavid du Colombier 		bp = bp->next;
1449ef1f84bSDavid du Colombier 	}
1459ef1f84bSDavid du Colombier 	if(bp == nil)
1469ef1f84bSDavid du Colombier 		return 0;
1479ef1f84bSDavid du Colombier 
1489ef1f84bSDavid du Colombier 	addr = bp->rp + offset;
1499ef1f84bSDavid du Colombier 	blocklen = BLEN(bp) - offset;
1509ef1f84bSDavid du Colombier 
1519ef1f84bSDavid du Colombier 	if(bp->next == nil) {
1529ef1f84bSDavid du Colombier 		if(blocklen < len)
1539ef1f84bSDavid du Colombier 			len = blocklen;
1549ef1f84bSDavid du Colombier 		return ~ptclbsum(addr, len) & 0xffff;
1559ef1f84bSDavid du Colombier 	}
1569ef1f84bSDavid du Colombier 
1579ef1f84bSDavid du Colombier 	losum = 0;
1589ef1f84bSDavid du Colombier 	hisum = 0;
1599ef1f84bSDavid du Colombier 
1609ef1f84bSDavid du Colombier 	odd = 0;
1619ef1f84bSDavid du Colombier 	while(len) {
1629ef1f84bSDavid du Colombier 		x = blocklen;
1639ef1f84bSDavid du Colombier 		if(len < x)
1649ef1f84bSDavid du Colombier 			x = len;
1659ef1f84bSDavid du Colombier 
1669ef1f84bSDavid du Colombier 		csum = ptclbsum(addr, x);
1679ef1f84bSDavid du Colombier 		if(odd)
1689ef1f84bSDavid du Colombier 			hisum += csum;
1699ef1f84bSDavid du Colombier 		else
1709ef1f84bSDavid du Colombier 			losum += csum;
1719ef1f84bSDavid du Colombier 		odd = (odd+x) & 1;
1729ef1f84bSDavid du Colombier 		len -= x;
1739ef1f84bSDavid du Colombier 
1749ef1f84bSDavid du Colombier 		bp = bp->next;
1759ef1f84bSDavid du Colombier 		if(bp == nil)
1769ef1f84bSDavid du Colombier 			break;
1779ef1f84bSDavid du Colombier 		blocklen = BLEN(bp);
1789ef1f84bSDavid du Colombier 		addr = bp->rp;
1799ef1f84bSDavid du Colombier 	}
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier 	losum += hisum>>8;
1829ef1f84bSDavid du Colombier 	losum += (hisum&0xff)<<8;
1839ef1f84bSDavid du Colombier 	while((csum = losum>>16) != 0)
1849ef1f84bSDavid du Colombier 		losum = csum + (losum & 0xffff);
1859ef1f84bSDavid du Colombier 
1869ef1f84bSDavid du Colombier 	return ~losum & 0xffff;
1879ef1f84bSDavid du Colombier }
1889ef1f84bSDavid du Colombier 
1899ef1f84bSDavid du Colombier enum
1909ef1f84bSDavid du Colombier {
1919ef1f84bSDavid du Colombier 	Isprefix= 16,
1929ef1f84bSDavid du Colombier };
1939ef1f84bSDavid du Colombier 
1949ef1f84bSDavid du Colombier #define CLASS(p) ((*(uchar*)(p))>>6)
1959ef1f84bSDavid du Colombier 
1969ef1f84bSDavid du Colombier void
ipv62smcast(uchar * smcast,uchar * a)1979ef1f84bSDavid du Colombier ipv62smcast(uchar *smcast, uchar *a)
1989ef1f84bSDavid du Colombier {
1999ef1f84bSDavid du Colombier 	assert(IPaddrlen == 16);
2009ef1f84bSDavid du Colombier 	memmove(smcast, v6solicitednode, IPaddrlen);
2019ef1f84bSDavid du Colombier 	smcast[13] = a[13];
2029ef1f84bSDavid du Colombier 	smcast[14] = a[14];
2039ef1f84bSDavid du Colombier 	smcast[15] = a[15];
2049ef1f84bSDavid du Colombier }
2059ef1f84bSDavid du Colombier 
2069ef1f84bSDavid du Colombier 
2079ef1f84bSDavid du Colombier /*
2089ef1f84bSDavid du Colombier  *  parse a hex mac address
2099ef1f84bSDavid du Colombier  */
2109ef1f84bSDavid du Colombier int
parsemac(uchar * to,char * from,int len)2119ef1f84bSDavid du Colombier parsemac(uchar *to, char *from, int len)
2129ef1f84bSDavid du Colombier {
2139ef1f84bSDavid du Colombier 	char nip[4];
2149ef1f84bSDavid du Colombier 	char *p;
2159ef1f84bSDavid du Colombier 	int i;
2169ef1f84bSDavid du Colombier 
2179ef1f84bSDavid du Colombier 	p = from;
2189ef1f84bSDavid du Colombier 	memset(to, 0, len);
2199ef1f84bSDavid du Colombier 	for(i = 0; i < len; i++){
2209ef1f84bSDavid du Colombier 		if(p[0] == '\0' || p[1] == '\0')
2219ef1f84bSDavid du Colombier 			break;
2229ef1f84bSDavid du Colombier 
2239ef1f84bSDavid du Colombier 		nip[0] = p[0];
2249ef1f84bSDavid du Colombier 		nip[1] = p[1];
2259ef1f84bSDavid du Colombier 		nip[2] = '\0';
2269ef1f84bSDavid du Colombier 		p += 2;
2279ef1f84bSDavid du Colombier 
2289ef1f84bSDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
2299ef1f84bSDavid du Colombier 		if(*p == ':')
2309ef1f84bSDavid du Colombier 			p++;
2319ef1f84bSDavid du Colombier 	}
2329ef1f84bSDavid du Colombier 	return i;
2339ef1f84bSDavid du Colombier }
2349ef1f84bSDavid du Colombier 
2359ef1f84bSDavid du Colombier /*
2369ef1f84bSDavid du Colombier  *  hashing tcp, udp, ... connections
2379ef1f84bSDavid du Colombier  */
2389ef1f84bSDavid du Colombier ulong
iphash(uchar * sa,ushort sp,uchar * da,ushort dp)2399ef1f84bSDavid du Colombier iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
2409ef1f84bSDavid du Colombier {
241*af94aef9SDavid du Colombier 	return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nipht;
2429ef1f84bSDavid du Colombier }
2439ef1f84bSDavid du Colombier 
2449ef1f84bSDavid du Colombier void
iphtadd(Ipht * ht,Conv * c)2459ef1f84bSDavid du Colombier iphtadd(Ipht *ht, Conv *c)
2469ef1f84bSDavid du Colombier {
2479ef1f84bSDavid du Colombier 	ulong hv;
2489ef1f84bSDavid du Colombier 	Iphash *h;
2499ef1f84bSDavid du Colombier 
2509ef1f84bSDavid du Colombier 	hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
2519ef1f84bSDavid du Colombier 	h = smalloc(sizeof(*h));
2529ef1f84bSDavid du Colombier 	if(ipcmp(c->raddr, IPnoaddr) != 0)
2539ef1f84bSDavid du Colombier 		h->match = IPmatchexact;
2549ef1f84bSDavid du Colombier 	else {
2559ef1f84bSDavid du Colombier 		if(ipcmp(c->laddr, IPnoaddr) != 0){
2569ef1f84bSDavid du Colombier 			if(c->lport == 0)
2579ef1f84bSDavid du Colombier 				h->match = IPmatchaddr;
2589ef1f84bSDavid du Colombier 			else
2599ef1f84bSDavid du Colombier 				h->match = IPmatchpa;
2609ef1f84bSDavid du Colombier 		} else {
2619ef1f84bSDavid du Colombier 			if(c->lport == 0)
2629ef1f84bSDavid du Colombier 				h->match = IPmatchany;
2639ef1f84bSDavid du Colombier 			else
2649ef1f84bSDavid du Colombier 				h->match = IPmatchport;
2659ef1f84bSDavid du Colombier 		}
2669ef1f84bSDavid du Colombier 	}
2679ef1f84bSDavid du Colombier 	h->c = c;
2689ef1f84bSDavid du Colombier 
2699ef1f84bSDavid du Colombier 	lock(ht);
2709ef1f84bSDavid du Colombier 	h->next = ht->tab[hv];
2719ef1f84bSDavid du Colombier 	ht->tab[hv] = h;
2729ef1f84bSDavid du Colombier 	unlock(ht);
2739ef1f84bSDavid du Colombier }
2749ef1f84bSDavid du Colombier 
2759ef1f84bSDavid du Colombier void
iphtrem(Ipht * ht,Conv * c)2769ef1f84bSDavid du Colombier iphtrem(Ipht *ht, Conv *c)
2779ef1f84bSDavid du Colombier {
2789ef1f84bSDavid du Colombier 	ulong hv;
2799ef1f84bSDavid du Colombier 	Iphash **l, *h;
2809ef1f84bSDavid du Colombier 
2819ef1f84bSDavid du Colombier 	hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
2829ef1f84bSDavid du Colombier 	lock(ht);
2839ef1f84bSDavid du Colombier 	for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
2849ef1f84bSDavid du Colombier 		if((*l)->c == c){
2859ef1f84bSDavid du Colombier 			h = *l;
2869ef1f84bSDavid du Colombier 			(*l) = h->next;
2879ef1f84bSDavid du Colombier 			free(h);
2889ef1f84bSDavid du Colombier 			break;
2899ef1f84bSDavid du Colombier 		}
2909ef1f84bSDavid du Colombier 	unlock(ht);
2919ef1f84bSDavid du Colombier }
2929ef1f84bSDavid du Colombier 
2939ef1f84bSDavid du Colombier /* look for a matching conversation with the following precedence
2949ef1f84bSDavid du Colombier  *	connected && raddr,rport,laddr,lport
2959ef1f84bSDavid du Colombier  *	announced && laddr,lport
2969ef1f84bSDavid du Colombier  *	announced && *,lport
2979ef1f84bSDavid du Colombier  *	announced && laddr,*
2989ef1f84bSDavid du Colombier  *	announced && *,*
2999ef1f84bSDavid du Colombier  */
3009ef1f84bSDavid du Colombier Conv*
iphtlook(Ipht * ht,uchar * sa,ushort sp,uchar * da,ushort dp)3019ef1f84bSDavid du Colombier iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
3029ef1f84bSDavid du Colombier {
3039ef1f84bSDavid du Colombier 	ulong hv;
3049ef1f84bSDavid du Colombier 	Iphash *h;
3059ef1f84bSDavid du Colombier 	Conv *c;
3069ef1f84bSDavid du Colombier 
3079ef1f84bSDavid du Colombier 	/* exact 4 pair match (connection) */
3089ef1f84bSDavid du Colombier 	hv = iphash(sa, sp, da, dp);
3099ef1f84bSDavid du Colombier 	lock(ht);
3109ef1f84bSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
3119ef1f84bSDavid du Colombier 		if(h->match != IPmatchexact)
3129ef1f84bSDavid du Colombier 			continue;
3139ef1f84bSDavid du Colombier 		c = h->c;
3149ef1f84bSDavid du Colombier 		if(sp == c->rport && dp == c->lport
3159ef1f84bSDavid du Colombier 		&& ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
3169ef1f84bSDavid du Colombier 			unlock(ht);
3179ef1f84bSDavid du Colombier 			return c;
3189ef1f84bSDavid du Colombier 		}
3199ef1f84bSDavid du Colombier 	}
3209ef1f84bSDavid du Colombier 
3219ef1f84bSDavid du Colombier 	/* match local address and port */
3229ef1f84bSDavid du Colombier 	hv = iphash(IPnoaddr, 0, da, dp);
3239ef1f84bSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
3249ef1f84bSDavid du Colombier 		if(h->match != IPmatchpa)
3259ef1f84bSDavid du Colombier 			continue;
3269ef1f84bSDavid du Colombier 		c = h->c;
3279ef1f84bSDavid du Colombier 		if(dp == c->lport && ipcmp(da, c->laddr) == 0){
3289ef1f84bSDavid du Colombier 			unlock(ht);
3299ef1f84bSDavid du Colombier 			return c;
3309ef1f84bSDavid du Colombier 		}
3319ef1f84bSDavid du Colombier 	}
3329ef1f84bSDavid du Colombier 
3339ef1f84bSDavid du Colombier 	/* match just port */
3349ef1f84bSDavid du Colombier 	hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
3359ef1f84bSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
3369ef1f84bSDavid du Colombier 		if(h->match != IPmatchport)
3379ef1f84bSDavid du Colombier 			continue;
3389ef1f84bSDavid du Colombier 		c = h->c;
3399ef1f84bSDavid du Colombier 		if(dp == c->lport){
3409ef1f84bSDavid du Colombier 			unlock(ht);
3419ef1f84bSDavid du Colombier 			return c;
3429ef1f84bSDavid du Colombier 		}
3439ef1f84bSDavid du Colombier 	}
3449ef1f84bSDavid du Colombier 
3459ef1f84bSDavid du Colombier 	/* match local address */
3469ef1f84bSDavid du Colombier 	hv = iphash(IPnoaddr, 0, da, 0);
3479ef1f84bSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
3489ef1f84bSDavid du Colombier 		if(h->match != IPmatchaddr)
3499ef1f84bSDavid du Colombier 			continue;
3509ef1f84bSDavid du Colombier 		c = h->c;
3519ef1f84bSDavid du Colombier 		if(ipcmp(da, c->laddr) == 0){
3529ef1f84bSDavid du Colombier 			unlock(ht);
3539ef1f84bSDavid du Colombier 			return c;
3549ef1f84bSDavid du Colombier 		}
3559ef1f84bSDavid du Colombier 	}
3569ef1f84bSDavid du Colombier 
3579ef1f84bSDavid du Colombier 	/* look for something that matches anything */
3589ef1f84bSDavid du Colombier 	hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
3599ef1f84bSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
3609ef1f84bSDavid du Colombier 		if(h->match != IPmatchany)
3619ef1f84bSDavid du Colombier 			continue;
3629ef1f84bSDavid du Colombier 		c = h->c;
3639ef1f84bSDavid du Colombier 		unlock(ht);
3649ef1f84bSDavid du Colombier 		return c;
3659ef1f84bSDavid du Colombier 	}
3669ef1f84bSDavid du Colombier 	unlock(ht);
3679ef1f84bSDavid du Colombier 	return nil;
3689ef1f84bSDavid du Colombier }
369