git: 9front

Download patch

ref: b73a9622499428876c88ddc9ff1746a871cda567
parent: a8654c9bb24316e6db9ebcaa4b3aeb8290610be5
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Sep 27 16:44:10 EDT 2022

arp: make sure arpresolve() only returns single packet

Due to locking changes, it is possible for arpresolve()
to return multiple packets in the multicast case,
resulting in etherbwrite() to fail assert(bp->list == nil).

Ensure that arpresolve() always returns the first packet
from the hold chain and frees the rest if any.

For arpenter(), we want to transmit the whole chain of
packets, so we detach them from the arp entry before
calling arpresolve() and ignoring its result.

--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -283,7 +283,7 @@
 
 /*
  * Copy out the mac address from the Arpent.  Return the
- * block waiting to get sent to this mac address.
+ * first block waiting to get sent to this mac address.
  *
  * called with arp locked
  */
@@ -305,6 +305,10 @@
 		rh->a = a;
 	wunlock(arp);
 
+	if(bp != nil){
+		freeblistchain(bp->list);
+		bp->list = nil;
+	}
 	return bp;
 }
 
@@ -350,7 +354,9 @@
 		}
 		a = newarpent(arp, ip, ifc);
 	}
-	bp = arpresolve(arp, a, mac, &rh);	/* unlocks arp */
+	bp = a->hold;
+	a->hold = a->last = nil;
+	arpresolve(arp, a, mac, &rh);	/* unlocks arp */
 	if(version == V4)
 		ip += IPv4off;
 	for(; bp != nil; bp = next){
--