Skip to content

Commit 125773e

Browse files
authored
Merge pull request #904 from chrysn-pull-requests/pktinfo
UDP: Store local and use local address in metadata
2 parents d3ed3cc + dc60300 commit 125773e

File tree

4 files changed

+84
-26
lines changed

4 files changed

+84
-26
lines changed

src/iface/interface/tests/ipv4.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,10 @@ fn test_raw_socket_with_udp_socket(#[case] medium: Medium) {
938938
socket.recv(),
939939
Ok((
940940
&UDP_PAYLOAD[..],
941-
IpEndpoint::new(src_addr.into(), 67).into()
941+
udp::UdpMetadata {
942+
local_address: Some(dst_addr.into()),
943+
..IpEndpoint::new(src_addr.into(), 67).into()
944+
}
942945
))
943946
);
944947
}

src/iface/interface/tests/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ fn test_handle_udp_broadcast(
109109
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
110110
hop_limit: 0x40,
111111
});
112+
let dst_addr = ip_repr.dst_addr();
112113

113114
// Bind the socket to port 68
114115
let socket = sockets.get_mut::<udp::Socket>(socket_handle);
@@ -143,7 +144,13 @@ fn test_handle_udp_broadcast(
143144
assert!(socket.can_recv());
144145
assert_eq!(
145146
socket.recv(),
146-
Ok((&UDP_PAYLOAD[..], IpEndpoint::new(src_ip.into(), 67).into()))
147+
Ok((
148+
&UDP_PAYLOAD[..],
149+
udp::UdpMetadata {
150+
local_address: Some(dst_addr),
151+
..IpEndpoint::new(src_ip.into(), 67).into()
152+
}
153+
))
147154
);
148155
}
149156

src/iface/interface/tests/sixlowpan.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -368,14 +368,23 @@ In at rhoncus tortor. Cras blandit tellus diam, varius vestibulum nibh commodo n
368368
socket.recv(),
369369
Ok((
370370
&udp_data[..],
371-
IpEndpoint {
372-
addr: IpAddress::Ipv6(Ipv6Address([
373-
0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42,
374-
0xb, 0x1a,
375-
])),
376-
port: 54217,
371+
udp::UdpMetadata {
372+
local_address: Some(
373+
Ipv6Address([
374+
0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92, 0xfc, 0x48, 0xc2, 0xa4,
375+
0x41, 0xfc, 0x76,
376+
])
377+
.into()
378+
),
379+
..IpEndpoint {
380+
addr: IpAddress::Ipv6(Ipv6Address([
381+
0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x42, 0x42, 0x42, 0x42,
382+
0x42, 0xb, 0x1a,
383+
])),
384+
port: 54217,
385+
}
386+
.into()
377387
}
378-
.into()
379388
))
380389
);
381390

src/socket/udp.rs

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,27 @@ use crate::socket::PollAt;
88
#[cfg(feature = "async")]
99
use crate::socket::WakerRegistration;
1010
use crate::storage::Empty;
11-
use crate::wire::{IpEndpoint, IpListenEndpoint, IpProtocol, IpRepr, UdpRepr};
11+
use crate::wire::{IpAddress, IpEndpoint, IpListenEndpoint, IpProtocol, IpRepr, UdpRepr};
1212

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

2127
impl<T: Into<IpEndpoint>> From<T> for UdpMetadata {
2228
fn from(value: T) -> Self {
2329
Self {
2430
endpoint: value.into(),
31+
local_address: None,
2532
meta: PacketMeta::default(),
2633
}
2734
}
@@ -493,6 +500,7 @@ impl<'a> Socket<'a> {
493500

494501
let metadata = UdpMetadata {
495502
endpoint: remote_endpoint,
503+
local_address: Some(ip_repr.dst_addr()),
496504
meta,
497505
};
498506

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

519527
let res = self.tx_buffer.dequeue_with(|packet_meta, payload_buf| {
520-
let src_addr = match endpoint.addr {
521-
Some(addr) => addr,
522-
None => match cx.get_source_address(&packet_meta.endpoint.addr) {
528+
let src_addr = if let Some(s) = packet_meta.local_address {
529+
s
530+
} else {
531+
match endpoint.addr {
523532
Some(addr) => addr,
524-
None => {
525-
net_trace!(
526-
"udp:{}:{}: cannot find suitable source address, dropping.",
527-
endpoint,
528-
packet_meta.endpoint
529-
);
530-
return Ok(());
531-
}
532-
},
533+
None => match cx.get_source_address(&packet_meta.endpoint.addr) {
534+
Some(addr) => addr,
535+
None => {
536+
net_trace!(
537+
"udp:{}:{}: cannot find suitable source address, dropping.",
538+
endpoint,
539+
packet_meta.endpoint
540+
);
541+
return Ok(());
542+
}
543+
},
544+
}
533545
};
534546

535547
net_trace!(
@@ -635,6 +647,13 @@ mod test {
635647
addr: REMOTE_ADDR.into_address(),
636648
port: REMOTE_PORT,
637649
};
650+
fn remote_metadata_with_local() -> UdpMetadata {
651+
// Would be great as a const once we have const `.into()`.
652+
UdpMetadata {
653+
local_address: Some(LOCAL_ADDR.into()),
654+
..REMOTE_END.into()
655+
}
656+
}
638657

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

746+
#[test]
747+
fn test_send_with_source() {
748+
let mut socket = socket(buffer(0), buffer(1));
749+
750+
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
751+
assert_eq!(
752+
socket.send_slice(b"abcdef", remote_metadata_with_local()),
753+
Ok(())
754+
);
755+
}
756+
727757
#[rstest]
728758
#[case::ip(Medium::Ip)]
729759
#[cfg(feature = "medium-ip")]
@@ -811,7 +841,10 @@ mod test {
811841
PAYLOAD,
812842
);
813843

814-
assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END.into())));
844+
assert_eq!(
845+
socket.recv(),
846+
Ok((&b"abcdef"[..], remote_metadata_with_local()))
847+
);
815848
assert!(!socket.can_recv());
816849
}
817850

@@ -839,8 +872,14 @@ mod test {
839872
&REMOTE_UDP_REPR,
840873
PAYLOAD,
841874
);
842-
assert_eq!(socket.peek(), Ok((&b"abcdef"[..], &REMOTE_END.into(),)));
843-
assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END.into(),)));
875+
assert_eq!(
876+
socket.peek(),
877+
Ok((&b"abcdef"[..], &remote_metadata_with_local(),))
878+
);
879+
assert_eq!(
880+
socket.recv(),
881+
Ok((&b"abcdef"[..], remote_metadata_with_local(),))
882+
);
844883
assert_eq!(socket.peek(), Err(RecvError::Exhausted));
845884
}
846885

@@ -1013,7 +1052,7 @@ mod test {
10131052
dst_port: LOCAL_PORT,
10141053
};
10151054
socket.process(cx, PacketMeta::default(), &REMOTE_IP_REPR, &repr, &[]);
1016-
assert_eq!(socket.recv(), Ok((&[][..], REMOTE_END.into())));
1055+
assert_eq!(socket.recv(), Ok((&[][..], remote_metadata_with_local())));
10171056
}
10181057

10191058
#[test]

0 commit comments

Comments
 (0)