From 070a9ef753990bc37696f059c1751d25831b5c17 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 16 Dec 2017 21:43:47 +0100 Subject: wifi: matt damon wifi bridging support --- sys/src/9/pc/mkfile | 2 +- sys/src/9/pc/wifi.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++- sys/src/9/pc/wifi.h | 17 +++++ sys/src/9/pc64/mkfile | 2 +- 4 files changed, 206 insertions(+), 3 deletions(-) diff --git a/sys/src/9/pc/mkfile b/sys/src/9/pc/mkfile index 63044be64..62b0eebf0 100644 --- a/sys/src/9/pc/mkfile +++ b/sys/src/9/pc/mkfile @@ -125,7 +125,7 @@ etherm10g.$O: etherm10g2k.i etherm10g4k.i etheriwl.$O: wifi.h etherwpi.$O: wifi.h etherrt2860.$O: wifi.h -wifi.$O: wifi.h +wifi.$O: wifi.h etherif.h ../port/netif.h ../ip/ip.h /sys/include/libsec.h init.h:D: ../port/initcode.c init9.c $CC ../port/initcode.c diff --git a/sys/src/9/pc/wifi.c b/sys/src/9/pc/wifi.c index f176883fd..9e4b5291a 100644 --- a/sys/src/9/pc/wifi.c +++ b/sys/src/9/pc/wifi.c @@ -7,6 +7,7 @@ #include "ureg.h" #include "../port/error.h" #include "../port/netif.h" +#include "../ip/ip.h" #include "etherif.h" #include "wifi.h" @@ -50,6 +51,8 @@ static Block* wifidecrypt(Wifi *, Wnode *, Block *); static Block* wifiencrypt(Wifi *, Wnode *, Block *); static void freewifikeys(Wifi *, Wnode *); +static void dmatproxy(Block *bp, int upstream, uchar proxy[Eaddrlen], DMAT *t); + static uchar* srcaddr(Wifipkt *w) { @@ -133,6 +136,9 @@ wifiiq(Wifi *wifi, Block *b) memmove(e->d, dstaddr(&h), Eaddrlen); memmove(e->s, srcaddr(&h), Eaddrlen); memmove(e->type, s.type, 2); + + dmatproxy(b, 0, wifi->ether->ea, &wifi->dmat); + etheriq(wifi->ether, b, 1); return; } @@ -502,6 +508,7 @@ wifideauth(Wifi *wifi, Wnode *wn) /* deassociate node, clear keys */ setstatus(wifi, wn, Sunauth); freewifikeys(wifi, wn); + memset(&wifi->dmat, 0, sizeof(wifi->dmat)); wn->aid = 0; if(wn == wifi->bss){ @@ -644,9 +651,10 @@ wifietheroq(Wifi *wifi, Block *b) if((wn = wifi->bss) == nil) goto drop; + dmatproxy(b, 1, wifi->ether->ea, &wifi->dmat); + memmove(&e, b->rp, ETHERHDRSIZE); b->rp += ETHERHDRSIZE; - if(wn->status == Sblocked){ /* only pass EAPOL frames when port is blocked */ if((e.type[0]<<8 | e.type[1]) != 0x888e) @@ -1688,3 +1696,181 @@ ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc) setupCCMP(w, tsc, nonce, auth), b->rp, BLEN(b), (AESstate*)k->key); } + +/* + * Dynamic Mac Address Translation (DMAT) + * + * Wifi does not allow spoofing of the source mac which breaks + * bridging. To solve this we proxy mac addresses, maintaining + * a translation table from ip address to destination mac address. + * Upstream ARP and NDP packets get ther source mac address changed + * to proxy and a translation entry is added with the original mac + * for downstream translation. The proxy does not appear in the + * table. + */ +static void +dmatproxy(Block *bp, int upstream, uchar proxy[Eaddrlen], DMAT *t) +{ + static uchar arp4[] = { + 0x00, 0x01, + 0x08, 0x00, + 0x06, 0x04, + 0x00, + }; + uchar ip[IPaddrlen], mac[Eaddrlen], *end, *a, *o; + ulong csum, c, h; + Etherpkt *pkt; + int proto, i; + DMTE *te; + + end = bp->wp; + pkt = (Etherpkt*)bp->rp; + a = pkt->data; + if(a >= end) + return; + + if(upstream) + memmove(pkt->s, proxy, Eaddrlen); + else if(t->map == 0 || (pkt->d[0]&1) != 0 || memcmp(pkt->d, proxy, Eaddrlen) != 0) + return; + + switch(pkt->type[0]<<8 | pkt->type[1]){ + default: + return; + case 0x0800: /* IPv4 */ + case 0x86dd: /* IPv6 */ + switch(a[0]&0xF0){ + default: + return; + case 0x40: /* IPv4 */ + if(a+20 > end) + return; + v4tov6(ip, a+12+4*(upstream==0)); + proto = a[9]; + a += (a[0]&15)*4; + break; + case 0x60: /* IPv6 */ + if(a+40 > end) + return; + memmove(ip, a+8+16*(upstream==0), 16); + proto = a[6]; + a += 40; + break; + } + if(!upstream) + break; + switch(proto){ + case 58: /* ICMPv6 */ + if(a+8 > end) + return; + switch(a[0]){ + default: + return; + case 133: /* Router Solicitation */ + o = a+8; + break; + case 134: /* Router Advertisement */ + o = a+8+8; + break; + case 135: /* Neighbor Solicitation */ + case 136: /* Neighbor Advertisement */ + o = a+8+16; + break; + case 137: /* Redirect */ + o = a+8+16+16; + break; + } + memset(mac, 0xFF, Eaddrlen); + csum = (a[2]<<8 | a[3])^0xFFFF; + while(o+8 <= end && o[1] != 0){ + switch(o[0]){ + case 1: /* SLLA, for RS, RA and NS */ + case 2: /* TLLA, for NA and RD */ + for(i=0; i> 16) != 0) + csum = (csum & 0xFFFF) + c; + csum ^= 0xFFFF; + a[2] = csum>>8; + a[3] = csum; + break; + case 17: /* UDP (bootp) */ + if(a+42 > end + || (a[0]<<8 | a[1]) != 68 + || (a[2]<<8 | a[3]) != 67 + || a[8] != 1 + || a[9] != 1 + || a[10] != Eaddrlen + || (a[18]&0x80) != 0 + || memcmp(a+36, proxy, Eaddrlen) == 0) + return; + + csum = (a[6]<<8 | a[7])^0xFFFF; + + /* set the broadcast flag so response reaches us */ + csum += (a[18]<<8)^0xFFFF; + a[18] |= 0x80; + csum += (a[18]<<8); + + while((c = csum >> 16) != 0) + csum = (csum & 0xFFFF) + c; + csum ^= 0xFFFF; + + a[6] = csum>>8; + a[7] = csum; + default: + return; + } + break; + case 0x0806: /* ARP */ + if(a+26 > end || memcmp(a, arp4, sizeof(arp4)) != 0 || (a[7] != 1 && a[7] != 2)) + return; + v4tov6(ip, a+14+10*(upstream==0)); + if(upstream){ + memmove(mac, a+8, Eaddrlen); + memmove(a+8, proxy, Eaddrlen); + } + break; + } + + h = ( (ip[IPaddrlen-1] ^ proxy[2])<<24 | + (ip[IPaddrlen-2] ^ proxy[3])<<16 | + (ip[IPaddrlen-3] ^ proxy[4])<<8 | + (ip[IPaddrlen-4] ^ proxy[5]) ) % nelem(t->tab); + te = &t->tab[h]; + h &= 63; + + if(upstream){ + if((mac[0]&1) != 0 || memcmp(mac, proxy, Eaddrlen) == 0) + return; + for(i=0; te->valid && itab); i++){ + if(memcmp(te->ip, ip, IPaddrlen) == 0) + break; + if(++te >= &t->tab[nelem(t->tab)]) + te = t->tab; + } + memmove(te->mac, mac, Eaddrlen); + memmove(te->ip, ip, IPaddrlen); + te->valid = 1; + t->map |= 1ULL<map>>h & 1) == 0) + return; + for(i=0; te->valid && itab); i++){ + if(memcmp(te->ip, ip, IPaddrlen) == 0){ + memmove(pkt->d, te->mac, Eaddrlen); + return; + } + if(++te >= &t->tab[nelem(t->tab)]) + te = t->tab; + } + } +} diff --git a/sys/src/9/pc/wifi.h b/sys/src/9/pc/wifi.h index 2171afd21..3abf4d1b9 100644 --- a/sys/src/9/pc/wifi.h +++ b/sys/src/9/pc/wifi.h @@ -2,6 +2,8 @@ typedef struct Wkey Wkey; typedef struct Wnode Wnode; typedef struct Wifi Wifi; typedef struct Wifipkt Wifipkt; +typedef struct DMAT DMAT; +typedef struct DMTE DMTE; enum { Essidlen = 32, @@ -52,6 +54,19 @@ struct Wnode uchar brsne[258]; }; +struct DMTE +{ + uchar ip[16]; + uchar mac[6]; + uchar valid; +}; + +struct DMAT +{ + DMTE tab[127]; /* prime */ + uvlong map; +}; + struct Wifi { Ether *ether; @@ -76,6 +91,8 @@ struct Wifi Wnode *bss; Wnode node[32]; + + DMAT dmat; }; struct Wifipkt diff --git a/sys/src/9/pc64/mkfile b/sys/src/9/pc64/mkfile index 4d145dc27..23be3ed10 100644 --- a/sys/src/9/pc64/mkfile +++ b/sys/src/9/pc64/mkfile @@ -125,7 +125,7 @@ ethermii.$O: ethermii.h etheriwl.$O: wifi.h etherwpi.$O: wifi.h etherrt2860.$O: wifi.h -wifi.$O: wifi.h +wifi.$O: wifi.h etherif.h ../port/netif.h ../ip/ip.h /sys/include/libsec.h init.h:D: ../port/initcode.c ../pc/init9.c $CC ../port/initcode.c -- cgit v1.2.3