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