ref: 8d9a4e15029b23e367b5ae6a399f22e4cf5f0c9f
parent: f28d61ca22c711e9449320f4ad13e71e8a2c2a5a
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Dec 7 11:23:04 EST 2023
devether: make dmatproxy part of devether As we want to keep applying dmat translations when bypassing a wifi interface, make the dmat handling code part of devether instead of doing it internally in the wifi driver. The wifi driver just needs to allocate and assign Ether.dmat pointer.
--- a/sys/src/9/bcm/ether4330.c
+++ b/sys/src/9/bcm/ether4330.c
@@ -196,7 +196,6 @@
uchar txwindow;
uchar txseq;
uchar rxseq;
- DMAT dmat;
};
enum{
@@ -1274,7 +1273,6 @@
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);
@@ -1379,7 +1377,6 @@
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;
}
@@ -2380,6 +2377,7 @@
ctlr = malloc(sizeof(Ctlr));
ctlr->chanid = Wifichan;
+ edev->dmat = malloc(sizeof(DMAT));
edev->ctlr = ctlr;
edev->attach = etherbcmattach;
edev->transmit = etherbcmtransmit;
--- a/sys/src/9/bcm64/mkfile
+++ b/sys/src/9/bcm64/mkfile
@@ -118,6 +118,7 @@
usbdwc.$O: dwcotg.h ../port/usb.h
i2cbcm.$O i2cgpio.$O: ../port/i2c.h
emmc.$O sdhc.$O sdhost.$O ether4330.$O: ../port/sd.h
+ethergenet.$O ether4330.$O: ../port/netif.h ../port/etherif.h
io.h: ../bcm/io.h
touch $target
--- a/sys/src/9/bcm64/pi3
+++ b/sys/src/9/bcm64/pi3
@@ -28,7 +28,7 @@
link
archbcm3
usbdwc
- ether4330 dmat
+ ether4330
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 dmat
+ ether4330
ethermedium
loopbackmedium
netdevmedium
--- a/sys/src/9/imx8/mkfile
+++ b/sys/src/9/imx8/mkfile
@@ -103,6 +103,7 @@
pciimx.$O: ../port/pci.h
usbxhciimx.$O: ../port/usbxhci.h
usdhc.$O: ../port/sd.h
+etherimx.$O: ../port/netif.h ../port/etherif.h
l.$O main.$O clock.$O gic.$O cache.v8.$O fpu.$O trap.$O rebootcode.$O: ../arm64/sysreg.h
--- a/sys/src/9/imx8/reform
+++ b/sys/src/9/imx8/reform
@@ -57,7 +57,6 @@
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,8 +146,6 @@
vgatvp3026 =cur
vgavesa
vgavmware +cur
-
- wifi dmat
dtracysys
dtracytimer
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -144,8 +144,6 @@
vgavesa
# vgavmware +cur
- wifi dmat
-
dtracysys
dtracytimer
dtracydev
--- a/sys/src/9/port/devether.c
+++ b/sys/src/9/port/devether.c
@@ -10,6 +10,9 @@
#include "../port/netif.h"
#include "../port/etherif.h"
+#include "../ip/ip.h"
+#include "../ip/ipv6.h"
+
extern int eipfmt(Fmt*);
extern ushort ipcsum(uchar *);
@@ -16,6 +19,8 @@
static Ether *etherxx[MaxEther];
static Ether *etherprobe(int cardno, int ctlrno, char *conf);
+static void dmatproxy(Block*, int, uchar*, DMAT*);
+
Chan*
etherattach(char* spec)
{
@@ -254,6 +259,8 @@
freeb(bp);
return;
}
+ if(ether->dmat != nil)
+ dmatproxy(bp, 0, ether->ea, ether->dmat);
ether->inpackets++;
ethermux(ether, bp, nil);
}
@@ -272,6 +279,8 @@
bp = ethermux(ether, bp, from);
if(bp == nil)
return;
+ if(ether->dmat != nil)
+ dmatproxy(bp, 1, ether->ea, ether->dmat);
if((x = ether->bypass) != nil){
if(qpass(x->in, bp) < 0)
ether->soverflows++;
@@ -697,4 +706,191 @@
err:
print("netconsole: invalid string %#q\n", getconf("console"));
print("netconsole: usage: srcip[!srcport][/srcdev],dstip[!dstport][/dstmac]\n");
+}
+
+/*
+ * 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], *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/dmat.c
+++ /dev/null
@@ -1,196 +1,0 @@
-/*
- * 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
@@ -3,6 +3,21 @@
Ntypes = 8,
};
+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;
+};
+
typedef struct Macent Macent;
struct Macent
{
@@ -33,6 +48,8 @@
uchar ea[Eaddrlen];
Macent mactab[127]; /* for bridge */
+
+ DMAT* dmat;
};
extern void etheriq(Ether*, Block*);
@@ -44,20 +61,3 @@
#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
@@ -111,12 +111,12 @@
devswap.$O: /sys/include/libsec.h
random.$O: /sys/include/libsec.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 dmat.$O: ../port/netif.h ../port/etherif.h
+devether.$O: ../ip/ip.h ../ip/ipv6.h
+devether.$O ethersink.$O etheriwl.$O ethervirtio10.$O wifi.$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
@@ -148,7 +148,6 @@
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);
return;
}
@@ -579,7 +578,6 @@
/* 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){
@@ -730,8 +728,6 @@
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){
@@ -856,6 +852,8 @@
free(wifi);
error(Enomem);
}
+ if(ether->dmat == nil)
+ ether->dmat = malloc(sizeof(DMAT));
wifi->ether = ether;
wifi->transmit = transmit;
--- a/sys/src/9/port/wifi.h
+++ b/sys/src/9/port/wifi.h
@@ -83,8 +83,6 @@
Wnode *bss;
Wnode node[32];
-
- DMAT dmat;
};
struct Wifipkt
--- a/sys/src/9/zynq/mkfile
+++ b/sys/src/9/zynq/mkfile
@@ -83,3 +83,4 @@
devusb.$O usbehci.$O usbehcizynq.$O: ../port/usb.h
usbehci.$O usbehcizynq.$O: usbehci.h
emmc.$O: ../port/sd.h
+etherzynq.$O: ../port/netif.h ../port/etherif.h