ref: 3f0f52ab69a8e821fcd1ac66b8d509ee3074c266
parent: 7137060d85fe04cce4a1984550a636672df7df7d
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Dec 7 09:50:09 EST 2023
ether4330: dmat support move dmatproxy() function in its own module so we can use it independently of wifi.c.
--- a/sys/src/9/bcm/ether4330.c
+++ b/sys/src/9/bcm/ether4330.c
@@ -196,6 +196,7 @@
uchar txwindow;
uchar txseq;
uchar rxseq;
+ DMAT dmat;
};
enum{
@@ -1273,6 +1274,7 @@
b = qget(edev->oq);
if(b == nil)
break;
+ dmatproxy(b, 1, edev->ea, &ctl->dmat);
off = ((uintptr)b->rp & 3) + Sdpcmsz;
b = padblock(b, off + 4);
len = BLEN(b);
@@ -1377,6 +1379,7 @@
bdc = 4 + (b->rp[p->doffset + 3] << 2);
if(BLEN(b) >= p->doffset + bdc + ETHERHDRSIZE){
b->rp += p->doffset + bdc; /* skip BDC header */
+ dmatproxy(b, 0, edev->ea, &ctl->dmat);
etheriq(edev, b);
continue;
}
--- a/sys/src/9/bcm64/pi3
+++ b/sys/src/9/bcm64/pi3
@@ -28,7 +28,7 @@
link
archbcm3
usbdwc
- ether4330
+ ether4330 dmat
ethermedium
loopbackmedium
netdevmedium
--- a/sys/src/9/bcm64/pi4
+++ b/sys/src/9/bcm64/pi4
@@ -32,7 +32,7 @@
archbcm4 pci
usbxhcipci pci usbxhci archbcm4
ethergenet ethermii
- ether4330
+ ether4330 dmat
ethermedium
loopbackmedium
netdevmedium
--- a/sys/src/9/imx8/reform
+++ b/sys/src/9/imx8/reform
@@ -57,6 +57,7 @@
iomux
sdnvme pci
sdmmc usdhc
+ wifi dmat
port
int cpuserver = 0;
bootdir
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -146,6 +146,8 @@
vgatvp3026 =cur
vgavesa
vgavmware +cur
+
+ wifi dmat
dtracysys
dtracytimer
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -144,6 +144,8 @@
vgavesa
# vgavmware +cur
+ wifi dmat
+
dtracysys
dtracytimer
dtracydev
--- /dev/null
+++ b/sys/src/9/port/dmat.c
@@ -1,0 +1,196 @@
+/*
+ * 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.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/netif.h"
+#include "../port/etherif.h"
+#include "../ip/ip.h"
+#include "../ip/ipv6.h"
+
+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], *targ, *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;
+
+ targ = nil;
+ switch(pkt->type[0]<<8 | pkt->type[1]){
+ default:
+ return;
+ case ETIP4:
+ case ETIP6:
+ switch(a[0]&0xF0){
+ default:
+ return;
+ case IP_VER4:
+ if(a+IP4HDR > end || (a[0]&15) < IP_HLEN4)
+ return;
+ v4tov6(ip, a+12+4*(upstream==0));
+ proto = a[9];
+ a += (a[0]&15)*4;
+ break;
+ case IP_VER6:
+ if(a+IP6HDR > end)
+ return;
+ memmove(ip, a+8+16*(upstream==0), 16);
+ proto = a[6];
+ a += IP6HDR;
+ break;
+ }
+ if(!upstream)
+ break;
+ switch(proto){
+ case 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 136: /* Neighbor Advertisement */
+ targ = a+8;
+ /* wet floor */
+ case 135: /* Neighbor Solicitation */
+ 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 SRC_LLADDR:
+ case TARGET_LLADDR:
+ for(i=0; i<Eaddrlen; i += 2)
+ csum += (o[2+i]<<8 | o[3+i])^0xFFFF;
+ memmove(mac, o+2, Eaddrlen);
+ memmove(o+2, proxy, Eaddrlen);
+ for(i=0; i<Eaddrlen; i += 2)
+ csum += (o[2+i]<<8 | o[3+i]);
+ break;
+ }
+ o += o[1]*8;
+ }
+ while((c = csum >> 16) != 0)
+ csum = (csum & 0xFFFF) + c;
+ csum ^= 0xFFFF;
+ a[2] = csum>>8;
+ a[3] = csum;
+ break;
+ case UDP: /* for 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 ETARP:
+ 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;
+ }
+
+Again:
+ 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 && i<nelem(t->tab); 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<<h;
+ if(targ != nil){
+ memmove(ip, targ, IPaddrlen);
+ targ = nil;
+ goto Again;
+ }
+ } else {
+ if((t->map>>h & 1) == 0)
+ return;
+ for(i=0; te->valid && i<nelem(t->tab); 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;
+ }
+ }
+}
--- a/sys/src/9/port/etherif.h
+++ b/sys/src/9/port/etherif.h
@@ -44,3 +44,20 @@
#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
#define HOWMANY(x, y) (((x)+((y)-1))/(y))
#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
+
+typedef struct DMAT DMAT;
+struct DMTE
+{
+ uchar ip[16];
+ uchar mac[Eaddrlen];
+ uchar valid;
+};
+
+typedef struct DMTE DMTE;
+struct DMAT
+{
+ DMTE tab[127]; /* prime */
+ uvlong map;
+};
+
+extern void dmatproxy(Block*, int, uchar*, DMAT*);
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -110,12 +110,13 @@
devtls.$O: /sys/include/libsec.h
devswap.$O: /sys/include/libsec.h
random.$O: /sys/include/libsec.h
-wifi.$O: /sys/include/libsec.h ../ip/ip.h ../ip/ipv6.h
+wifi.$O: /sys/include/libsec.h
+dmat.$O: ../ip/ip.h ../ip/ipv6.h
devaoe.$O sdaoe.$O: /sys/include/fis.h
sysproc.$O: /sys/include/a.out.h
syscallfmt.$O: /sys/src/libc/9syscall/sys.h
devusb.$O usbxhci.$O usbxhcipci.$O: ../port/usb.h
usbxhci.$O usbxhcipci.$O: ../port/usbxhci.h
-devether.$O ethersink.$O etheriwl.$O wifi.$O: ../port/netif.h ../port/etherif.h
+devether.$O ethersink.$O etheriwl.$O wifi.$O dmat.$O: ../port/netif.h ../port/etherif.h
etheriwl.$O wifi.$O: ../port/wifi.h
ethermii.$O: ../port/ethermii.h
--- a/sys/src/9/port/wifi.c
+++ b/sys/src/9/port/wifi.c
@@ -3,8 +3,6 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
-#include "io.h"
-#include "ureg.h"
#include "../port/error.h"
#include "../port/netif.h"
#include "../port/etherif.h"
@@ -49,8 +47,6 @@
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)
{
@@ -1760,194 +1756,4 @@
return aesCCMdecrypt(2, 8, nonce, auth,
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.
- */
-#include "../ip/ip.h"
-#include "../ip/ipv6.h"
-
-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], *targ, *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;
-
- targ = nil;
- switch(pkt->type[0]<<8 | pkt->type[1]){
- default:
- return;
- case ETIP4:
- case ETIP6:
- switch(a[0]&0xF0){
- default:
- return;
- case IP_VER4:
- if(a+IP4HDR > end || (a[0]&15) < IP_HLEN4)
- return;
- v4tov6(ip, a+12+4*(upstream==0));
- proto = a[9];
- a += (a[0]&15)*4;
- break;
- case IP_VER6:
- if(a+IP6HDR > end)
- return;
- memmove(ip, a+8+16*(upstream==0), 16);
- proto = a[6];
- a += IP6HDR;
- break;
- }
- if(!upstream)
- break;
- switch(proto){
- case 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 136: /* Neighbor Advertisement */
- targ = a+8;
- /* wet floor */
- case 135: /* Neighbor Solicitation */
- 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 SRC_LLADDR:
- case TARGET_LLADDR:
- for(i=0; i<Eaddrlen; i += 2)
- csum += (o[2+i]<<8 | o[3+i])^0xFFFF;
- memmove(mac, o+2, Eaddrlen);
- memmove(o+2, proxy, Eaddrlen);
- for(i=0; i<Eaddrlen; i += 2)
- csum += (o[2+i]<<8 | o[3+i]);
- break;
- }
- o += o[1]*8;
- }
- while((c = csum >> 16) != 0)
- csum = (csum & 0xFFFF) + c;
- csum ^= 0xFFFF;
- a[2] = csum>>8;
- a[3] = csum;
- break;
- case UDP: /* for 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 ETARP:
- 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;
- }
-
-Again:
- 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 && i<nelem(t->tab); 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<<h;
- if(targ != nil){
- memmove(ip, targ, IPaddrlen);
- targ = nil;
- goto Again;
- }
- } else {
- if((t->map>>h & 1) == 0)
- return;
- for(i=0; te->valid && i<nelem(t->tab); 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;
- }
- }
}
--- a/sys/src/9/port/wifi.h
+++ b/sys/src/9/port/wifi.h
@@ -2,8 +2,6 @@
typedef struct Wnode Wnode;
typedef struct Wifi Wifi;
typedef struct Wifipkt Wifipkt;
-typedef struct DMAT DMAT;
-typedef struct DMTE DMTE;
enum {
Essidlen = 32,
@@ -59,19 +57,6 @@
int channel;
int brsnelen;
uchar brsne[258];
-};
-
-struct DMTE
-{
- uchar ip[16];
- uchar mac[6];
- uchar valid;
-};
-
-struct DMAT
-{
- DMTE tab[127]; /* prime */
- uvlong map;
};
struct Wifi