3101345fe6
CRITICAL/MEDIUM BUGS FIXED: 1. ethernet.rs send_ndp_solicit: state corruption via recursive call The function destructured self.ndp_state by value (target, tries, silent_until) at the start and wrote back at the end. But between destructuring and writing back, self.drop_waiting_packets_v6(target) could recursively call self.send_ndp_solicit(Instant::ZERO) for a different target. The recursive call updated self.ndp_state with the new target's state. When control returned to the original frame, the original write-back clobbered the recursive call's state, silently losing neighbor discovery for the new target. Fix: use scoped pattern matches to read target/tries/silent_until from the live state right before they are needed, so the recursive call's writes are preserved. This matches the pattern used by send_arp (which uses ref mut and is correct). 2. scheme/socket.rs on_close: port double-free close_file() was called before the refcount check, so the port was released on every close. For a dup'd socket, the second close tried to release the port again — double-free. Fix: compute the new refcount first, only call close_file and remove from socket_set when the count reaches 0 (last reference). 3. scheme/tcp.rs new_socket: port + socket leak on connect failure If get_port() succeeded but connect() later failed, the port was claimed and the socket was added to socket_set, but new_socket returned Err. The caller (open_inner) did not insert the file handle, so on_close was never called. Both the port and the socket slot leaked. Fix: when connect() fails, release the auto-allocated port before returning. Explicit user-provided ports are still released by on_close when the last file is dropped (preserves the existing on_close-based release). 4. observer.rs capture: per-packet size limit not enforced Vec::with_capacity only pre-allocates; extend_from_slice copies the full packet. The intended per-packet limit (MAX_CAPTURE_BYTES / max_packets = 256 bytes) was being bypassed, allowing a single 1500-byte packet to consume the full capture buffer. Fix: truncate to per_packet_limit before extending. 5. observer.rs capture: short packets bypassed filter Packets < 20 bytes returned true (capture anyway) regardless of the user's filter. A filter like 'tcp port 80' would capture all short packets, including non-TCP. Fix: return false (no match) for short packets. Filter semantics are now consistent: if a packet can't be matched, it's not captured. All 29 existing tests still pass.