xref: /plan9/sys/src/9/ip/ipaux.c (revision ea58ad6fbee60d5a3fca57ac646881779dd8f0ea)
17dd7cddfSDavid du Colombier #include	"u.h"
27dd7cddfSDavid du Colombier #include	"../port/lib.h"
37dd7cddfSDavid du Colombier #include	"mem.h"
47dd7cddfSDavid du Colombier #include	"dat.h"
57dd7cddfSDavid du Colombier #include	"fns.h"
67dd7cddfSDavid du Colombier #include	"../port/error.h"
77dd7cddfSDavid du Colombier #include	"ip.h"
83ff48bf5SDavid du Colombier #include	"ipv6.h"
97dd7cddfSDavid du Colombier 
103ff48bf5SDavid du Colombier char *v6hdrtypes[Maxhdrtype] =
113ff48bf5SDavid du Colombier {
123ff48bf5SDavid du Colombier 	[HBH]		"HopbyHop",
133ff48bf5SDavid du Colombier 	[ICMP]		"ICMP",
143ff48bf5SDavid du Colombier 	[IGMP]		"IGMP",
153ff48bf5SDavid du Colombier 	[GGP]		"GGP",
163ff48bf5SDavid du Colombier 	[IPINIP]	"IP",
173ff48bf5SDavid du Colombier 	[ST]		"ST",
183ff48bf5SDavid du Colombier 	[TCP]		"TCP",
193ff48bf5SDavid du Colombier 	[UDP]		"UDP",
203ff48bf5SDavid du Colombier 	[ISO_TP4]	"ISO_TP4",
213ff48bf5SDavid du Colombier 	[RH]		"Routinghdr",
223ff48bf5SDavid du Colombier 	[FH]		"Fraghdr",
233ff48bf5SDavid du Colombier 	[IDRP]		"IDRP",
243ff48bf5SDavid du Colombier 	[RSVP]		"RSVP",
253ff48bf5SDavid du Colombier 	[AH]		"Authhdr",
263ff48bf5SDavid du Colombier 	[ESP]		"ESP",
273ff48bf5SDavid du Colombier 	[ICMPv6]	"ICMPv6",
283ff48bf5SDavid du Colombier 	[NNH]		"Nonexthdr",
293ff48bf5SDavid du Colombier 	[ISO_IP]	"ISO_IP",
303ff48bf5SDavid du Colombier 	[IGRP]		"IGRP",
313ff48bf5SDavid du Colombier 	[OSPF]		"OSPF",
323ff48bf5SDavid du Colombier };
333ff48bf5SDavid du Colombier 
343ff48bf5SDavid du Colombier /*
353ff48bf5SDavid du Colombier  *  well known IPv6 addresses
363ff48bf5SDavid du Colombier  */
373ff48bf5SDavid du Colombier uchar v6Unspecified[IPaddrlen] = {
383ff48bf5SDavid du Colombier 	0, 0, 0, 0,
393ff48bf5SDavid du Colombier 	0, 0, 0, 0,
403ff48bf5SDavid du Colombier 	0, 0, 0, 0,
413ff48bf5SDavid du Colombier 	0, 0, 0, 0
423ff48bf5SDavid du Colombier };
433ff48bf5SDavid du Colombier uchar v6loopback[IPaddrlen] = {
443ff48bf5SDavid du Colombier 	0, 0, 0, 0,
453ff48bf5SDavid du Colombier 	0, 0, 0, 0,
463ff48bf5SDavid du Colombier 	0, 0, 0, 0,
473ff48bf5SDavid du Colombier 	0, 0, 0, 0x01
483ff48bf5SDavid du Colombier };
49*6e712d44SDavid du Colombier 
503ff48bf5SDavid du Colombier uchar v6linklocal[IPaddrlen] = {
513ff48bf5SDavid du Colombier 	0xfe, 0x80, 0, 0,
523ff48bf5SDavid du Colombier 	0, 0, 0, 0,
533ff48bf5SDavid du Colombier 	0, 0, 0, 0,
543ff48bf5SDavid du Colombier 	0, 0, 0, 0
553ff48bf5SDavid du Colombier };
563ff48bf5SDavid du Colombier uchar v6linklocalmask[IPaddrlen] = {
573ff48bf5SDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
583ff48bf5SDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
593ff48bf5SDavid du Colombier 	0, 0, 0, 0,
603ff48bf5SDavid du Colombier 	0, 0, 0, 0
613ff48bf5SDavid du Colombier };
62*6e712d44SDavid du Colombier int v6llpreflen = 8;	/* link-local prefix length in bytes */
63*6e712d44SDavid du Colombier 
643ff48bf5SDavid du Colombier uchar v6multicast[IPaddrlen] = {
653ff48bf5SDavid du Colombier 	0xff, 0, 0, 0,
663ff48bf5SDavid du Colombier 	0, 0, 0, 0,
673ff48bf5SDavid du Colombier 	0, 0, 0, 0,
683ff48bf5SDavid du Colombier 	0, 0, 0, 0
693ff48bf5SDavid du Colombier };
703ff48bf5SDavid du Colombier uchar v6multicastmask[IPaddrlen] = {
713ff48bf5SDavid du Colombier 	0xff, 0, 0, 0,
723ff48bf5SDavid du Colombier 	0, 0, 0, 0,
733ff48bf5SDavid du Colombier 	0, 0, 0, 0,
743ff48bf5SDavid du Colombier 	0, 0, 0, 0
753ff48bf5SDavid du Colombier };
7641dd6b47SDavid du Colombier int v6mcpreflen = 1;	/* multicast prefix length */
77*6e712d44SDavid du Colombier 
783ff48bf5SDavid du Colombier uchar v6allnodesN[IPaddrlen] = {
793ff48bf5SDavid du Colombier 	0xff, 0x01, 0, 0,
803ff48bf5SDavid du Colombier 	0, 0, 0, 0,
813ff48bf5SDavid du Colombier 	0, 0, 0, 0,
823ff48bf5SDavid du Colombier 	0, 0, 0, 0x01
833ff48bf5SDavid du Colombier };
84*6e712d44SDavid du Colombier uchar v6allroutersN[IPaddrlen] = {
85*6e712d44SDavid du Colombier 	0xff, 0x01, 0, 0,
86*6e712d44SDavid du Colombier 	0, 0, 0, 0,
87*6e712d44SDavid du Colombier 	0, 0, 0, 0,
88*6e712d44SDavid du Colombier 	0, 0, 0, 0x02
89*6e712d44SDavid du Colombier };
903ff48bf5SDavid du Colombier uchar v6allnodesNmask[IPaddrlen] = {
913ff48bf5SDavid du Colombier 	0xff, 0xff, 0, 0,
923ff48bf5SDavid du Colombier 	0, 0, 0, 0,
933ff48bf5SDavid du Colombier 	0, 0, 0, 0,
943ff48bf5SDavid du Colombier 	0, 0, 0, 0
953ff48bf5SDavid du Colombier };
9641dd6b47SDavid du Colombier int v6aNpreflen = 2;	/* all nodes (N) prefix */
97*6e712d44SDavid du Colombier 
983ff48bf5SDavid du Colombier uchar v6allnodesL[IPaddrlen] = {
993ff48bf5SDavid du Colombier 	0xff, 0x02, 0, 0,
1003ff48bf5SDavid du Colombier 	0, 0, 0, 0,
1013ff48bf5SDavid du Colombier 	0, 0, 0, 0,
1023ff48bf5SDavid du Colombier 	0, 0, 0, 0x01
1033ff48bf5SDavid du Colombier };
104*6e712d44SDavid du Colombier uchar v6allroutersL[IPaddrlen] = {
105*6e712d44SDavid du Colombier 	0xff, 0x02, 0, 0,
106*6e712d44SDavid du Colombier 	0, 0, 0, 0,
107*6e712d44SDavid du Colombier 	0, 0, 0, 0,
108*6e712d44SDavid du Colombier 	0, 0, 0, 0x02
109*6e712d44SDavid du Colombier };
1103ff48bf5SDavid du Colombier uchar v6allnodesLmask[IPaddrlen] = {
1113ff48bf5SDavid du Colombier 	0xff, 0xff, 0, 0,
1123ff48bf5SDavid du Colombier 	0, 0, 0, 0,
1133ff48bf5SDavid du Colombier 	0, 0, 0, 0,
1143ff48bf5SDavid du Colombier 	0, 0, 0, 0
1153ff48bf5SDavid du Colombier };
11641dd6b47SDavid du Colombier int v6aLpreflen = 2;	/* all nodes (L) prefix */
117*6e712d44SDavid du Colombier 
1183ff48bf5SDavid du Colombier uchar v6solicitednode[IPaddrlen] = {
1193ff48bf5SDavid du Colombier 	0xff, 0x02, 0, 0,
1203ff48bf5SDavid du Colombier 	0, 0, 0, 0,
1213ff48bf5SDavid du Colombier 	0, 0, 0, 0x01,
1223ff48bf5SDavid du Colombier 	0xff, 0, 0, 0
1233ff48bf5SDavid du Colombier };
1243ff48bf5SDavid du Colombier uchar v6solicitednodemask[IPaddrlen] = {
1253ff48bf5SDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
1263ff48bf5SDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
1273ff48bf5SDavid du Colombier 	0xff, 0xff, 0xff, 0xff,
1283ff48bf5SDavid du Colombier 	0xff, 0x0, 0x0, 0x0
1293ff48bf5SDavid du Colombier };
13067493d07SDavid du Colombier int v6snpreflen = 13;
1313ff48bf5SDavid du Colombier 
1327dd7cddfSDavid du Colombier ushort
ptclcsum(Block * bp,int offset,int len)1337dd7cddfSDavid du Colombier ptclcsum(Block *bp, int offset, int len)
1347dd7cddfSDavid du Colombier {
1357dd7cddfSDavid du Colombier 	uchar *addr;
1367dd7cddfSDavid du Colombier 	ulong losum, hisum;
1377dd7cddfSDavid du Colombier 	ushort csum;
1387dd7cddfSDavid du Colombier 	int odd, blocklen, x;
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 	/* Correct to front of data area */
1417dd7cddfSDavid du Colombier 	while(bp != nil && offset && offset >= BLEN(bp)) {
1427dd7cddfSDavid du Colombier 		offset -= BLEN(bp);
1437dd7cddfSDavid du Colombier 		bp = bp->next;
1447dd7cddfSDavid du Colombier 	}
1457dd7cddfSDavid du Colombier 	if(bp == nil)
1467dd7cddfSDavid du Colombier 		return 0;
1477dd7cddfSDavid du Colombier 
1487dd7cddfSDavid du Colombier 	addr = bp->rp + offset;
1497dd7cddfSDavid du Colombier 	blocklen = BLEN(bp) - offset;
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier 	if(bp->next == nil) {
1527dd7cddfSDavid du Colombier 		if(blocklen < len)
1537dd7cddfSDavid du Colombier 			len = blocklen;
1547dd7cddfSDavid du Colombier 		return ~ptclbsum(addr, len) & 0xffff;
1557dd7cddfSDavid du Colombier 	}
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 	losum = 0;
1587dd7cddfSDavid du Colombier 	hisum = 0;
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier 	odd = 0;
1617dd7cddfSDavid du Colombier 	while(len) {
1627dd7cddfSDavid du Colombier 		x = blocklen;
1637dd7cddfSDavid du Colombier 		if(len < x)
1647dd7cddfSDavid du Colombier 			x = len;
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier 		csum = ptclbsum(addr, x);
1677dd7cddfSDavid du Colombier 		if(odd)
1687dd7cddfSDavid du Colombier 			hisum += csum;
1697dd7cddfSDavid du Colombier 		else
1707dd7cddfSDavid du Colombier 			losum += csum;
1717dd7cddfSDavid du Colombier 		odd = (odd+x) & 1;
1727dd7cddfSDavid du Colombier 		len -= x;
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier 		bp = bp->next;
1757dd7cddfSDavid du Colombier 		if(bp == nil)
1767dd7cddfSDavid du Colombier 			break;
1777dd7cddfSDavid du Colombier 		blocklen = BLEN(bp);
1787dd7cddfSDavid du Colombier 		addr = bp->rp;
1797dd7cddfSDavid du Colombier 	}
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 	losum += hisum>>8;
1827dd7cddfSDavid du Colombier 	losum += (hisum&0xff)<<8;
1837dd7cddfSDavid du Colombier 	while((csum = losum>>16) != 0)
1847dd7cddfSDavid du Colombier 		losum = csum + (losum & 0xffff);
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier 	return ~losum & 0xffff;
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier enum
1907dd7cddfSDavid du Colombier {
1917dd7cddfSDavid du Colombier 	Isprefix= 16,
1927dd7cddfSDavid du Colombier };
1937dd7cddfSDavid du Colombier 
1947dd7cddfSDavid du Colombier #define CLASS(p) ((*(uchar*)(p))>>6)
1957dd7cddfSDavid du Colombier 
1963ff48bf5SDavid du Colombier void
ipv62smcast(uchar * smcast,uchar * a)1973ff48bf5SDavid du Colombier ipv62smcast(uchar *smcast, uchar *a)
1983ff48bf5SDavid du Colombier {
1993ff48bf5SDavid du Colombier 	assert(IPaddrlen == 16);
2003ff48bf5SDavid du Colombier 	memmove(smcast, v6solicitednode, IPaddrlen);
2013ff48bf5SDavid du Colombier 	smcast[13] = a[13];
2023ff48bf5SDavid du Colombier 	smcast[14] = a[14];
2033ff48bf5SDavid du Colombier 	smcast[15] = a[15];
2043ff48bf5SDavid du Colombier }
2053ff48bf5SDavid du Colombier 
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier /*
2087dd7cddfSDavid du Colombier  *  parse a hex mac address
2097dd7cddfSDavid du Colombier  */
2107dd7cddfSDavid du Colombier int
parsemac(uchar * to,char * from,int len)2117dd7cddfSDavid du Colombier parsemac(uchar *to, char *from, int len)
2127dd7cddfSDavid du Colombier {
2137dd7cddfSDavid du Colombier 	char nip[4];
2147dd7cddfSDavid du Colombier 	char *p;
2157dd7cddfSDavid du Colombier 	int i;
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier 	p = from;
2187dd7cddfSDavid du Colombier 	memset(to, 0, len);
2197dd7cddfSDavid du Colombier 	for(i = 0; i < len; i++){
2207dd7cddfSDavid du Colombier 		if(p[0] == '\0' || p[1] == '\0')
2217dd7cddfSDavid du Colombier 			break;
2227dd7cddfSDavid du Colombier 
2237dd7cddfSDavid du Colombier 		nip[0] = p[0];
2247dd7cddfSDavid du Colombier 		nip[1] = p[1];
2257dd7cddfSDavid du Colombier 		nip[2] = '\0';
2267dd7cddfSDavid du Colombier 		p += 2;
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
2297dd7cddfSDavid du Colombier 		if(*p == ':')
2307dd7cddfSDavid du Colombier 			p++;
2317dd7cddfSDavid du Colombier 	}
2327dd7cddfSDavid du Colombier 	return i;
2337dd7cddfSDavid du Colombier }
23480ee5cbfSDavid du Colombier 
23580ee5cbfSDavid du Colombier /*
23680ee5cbfSDavid du Colombier  *  hashing tcp, udp, ... connections
23780ee5cbfSDavid du Colombier  */
23880ee5cbfSDavid du Colombier ulong
iphash(uchar * sa,ushort sp,uchar * da,ushort dp)23980ee5cbfSDavid du Colombier iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
24080ee5cbfSDavid du Colombier {
24180ee5cbfSDavid du Colombier 	return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nhash;
24280ee5cbfSDavid du Colombier }
24380ee5cbfSDavid du Colombier 
24480ee5cbfSDavid du Colombier void
iphtadd(Ipht * ht,Conv * c)24580ee5cbfSDavid du Colombier iphtadd(Ipht *ht, Conv *c)
24680ee5cbfSDavid du Colombier {
24780ee5cbfSDavid du Colombier 	ulong hv;
24880ee5cbfSDavid du Colombier 	Iphash *h;
24980ee5cbfSDavid du Colombier 
25080ee5cbfSDavid du Colombier 	hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
25180ee5cbfSDavid du Colombier 	h = smalloc(sizeof(*h));
25280ee5cbfSDavid du Colombier 	if(ipcmp(c->raddr, IPnoaddr) != 0)
25380ee5cbfSDavid du Colombier 		h->match = IPmatchexact;
25480ee5cbfSDavid du Colombier 	else {
25580ee5cbfSDavid du Colombier 		if(ipcmp(c->laddr, IPnoaddr) != 0){
25680ee5cbfSDavid du Colombier 			if(c->lport == 0)
25780ee5cbfSDavid du Colombier 				h->match = IPmatchaddr;
25880ee5cbfSDavid du Colombier 			else
25980ee5cbfSDavid du Colombier 				h->match = IPmatchpa;
26080ee5cbfSDavid du Colombier 		} else {
26180ee5cbfSDavid du Colombier 			if(c->lport == 0)
26280ee5cbfSDavid du Colombier 				h->match = IPmatchany;
26380ee5cbfSDavid du Colombier 			else
26480ee5cbfSDavid du Colombier 				h->match = IPmatchport;
26580ee5cbfSDavid du Colombier 		}
26680ee5cbfSDavid du Colombier 	}
26780ee5cbfSDavid du Colombier 	h->c = c;
26880ee5cbfSDavid du Colombier 
26980ee5cbfSDavid du Colombier 	lock(ht);
27080ee5cbfSDavid du Colombier 	h->next = ht->tab[hv];
27180ee5cbfSDavid du Colombier 	ht->tab[hv] = h;
27280ee5cbfSDavid du Colombier 	unlock(ht);
27380ee5cbfSDavid du Colombier }
27480ee5cbfSDavid du Colombier 
27580ee5cbfSDavid du Colombier void
iphtrem(Ipht * ht,Conv * c)27680ee5cbfSDavid du Colombier iphtrem(Ipht *ht, Conv *c)
27780ee5cbfSDavid du Colombier {
27880ee5cbfSDavid du Colombier 	ulong hv;
27980ee5cbfSDavid du Colombier 	Iphash **l, *h;
28080ee5cbfSDavid du Colombier 
28180ee5cbfSDavid du Colombier 	hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
28280ee5cbfSDavid du Colombier 	lock(ht);
28380ee5cbfSDavid du Colombier 	for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
28480ee5cbfSDavid du Colombier 		if((*l)->c == c){
28580ee5cbfSDavid du Colombier 			h = *l;
28680ee5cbfSDavid du Colombier 			(*l) = h->next;
28780ee5cbfSDavid du Colombier 			free(h);
28880ee5cbfSDavid du Colombier 			break;
28980ee5cbfSDavid du Colombier 		}
29080ee5cbfSDavid du Colombier 	unlock(ht);
29180ee5cbfSDavid du Colombier }
29280ee5cbfSDavid du Colombier 
29380ee5cbfSDavid du Colombier /* look for a matching conversation with the following precedence
29480ee5cbfSDavid du Colombier  *	connected && raddr,rport,laddr,lport
29580ee5cbfSDavid du Colombier  *	announced && laddr,lport
29680ee5cbfSDavid du Colombier  *	announced && *,lport
29780ee5cbfSDavid du Colombier  *	announced && laddr,*
29880ee5cbfSDavid du Colombier  *	announced && *,*
29980ee5cbfSDavid du Colombier  */
30080ee5cbfSDavid du Colombier Conv*
iphtlook(Ipht * ht,uchar * sa,ushort sp,uchar * da,ushort dp)30180ee5cbfSDavid du Colombier iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
30280ee5cbfSDavid du Colombier {
30380ee5cbfSDavid du Colombier 	ulong hv;
30480ee5cbfSDavid du Colombier 	Iphash *h;
30580ee5cbfSDavid du Colombier 	Conv *c;
30680ee5cbfSDavid du Colombier 
30780ee5cbfSDavid du Colombier 	/* exact 4 pair match (connection) */
30880ee5cbfSDavid du Colombier 	hv = iphash(sa, sp, da, dp);
30980ee5cbfSDavid du Colombier 	lock(ht);
31080ee5cbfSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
31180ee5cbfSDavid du Colombier 		if(h->match != IPmatchexact)
31280ee5cbfSDavid du Colombier 			continue;
31380ee5cbfSDavid du Colombier 		c = h->c;
31480ee5cbfSDavid du Colombier 		if(sp == c->rport && dp == c->lport
31580ee5cbfSDavid du Colombier 		&& ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
31680ee5cbfSDavid du Colombier 			unlock(ht);
31780ee5cbfSDavid du Colombier 			return c;
31880ee5cbfSDavid du Colombier 		}
31980ee5cbfSDavid du Colombier 	}
32080ee5cbfSDavid du Colombier 
32180ee5cbfSDavid du Colombier 	/* match local address and port */
32280ee5cbfSDavid du Colombier 	hv = iphash(IPnoaddr, 0, da, dp);
32380ee5cbfSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
32480ee5cbfSDavid du Colombier 		if(h->match != IPmatchpa)
32580ee5cbfSDavid du Colombier 			continue;
32680ee5cbfSDavid du Colombier 		c = h->c;
32780ee5cbfSDavid du Colombier 		if(dp == c->lport && ipcmp(da, c->laddr) == 0){
32880ee5cbfSDavid du Colombier 			unlock(ht);
32980ee5cbfSDavid du Colombier 			return c;
33080ee5cbfSDavid du Colombier 		}
33180ee5cbfSDavid du Colombier 	}
33280ee5cbfSDavid du Colombier 
33380ee5cbfSDavid du Colombier 	/* match just port */
33480ee5cbfSDavid du Colombier 	hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
33580ee5cbfSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
33680ee5cbfSDavid du Colombier 		if(h->match != IPmatchport)
33780ee5cbfSDavid du Colombier 			continue;
33880ee5cbfSDavid du Colombier 		c = h->c;
33980ee5cbfSDavid du Colombier 		if(dp == c->lport){
34080ee5cbfSDavid du Colombier 			unlock(ht);
34180ee5cbfSDavid du Colombier 			return c;
34280ee5cbfSDavid du Colombier 		}
34380ee5cbfSDavid du Colombier 	}
34480ee5cbfSDavid du Colombier 
34580ee5cbfSDavid du Colombier 	/* match local address */
34680ee5cbfSDavid du Colombier 	hv = iphash(IPnoaddr, 0, da, 0);
34780ee5cbfSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
34880ee5cbfSDavid du Colombier 		if(h->match != IPmatchaddr)
34980ee5cbfSDavid du Colombier 			continue;
35080ee5cbfSDavid du Colombier 		c = h->c;
35180ee5cbfSDavid du Colombier 		if(ipcmp(da, c->laddr) == 0){
35280ee5cbfSDavid du Colombier 			unlock(ht);
35380ee5cbfSDavid du Colombier 			return c;
35480ee5cbfSDavid du Colombier 		}
35580ee5cbfSDavid du Colombier 	}
35680ee5cbfSDavid du Colombier 
35780ee5cbfSDavid du Colombier 	/* look for something that matches anything */
35880ee5cbfSDavid du Colombier 	hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
35980ee5cbfSDavid du Colombier 	for(h = ht->tab[hv]; h != nil; h = h->next){
36080ee5cbfSDavid du Colombier 		if(h->match != IPmatchany)
36180ee5cbfSDavid du Colombier 			continue;
36280ee5cbfSDavid du Colombier 		c = h->c;
36380ee5cbfSDavid du Colombier 		unlock(ht);
36480ee5cbfSDavid du Colombier 		return c;
36580ee5cbfSDavid du Colombier 	}
36680ee5cbfSDavid du Colombier 	unlock(ht);
36780ee5cbfSDavid du Colombier 	return nil;
36880ee5cbfSDavid du Colombier }
369