udp: do not include payload in UdpRepr

This makes UdpRepr work like IpRepr, where it only emits the header, and the user
must emit the payload.

This makes it easier to emit UDP packets with payloads that come from protocol-specific
reprs, like DHCP and in the future DNS.
This commit is contained in:
Dario Nieuwenhuis 2021-04-02 00:14:30 +02:00
parent f2231c1cb5
commit ab47db24e0
6 changed files with 135 additions and 105 deletions

View File

@ -1,9 +1,9 @@
use crate::{Result, Error};
use crate::{Error, Result};
use crate::wire::{IpVersion, IpProtocol, IpEndpoint, IpAddress,
Ipv4Cidr, Ipv4Address, Ipv4Packet, Ipv4Repr,
UdpPacket, UdpRepr,
DhcpPacket, DhcpRepr, DhcpMessageType};
use crate::wire::dhcpv4::field as dhcpv4_field;
use crate::wire::dhcpv4::{field as dhcpv4_field, Packet as Dhcpv4Packet};
use crate::socket::{SocketSet, SocketHandle, RawSocket, RawSocketBuffer};
use crate::phy::{Device, ChecksumCapabilities};
use crate::iface::Interface;
@ -361,18 +361,10 @@ impl Client {
}
fn send_packet<DeviceT: for<'d> Device<'d>>(iface: &mut Interface<DeviceT>, raw_socket: &mut RawSocket, endpoint: &IpEndpoint, dhcp_repr: &DhcpRepr, checksum_caps: &ChecksumCapabilities) -> Result<()> {
let mut dhcp_payload_buf = [0; 320];
assert!(dhcp_repr.buffer_len() <= dhcp_payload_buf.len());
let dhcp_payload = &mut dhcp_payload_buf[0..dhcp_repr.buffer_len()];
{
let mut dhcp_packet = DhcpPacket::new_checked(&mut dhcp_payload[..])?;
dhcp_repr.emit(&mut dhcp_packet)?;
}
let udp_repr = UdpRepr {
src_port: UDP_CLIENT_PORT,
dst_port: endpoint.port,
payload: dhcp_payload,
};
let src_addr = iface.ipv4_addr().unwrap();
@ -384,12 +376,12 @@ fn send_packet<DeviceT: for<'d> Device<'d>>(iface: &mut Interface<DeviceT>, raw_
src_addr,
dst_addr,
protocol: IpProtocol::Udp,
payload_len: udp_repr.buffer_len(),
payload_len: udp_repr.header_len() + dhcp_repr.buffer_len(),
hop_limit: 64,
};
let mut packet = raw_socket.send(
ipv4_repr.buffer_len() + udp_repr.buffer_len()
ipv4_repr.buffer_len() + udp_repr.header_len() + dhcp_repr.buffer_len()
)?;
{
let mut ipv4_packet = Ipv4Packet::new_unchecked(&mut packet);
@ -401,6 +393,8 @@ fn send_packet<DeviceT: for<'d> Device<'d>>(iface: &mut Interface<DeviceT>, raw_
);
udp_repr.emit(&mut udp_packet,
&src_addr.into(), &dst_addr.into(),
dhcp_repr.buffer_len(),
|buf| dhcp_repr.emit(&mut Dhcpv4Packet::new_unchecked(buf)).unwrap(),
checksum_caps);
}
Ok(())
@ -423,6 +417,6 @@ fn parse_udp<'a>(data: &'a [u8], checksum_caps: &ChecksumCapabilities) -> Result
addr: ipv4_repr.dst_addr.into(),
port: udp_repr.dst_port,
};
let data = udp_repr.payload;
let data = udp_packet.payload();
Ok((src, dst, data))
}

View File

