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