2024-01-03 03:22:36 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2024-09-06 10:49:37 +00:00
|
|
|
use alloc::{
|
|
|
|
|
boxed::Box,
|
|
|
|
|
collections::{
|
|
|
|
|
btree_map::{BTreeMap, Entry},
|
|
|
|
|
btree_set::BTreeSet,
|
|
|
|
|
},
|
2024-12-03 01:47:47 +00:00
|
|
|
string::String,
|
2024-09-06 10:49:37 +00:00
|
|
|
sync::Arc,
|
|
|
|
|
};
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-07-23 15:03:10 +00:00
|
|
|
use keyable_arc::KeyableArc;
|
2024-09-20 03:33:20 +00:00
|
|
|
use ostd::sync::{LocalIrqDisabled, PreemptDisabled, SpinLock, SpinLockGuard};
|
2023-05-31 02:47:52 +00:00
|
|
|
use smoltcp::{
|
2024-09-20 03:33:20 +00:00
|
|
|
iface::{packet::Packet, Context},
|
2023-05-31 02:47:52 +00:00
|
|
|
phy::Device,
|
2024-09-20 03:33:20 +00:00
|
|
|
wire::{Ipv4Address, Ipv4Packet},
|
2023-05-31 02:47:52 +00:00
|
|
|
};
|
|
|
|
|
|
2024-09-20 03:33:20 +00:00
|
|
|
use super::{
|
|
|
|
|
poll::{FnHelper, PollContext},
|
|
|
|
|
port::BindPortConfig,
|
|
|
|
|
time::get_network_timestamp,
|
|
|
|
|
Iface,
|
|
|
|
|
};
|
2024-09-06 10:49:37 +00:00
|
|
|
use crate::{
|
|
|
|
|
errors::BindError,
|
2024-12-03 01:47:47 +00:00
|
|
|
ext::Ext,
|
2024-09-20 03:33:20 +00:00
|
|
|
socket::{
|
|
|
|
|
BoundTcpSocket, BoundTcpSocketInner, BoundUdpSocket, BoundUdpSocketInner, UnboundTcpSocket,
|
|
|
|
|
UnboundUdpSocket,
|
|
|
|
|
},
|
2023-05-31 02:47:52 +00:00
|
|
|
};
|
|
|
|
|
|
2024-12-03 01:47:47 +00:00
|
|
|
pub struct IfaceCommon<E: Ext> {
|
|
|
|
|
name: String,
|
2024-09-12 01:52:40 +00:00
|
|
|
interface: SpinLock<smoltcp::iface::Interface, LocalIrqDisabled>,
|
2024-09-19 11:13:56 +00:00
|
|
|
used_ports: SpinLock<BTreeMap<u16, usize>, PreemptDisabled>,
|
2024-09-20 03:33:20 +00:00
|
|
|
tcp_sockets: SpinLock<BTreeSet<KeyableArc<BoundTcpSocketInner<E>>>, LocalIrqDisabled>,
|
|
|
|
|
udp_sockets: SpinLock<BTreeSet<KeyableArc<BoundUdpSocketInner<E>>>, LocalIrqDisabled>,
|
2024-12-03 01:47:47 +00:00
|
|
|
sched_poll: E::ScheduleNextPoll,
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-03 01:47:47 +00:00
|
|
|
impl<E: Ext> IfaceCommon<E> {
|
|
|
|
|
pub(super) fn new(
|
|
|
|
|
name: String,
|
|
|
|
|
interface: smoltcp::iface::Interface,
|
|
|
|
|
sched_poll: E::ScheduleNextPoll,
|
|
|
|
|
) -> Self {
|
2023-05-31 02:47:52 +00:00
|
|
|
Self {
|
2024-12-03 01:47:47 +00:00
|
|
|
name,
|
2023-05-30 08:34:28 +00:00
|
|
|
interface: SpinLock::new(interface),
|
2024-09-20 03:33:20 +00:00
|
|
|
used_ports: SpinLock::new(BTreeMap::new()),
|
|
|
|
|
tcp_sockets: SpinLock::new(BTreeSet::new()),
|
|
|
|
|
udp_sockets: SpinLock::new(BTreeSet::new()),
|
2024-12-03 01:47:47 +00:00
|
|
|
sched_poll,
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 01:47:47 +00:00
|
|
|
pub(super) fn name(&self) -> &str {
|
|
|
|
|
&self.name
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-24 05:27:17 +00:00
|
|
|
pub(super) fn ipv4_addr(&self) -> Option<Ipv4Address> {
|
|
|
|
|
self.interface.lock().ipv4_addr()
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 01:47:47 +00:00
|
|
|
pub(super) fn sched_poll(&self) -> &E::ScheduleNextPoll {
|
|
|
|
|
&self.sched_poll
|
2024-09-24 05:27:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 01:47:47 +00:00
|
|
|
impl<E: Ext> IfaceCommon<E> {
|
2024-07-29 02:40:00 +00:00
|
|
|
/// Acquires the lock to the interface.
|
2024-09-06 10:49:37 +00:00
|
|
|
pub(crate) fn interface(&self) -> SpinLockGuard<smoltcp::iface::Interface, LocalIrqDisabled> {
|
2024-09-12 01:52:40 +00:00
|
|
|
self.interface.lock()
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
2024-09-24 05:27:17 +00:00
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-09-24 05:27:17 +00:00
|
|
|
const IP_LOCAL_PORT_START: u16 = 32768;
|
|
|
|
|
const IP_LOCAL_PORT_END: u16 = 60999;
|
|
|
|
|
|
2024-12-03 01:47:47 +00:00
|
|
|
impl<E: Ext> IfaceCommon<E> {
|
2024-09-20 03:33:20 +00:00
|
|
|
pub(super) fn bind_tcp(
|
2024-09-24 05:27:17 +00:00
|
|
|
&self,
|
|
|
|
|
iface: Arc<dyn Iface<E>>,
|
2024-09-20 03:33:20 +00:00
|
|
|
socket: Box<UnboundTcpSocket>,
|
2024-12-02 15:53:19 +00:00
|
|
|
observer: E::TcpEventObserver,
|
2024-09-24 05:27:17 +00:00
|
|
|
config: BindPortConfig,
|
2024-09-20 03:33:20 +00:00
|
|
|
) -> core::result::Result<BoundTcpSocket<E>, (BindError, Box<UnboundTcpSocket>)> {
|
|
|
|
|
let port = match self.bind_port(config) {
|
|
|
|
|
Ok(port) => port,
|
|
|
|
|
Err(err) => return Err((err, socket)),
|
2024-09-24 05:27:17 +00:00
|
|
|
};
|
|
|
|
|
|
2024-12-02 15:53:19 +00:00
|
|
|
let raw_socket = socket.into_raw();
|
2024-09-20 03:33:20 +00:00
|
|
|
let bound_socket = BoundTcpSocket::new(iface, port, raw_socket, observer);
|
|
|
|
|
|
|
|
|
|
let inserted = self
|
|
|
|
|
.tcp_sockets
|
|
|
|
|
.lock()
|
|
|
|
|
.insert(KeyableArc::from(bound_socket.inner().clone()));
|
|
|
|
|
assert!(inserted);
|
|
|
|
|
|
|
|
|
|
Ok(bound_socket)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn bind_udp(
|
|
|
|
|
&self,
|
|
|
|
|
iface: Arc<dyn Iface<E>>,
|
|
|
|
|
socket: Box<UnboundUdpSocket>,
|
2024-12-02 15:53:19 +00:00
|
|
|
observer: E::UdpEventObserver,
|
2024-09-20 03:33:20 +00:00
|
|
|
config: BindPortConfig,
|
|
|
|
|
) -> core::result::Result<BoundUdpSocket<E>, (BindError, Box<UnboundUdpSocket>)> {
|
|
|
|
|
let port = match self.bind_port(config) {
|
|
|
|
|
Ok(port) => port,
|
|
|
|
|
Err(err) => return Err((err, socket)),
|
2024-09-24 05:27:17 +00:00
|
|
|
};
|
2024-09-20 03:33:20 +00:00
|
|
|
|
2024-12-02 15:53:19 +00:00
|
|
|
let raw_socket = socket.into_raw();
|
2024-09-20 03:33:20 +00:00
|
|
|
let bound_socket = BoundUdpSocket::new(iface, port, raw_socket, observer);
|
|
|
|
|
|
|
|
|
|
let inserted = self
|
|
|
|
|
.udp_sockets
|
|
|
|
|
.lock()
|
|
|
|
|
.insert(KeyableArc::from(bound_socket.inner().clone()));
|
|
|
|
|
assert!(inserted);
|
2024-09-24 05:27:17 +00:00
|
|
|
|
|
|
|
|
Ok(bound_socket)
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-24 05:30:47 +00:00
|
|
|
/// Allocates an unused ephemeral port.
|
|
|
|
|
///
|
|
|
|
|
/// We follow the port range that many Linux kernels use by default, which is 32768-60999.
|
|
|
|
|
///
|
|
|
|
|
/// See <https://en.wikipedia.org/wiki/Ephemeral_port>.
|
2024-09-06 10:49:37 +00:00
|
|
|
fn alloc_ephemeral_port(&self) -> Option<u16> {
|
2024-09-19 11:13:56 +00:00
|
|
|
let mut used_ports = self.used_ports.lock();
|
2023-05-31 02:47:52 +00:00
|
|
|
for port in IP_LOCAL_PORT_START..=IP_LOCAL_PORT_END {
|
2023-09-04 03:04:42 +00:00
|
|
|
if let Entry::Vacant(e) = used_ports.entry(port) {
|
|
|
|
|
e.insert(0);
|
2024-09-06 10:49:37 +00:00
|
|
|
return Some(port);
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-09-06 10:49:37 +00:00
|
|
|
None
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-20 03:33:20 +00:00
|
|
|
fn bind_port(&self, config: BindPortConfig) -> Result<u16, BindError> {
|
|
|
|
|
let port = if let Some(port) = config.port() {
|
|
|
|
|
port
|
|
|
|
|
} else {
|
|
|
|
|
match self.alloc_ephemeral_port() {
|
|
|
|
|
Some(port) => port,
|
|
|
|
|
None => return Err(BindError::Exhausted),
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-09-19 11:13:56 +00:00
|
|
|
let mut used_ports = self.used_ports.lock();
|
2024-09-20 03:33:20 +00:00
|
|
|
|
2023-05-31 02:47:52 +00:00
|
|
|
if let Some(used_times) = used_ports.get_mut(&port) {
|
2024-09-20 03:33:20 +00:00
|
|
|
if *used_times == 0 || config.can_reuse() {
|
2024-08-24 04:01:08 +00:00
|
|
|
// FIXME: Check if the previous socket was bound with SO_REUSEADDR.
|
2023-09-04 03:04:42 +00:00
|
|
|
*used_times += 1;
|
2023-05-31 02:47:52 +00:00
|
|
|
} else {
|
2024-09-20 03:33:20 +00:00
|
|
|
return Err(BindError::InUse);
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
used_ports.insert(port, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-20 03:33:20 +00:00
|
|
|
Ok(port)
|
2024-09-24 05:27:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-03 01:47:47 +00:00
|
|
|
impl<E: Ext> IfaceCommon<E> {
|
2024-09-20 03:33:20 +00:00
|
|
|
#[allow(clippy::mutable_key_type)]
|
|
|
|
|
fn remove_dead_tcp_sockets(&self, sockets: &mut BTreeSet<KeyableArc<BoundTcpSocketInner<E>>>) {
|
|
|
|
|
sockets.retain(|socket| {
|
|
|
|
|
if socket.is_dead() {
|
|
|
|
|
self.release_port(socket.port());
|
|
|
|
|
false
|
|
|
|
|
} else {
|
|
|
|
|
true
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
2024-09-20 03:33:20 +00:00
|
|
|
});
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-20 03:33:20 +00:00
|
|
|
pub(crate) fn remove_udp_socket(&self, socket: &Arc<BoundUdpSocketInner<E>>) {
|
2024-09-24 05:27:17 +00:00
|
|
|
let keyable_socket = KeyableArc::from(socket.clone());
|
|
|
|
|
|
2024-09-20 03:33:20 +00:00
|
|
|
let removed = self.udp_sockets.lock().remove(&keyable_socket);
|
2024-09-24 05:27:17 +00:00
|
|
|
assert!(removed);
|
|
|
|
|
|
2024-09-20 03:33:20 +00:00
|
|
|
self.release_port(keyable_socket.port());
|
|
|
|
|
}
|
2024-09-24 05:27:17 +00:00
|
|
|
|
2024-09-20 03:33:20 +00:00
|
|
|
/// Releases the port so that it can be used again (if it is not being reused).
|
|
|
|
|
fn release_port(&self, port: u16) {
|
|
|
|
|
let mut used_ports = self.used_ports.lock();
|
|
|
|
|
if let Some(used_times) = used_ports.remove(&port) {
|
|
|
|
|
if used_times != 1 {
|
|
|
|
|
used_ports.insert(port, used_times - 1);
|
|
|
|
|
}
|
2024-09-24 05:27:17 +00:00
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
2024-09-24 05:27:17 +00:00
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
|
2024-12-03 01:47:47 +00:00
|
|
|
impl<E: Ext> IfaceCommon<E> {
|
2024-09-20 03:33:20 +00:00
|
|
|
pub(super) fn poll<D, P, Q>(
|
|
|
|
|
&self,
|
|
|
|
|
device: &mut D,
|
|
|
|
|
process_phy: P,
|
|
|
|
|
mut dispatch_phy: Q,
|
|
|
|
|
) -> Option<u64>
|
|
|
|
|
where
|
|
|
|
|
D: Device + ?Sized,
|
|
|
|
|
P: for<'pkt, 'cx, 'tx> FnHelper<
|
|
|
|
|
&'pkt [u8],
|
|
|
|
|
&'cx mut Context,
|
|
|
|
|
D::TxToken<'tx>,
|
|
|
|
|
Option<(Ipv4Packet<&'pkt [u8]>, D::TxToken<'tx>)>,
|
|
|
|
|
>,
|
|
|
|
|
Q: FnMut(&Packet, &mut Context, D::TxToken<'_>),
|
|
|
|
|
{
|
|
|
|
|
let mut interface = self.interface();
|
|
|
|
|
interface.context().now = get_network_timestamp();
|
|
|
|
|
|
|
|
|
|
let mut tcp_sockets = self.tcp_sockets.lock();
|
|
|
|
|
let udp_sockets = self.udp_sockets.lock();
|
|
|
|
|
|
|
|
|
|
let mut context = PollContext::new(interface.context(), &tcp_sockets, &udp_sockets);
|
|
|
|
|
context.poll_ingress(device, process_phy, &mut dispatch_phy);
|
|
|
|
|
context.poll_egress(device, dispatch_phy);
|
|
|
|
|
|
|
|
|
|
tcp_sockets.iter().for_each(|socket| {
|
2024-11-13 15:39:55 +00:00
|
|
|
if socket.has_events() {
|
|
|
|
|
socket.on_events();
|
2024-06-18 07:41:52 +00:00
|
|
|
}
|
2024-09-20 03:33:20 +00:00
|
|
|
});
|
|
|
|
|
udp_sockets.iter().for_each(|socket| {
|
2024-11-13 15:39:55 +00:00
|
|
|
if socket.has_events() {
|
|
|
|
|
socket.on_events();
|
2024-09-20 03:33:20 +00:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
self.remove_dead_tcp_sockets(&mut tcp_sockets);
|
|
|
|
|
|
|
|
|
|
match (
|
|
|
|
|
tcp_sockets
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|socket| socket.next_poll_at_ms())
|
|
|
|
|
.min(),
|
|
|
|
|
udp_sockets
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|socket| socket.next_poll_at_ms())
|
|
|
|
|
.min(),
|
|
|
|
|
) {
|
|
|
|
|
(Some(tcp_poll_at), Some(udp_poll_at)) if tcp_poll_at <= udp_poll_at => {
|
|
|
|
|
Some(tcp_poll_at)
|
|
|
|
|
}
|
|
|
|
|
(tcp_poll_at, None) => tcp_poll_at,
|
|
|
|
|
(_, udp_poll_at) => udp_poll_at,
|
2024-06-18 07:41:52 +00:00
|
|
|
}
|
2023-05-31 02:47:52 +00:00
|
|
|
}
|
|
|
|
|
}
|