@ -263,7 +263,7 @@ pub(crate) enum IpPacket<'a> {
#[cfg(feature = "socket-raw")]
Raw((IpRepr, &'a [u8])),
#[cfg(feature = "socket-udp")]
Udp((IpRepr, UdpRepr<'a>)),
Udp((IpRepr, UdpRepr, &'a [u8])),
#[cfg(feature = "socket-tcp")]
Tcp((IpRepr, TcpRepr<'a>))
}
@ -280,7 +280,7 @@ impl<'a> IpPacket<'a> {
#[cfg(feature = "socket-raw")]
IpPacket::Raw((ip_repr, _)) => ip_repr.clone(),
#[cfg(feature = "socket-udp")]
IpPacket::Udp((ip_repr, _)) => ip_repr.clone(),
IpPacket::Udp((ip_repr, _, _)) => ip_repr.clone(),
#[cfg(feature = "socket-tcp")]
IpPacket::Tcp((ip_repr, _)) => ip_repr.clone(),
}
@ -289,7 +289,7 @@ impl<'a> IpPacket<'a> {
pub(crate) fn emit_payload(&self, _ip_repr: IpRepr, payload: &mut [u8], caps: &DeviceCapabilities) {
match self {
#[cfg(feature = "proto-ipv4")]
IpPacket::Icmpv4((_, icmpv4_repr)) =>
IpPacket::Icmpv4((_, icmpv4_repr)) =>
icmpv4_repr.emit(&mut Icmpv4Packet::new_unchecked(payload), &caps.checksum),
#[cfg(feature = "proto-igmp")]
IpPacket::Igmp((_, igmp_repr)) =>
@ -302,9 +302,11 @@ impl<'a> IpPacket<'a> {
IpPacket::Raw((_, raw_packet)) =>
payload.copy_from_slice(raw_packet),
#[cfg(feature = "socket-udp")]
IpPacket::Udp((_, udp_repr)) =>
IpPacket::Udp((_, udp_repr, inner_payload)) =>
udp_repr.emit(&mut UdpPacket::new_unchecked(payload),
&_ip_repr.src_addr(), &_ip_repr.dst_addr(), &caps.checksum),
&_ip_repr.src_addr(), &_ip_repr.dst_addr(),
inner_payload.len(), |buf| buf.copy_from_slice(inner_payload),
&caps.checksum),
#[cfg(feature = "socket-tcp")]
IpPacket::Tcp((_, mut tcp_repr)) => {
// This is a terrible hack to make TCP performance more acceptable on systems
@ -880,7 +882,7 @@ impl<'a> InterfaceInner<'a> {
self.neighbor_cache.as_mut().unwrap().fill(ip_addr, eth_frame.src_addr(), timestamp);
}
}
self.process_ipv6(sockets, timestamp, &ipv6_packet).map(|o| o.map(EthernetPacket::Ip))
}
// Drop all other traffic.
@ -1439,11 +1441,12 @@ impl<'a> InterfaceInner<'a> {
let udp_packet = UdpPacket::new_checked(ip_payload)?;
let checksum_caps = self.device_capabilities.checksum.clone();
let udp_repr = UdpRepr::parse(&udp_packet, &src_addr, &dst_addr, &checksum_caps)?;
let udp_payload = udp_packet.payload();
for mut udp_socket in sockets.iter_mut().filter_map(UdpSocket::downcast) {
if !udp_socket.accepts(&ip_repr, &udp_repr) { continue }
match udp_socket.process(&ip_repr, &udp_repr) {
match udp_socket.process(&ip_repr, &udp_repr, udp_payload) {
// The packet is valid and handled by socket.
Ok(()) => return Ok(None),
// The packet is malformed, or the socket buffer is full.
@ -1787,6 +1790,13 @@ mod test {
use crate::socket::SocketSet;
use crate::phy::{Loopback, ChecksumCapabilities};
#[allow(unused)]
fn fill_slice(s: &mut [u8], val: u8) {
for x in s.iter_mut() {
*x = val
}
}
fn create_loopback<'a>() -> (Interface<'a, Loopback>, SocketSet<'a>) {
#[cfg(feature = "medium-ethernet")]
return create_loopback_ethernet();
@ -2035,20 +2045,21 @@ mod test {
let udp_repr = UdpRepr {
src_port: 67,
dst_port: 68,
payload: &UDP_PAYLOAD
};
let ip_repr = IpRepr::Ipv4(Ipv4Repr {
src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
protocol: IpProtocol::Udp,
payload_len: udp_repr.buffer_len(),
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
hop_limit: 64
});
// Emit the representations to a packet
udp_repr.emit(&mut packet_unicast, &ip_repr.src_addr(),
&ip_repr.dst_addr(), &ChecksumCapabilities::default());
&ip_repr.dst_addr(),
UDP_PAYLOAD.len(), |buf| buf.copy_from_slice( &UDP_PAYLOAD),
&ChecksumCapabilities::default());
let data = packet_unicast.into_inner();
@ -2060,7 +2071,7 @@ mod test {
src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
protocol: IpProtocol::Udp,
payload_len: udp_repr.buffer_len(),
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
hop_limit: 64
},
data: &data
@ -2085,13 +2096,14 @@ mod test {
src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
dst_addr: Ipv4Address::BROADCAST,
protocol: IpProtocol::Udp,
payload_len: udp_repr.buffer_len(),
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
hop_limit: 64
});
// Emit the representations to a packet
udp_repr.emit(&mut packet_broadcast, &ip_repr.src_addr(),
&IpAddress::Ipv4(Ipv4Address::BROADCAST),
UDP_PAYLOAD.len(), |buf| buf.copy_from_slice( &UDP_PAYLOAD),
&ChecksumCapabilities::default());
// Ensure that the port unreachable error does not trigger an
@ -2129,7 +2141,6 @@ mod test {
let udp_repr = UdpRepr {
src_port: 67,
dst_port: 68,
payload: &UDP_PAYLOAD
};
#[cfg(feature = "proto-ipv6")]
@ -2137,7 +2148,7 @@ mod test {
src_addr: src_ip,
dst_addr: Ipv6Address::LINK_LOCAL_ALL_NODES,
next_header: IpProtocol::Udp,
payload_len: udp_repr.buffer_len(),
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
hop_limit: 0x40
});
#[cfg(all(not(feature = "proto-ipv6"), feature = "proto-ipv4"))]
@ -2145,7 +2156,7 @@ mod test {
src_addr: src_ip,
dst_addr: Ipv4Address::BROADCAST,
protocol: IpProtocol::Udp,
payload_len: udp_repr.buffer_len(),
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
hop_limit: 0x40
});
@ -2158,6 +2169,7 @@ mod test {
}
udp_repr.emit(&mut packet, &ip_repr.src_addr(), &ip_repr.dst_addr(),
UDP_PAYLOAD.len(), |buf| buf.copy_from_slice( &UDP_PAYLOAD),
&ChecksumCapabilities::default());
// Packet should be handled by bound UDP socket
@ -2260,18 +2272,19 @@ mod test {
let udp_repr = UdpRepr {
src_port: 67,
dst_port: 68,
payload: &[0x2a; MAX_PAYLOAD_LEN]
};
let mut bytes = vec![0xff; udp_repr.buffer_len()];
let mut bytes = vec![0xff; udp_repr.header_len() + MAX_PAYLOAD_LEN];
let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(), &ChecksumCapabilities::default());
udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(),
MAX_PAYLOAD_LEN, |buf| fill_slice(buf, 0x2a),
&ChecksumCapabilities::default());
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
let ip_repr = Ipv4Repr {
src_addr: src_addr,
dst_addr: dst_addr,
protocol: IpProtocol::Udp,
hop_limit: 64,
payload_len: udp_repr.buffer_len()
payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN
};
#[cfg(feature = "proto-ipv6")]
let ip_repr = Ipv6Repr {
@ -2279,7 +2292,7 @@ mod test {
dst_addr: dst_addr,
next_header: IpProtocol::Udp,
hop_limit: 64,
payload_len: udp_repr.buffer_len()
payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN
};
let payload = packet.into_inner();
@ -2619,7 +2632,7 @@ mod test {
recv_all(&mut iface, timestamp)
.iter()
.filter_map(|frame| {
let ipv4_packet = match caps.medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => {
@ -2666,11 +2679,11 @@ mod test {
// General query
let timestamp = Instant::now();
const GENERAL_QUERY_BYTES: &[u8] = &[
0x46, 0xc0, 0x00, 0x24, 0xed, 0xb4, 0x00, 0x00,
0x01, 0x02, 0x47, 0x43, 0xac, 0x16, 0x63, 0x04,
0xe0, 0x00, 0x00, 0x01, 0x94, 0x04, 0x00, 0x00,
0x11, 0x64, 0xec, 0x8f, 0x00, 0x00, 0x00, 0x00,
0x02, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0xc0, 0x00, 0x24, 0xed, 0xb4, 0x00, 0x00,
0x01, 0x02, 0x47, 0x43, 0xac, 0x16, 0x63, 0x04,
0xe0, 0x00, 0x00, 0x01, 0x94, 0x04, 0x00, 0x00,
0x11, 0x64, 0xec, 0x8f, 0x00, 0x00, 0x00, 0x00,
0x02, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];
{
@ -2722,25 +2735,28 @@ mod test {
let src_addr = Ipv4Address([127, 0, 0, 2]);
let dst_addr = Ipv4Address([127, 0, 0, 1]);
const PAYLOAD_LEN: usize = 10;
let udp_repr = UdpRepr {
src_port: 67,
dst_port: 68,
payload: &[0x2a; 10]
};
let mut bytes = vec![0xff; udp_repr.buffer_len()];
let mut bytes = vec![0xff; udp_repr.header_len() + PAYLOAD_LEN];
let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(), &ChecksumCapabilities::default());
udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(),
PAYLOAD_LEN, |buf| fill_slice(buf, 0x2a),
&ChecksumCapabilities::default());
let ipv4_repr = Ipv4Repr {
src_addr: src_addr,
dst_addr: dst_addr,
protocol: IpProtocol::Udp,
hop_limit: 64,
payload_len: udp_repr.buffer_len()
payload_len: udp_repr.header_len() + PAYLOAD_LEN
};
// Emit to frame
let mut bytes = vec![0u8;
ipv4_repr.buffer_len() + udp_repr.buffer_len()
ipv4_repr.buffer_len() + udp_repr.header_len() + PAYLOAD_LEN
];
let frame = {
ipv4_repr.emit(
@ -2751,6 +2767,7 @@ mod test {
&mut bytes[ipv4_repr.buffer_len()..]),
&src_addr.into(),
&dst_addr.into(),
PAYLOAD_LEN, |buf| fill_slice(buf, 0x2a),
&ChecksumCapabilities::default());
Ipv4Packet::new_unchecked(&bytes)
};
@ -2776,25 +2793,28 @@ mod test {
let src_addr = Ipv4Address([127, 0, 0, 2]);
let dst_addr = Ipv4Address([127, 0, 0, 1]);
const PAYLOAD_LEN: usize = 49; // 49 > 48, hence packet will be truncated
let udp_repr = UdpRepr {
src_port: 67,
dst_port: 68,
payload: &[0x2a; 49] // 49 > 48, hence packet will be truncated
};
let mut bytes = vec![0xff; udp_repr.buffer_len()];
let mut bytes = vec![0xff; udp_repr.header_len() + PAYLOAD_LEN];
let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(), &ChecksumCapabilities::default());
udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(),
PAYLOAD_LEN, |buf| fill_slice(buf, 0x2a),
&ChecksumCapabilities::default());
let ipv4_repr = Ipv4Repr {
src_addr: src_addr,
dst_addr: dst_addr,
protocol: IpProtocol::Udp,
hop_limit: 64,
payload_len: udp_repr.buffer_len()
payload_len: udp_repr.header_len() + PAYLOAD_LEN
};
// Emit to frame
let mut bytes = vec![0u8;
ipv4_repr.buffer_len() + udp_repr.buffer_len()
ipv4_repr.buffer_len() + udp_repr.header_len() + PAYLOAD_LEN
];
let frame = {
ipv4_repr.emit(
@ -2802,9 +2822,10 @@ mod test {
&ChecksumCapabilities::default());
udp_repr.emit(
&mut UdpPacket::new_unchecked(
&mut bytes[ipv4_repr.buffer_len()..]),
&mut bytes[ipv4_repr.buffer_len()..]),
&src_addr.into(),
&dst_addr.into(),
PAYLOAD_LEN, |buf| fill_slice(buf, 0x2a),
&ChecksumCapabilities::default());
Ipv4Packet::new_unchecked(&bytes)
};
@ -2812,7 +2833,7 @@ mod test {
let frame = iface.inner.process_ipv4(&mut socket_set, Instant::from_millis(0), &frame);
// because the packet could not be handled we should send an Icmp message
assert!(match frame {
assert!(match frame {
Ok(Some(IpPacket::Icmpv4(_))) => true,
_ => false,
});
@ -2853,22 +2874,23 @@ mod test {
let udp_repr = UdpRepr {
src_port: 67,
dst_port: 68,
payload: &UDP_PAYLOAD
};
let mut bytes = vec![0xff; udp_repr.buffer_len()];
let mut bytes = vec![0xff; udp_repr.header_len() + UDP_PAYLOAD.len()];
let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(), &ChecksumCapabilities::default());
udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(),
UDP_PAYLOAD.len(), |buf| buf.copy_from_slice( &UDP_PAYLOAD),
&ChecksumCapabilities::default());
let ipv4_repr = Ipv4Repr {
src_addr: src_addr,
dst_addr: dst_addr,
protocol: IpProtocol::Udp,
hop_limit: 64,
payload_len: udp_repr.buffer_len()
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len()
};
// Emit to frame
let mut bytes = vec![0u8;
ipv4_repr.buffer_len() + udp_repr.buffer_len()
ipv4_repr.buffer_len() + udp_repr.header_len() + UDP_PAYLOAD.len()
];
let frame = {
ipv4_repr.emit(
@ -2876,9 +2898,10 @@ mod test {
&ChecksumCapabilities::default());
udp_repr.emit(
&mut UdpPacket::new_unchecked(
&mut bytes[ipv4_repr.buffer_len()..]),
&mut bytes[ipv4_repr.buffer_len()..]),
&src_addr.into(),
&dst_addr.into(),
UDP_PAYLOAD.len(), |buf| buf.copy_from_slice( &UDP_PAYLOAD),
&ChecksumCapabilities::default());
Ipv4Packet::new_unchecked(&bytes)
};

View File

@ -94,12 +94,12 @@ impl<'a> IcmpSocket<'a> {
///
/// The waker is woken on state changes that might affect the return value
/// of `recv` method calls, such as receiving data, or the socket closing.
///
///
/// Notes:
///
/// - Only one waker can be registered at a time. If another waker was previously registered,
/// it is overwritten and will no longer be woken.
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
/// necessarily changed.
#[cfg(feature = "async")]
@ -112,12 +112,12 @@ impl<'a> IcmpSocket<'a> {
/// The waker is woken on state changes that might affect the return value
/// of `send` method calls, such as space becoming available in the transmit
/// buffer, or the socket closing.
///
///
/// Notes:
///
/// - Only one waker can be registered at a time. If another waker was previously registered,
/// it is overwritten and will no longer be woken.
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
/// necessarily changed.
#[cfg(feature = "async")]
@ -440,7 +440,7 @@ impl<'a> IcmpSocket<'a> {
_ => Err(Error::Unaddressable)
}
})?;
#[cfg(feature = "async")]
self.tx_waker.wake();
@ -482,8 +482,9 @@ mod tests_common {
pub static UDP_REPR: UdpRepr = UdpRepr {
src_port: 53,
dst_port: 9090,
payload: &[0xff; 10]
};
pub static UDP_PAYLOAD: &[u8] = &[0xff; 10];
}
#[cfg(all(test, feature = "proto-ipv4"))]
@ -644,7 +645,13 @@ mod test_ipv4 {
let mut bytes = [0xff; 18];
let mut packet = UdpPacket::new_unchecked(&mut bytes);
UDP_REPR.emit(&mut packet, &REMOTE_IPV4.into(), &LOCAL_IPV4.into(), &checksum);
UDP_REPR.emit(
&mut packet,
&REMOTE_IPV4.into(),
&LOCAL_IPV4.into(),
UDP_PAYLOAD.len(),
|buf| buf.copy_from_slice(UDP_PAYLOAD),
&checksum);
let data = &packet.into_inner()[..];
@ -843,7 +850,13 @@ mod test_ipv6 {
let mut bytes = [0xff; 18];
let mut packet = UdpPacket::new_unchecked(&mut bytes);
UDP_REPR.emit(&mut packet, &REMOTE_IPV6.into(), &LOCAL_IPV6.into(), &checksum);
UDP_REPR.emit(
&mut packet,
&REMOTE_IPV6.into(),
&LOCAL_IPV6.into(),
UDP_PAYLOAD.len(),
|buf| buf.copy_from_slice(UDP_PAYLOAD),
&checksum);
let data = &packet.into_inner()[..];

View File

@ -54,12 +54,12 @@ impl<'a> UdpSocket<'a> {
///
/// The waker is woken on state changes that might affect the return value
/// of `recv` method calls, such as receiving data, or the socket closing.
///
///
/// Notes:
///
/// - Only one waker can be registered at a time. If another waker was previously registered,
/// it is overwritten and will no longer be woken.
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
/// necessarily changed.
#[cfg(feature = "async")]
@ -72,12 +72,12 @@ impl<'a> UdpSocket<'a> {
/// The waker is woken on state changes that might affect the return value
/// of `send` method calls, such as space becoming available in the transmit
/// buffer, or the socket closing.
///
///
/// Notes:
///
/// - Only one waker can be registered at a time. If another waker was previously registered,
/// it is overwritten and will no longer be woken.
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
/// necessarily changed.
#[cfg(feature = "async")]
@ -277,13 +277,13 @@ impl<'a> UdpSocket<'a> {
true
}
pub(crate) fn process(&mut self, ip_repr: &IpRepr, repr: &UdpRepr) -> Result<()> {
pub(crate) fn process(&mut self, ip_repr: &IpRepr, repr: &UdpRepr, payload: &[u8]) -> Result<()> {
debug_assert!(self.accepts(ip_repr, repr));
let size = repr.payload.len();
let size = payload.len();
let endpoint = IpEndpoint { addr: ip_repr.src_addr(), port: repr.src_port };
self.rx_buffer.enqueue(size, endpoint)?.copy_from_slice(repr.payload);
self.rx_buffer.enqueue(size, endpoint)?.copy_from_slice(payload);
net_trace!("{}:{}:{}: receiving {} octets",
self.meta.handle, self.endpoint,
@ -296,7 +296,7 @@ impl<'a> UdpSocket<'a> {
}
pub(crate) fn dispatch<F>(&mut self, emit: F) -> Result<()>
where F: FnOnce((IpRepr, UdpRepr)) -> Result<()> {
where F: FnOnce((IpRepr, UdpRepr, &[u8])) -> Result<()> {
let handle = self.handle();
let endpoint = self.endpoint;
let hop_limit = self.hop_limit.unwrap_or(64);
@ -309,16 +309,15 @@ impl<'a> UdpSocket<'a> {
let repr = UdpRepr {
src_port: endpoint.port,
dst_port: remote_endpoint.port,
payload: payload_buf,
};
let ip_repr = IpRepr::Unspecified {
src_addr: endpoint.addr,
dst_addr: remote_endpoint.addr,
protocol: IpProtocol::Udp,
payload_len: repr.buffer_len(),
payload_len: repr.header_len() + payload_buf.len(),
hop_limit: hop_limit,
};
emit((ip_repr, repr))
emit((ip_repr, repr, payload_buf))
})?;
#[cfg(feature = "async")]
@ -379,15 +378,15 @@ mod test {
const LOCAL_UDP_REPR: UdpRepr = UdpRepr {
src_port: LOCAL_PORT,
dst_port: REMOTE_PORT,
payload: b"abcdef"
};
const REMOTE_UDP_REPR: UdpRepr = UdpRepr {
src_port: REMOTE_PORT,
dst_port: LOCAL_PORT,
payload: b"abcdef"
};
const PAYLOAD: &[u8] = b"abcdef";
fn remote_ip_repr() -> IpRepr {
match (MOCK_IP_ADDR_2, MOCK_IP_ADDR_1) {
#[cfg(feature = "proto-ipv4")]
@ -457,16 +456,18 @@ mod test {
assert_eq!(socket.send_slice(b"123456", REMOTE_END), Err(Error::Exhausted));
assert!(!socket.can_send());
assert_eq!(socket.dispatch(|(ip_repr, udp_repr)| {
assert_eq!(socket.dispatch(|(ip_repr, udp_repr, payload)| {
assert_eq!(ip_repr, LOCAL_IP_REPR);
assert_eq!(udp_repr, LOCAL_UDP_REPR);
assert_eq!(payload, PAYLOAD);
Err(Error::Unaddressable)
}), Err(Error::Unaddressable));
assert!(!socket.can_send());
assert_eq!(socket.dispatch(|(ip_repr, udp_repr)| {
assert_eq!(socket.dispatch(|(ip_repr, udp_repr, payload)| {
assert_eq!(ip_repr, LOCAL_IP_REPR);
assert_eq!(udp_repr, LOCAL_UDP_REPR);
assert_eq!(payload, PAYLOAD);
Ok(())
}), Ok(()));
assert!(socket.can_send());
@ -481,12 +482,12 @@ mod test {
assert_eq!(socket.recv(), Err(Error::Exhausted));
assert!(socket.accepts(&remote_ip_repr(), &REMOTE_UDP_REPR));
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR),
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
Ok(()));
assert!(socket.can_recv());
assert!(socket.accepts(&remote_ip_repr(), &REMOTE_UDP_REPR));
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR),
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
Err(Error::Exhausted));
assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END)));
assert!(!socket.can_recv());
@ -499,7 +500,7 @@ mod test {
assert_eq!(socket.peek(), Err(Error::Exhausted));
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR),
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
Ok(()));
assert_eq!(socket.peek(), Ok((&b"abcdef"[..], &REMOTE_END)));
assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END)));
@ -512,7 +513,7 @@ mod test {
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
assert!(socket.accepts(&remote_ip_repr(), &REMOTE_UDP_REPR));
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR),
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
Ok(()));
let mut slice = [0; 4];
@ -525,7 +526,7 @@ mod test {
let mut socket = socket(buffer(1), buffer(0));
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR),
assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR, PAYLOAD),
Ok(()));
let mut slice = [0; 4];
@ -543,7 +544,7 @@ mod test {
s.set_hop_limit(Some(0x2a));
assert_eq!(s.send_slice(b"abcdef", REMOTE_END), Ok(()));
assert_eq!(s.dispatch(|(ip_repr, _)| {
assert_eq!(s.dispatch(|(ip_repr, _, _)| {
assert_eq!(ip_repr, IpRepr::Unspecified{
src_addr: MOCK_IP_ADDR_1,
dst_addr: MOCK_IP_ADDR_2,
@ -619,9 +620,8 @@ mod test {
let repr = UdpRepr {
src_port: REMOTE_PORT,
dst_port: LOCAL_PORT,
payload: &[]
};
assert_eq!(socket.process(&remote_ip_repr(), &repr), Ok(()));
assert_eq!(socket.process(&remote_ip_repr(), &repr, &[]), Ok(()));
assert_eq!(socket.recv(), Ok((&[][..], REMOTE_END)));
}
}

View File

@ -887,7 +887,7 @@ pub fn pretty_print_ip_payload<T: Into<Repr>>(f: &mut fmt::Formatter, indent: &m
&repr.dst_addr(), &checksum_caps) {
Err(err) => write!(f, "{}{} ({})", indent, udp_packet, err),
Ok(udp_repr) => {
write!(f, "{}{}", indent, udp_repr)?;
write!(f, "{}{} len={}", indent, udp_repr, udp_packet.payload().len())?;
let valid = udp_packet.verify_checksum(&repr.src_addr(),
&repr.dst_addr());
format_checksum(f, valid)

View File

@ -201,16 +201,15 @@ impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
/// A high-level representation of an User Datagram Protocol packet.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Repr<'a> {
pub struct Repr {
pub src_port: u16,
pub dst_port: u16,
pub payload: &'a [u8]
}
impl<'a> Repr<'a> {
impl Repr {
/// Parse an User Datagram Protocol packet and return a high-level representation.
pub fn parse<T>(packet: &Packet<&'a T>, src_addr: &IpAddress, dst_addr: &IpAddress,
checksum_caps: &ChecksumCapabilities) -> Result<Repr<'a>>
pub fn parse<T>(packet: &Packet<&T>, src_addr: &IpAddress, dst_addr: &IpAddress,
checksum_caps: &ChecksumCapabilities) -> Result<Repr>
where T: AsRef<[u8]> + ?Sized {
// Destination port cannot be omitted (but source port can be).
if packet.dst_port() == 0 { return Err(Error::Malformed) }
@ -230,25 +229,26 @@ impl<'a> Repr<'a> {
Ok(Repr {
src_port: packet.src_port(),
dst_port: packet.dst_port(),
payload: packet.payload()
})
}
/// Return the length of a packet that will be emitted from this high-level representation.
pub fn buffer_len(&self) -> usize {
field::CHECKSUM.end + self.payload.len()
pub fn header_len(&self) -> usize {
field::CHECKSUM.end
}
/// Emit a high-level representation into an User Datagram Protocol packet.
pub fn emit<T: ?Sized>(&self, packet: &mut Packet<&mut T>,
src_addr: &IpAddress,
dst_addr: &IpAddress,
payload_len: usize,
emit_payload: impl FnOnce(&mut [u8]),
checksum_caps: &ChecksumCapabilities)
where T: AsRef<[u8]> + AsMut<[u8]> {
packet.set_src_port(self.src_port);
packet.set_dst_port(self.dst_port);
packet.set_len((field::CHECKSUM.end + self.payload.len()) as u16);
packet.payload_mut().copy_from_slice(self.payload);
packet.set_len((field::CHECKSUM.end + payload_len) as u16);
emit_payload(packet.payload_mut());
if checksum_caps.udp.tx() {
packet.fill_checksum(src_addr, dst_addr)
@ -268,10 +268,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
}
}
impl<'a> fmt::Display for Repr<'a> {
impl fmt::Display for Repr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UDP src={} dst={} len={}",
self.src_port, self.dst_port, self.payload.len())
write!(f, "UDP src={} dst={}", self.src_port, self.dst_port)
}
}
@ -361,11 +360,10 @@ mod test {
}
#[cfg(feature = "proto-ipv4")]
fn packet_repr() -> Repr<'static> {
fn packet_repr() -> Repr {
Repr {
src_port: 48896,
dst_port: 53,
payload: &PAYLOAD_BYTES
}
}
@ -382,9 +380,11 @@ mod test {
#[cfg(feature = "proto-ipv4")]
fn test_emit() {
let repr = packet_repr();
let mut bytes = vec![0xa5; repr.buffer_len()];
let mut bytes = vec![0xa5; repr.header_len() + PAYLOAD_BYTES.len()];
let mut packet = Packet::new_unchecked(&mut bytes);
repr.emit(&mut packet, &SRC_ADDR.into(), &DST_ADDR.into(),
PAYLOAD_BYTES.len(),
|payload| payload.copy_from_slice(&PAYLOAD_BYTES),
&ChecksumCapabilities::default());
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
}