git: 9front

Download patch

ref: 62612f92fb7cc773c41096d50e02abaf2b22a37e
parent: 1e0f61fbb332c08a643855c49bf0c00992b9afbb
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Mar 15 14:00:17 EDT 2026

devether: inhibit transmission when link is down

When the link is explicitely set down, bypass Ether.oq
with a drop() function. This also flushes the transmit
queue when link is being set down.

The Ether.transmit() function is basically Queue.kick(),
which already handles bypass case. So use it like that
instead. Those drivers that create the Ether.oq themselfs
need to be adjusted to pass their transmit function and
Ether* arg to qopen().

Introduce initial Ether.link == -1 that signifies
initial "unknown" link state. This is here to ensure
that drivers which do not handle link management
by calling ethersetlink() continue to work.

--- a/sys/src/9/mtx/ether2114x.c
+++ b/sys/src/9/mtx/ether2114x.c
@@ -604,7 +604,7 @@
 	bp->wp += sizeof(bi)*16;
 
 	ctlr->setupbp = bp;
-	ether->oq = qopen(256*1024, Qmsg, 0, 0);
+	ether->oq = qopen(256*1024, Qmsg, (void (*)(void*))transmit, ether);
 	transmit(ether);
 }
 
--- a/sys/src/9/pc/ether2114x.c
+++ b/sys/src/9/pc/ether2114x.c
@@ -627,7 +627,7 @@
 	bp->wp += sizeof(bi)*16;
 
 	ctlr->setupbp = bp;
-	ether->oq = qopen(256*1024, Qmsg, 0, 0);
+	ether->oq = qopen(256*1024, Qmsg, (void (*)(void*))transmit, ether);
 	transmit(ether);
 }
 
--- a/sys/src/9/pc/ether82557.c
+++ b/sys/src/9/pc/ether82557.c
@@ -1292,7 +1292,7 @@
 	 * Load the chip configuration and start it off.
 	 */
 	if(ether->oq == 0)
-		ether->oq = qopen(256*1024, Qmsg, 0, 0);
+		ether->oq = qopen(256*1024, Qmsg, (void (*)(void*))transmit, ether);
 	configure(ether, 0);
 	command(ctlr, CUstart, PADDR(&ctlr->cbr->status));
 
--- a/sys/src/9/port/devether.c
+++ b/sys/src/9/port/devether.c
@@ -24,6 +24,12 @@
 static int etheroqsize(Ether*);
 static int etheriqsize(Ether*);
 
+static void
+drop(void*, Block *b)
+{
+	freeb(b);
+}
+
 Chan*
 etherattach(char* spec)
 {
@@ -98,6 +104,7 @@
 		if(f->bridge || f->bypass)
 			memset(ether->mactab, 0, sizeof(ether->mactab));
 		if(f->bypass){
+			qsetbypass(ether->oq, ether->link? nil: drop);
 			qsetlimit(ether->oq, etheroqsize(ether));
 			netifsetlimit(ether, etheriqsize(ether));
 		}
@@ -292,8 +299,6 @@
 	}
 	ether->outpackets++;
 	qbwrite(ether->oq, bp);
-	if(ether->transmit != nil)
-		ether->transmit(ether);
 }
 
 static long
@@ -307,9 +312,11 @@
 	if(NETTYPE(chan->qid.path) != Ndataqid) {
 		nn = netifwrite(ether, chan, buf, n);
 		if(nn >= 0){
-			/* ignore mbps and use large input queue size when bypassed */
+			/* got bypassed? */
 			if(ether->f[NETID(chan->qid.path)]->bypass){
-				qflush(ether->oq);
+				/* flush and bypass output queue */
+				qsetbypass(ether->oq, drop);
+				/* ignore mbps and use large input queue size */
 				netifsetlimit(ether, MB);
 			}
 			return nn;
@@ -431,7 +438,7 @@
 	ether->irq = -1;
 	ether->ctlrno = ctlrno;
 	ether->mbps = 10;
-	ether->link = 0;
+	ether->link = -1;	/* unknown state */
 	ether->minmtu = ETHERMINTU;
 	ether->maxmtu = ETHERMAXTU;
 
@@ -470,7 +477,7 @@
 
 	q = etheroqsize(ether);
 	if(ether->oq == nil){
-		ether->oq = qopen(q, Qmsg, 0, 0);
+		ether->oq = qopen(q, Qmsg, (void (*)(void*))ether->transmit, ether);
 		if(ether->oq == nil)
 			panic("etherreset %s: can't allocate output queue", ether->name);
 	} else {
@@ -497,19 +504,22 @@
 }
 
 void
-ethersetlink(Ether *ether, int link)
+ethersetlink(Ether *ether, int new)
 {
-	link = !!link;
-	if(!!ether->link == link)
+	int old = ether->link;
+
+	new = !!new;
+	if(old == new)
 		return;
-	ether->link = link;
+	ether->link = new;
 	if(ether->f == nil || ether->bypass)
 		return;
 	memset(ether->mactab, 0, sizeof(ether->mactab));
-	if(link)
+	qsetbypass(ether->oq, ether->link? nil: drop);
+	if(ether->link)
 		print("#l%d: %s: link up: %dMbps\n",
 			ether->ctlrno, ether->type, ether->mbps);
-	else
+	else if(old > 0)
 		print("#l%d: %s: link down\n",
 			ether->ctlrno, ether->type);
 }
@@ -647,8 +657,6 @@
 	qiwrite(netcons->ether->oq, p, netcons->n);
 	netcons->n = PktHdr;
 	iunlock(netcons);
-	if(netcons->ether->transmit != nil)
-		netcons->ether->transmit(netcons->ether);
 }
 
 static PhysUart netconsphys = { .putc = netconsputc };
--