Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UDP: Store local and use local address in metadata #904

Merged
merged 3 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/iface/interface/tests/ipv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,10 @@ fn test_raw_socket_with_udp_socket(#[case] medium: Medium) {
socket.recv(),
Ok((
&UDP_PAYLOAD[..],
IpEndpoint::new(src_addr.into(), 67).into()
udp::UdpMetadata {
local_address: Some(dst_addr.into()),
..IpEndpoint::new(src_addr.into(), 67).into()
}
))
);
}
Expand Down
9 changes: 8 additions & 1 deletion src/iface/interface/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ fn test_handle_udp_broadcast(
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
hop_limit: 0x40,
});
let dst_addr = ip_repr.dst_addr();

// Bind the socket to port 68
let socket = sockets.get_mut::<udp::Socket>(socket_handle);
Expand Down Expand Up @@ -143,7 +144,13 @@ fn test_handle_udp_broadcast(
assert!(socket.can_recv());
assert_eq!(
socket.recv(),
Ok((&UDP_PAYLOAD[..], IpEndpoint::new(src_ip.into(), 67).into()))
Ok((
&UDP_PAYLOAD[..],
udp::UdpMetadata {
local_address: Some(dst_addr),
..IpEndpoint::new(src_ip.into(), 67).into()
}
))
);
}

Expand Down
23 changes: 16 additions & 7 deletions src/iface/interface/tests/sixlowpan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,14 +368,23 @@ In at rhoncus tortor. Cras blandit tellus diam, varius vestibulum nibh commodo n
socket.recv(),
Ok((
&udp_data[..],
IpEndpoint {
addr: IpAddress::Ipv6(Ipv6Address([
0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42,
0xb, 0x1a,
])),
port: 54217,
udp::UdpMetadata {
local_address: Some(
Ipv6Address([
0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92, 0xfc, 0x48, 0xc2, 0xa4,
0x41, 0xfc, 0x76,
])
.into()
),
..IpEndpoint {
addr: IpAddress::Ipv6(Ipv6Address([
0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x42, 0x42, 0x42, 0x42,
0x42, 0xb, 0x1a,
])),
port: 54217,
}
.into()
}
.into()
))
);

Expand Down
73 changes: 56 additions & 17 deletions src/socket/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,27 @@ use crate::socket::PollAt;
#[cfg(feature = "async")]
use crate::socket::WakerRegistration;
use crate::storage::Empty;
use crate::wire::{IpEndpoint, IpListenEndpoint, IpProtocol, IpRepr, UdpRepr};
use crate::wire::{IpAddress, IpEndpoint, IpListenEndpoint, IpProtocol, IpRepr, UdpRepr};

/// Metadata for a sent or received UDP packet.
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct UdpMetadata {
pub endpoint: IpEndpoint,
/// The IP address to which an incoming datagram was sent, or to which an outgoing datagram
/// will be sent. Incoming datagrams always have this set. On outgoing datagrams, if it is not
/// set, and the socket is not bound to a single address anyway, a suitable address will be
/// determined using the algorithms of RFC 6724 (candidate source address selection) or some
/// heuristic (for IPv4).
pub local_address: Option<IpAddress>,
pub meta: PacketMeta,
}

impl<T: Into<IpEndpoint>> From<T> for UdpMetadata {
fn from(value: T) -> Self {
Self {
endpoint: value.into(),
local_address: None,
meta: PacketMeta::default(),
}
}
Expand Down Expand Up @@ -493,6 +500,7 @@ impl<'a> Socket<'a> {

let metadata = UdpMetadata {
endpoint: remote_endpoint,
local_address: Some(ip_repr.dst_addr()),
meta,
};

Expand All @@ -517,19 +525,23 @@ impl<'a> Socket<'a> {
let hop_limit = self.hop_limit.unwrap_or(64);

let res = self.tx_buffer.dequeue_with(|packet_meta, payload_buf| {
let src_addr = match endpoint.addr {
Some(addr) => addr,
None => match cx.get_source_address(&packet_meta.endpoint.addr) {
let src_addr = if let Some(s) = packet_meta.local_address {
s
} else {
match endpoint.addr {
Some(addr) => addr,
None => {
net_trace!(
"udp:{}:{}: cannot find suitable source address, dropping.",
endpoint,
packet_meta.endpoint
);
return Ok(());
}
},
None => match cx.get_source_address(&packet_meta.endpoint.addr) {
Some(addr) => addr,
None => {
net_trace!(
"udp:{}:{}: cannot find suitable source address, dropping.",
endpoint,
packet_meta.endpoint
);
return Ok(());
}
},
}
};

net_trace!(
Expand Down Expand Up @@ -635,6 +647,13 @@ mod test {
addr: REMOTE_ADDR.into_address(),
port: REMOTE_PORT,
};
fn remote_metadata_with_local() -> UdpMetadata {
// Would be great as a const once we have const `.into()`.
UdpMetadata {
local_address: Some(LOCAL_ADDR.into()),
..REMOTE_END.into()
}
}

pub const LOCAL_IP_REPR: IpRepr = IpReprIpvX(IpvXRepr {
src_addr: LOCAL_ADDR,
Expand Down Expand Up @@ -724,6 +743,17 @@ mod test {
assert_eq!(socket.send_slice(b"abcdef", REMOTE_END), Ok(()));
}

#[test]
fn test_send_with_source() {
let mut socket = socket(buffer(0), buffer(1));

assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
assert_eq!(
socket.send_slice(b"abcdef", remote_metadata_with_local()),
Ok(())
);
}

#[rstest]
#[case::ip(Medium::Ip)]
#[cfg(feature = "medium-ip")]
Expand Down Expand Up @@ -811,7 +841,10 @@ mod test {
PAYLOAD,
);

assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END.into())));
assert_eq!(
socket.recv(),
Ok((&b"abcdef"[..], remote_metadata_with_local()))
);
assert!(!socket.can_recv());
}

Expand Down Expand Up @@ -839,8 +872,14 @@ mod test {
&REMOTE_UDP_REPR,
PAYLOAD,
);
assert_eq!(socket.peek(), Ok((&b"abcdef"[..], &REMOTE_END.into(),)));
assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END.into(),)));
assert_eq!(
socket.peek(),
Ok((&b"abcdef"[..], &remote_metadata_with_local(),))
);
assert_eq!(
socket.recv(),
Ok((&b"abcdef"[..], remote_metadata_with_local(),))
);
assert_eq!(socket.peek(), Err(RecvError::Exhausted));
}

Expand Down Expand Up @@ -1013,7 +1052,7 @@ mod test {
dst_port: LOCAL_PORT,
};
socket.process(cx, PacketMeta::default(), &REMOTE_IP_REPR, &repr, &[]);
assert_eq!(socket.recv(), Ok((&[][..], REMOTE_END.into())));
assert_eq!(socket.recv(), Ok((&[][..], remote_metadata_with_local())));
}

#[test]
Expand Down