Skip to content

Commit

Permalink
rand: use simple PRNG owned by Interface, sockets access it through C…
Browse files Browse the repository at this point in the history
…ontext.
  • Loading branch information
Dirbaio committed Nov 26, 2021
1 parent b1274a5 commit f2476fc
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 103 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
include:
# Test alloc feature which requires nightly.
- rust: nightly
features: alloc rand-custom-impl medium-ethernet proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp
features: alloc medium-ethernet proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
Expand All @@ -73,8 +73,8 @@ jobs:

features:
# These feature sets cannot run tests, so we only check they build.
- rand-custom-impl medium-ip medium-ethernet medium-ieee802154 proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async
- rand-custom-impl defmt medium-ip medium-ethernet proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async
- medium-ip medium-ethernet medium-ieee802154 proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async
- defmt medium-ip medium-ethernet proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async

steps:
- uses: actions/checkout@v2
Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ url = "1.0"
std = ["managed/std", "rand_core/std"]
alloc = ["managed/alloc"]
verbose = []
rand-custom-impl = []
"medium-ethernet" = ["socket"]
"medium-ip" = ["socket"]
"medium-ieee802154" = ["socket", "proto-sixlowpan"]
Expand Down
4 changes: 2 additions & 2 deletions examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ fn main() {

let tcp_handle = iface.add_socket(tcp_socket);

let socket = iface.get_socket::<TcpSocket>(tcp_handle);
socket.connect((address, port), 49500).unwrap();
let (socket, cx) = iface.get_socket_and_context::<TcpSocket>(tcp_handle);
socket.connect(cx, (address, port), 49500).unwrap();

let mut tcp_active = false;
loop {
Expand Down
4 changes: 2 additions & 2 deletions examples/httpclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ fn main() {
}
}

let socket = iface.get_socket::<TcpSocket>(tcp_handle);
let (socket, cx) = iface.get_socket_and_context::<TcpSocket>(tcp_handle);

state = match state {
State::Connect if !socket.is_active() => {
debug!("connecting");
let local_port = 49152 + rand::random::<u16>() % 16384;
socket
.connect((address, url.port().unwrap_or(80)), local_port)
.connect(cx, (address, url.port().unwrap_or(80)), local_port)
.unwrap();
State::Request
}
Expand Down
11 changes: 2 additions & 9 deletions examples/loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ mod mock {
self.0.get()
}
}

struct Rand;
smoltcp::rand_custom_impl!(Rand);
impl smoltcp::Rand for Rand {
fn rand_bytes(buf: &mut [u8]) {
buf.fill(0x42);
}
}
}

#[cfg(feature = "std")]
Expand Down Expand Up @@ -153,12 +145,13 @@ fn main() {
done = true;
}

let mut socket = iface.get_socket::<TcpSocket>(client_handle);
let (mut socket, cx) = iface.get_socket_and_context::<TcpSocket>(client_handle);
if !socket.is_open() {
if !did_connect {
debug!("connecting");
socket
.connect(
cx,
(IpAddress::v4(127, 0, 0, 1), 1234),
(IpAddress::Unspecified, 65000),
)
Expand Down
36 changes: 36 additions & 0 deletions src/iface/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::iface::Routes;
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
use crate::iface::{NeighborAnswer, NeighborCache};
use crate::phy::{ChecksumCapabilities, Device, DeviceCapabilities, Medium, RxToken, TxToken};
use crate::rand::Rand;
use crate::socket::*;
use crate::time::{Duration, Instant};
use crate::wire::*;
Expand Down Expand Up @@ -54,6 +55,7 @@ pub struct InterfaceInner<'a> {
/// When to report for (all or) the next multicast group membership via IGMP
#[cfg(feature = "proto-igmp")]
igmp_report_state: IgmpReportState,
rand: Rand,
}

/// A builder structure used for creating a network interface.
Expand All @@ -75,6 +77,7 @@ pub struct InterfaceBuilder<'a, DeviceT: for<'d> Device<'d>> {
/// Does not share storage with `ipv6_multicast_groups` to avoid IPv6 size overhead.
#[cfg(feature = "proto-igmp")]
ipv4_multicast_groups: ManagedMap<'a, Ipv4Address, ()>,
random_seed: u64,
}

impl<'a, DeviceT> InterfaceBuilder<'a, DeviceT>
Expand Down Expand Up @@ -134,9 +137,21 @@ let iface = InterfaceBuilder::new(device, vec![])
routes: Routes::new(ManagedMap::Borrowed(&mut [])),
#[cfg(feature = "proto-igmp")]
ipv4_multicast_groups: ManagedMap::Borrowed(&mut []),
random_seed: 0,
}
}

/// Set the random seed for this interface.
///
/// It is strongly recommended that the random seed is different on each boot,
/// to avoid problems with TCP port/sequence collisions.
///
/// The seed doesn't have to be cryptographically secure.
pub fn random_seed(mut self, random_seed: u64) -> Self {
self.random_seed = random_seed;
self
}

/// Set the Hardware address the interface will use. See also
/// [hardware_addr].
///
Expand Down Expand Up @@ -319,6 +334,7 @@ let iface = InterfaceBuilder::new(device, vec![])
sequence_no: self.sequence_no,
#[cfg(feature = "medium-ieee802154")]
pan_id: self.pan_id,
rand: Rand::new(self.random_seed),
},
}
}
Expand Down Expand Up @@ -495,6 +511,20 @@ where
self.sockets.get(handle)
}

