summaryrefslogtreecommitdiff
path: root/sys/src
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2022-09-27 20:44:10 +0000
committercinap_lenrek <cinap_lenrek@felloff.net>2022-09-27 20:44:10 +0000
commit7b186b0779561d1d63d291d10143e8cdfc6e3064 (patch)
treef6d71acdbcc68aaa17c5128df805a6d9633da63a /sys/src
parent14aea8266dbbbdcfe9947451e10db4889e3cbcb7 (diff)
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.
Diffstat (limited to 'sys/src')
-rw-r--r--sys/src/9/ip/arp.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/sys/src/9/ip/arp.c b/sys/src/9/ip/arp.c
index 08c934dbe..0bef6d08d 100644
--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -283,7 +283,7 @@ arprelease(Arp *arp, Arpent*)
/*
* 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 @@ arpresolve(Arp *arp, Arpent *a, uchar *mac, Routehint *rh)
rh->a = a;
wunlock(arp);
+ if(bp != nil){
+ freeblistchain(bp->list);
+ bp->list = nil;
+ }
return bp;
}
@@ -350,7 +354,9 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *if
}
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){