diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2022-09-27 20:44:10 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2022-09-27 20:44:10 +0000 |
commit | 7b186b0779561d1d63d291d10143e8cdfc6e3064 (patch) | |
tree | f6d71acdbcc68aaa17c5128df805a6d9633da63a /sys | |
parent | 14aea8266dbbbdcfe9947451e10db4889e3cbcb7 (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')
-rw-r--r-- | sys/src/9/ip/arp.c | 10 |
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){ |