/// Get a socket by handle, and the socket context.
///
/// The context is needed for some socket methods.
///
/// # Panics
/// This function may panic if the handle does not belong to this socket set
/// or the socket has the wrong type.
pub fn get_socket_and_context<T: AnySocket<'a>>(
&mut self,
handle: SocketHandle,
) -> (&mut T, &mut InterfaceInner<'a>) {
(self.sockets.get(handle), &mut self.inner)
}

/// Remove a socket from the set, without changing its state.
///
/// # Panics
Expand Down Expand Up @@ -1017,6 +1047,11 @@ impl<'a> InterfaceInner<'a> {
self.caps.ip_mtu()
}

#[allow(unused)] // unused in tests
pub(crate) fn rand_u32(&mut self) -> u32 {
self.rand.rand_u32()
}

#[cfg(test)]
pub(crate) fn mock() -> Self {
Self {
Expand All @@ -1043,6 +1078,7 @@ impl<'a> InterfaceInner<'a> {
now: Instant::from_millis_const(0),

ip_addrs: ManagedSlice::Owned(vec![]),
rand: Rand::new(1234),
routes: Routes::new(&mut [][..]),

#[cfg(feature = "proto-ipv4")]
Expand Down
3 changes: 0 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,7 @@ use core::fmt;
#[macro_use]
mod macros;
mod parsers;

mod rand;
#[cfg(feature = "rand-custom-impl")]
pub use crate::rand::Rand;

#[cfg(any(
feature = "medium-ethernet",
Expand Down
73 changes: 16 additions & 57 deletions src/rand.rs
Original file line number Diff line number Diff line change
@@ -1,67 +1,26 @@
#![allow(unsafe_code)]
#![allow(unused)]

#[cfg(not(any(test, feature = "std", feature = "rand-custom-impl")))]
compile_error!("None of the Cargo features `std` or `rand-custom-impl` is enabled. smoltcp needs a `rand` implementation to work. If your target supports `std`, enable the `std` feature to use the OS's RNG. Otherwise, you must enable the `rand-custom-impl` Cargo feature, and supply your own custom implementation using the `smoltcp::rand_custom_impl!()` macro");

pub fn rand_u32() -> u32 {
let mut val = [0; 4];
rand_bytes(&mut val);
u32::from_ne_bytes(val)
#[derive(Debug)]
pub(crate) struct Rand {
state: u64,
}

/// Fill `buf` with random bytes.
pub fn rand_bytes(buf: &mut [u8]) {
extern "Rust" {
fn _smoltcp_rand(buf: &mut [u8]);
impl Rand {
pub(crate) const fn new(seed: u64) -> Self {
Self { state: seed }
}

unsafe { _smoltcp_rand(buf) }
}
pub(crate) fn rand_u32(&mut self) -> u32 {
// sPCG32 from https://www.pcg-random.org/paper.html
// see also https://nullprogram.com/blog/2017/09/21/
const M: u64 = 0xbb2efcec3c39611d;
const A: u64 = 0x7590ef39;

/// Methods required for a custom rand implementation.
///
/// This trait is not intended to be used directly, just to supply a custom rand implementation to smoltcp.
#[cfg(feature = "rand-custom-impl")]
pub trait Rand {
/// Fill `buf` with random bytes.
fn rand_bytes(buf: &mut [u8]);
}

/// Set the custom rand implementation.
///
/// # Example
///
/// ```
/// struct Rand;
/// smoltcp::rand_custom_impl!(Rand);
/// impl smoltcp::Rand for Rand {
/// fn rand_bytes(buf: &mut [u8]) {
/// // TODO
/// }
/// }
///
#[macro_export]
#[cfg(feature = "rand-custom-impl")]
macro_rules! rand_custom_impl {
($t: ty) => {
#[no_mangle]
fn _smoltcp_rand(buf: &mut [u8]) {
<$t as $crate::Rand>::rand_bytes(buf)
}
};
}
let s = self.state * M + A;
self.state = s;

#[cfg(all(feature = "std", not(feature = "rand-custom-impl"), not(test)))]
#[no_mangle]
fn _smoltcp_rand(buf: &mut [u8]) {
use rand_core::RngCore;

rand_core::OsRng.fill_bytes(buf)
}

#[cfg(test)]
#[no_mangle]
fn _smoltcp_rand(buf: &mut [u8]) {
panic!("Rand should not be used when testing");
let shift = 29 - (s >> 61);
(s >> shift) as u32
}
}
8 changes: 4 additions & 4 deletions src/socket/dhcpv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,12 @@ impl Dhcpv4Socket {
}

#[cfg(not(test))]
fn random_transaction_id() -> u32 {
crate::rand::rand_u32()
fn random_transaction_id(cx: &mut Context) -> u32 {
cx.rand_u32()
}

#[cfg(test)]
fn random_transaction_id() -> u32 {
fn random_transaction_id(_cx: &mut Context) -> u32 {
0x12345678
}

Expand All @@ -397,7 +397,7 @@ impl Dhcpv4Socket {

// We don't directly modify self.transaction_id because sending the packet
// may fail. We only want to update state after succesfully sending.
let next_transaction_id = Self::random_transaction_id();
let next_transaction_id = Self::random_transaction_id(cx);

let mut dhcp_repr = DhcpRepr {
message_type: DhcpMessageType::Discover,
Expand Down
Loading

0 comments on commit f2476fc

Please sign in to comment.