xref: /plan9/sys/src/9/ip/ipaux.c (revision ea58ad6fbee60d5a3fca57ac646881779dd8f0ea)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 #include	"ip.h"
8 #include	"ipv6.h"
9 
10 char *v6hdrtypes[Maxhdrtype] =
11 {
12 	[HBH]		"HopbyHop",
13 	[ICMP]		"ICMP",
14 	[IGMP]		"IGMP",
15 	[GGP]		"GGP",
16 	[IPINIP]	"IP",
17 	[ST]		"ST",
18 	[TCP]		"TCP",
19 	[UDP]		"UDP",
20 	[ISO_TP4]	"ISO_TP4",
21 	[RH]		"Routinghdr",
22 	[FH]		"Fraghdr",
23 	[IDRP]		"IDRP",
24 	[RSVP]		"RSVP",
25 	[AH]		"Authhdr",
26 	[ESP]		"ESP",
27 	[ICMPv6]	"ICMPv6",
28 	[NNH]		"Nonexthdr",
29 	[ISO_IP]	"ISO_IP",
30 	[IGRP]		"IGRP",
31 	[OSPF]		"OSPF",
32 };
33 
34 /*
35  *  well known IPv6 addresses
36  */
37 uchar v6Unspecified[IPaddrlen] = {
38 	0, 0, 0, 0,
39 	0, 0, 0, 0,
40 	0, 0, 0, 0,
41 	0, 0, 0, 0
42 };
43 uchar v6loopback[IPaddrlen] = {
44 	0, 0, 0, 0,
45 	0, 0, 0, 0,
46 	0, 0, 0, 0,
47 	0, 0, 0, 0x01
48 };
49 
50 uchar v6linklocal[IPaddrlen] = {
51 	0xfe, 0x80, 0, 0,
52 	0, 0, 0, 0,
53 	0, 0, 0, 0,
54 	0, 0, 0, 0
55 };
56 uchar v6linklocalmask[IPaddrlen] = {
57 	0xff, 0xff, 0xff, 0xff,
58 	0xff, 0xff, 0xff, 0xff,
59 	0, 0, 0, 0,
60 	0, 0, 0, 0
61 };
62 int v6llpreflen = 8;	/* link-local prefix length in bytes */
63 
64 uchar v6multicast[IPaddrlen] = {
65 	0xff, 0, 0, 0,
66 	0, 0, 0, 0,
67 	0, 0, 0, 0,
68 	0, 0, 0, 0
69 };
70 uchar v6multicastmask[IPaddrlen] = {
71 	0xff, 0, 0, 0,
72 	0, 0, 0, 0,
73 	0, 0, 0, 0,
74 	0, 0, 0, 0
75 };
76 int v6mcpreflen = 1;	/* multicast prefix length */
77 
78 uchar v6allnodesN[IPaddrlen] = {
79 	0xff, 0x01, 0, 0,
80 	0, 0, 0, 0,
81 	0, 0, 0, 0,
82 	0, 0, 0, 0x01
83 };
84 uchar v6allroutersN[IPaddrlen] = {
85 	0xff, 0x01, 0, 0,
86 	0, 0, 0, 0,
87 	0, 0, 0, 0,
88 	0, 0, 0, 0x02
89 };
90 uchar v6allnodesNmask[IPaddrlen] = {
91 	0xff, 0xff, 0, 0,
92 	0, 0, 0, 0,
93 	0, 0, 0, 0,
94 	0, 0, 0, 0
95 };
96 int v6aNpreflen = 2;	/* all nodes (N) prefix */
97 
98 uchar v6allnodesL[IPaddrlen] = {
99 	0xff, 0x02, 0, 0,
100 	0, 0, 0, 0,
101 	0, 0, 0, 0,
102 	0, 0, 0, 0x01
103 };
104 uchar v6allroutersL[IPaddrlen] = {
105 	0xff, 0x02, 0, 0,
106 	0, 0, 0, 0,
107 	0, 0, 0, 0,
108 	0, 0, 0, 0x02
109 };
110 uchar v6allnodesLmask[IPaddrlen] = {
111 	0xff, 0xff, 0, 0,
112 	0, 0, 0, 0,
113 	0, 0, 0, 0,
114 	0, 0, 0, 0
115 };
116 int v6aLpreflen = 2;	/* all nodes (L) prefix */
117 
118 uchar v6solicitednode[IPaddrlen] = {
119 	0xff, 0x02, 0, 0,
120 	0, 0, 0, 0,
121 	0, 0, 0, 0x01,
122 	0xff, 0, 0, 0
123 };
124 uchar v6solicitednodemask[IPaddrlen] = {
125 	0xff, 0xff, 0xff, 0xff,
126 	0xff, 0xff, 0xff, 0xff,
127 	0xff, 0xff, 0xff, 0xff,
128 	0xff, 0x0, 0x0, 0x0
129 };
130 int v6snpreflen = 13;
131 
132 ushort
ptclcsum(Block * bp,int offset,int len)133 ptclcsum(Block *bp, int offset, int len)
134 {
135 	uchar *addr;
136 	ulong losum, hisum;
137 	ushort csum;
138 	int odd, blocklen, x;
139 
140 	/* Correct to front of data area */
141 	while(bp != nil && offset && offset >= BLEN(bp)) {
142 		offset -= BLEN(bp);
143 		bp = bp->next;
144 	}
145 	if(bp == nil)
146 		return 0;
147 
148 	addr = bp->rp + offset;
149 	blocklen = BLEN(bp) - offset;
150 
151 	if(bp->next == nil) {
152 		if(blocklen < len)
153 			len = blocklen;
154 		return ~ptclbsum(addr, len) & 0xffff;
155 	}
156 
157 	losum = 0;
158 	hisum = 0;
159 
160 	odd = 0;
161 	while(len) {
162 		x = blocklen;
163 		if(len < x)
164 			x = len;
165 
166 		csum = ptclbsum(addr, x);
167 		if(odd)
168 			hisum += csum;
169 		else
170 			losum += csum;
171 		odd = (odd+x) & 1;
172 		len -= x;
173 
174 		bp = bp->next;
175 		if(bp == nil)
176 			break;
177 		blocklen = BLEN(bp);
178 		addr = bp->rp;
179 	}
180 
181 	losum += hisum>>8;
182 	losum += (hisum&0xff)<<8;
183 	while((csum = losum>>16) != 0)
184 		losum = csum + (losum & 0xffff);
185 
186 	return ~losum & 0xffff;
187 }
188 
189 enum
190 {
191 	Isprefix= 16,
192 };
193 
194 #define CLASS(p) ((*(uchar*)(p))>>6)
195 
196 void
ipv62smcast(uchar * smcast,uchar * a)197 ipv62smcast(uchar *smcast, uchar *a)
198 {
199 	assert(IPaddrlen == 16);
200 	memmove(smcast, v6solicitednode, IPaddrlen);
201 	smcast[13] = a[13];
202 	smcast[14] = a[14];
203 	smcast[15] = a[15];
204 }
205 
206 
207 /*
208  *  parse a hex mac address
209  */
210 int
parsemac(uchar * to,char * from,int len)211 parsemac(uchar *to, char *from, int len)
212 {
213 	char nip[4];
214 	char *p;
215 	int i;
216 
217 	p = from;
218 	memset(to, 0, len);
219 	for(i = 0; i < len; i++){
220 		if(p[0] == '\0' || p[1] == '\0')
221 			break;
222 
223 		nip[0] = p[0];
224 		nip[1] = p[1];
225 		nip[2] = '\0';
226 		p += 2;
227 
228 		to[i] = strtoul(nip, 0, 16);
229 		if(*p == ':')
230 			p++;
231 	}
232 	return i;
233 }
234 
235 /*
236  *  hashing tcp, udp, ... connections
237  */
238 ulong
iphash(uchar * sa,ushort sp,uchar * da,ushort dp)239 iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
240 {
241 	return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nhash;
242 }
243 
244 void
iphtadd(Ipht * ht,Conv * c)245 iphtadd(Ipht *ht, Conv *c)
246 {
247 	ulong hv;
248 	Iphash *h;
249 
250 	hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
251 	h = smalloc(sizeof(*h));
252 	if(ipcmp(c->raddr, IPnoaddr) != 0)
253 		h->match = IPmatchexact;
254 	else {
255 		if(ipcmp(c->laddr, IPnoaddr) != 0){
256 			if(c->lport == 0)
257 				h->match = IPmatchaddr;
258 			else
259 				h->match = IPmatchpa;
260 		} else {
261 			if(c->lport == 0)
262 				h->match = IPmatchany;
263 			else
264 				h->match = IPmatchport;
265 		}
266 	}
267 	h->c = c;
268 
269 	lock(ht);
270 	h->next = ht->tab[hv];
271 	ht->tab[hv] = h;
272 	unlock(ht);
273 }
274 
275 void
iphtrem(Ipht * ht,Conv * c)276 iphtrem(Ipht *ht, Conv *c)
277 {
278 	ulong hv;
279 	Iphash **l, *h;
280 
281 	hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
282 	lock(ht);
283 	for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
284 		if((*l)->c == c){
285 			h = *l;
286 			(*l) = h->next;
287 			free(h);
288 			break;
289 		}
290 	unlock(ht);
291 }
292 
293 /* look for a matching conversation with the following precedence
294  *	connected && raddr,rport,laddr,lport
295  *	announced && laddr,lport
296  *	announced && *,lport
297  *	announced && laddr,*
298  *	announced && *,*
299  */
300 Conv*
iphtlook(Ipht * ht,uchar * sa,ushort sp,uchar * da,ushort dp)301 iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
302 {
303 	ulong hv;
304 	Iphash *h;
305 	Conv *c;
306 
307 	/* exact 4 pair match (connection) */
308 	hv = iphash(sa, sp, da, dp);
309 	lock(ht);
310 	for(h = ht->tab[hv]; h != nil; h = h->next){
311 		if(h->match != IPmatchexact)
312 			continue;
313 		c = h->c;
314 		if(sp == c->rport && dp == c->lport
315 		&& ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
316 			unlock(ht);
317 			return c;
318 		}
319 	}
320 
321 	/* match local address and port */
322 	hv = iphash(IPnoaddr, 0, da, dp);
323 	for(h = ht->tab[hv]; h != nil; h = h->next){
324 		if(h->match != IPmatchpa)
325 			continue;
326 		c = h->c;
327 		if(dp == c->lport && ipcmp(da, c->laddr) == 0){
328 			unlock(ht);
329 			return c;
330 		}
331 	}
332 
333 	/* match just port */
334 	hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
335 	for(h = ht->tab[hv]; h != nil; h = h->next){
336 		if(h->match != IPmatchport)
337 			continue;
338 		c = h->c;
339 		if(dp == c->lport){
340 			unlock(ht);
341 			return c;
342 		}
343 	}
344 
345 	/* match local address */
346 	hv = iphash(IPnoaddr, 0, da, 0);
347 	for(h = ht->tab[hv]; h != nil; h = h->next){
348 		if(h->match != IPmatchaddr)
349 			continue;
350 		c = h->c;
351 		if(ipcmp(da, c->laddr) == 0){
352 			unlock(ht);
353 			return c;
354 		}
355 	}
356 
357 	/* look for something that matches anything */
358 	hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
359 	for(h = ht->tab[hv]; h != nil; h = h->next){
360 		if(h->match != IPmatchany)
361 			continue;
362 		c = h->c;
363 		unlock(ht);
364 		return c;
365 	}
366 	unlock(ht);
367 	return nil;
368 }
369