code: plan9front

Download patch

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