diff --git a/netstack/src/scheme/icmp.rs b/netstack/src/scheme/icmp.rs index 9854a4df4e..c2b1b5d0c6 100644 --- a/netstack/src/scheme/icmp.rs +++ b/netstack/src/scheme/icmp.rs @@ -40,8 +40,8 @@ impl<'a> SchemeSocket for IcmpSocket<'a> { self.can_send() } - fn can_recv(&self) -> bool { - self.can_recv() + fn can_recv(&mut self, _data: &Self::DataT) -> bool { + smoltcp::socket::icmp::Socket::can_recv(self) } fn may_recv(&self) -> bool { @@ -212,7 +212,7 @@ impl<'a> SchemeSocket for IcmpSocket<'a> { if !file.read_enabled { return Ok(0); } - while self.can_recv() { + while self.can_recv(&file.data) { let (payload, _) = self.recv().expect("Can't recv icmp packet"); let icmp_packet = Icmpv4Packet::new_unchecked(&payload); //TODO: replace default with actual caps diff --git a/netstack/src/scheme/ip.rs b/netstack/src/scheme/ip.rs index 21b83aedd4..f39d00a638 100644 --- a/netstack/src/scheme/ip.rs +++ b/netstack/src/scheme/ip.rs @@ -27,8 +27,8 @@ impl<'a> SchemeSocket for RawSocket<'a> { self.can_send() } - fn can_recv(&self) -> bool { - self.can_recv() + fn can_recv(&mut self, _data: &Self::DataT) -> bool { + smoltcp::socket::raw::Socket::can_recv(self) } fn may_recv(&self) -> bool { @@ -117,7 +117,7 @@ impl<'a> SchemeSocket for RawSocket<'a> { ) -> SyscallResult { if !file.read_enabled { Ok(0) - } else if self.can_recv() { + } else if self.can_recv(&file.data) { let length = self.recv_slice(buf).expect("Can't receive slice"); Ok(length) } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { diff --git a/netstack/src/scheme/socket.rs b/netstack/src/scheme/socket.rs index 842dd0bd53..ab6690c8cd 100644 --- a/netstack/src/scheme/socket.rs +++ b/netstack/src/scheme/socket.rs @@ -133,13 +133,14 @@ where events, ref mut read_notified, ref mut write_notified, + ref data, .. }) = self { - let socket = socket_set.get::(socket_handle); + let socket = socket_set.get_mut::(socket_handle); if events & syscall::EVENT_READ.bits() == syscall::EVENT_READ.bits() - && (socket.can_recv() || !socket.may_recv()) + && (socket.can_recv(data) || !socket.may_recv()) { if !*read_notified { *read_notified = true; @@ -180,7 +181,7 @@ where fn new_scheme_data() -> Self::SchemeDataT; fn can_send(&self) -> bool; - fn can_recv(&self) -> bool; + fn can_recv(&mut self, data: &Self::DataT) -> bool; fn may_recv(&self) -> bool; fn hop_limit(&self) -> u8; diff --git a/netstack/src/scheme/tcp.rs b/netstack/src/scheme/tcp.rs index 1fbb7dc22c..584426b340 100644 --- a/netstack/src/scheme/tcp.rs +++ b/netstack/src/scheme/tcp.rs @@ -25,8 +25,8 @@ impl<'a> SchemeSocket for TcpSocket<'a> { self.can_send() } - fn can_recv(&self) -> bool { - self.can_recv() + fn can_recv(&mut self, _data: &Self::DataT) -> bool { + smoltcp::socket::tcp::Socket::can_recv(self) } fn may_recv(&self) -> bool { @@ -176,7 +176,7 @@ impl<'a> SchemeSocket for TcpSocket<'a> { Ok(0) } else if !self.is_active() { Err(SyscallError::new(syscall::ENOTCONN)) - } else if self.can_recv() { + } else if self.can_recv(&file.data) { let length = self.recv_slice(buf).expect("Can't receive slice"); Ok(length) } else if !self.may_recv() { diff --git a/netstack/src/scheme/udp.rs b/netstack/src/scheme/udp.rs index f1a7d46d77..2ad0bb771e 100644 --- a/netstack/src/scheme/udp.rs +++ b/netstack/src/scheme/udp.rs @@ -28,8 +28,46 @@ impl<'a> SchemeSocket for UdpSocket<'a> { self.can_send() } - fn can_recv(&self) -> bool { - self.can_recv() + fn can_recv(&mut self, data: &IpListenEndpoint) -> bool { + loop { + // If buffer is empty, we definitely can't recv + if !UdpSocket::can_recv(self) { + return false; + } + + // If we are not connected to a specific remote, any packet is valid + if !data.is_specified() { + return true; + } + + // If we are connected, peek at the packet. + match self.peek() { + Ok((_, meta)) => { + let source = meta.endpoint; + let connected_addr = data.addr.unwrap(); // Safe because is_specified() checked it + + // Allow Broadcast special case (DHCP) + let is_broadcast = match connected_addr { + smoltcp::wire::IpAddress::Ipv4(ip) => { + ip == smoltcp::wire::Ipv4Address::BROADCAST + } + _ => false, + }; + + if !is_broadcast && !connected_addr.is_unspecified() { + if source.addr != connected_addr || source.port != data.port { + // Bad packet detetced + // Remove it from the buffer immediately so poll() doesn't trigger + let _ = self.recv(); + continue; // Loop again to check the next packet + } + } + // Packet is valid + return true; + } + Err(_) => return false, + } + } } fn may_recv(&self) -> bool {