123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "ip.h"
- #include "ipv6.h"
- char *v6hdrtypes[Maxhdrtype] =
- {
- [HBH] "HopbyHop",
- [ICMP] "ICMP",
- [IGMP] "IGMP",
- [GGP] "GGP",
- [IPINIP] "IP",
- [ST] "ST",
- [TCP] "TCP",
- [UDP] "UDP",
- [ISO_TP4] "ISO_TP4",
- [RH] "Routinghdr",
- [FH] "Fraghdr",
- [IDRP] "IDRP",
- [RSVP] "RSVP",
- [AH] "Authhdr",
- [ESP] "ESP",
- [ICMPv6] "ICMPv6",
- [NNH] "Nonexthdr",
- [ISO_IP] "ISO_IP",
- [IGRP] "IGRP",
- [OSPF] "OSPF",
- };
- /*
- * well known IPv6 addresses
- */
- uchar v6Unspecified[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uchar v6loopback[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01
- };
- uchar v6linklocal[IPaddrlen] = {
- 0xfe, 0x80, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uchar v6linklocalmask[IPaddrlen] = {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6llpreflen = 8; /* link-local prefix length in bytes */
- uchar v6multicast[IPaddrlen] = {
- 0xff, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uchar v6multicastmask[IPaddrlen] = {
- 0xff, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6mcpreflen = 1; /* multicast prefix length */
- uchar v6allnodesN[IPaddrlen] = {
- 0xff, 0x01, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01
- };
- uchar v6allroutersN[IPaddrlen] = {
- 0xff, 0x01, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x02
- };
- uchar v6allnodesNmask[IPaddrlen] = {
- 0xff, 0xff, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6aNpreflen = 2; /* all nodes (N) prefix */
- uchar v6allnodesL[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01
- };
- uchar v6allroutersL[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x02
- };
- uchar v6allnodesLmask[IPaddrlen] = {
- 0xff, 0xff, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6aLpreflen = 2; /* all nodes (L) prefix */
- uchar v6solicitednode[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01,
- 0xff, 0, 0, 0
- };
- uchar v6solicitednodemask[IPaddrlen] = {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x0, 0x0, 0x0
- };
- int v6snpreflen = 13;
- ushort
- ptclcsum(Block *bp, int offset, int len)
- {
- uchar *addr;
- ulong losum, hisum;
- ushort csum;
- int odd, blocklen, x;
- /* Correct to front of data area */
- while(bp != nil && offset && offset >= BLEN(bp)) {
- offset -= BLEN(bp);
- bp = bp->next;
- }
- if(bp == nil)
- return 0;
- addr = bp->rp + offset;
- blocklen = BLEN(bp) - offset;
- if(bp->next == nil) {
- if(blocklen < len)
- len = blocklen;
- return ~ptclbsum(addr, len) & 0xffff;
- }
- losum = 0;
- hisum = 0;
- odd = 0;
- while(len) {
- x = blocklen;
- if(len < x)
- x = len;
- csum = ptclbsum(addr, x);
- if(odd)
- hisum += csum;
- else
- losum += csum;
- odd = (odd+x) & 1;
- len -= x;
- bp = bp->next;
- if(bp == nil)
- break;
- blocklen = BLEN(bp);
- addr = bp->rp;
- }
- losum += hisum>>8;
- losum += (hisum&0xff)<<8;
- while((csum = losum>>16) != 0)
- losum = csum + (losum & 0xffff);
- return ~losum & 0xffff;
- }
- enum
- {
- Isprefix= 16,
- };
- #define CLASS(p) ((*(uchar*)(p))>>6)
- void
- ipv62smcast(uchar *smcast, uchar *a)
- {
- assert(IPaddrlen == 16);
- memmove(smcast, v6solicitednode, IPaddrlen);
- smcast[13] = a[13];
- smcast[14] = a[14];
- smcast[15] = a[15];
- }
- /*
- * parse a hex mac address
- */
- int
- parsemac(uchar *to, char *from, int len)
- {
- char nip[4];
- char *p;
- int i;
- p = from;
- memset(to, 0, len);
- for(i = 0; i < len; i++){
- if(p[0] == '\0' || p[1] == '\0')
- break;
- nip[0] = p[0];
- nip[1] = p[1];
- nip[2] = '\0';
- p += 2;
- to[i] = strtoul(nip, 0, 16);
- if(*p == ':')
- p++;
- }
- return i;
- }
- /*
- * hashing tcp, udp, ... connections
- */
- ulong
- iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
- {
- return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nhash;
- }
- void
- iphtadd(Ipht *ht, Conv *c)
- {
- ulong hv;
- Iphash *h;
- hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
- h = smalloc(sizeof(*h));
- if(ipcmp(c->raddr, IPnoaddr) != 0)
- h->match = IPmatchexact;
- else {
- if(ipcmp(c->laddr, IPnoaddr) != 0){
- if(c->lport == 0)
- h->match = IPmatchaddr;
- else
- h->match = IPmatchpa;
- } else {
- if(c->lport == 0)
- h->match = IPmatchany;
- else
- h->match = IPmatchport;
- }
- }
- h->c = c;
- lock(ht);
- h->next = ht->tab[hv];
- ht->tab[hv] = h;
- unlock(ht);
- }
- void
- iphtrem(Ipht *ht, Conv *c)
- {
- ulong hv;
- Iphash **l, *h;
- hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
- lock(ht);
- for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
- if((*l)->c == c){
- h = *l;
- (*l) = h->next;
- free(h);
- break;
- }
- unlock(ht);
- }
- /* look for a matching conversation with the following precedence
- * connected && raddr,rport,laddr,lport
- * announced && laddr,lport
- * announced && *,lport
- * announced && laddr,*
- * announced && *,*
- */
- Conv*
- iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
- {
- ulong hv;
- Iphash *h;
- Conv *c;
- /* exact 4 pair match (connection) */
- hv = iphash(sa, sp, da, dp);
- lock(ht);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchexact)
- continue;
- c = h->c;
- if(sp == c->rport && dp == c->lport
- && ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
- unlock(ht);
- return c;
- }
- }
- /* match local address and port */
- hv = iphash(IPnoaddr, 0, da, dp);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchpa)
- continue;
- c = h->c;
- if(dp == c->lport && ipcmp(da, c->laddr) == 0){
- unlock(ht);
- return c;
- }
- }
- /* match just port */
- hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchport)
- continue;
- c = h->c;
- if(dp == c->lport){
- unlock(ht);
- return c;
- }
- }
- /* match local address */
- hv = iphash(IPnoaddr, 0, da, 0);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchaddr)
- continue;
- c = h->c;
- if(ipcmp(da, c->laddr) == 0){
- unlock(ht);
- return c;
- }
- }
- /* look for something that matches anything */
- hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchany)
- continue;
- c = h->c;
- unlock(ht);
- return c;
- }
- unlock(ht);
- return nil;
- }
|