/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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; ushortptclcsum(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) voidipv62smcast(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 */intparsemac(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 */ulongiphash(uchar *sa, ushort sp, uchar *da, ushort dp){ return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nhash;} voidiphtadd(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);} voidiphtrem(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;}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#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;
}