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