Adds chaninfo()
[akaros.git] / kern / src / net / ipaux.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 /*
17  *  well known IP addresses
18  */
19 uint8_t IPv4bcast[IPaddrlen] = {
20         0, 0, 0, 0,
21         0, 0, 0, 0,
22         0, 0, 0xff, 0xff,
23         0xff, 0xff, 0xff, 0xff
24 };
25 uint8_t IPv4allsys[IPaddrlen] = {
26         0, 0, 0, 0,
27         0, 0, 0, 0,
28         0, 0, 0xff, 0xff,
29         0xe0, 0, 0, 0x01
30 };
31 uint8_t IPv4allrouter[IPaddrlen] = {
32         0, 0, 0, 0,
33         0, 0, 0, 0,
34         0, 0, 0xff, 0xff,
35         0xe0, 0, 0, 0x02
36 };
37 uint8_t IPallbits[IPaddrlen] = {
38         0xff, 0xff, 0xff, 0xff,
39         0xff, 0xff, 0xff, 0xff,
40         0xff, 0xff, 0xff, 0xff,
41         0xff, 0xff, 0xff, 0xff
42 };
43
44 uint8_t IPnoaddr[IPaddrlen];
45
46 /*
47  *  prefix of all v4 addresses
48  */
49 uint8_t v4prefix[IPaddrlen] = {
50         0, 0, 0, 0,
51         0, 0, 0, 0,
52         0, 0, 0xff, 0xff,
53         0, 0, 0, 0
54 };
55
56 char *v6hdrtypes[Maxhdrtype] =
57 {
58         [HBH]           "HopbyHop",
59         [ICMP]          "ICMP",
60         [IGMP]          "IGMP",
61         [GGP]           "GGP",
62         [IPINIP]                "IP",
63         [ST]            "ST",
64         [TCP]           "TCP",
65         [UDP]           "UDP",
66         [ISO_TP4]       "ISO_TP4",
67         [RH]            "Routinghdr",
68         [FH]            "Fraghdr",
69         [IDRP]          "IDRP",
70         [RSVP]          "RSVP",
71         [AH]            "Authhdr",
72         [ESP]           "ESP",
73         [ICMPv6]        "ICMPv6",
74         [NNH]           "Nonexthdr",
75         [ISO_IP]        "ISO_IP",
76         [IGRP]          "IGRP",
77         [OSPF]          "OSPF",
78 };
79
80 /*
81  *  well known IPv6 addresses
82  */
83 uint8_t v6Unspecified[IPaddrlen] = {
84         0, 0, 0, 0,
85         0, 0, 0, 0,
86         0, 0, 0, 0,
87         0, 0, 0, 0
88 };
89 uint8_t v6loopback[IPaddrlen] = {
90         0, 0, 0, 0,
91         0, 0, 0, 0,
92         0, 0, 0, 0,
93         0, 0, 0, 0x01
94 };
95 uint8_t v6linklocal[IPaddrlen] = {
96         0xfe, 0x80, 0, 0,
97         0, 0, 0, 0,
98         0, 0, 0, 0,
99         0, 0, 0, 0
100 };
101 uint8_t v6linklocalmask[IPaddrlen] = {
102         0xff, 0xff, 0xff, 0xff,
103         0xff, 0xff, 0xff, 0xff,
104         0, 0, 0, 0,
105         0, 0, 0, 0
106 };
107 int v6llpreflen = 8;    // link-local prefix length
108 uint8_t v6sitelocal[IPaddrlen] = {
109         0xfe, 0xc0, 0, 0,
110         0, 0, 0, 0,
111         0, 0, 0, 0,
112         0, 0, 0, 0
113 };
114 uint8_t v6sitelocalmask[IPaddrlen] = {
115         0xff, 0xff, 0xff, 0xff,
116         0xff, 0xff, 0xff, 0xff,
117         0, 0, 0, 0,
118         0, 0, 0, 0
119 };
120 int v6slpreflen = 6;    // site-local prefix length
121 uint8_t v6glunicast[IPaddrlen] = {
122         0x08, 0, 0, 0,
123         0, 0, 0, 0,
124         0, 0, 0, 0,
125         0, 0, 0, 0
126 };
127 uint8_t v6multicast[IPaddrlen] = {
128         0xff, 0, 0, 0,
129         0, 0, 0, 0,
130         0, 0, 0, 0,
131         0, 0, 0, 0
132 };
133 uint8_t v6multicastmask[IPaddrlen] = {
134         0xff, 0, 0, 0,
135         0, 0, 0, 0,
136         0, 0, 0, 0,
137         0, 0, 0, 0
138 };
139 int v6mcpreflen = 1;    // multicast prefix length
140 uint8_t v6allnodesN[IPaddrlen] = {
141         0xff, 0x01, 0, 0,
142         0, 0, 0, 0,
143         0, 0, 0, 0,
144         0, 0, 0, 0x01
145 };
146 uint8_t v6allnodesNmask[IPaddrlen] = {
147         0xff, 0xff, 0, 0,
148         0, 0, 0, 0,
149         0, 0, 0, 0,
150         0, 0, 0, 0
151 };
152 int v6aNpreflen = 2;    // all nodes (N) prefix
153 uint8_t v6allnodesL[IPaddrlen] = {
154         0xff, 0x02, 0, 0,
155         0, 0, 0, 0,
156         0, 0, 0, 0,
157         0, 0, 0, 0x01
158 };
159 uint8_t v6allnodesLmask[IPaddrlen] = {
160         0xff, 0xff, 0, 0,
161         0, 0, 0, 0,
162         0, 0, 0, 0,
163         0, 0, 0, 0
164 };
165 int v6aLpreflen = 2;    // all nodes (L) prefix
166 uint8_t v6allroutersN[IPaddrlen] = {
167         0xff, 0x01, 0, 0,
168         0, 0, 0, 0,
169         0, 0, 0, 0,
170         0, 0, 0, 0x02
171 };
172 uint8_t v6allroutersL[IPaddrlen] = {
173         0xff, 0x02, 0, 0,
174         0, 0, 0, 0,
175         0, 0, 0, 0,
176         0, 0, 0, 0x02
177 };
178 uint8_t v6allroutersS[IPaddrlen] = {
179         0xff, 0x05, 0, 0,
180         0, 0, 0, 0,
181         0, 0, 0, 0,
182         0, 0, 0, 0x02
183 };
184 uint8_t v6solicitednode[IPaddrlen] = {
185         0xff, 0x02, 0, 0,
186         0, 0, 0, 0,
187         0, 0, 0, 0x01,
188         0xff, 0, 0, 0
189 };
190 uint8_t v6solicitednodemask[IPaddrlen] = {
191         0xff, 0xff, 0xff, 0xff,
192         0xff, 0xff, 0xff, 0xff,
193         0xff, 0xff, 0xff, 0xff,
194         0xff, 0x0, 0x0, 0x0
195 };
196 int v6snpreflen = 13;
197
198
199
200
201 uint16_t
202 ptclcsum(struct block *bp, int offset, int len)
203 {
204         uint8_t *addr;
205         uint32_t losum, hisum;
206         uint16_t csum;
207         int odd, blocklen, x;
208
209         /* Correct to front of data area */
210         while(bp != NULL && offset && offset >= BLEN(bp)) {
211                 offset -= BLEN(bp);
212                 bp = bp->next;
213         }
214         if(bp == NULL)
215                 return 0;
216
217         addr = bp->rp + offset;
218         blocklen = BLEN(bp) - offset;
219
220         if(bp->next == NULL) {
221                 if(blocklen < len)
222                         len = blocklen;
223                 return ~ptclbsum(addr, len) & 0xffff;
224         }
225
226         losum = 0;
227         hisum = 0;
228
229         odd = 0;
230         while(len) {
231                 x = blocklen;
232                 if(len < x)
233                         x = len;
234
235                 csum = ptclbsum(addr, x);
236                 if(odd)
237                         hisum += csum;
238                 else
239                         losum += csum;
240                 odd = (odd+x) & 1;
241                 len -= x;
242
243                 bp = bp->next;
244                 if(bp == NULL)
245                         break;
246                 blocklen = BLEN(bp);
247                 addr = bp->rp;
248         }
249
250         losum += hisum>>8;
251         losum += (hisum&0xff)<<8;
252         while((csum = losum>>16) != 0)
253                 losum = csum + (losum & 0xffff);
254
255         return ~losum & 0xffff;
256 }
257
258 enum
259 {
260         Isprefix= 16,
261 };
262
263 static uint8_t prefixvals[256] =
264 {
265 [0x00] 0 | Isprefix,
266 [0x80] 1 | Isprefix,
267 [0xC0] 2 | Isprefix,
268 [0xE0] 3 | Isprefix,
269 [0xF0] 4 | Isprefix,
270 [0xF8] 5 | Isprefix,
271 [0xFC] 6 | Isprefix,
272 [0xFE] 7 | Isprefix,
273 [0xFF] 8 | Isprefix,
274 };
275
276 #define CLASS(p) ((*( uint8_t *)(p))>>6)
277
278 extern char*
279 v4parseip(uint8_t *to, char *from)
280 {
281         int i;
282         char *p;
283
284         p = from;
285         for(i = 0; i < 4 && *p; i++){
286                 to[i] = strtoul(p, &p, 0);
287                 if(*p == '.')
288                         p++;
289         }
290         switch(CLASS(to)){
291         case 0: /* class A - 1 uint8_t net */
292         case 1:
293                 if(i == 3){
294                         to[3] = to[2];
295                         to[2] = to[1];
296                         to[1] = 0;
297                 } else if(i == 2){
298                         to[3] = to[1];
299                         to[1] = 0;
300                 }
301                 break;
302         case 2: /* class B - 2 uint8_t net */
303                 if(i == 3){
304                         to[3] = to[2];
305                         to[2] = 0;
306                 }
307                 break;
308         }
309         return p;
310 }
311
312 int
313 isv4(uint8_t *ip)
314 {
315         return memcmp(ip, v4prefix, IPv4off) == 0;
316 }
317
318
319 /*
320  *  the following routines are unrolled with no memset's to speed
321  *  up the usual case
322  */
323 void
324 v4tov6(uint8_t *v6, uint8_t *v4)
325 {
326         v6[0] = 0;
327         v6[1] = 0;
328         v6[2] = 0;
329         v6[3] = 0;
330         v6[4] = 0;
331         v6[5] = 0;
332         v6[6] = 0;
333         v6[7] = 0;
334         v6[8] = 0;
335         v6[9] = 0;
336         v6[10] = 0xff;
337         v6[11] = 0xff;
338         v6[12] = v4[0];
339         v6[13] = v4[1];
340         v6[14] = v4[2];
341         v6[15] = v4[3];
342 }
343
344 int
345 v6tov4(uint8_t *v4, uint8_t *v6)
346 {
347         if(v6[0] == 0
348         && v6[1] == 0
349         && v6[2] == 0
350         && v6[3] == 0
351         && v6[4] == 0
352         && v6[5] == 0
353         && v6[6] == 0
354         && v6[7] == 0
355         && v6[8] == 0
356         && v6[9] == 0
357         && v6[10] == 0xff
358         && v6[11] == 0xff)
359         {
360                 v4[0] = v6[12];
361                 v4[1] = v6[13];
362                 v4[2] = v6[14];
363                 v4[3] = v6[15];
364                 return 0;
365         } else {
366                 memset(v4, 0, 4);
367                 return -1;
368         }
369 }
370
371 uint32_t
372 parseip(uint8_t *to, char *from)
373 {
374         int i, elipsis = 0, v4 = 1;
375         uint32_t x;
376         char *p, *op;
377
378         memset(to, 0, IPaddrlen);
379         p = from;
380         for(i = 0; i < 16 && *p; i+=2){
381                 op = p;
382                 x = strtoul(p, &p, 16);
383                 if(*p == '.' || (*p == 0 && i == 0)){
384                         p = v4parseip(to+i, op);
385                         i += 4;
386                         break;
387                 } else {
388                         to[i] = x>>8;
389                         to[i+1] = x;
390                 }
391                 if(*p == ':'){
392                         v4 = 0;
393                         if(*++p == ':'){
394                                 elipsis = i+2;
395                                 p++;
396                         }
397                 }
398         }
399         if(i < 16){
400                 memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
401                 memset(&to[elipsis], 0, 16-i);
402         }
403         if(v4){
404                 to[10] = to[11] = 0xff;
405                 return nhgetl(to+12);
406         } else
407                 return 6;
408 }
409
410 /*
411  *  hack to allow ip v4 masks to be entered in the old
412  *  style
413  */
414 uint32_t
415 parseipmask(uint8_t *to, char *from)
416 {
417         uint32_t x;
418         int i;
419         uint8_t *p;
420
421         if(*from == '/'){
422                 /* as a number of prefix bits */
423                 i = atoi(from+1);
424                 if(i < 0)
425                         i = 0;
426                 if(i > 128)
427                         i = 128;
428                 memset(to, 0, IPaddrlen);
429                 for(p = to; i >= 8; i -= 8)
430                         *p++ = 0xff;
431                 if(i > 0)
432                         *p = ~((1<<(8-i))-1);
433                 x = nhgetl(to+IPv4off);
434         } else {
435                 /* as a straight bit mask */
436                 x = parseip(to, from);
437                 if(memcmp(to, v4prefix, IPv4off) == 0)
438                         memset(to, 0xff, IPv4off);
439         }
440         return x;
441 }
442
443 void
444 maskip(uint8_t *from, uint8_t *mask, uint8_t *to)
445 {
446         int i;
447
448         for(i = 0; i < IPaddrlen; i++)
449                 to[i] = from[i] & mask[i];
450 }
451
452 uint8_t classmask[4][16] = {
453         {0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0x00,0x00,0x00},
454         {0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0x00,0x00,0x00},
455         {0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0x00,0x00},
456         
457         {0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0xff,  0xff,0xff,0xff,0x00},
458 };
459
460 uint8_t*
461 defmask(uint8_t *ip)
462 {
463         if(isv4(ip))
464                 return classmask[ip[IPv4off]>>6];
465         else {
466                 if(ipcmp(ip, v6loopback) == 0)
467                         return IPallbits;
468                 else if(memcmp(ip, v6linklocal, v6llpreflen) == 0)
469                         return v6linklocalmask;
470                 else if(memcmp(ip, v6sitelocal, v6slpreflen) == 0)
471                         return v6sitelocalmask;
472                 else if(memcmp(ip, v6solicitednode, v6snpreflen) == 0)
473                         return v6solicitednodemask;
474                 else if(memcmp(ip, v6multicast, v6mcpreflen) == 0)
475                         return v6multicastmask;
476                 return IPallbits;
477         }
478 }
479
480 void
481 ipv62smcast(uint8_t *smcast, uint8_t *a)
482 {
483         assert(IPaddrlen == 16);
484         memmove(smcast, v6solicitednode, IPaddrlen);
485         smcast[13] = a[13];
486         smcast[14] = a[14];
487         smcast[15] = a[15];
488 }
489
490
491 /*
492  *  parse a hex mac address
493  */
494 int
495 parsemac(uint8_t *to, char *from, int len)
496 {
497         char nip[4];
498         char *p;
499         int i;
500
501         p = from;
502         memset(to, 0, len);
503         for(i = 0; i < len; i++){
504                 if(p[0] == '\0' || p[1] == '\0')
505                         break;
506
507                 nip[0] = p[0];
508                 nip[1] = p[1];
509                 nip[2] = '\0';
510                 p += 2;
511
512                 to[i] = strtoul(nip, 0, 16);
513                 if(*p == ':')
514                         p++;
515         }
516         return i;
517 }
518
519 /*
520  *  hashing tcp, udp, ... connections
521  *  gcc weirdness: it gave a bogus result until ron split the %= out.
522  */
523 uint32_t iphash(uint8_t * sa, uint16_t sp, uint8_t * da, uint16_t dp)
524 {
525         uint32_t ret;
526         ret = (sa[IPaddrlen - 1] << 24) ^ (sp << 16) ^ (da[IPaddrlen - 1] << 8)
527               ^ dp;
528         ret %= Nhash;
529         return ret;
530 }
531
532 void
533 iphtadd(struct Ipht *ht, struct conv *c)
534 {
535         uint32_t hv;
536         struct Iphash *h;
537
538         hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
539         h = kzmalloc(sizeof(*h), 0);
540         if(ipcmp(c->raddr, IPnoaddr) != 0)
541                 h->match = IPmatchexact;
542         else {
543                 if(ipcmp(c->laddr, IPnoaddr) != 0){
544                         if(c->lport == 0)
545                                 h->match = IPmatchaddr;
546                         else
547                                 h->match = IPmatchpa;
548                 } else {
549                         if(c->lport == 0)
550                                 h->match = IPmatchany;
551                         else
552                                 h->match = IPmatchport;
553                 }
554         }
555         h->c = c;
556
557         spin_lock(&ht->lock);
558         h->next = ht->tab[hv];
559         ht->tab[hv] = h;
560         spin_unlock(&ht->lock);
561 }
562
563 void
564 iphtrem(struct Ipht *ht, struct conv *c)
565 {
566         uint32_t hv;
567         struct Iphash **l, *h;
568
569         hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
570         spin_lock(&ht->lock);
571         for(l = &ht->tab[hv]; (*l) != NULL; l = &(*l)->next)
572                 if((*l)->c == c){
573                         h = *l;
574                         (*l) = h->next;
575                         kfree(h);
576                         break;
577                 }
578         spin_unlock(&ht->lock);
579 }
580
581 /* look for a matching conversation with the following precedence
582  *      connected && raddr,rport,laddr,lport
583  *      announced && laddr,lport
584  *      announced && *,lport
585  *      announced && laddr,*
586  *      announced && *,*
587  */
588 struct conv*
589 iphtlook(struct Ipht *ht, uint8_t *sa, uint16_t sp, uint8_t *da, uint16_t dp)
590 {
591         uint32_t hv;
592         struct Iphash *h;
593         struct conv *c;
594
595         /* exact 4 pair match (connection) */
596         hv = iphash(sa, sp, da, dp);
597         spin_lock(&ht->lock);
598         for(h = ht->tab[hv]; h != NULL; h = h->next){
599                 if(h->match != IPmatchexact)
600                         continue;
601                 c = h->c;
602                 if(sp == c->rport && dp == c->lport
603                 && ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
604                         spin_unlock(&ht->lock);
605                         return c;
606                 }
607         }
608         
609         /* match local address and port */
610         hv = iphash(IPnoaddr, 0, da, dp);
611         for(h = ht->tab[hv]; h != NULL; h = h->next){
612                 if(h->match != IPmatchpa)
613                         continue;
614                 c = h->c;
615                 if(dp == c->lport && ipcmp(da, c->laddr) == 0){
616                         spin_unlock(&ht->lock);
617                         return c;
618                 }
619         }
620         
621         /* match just port */
622         hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
623         for(h = ht->tab[hv]; h != NULL; h = h->next){
624                 if(h->match != IPmatchport)
625                         continue;
626                 c = h->c;
627                 if(dp == c->lport){
628                         spin_unlock(&ht->lock);
629                         return c;
630                 }
631         }
632         
633         /* match local address */
634         hv = iphash(IPnoaddr, 0, da, 0);
635         for(h = ht->tab[hv]; h != NULL; h = h->next){
636                 if(h->match != IPmatchaddr)
637                         continue;
638                 c = h->c;
639                 if(ipcmp(da, c->laddr) == 0){
640                         spin_unlock(&ht->lock);
641                         return c;
642                 }
643         }
644         
645         /* look for something that matches anything */
646         hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
647         for(h = ht->tab[hv]; h != NULL; h = h->next){
648                 if(h->match != IPmatchany)
649                         continue;
650                 c = h->c;
651                 spin_unlock(&ht->lock);
652                 return c;
653         }
654         spin_unlock(&ht->lock);
655         return NULL;
656 }