1mod integration;
59
60use derivative::Derivative;
61use net_types::ip::{Ip, Ipv4, Ipv6};
62use netstack3_base::socket::SocketInfo;
63use netstack3_base::{
64 ChecksumOffloadResult, CoreTxMetadataContext, HandleableTimer, TimerHandler, TxMetadata,
65};
66use netstack3_datagram as datagram;
67use netstack3_device::WeakDeviceId;
68use netstack3_icmp_echo::{IcmpSocketTxMetadata, IcmpSockets};
69use netstack3_tcp::{
70 self as tcp, TcpCountersWithSocket, TcpCountersWithoutSocket, TcpSocketTxMetadata, TcpState,
71 TcpTimerId,
72};
73use netstack3_udp::{
74 UdpCountersWithSocket, UdpCountersWithoutSocket, UdpSocketTxMetadata, UdpState,
75};
76
77use crate::{BindingsContext, BindingsTypes, CoreCtx, IpExt};
78
79#[derive(Default, Clone)]
81pub struct TransportStateBuilder;
82
83impl TransportStateBuilder {
84 pub(crate) fn build_with_ctx<BC: BindingsContext>(
85 self,
86 bindings_ctx: &mut BC,
87 ) -> TransportLayerState<BC> {
88 let now = bindings_ctx.now();
89 let mut rng = bindings_ctx.rng();
90 TransportLayerState {
91 udpv4: Default::default(),
92 udpv6: Default::default(),
93 tcpv4: TcpState::new(now, &mut rng),
94 tcpv6: TcpState::new(now, &mut rng),
95 icmp_echo_v4: Default::default(),
96 icmp_echo_v6: Default::default(),
97 }
98 }
99}
100
101pub struct TransportLayerState<BT: BindingsTypes> {
103 udpv4: UdpState<Ipv4, WeakDeviceId<BT>, BT>,
104 udpv6: UdpState<Ipv6, WeakDeviceId<BT>, BT>,
105 tcpv4: TcpState<Ipv4, WeakDeviceId<BT>, BT>,
106 tcpv6: TcpState<Ipv6, WeakDeviceId<BT>, BT>,
107 icmp_echo_v4: IcmpSockets<Ipv4, WeakDeviceId<BT>, BT>,
108 icmp_echo_v6: IcmpSockets<Ipv6, WeakDeviceId<BT>, BT>,
109}
110
111impl<BT: BindingsTypes> TransportLayerState<BT> {
112 fn tcp_state<I: tcp::DualStackIpExt>(&self) -> &TcpState<I, WeakDeviceId<BT>, BT> {
113 I::map_ip((), |()| &self.tcpv4, |()| &self.tcpv6)
114 }
115
116 fn udp_state<I: datagram::IpExt>(&self) -> &UdpState<I, WeakDeviceId<BT>, BT> {
117 I::map_ip((), |()| &self.udpv4, |()| &self.udpv6)
118 }
119
120 pub(crate) fn icmp_echo_state<I: datagram::IpExt>(
121 &self,
122 ) -> &IcmpSockets<I, WeakDeviceId<BT>, BT> {
123 I::map_ip((), |()| &self.icmp_echo_v4, |()| &self.icmp_echo_v6)
124 }
125
126 pub(crate) fn udp_counters_with_socket<I: Ip>(&self) -> &UdpCountersWithSocket<I> {
127 I::map_ip((), |()| &self.udpv4.counters_with_socket, |()| &self.udpv6.counters_with_socket)
128 }
129
130 pub(crate) fn udp_counters_without_socket<I: Ip>(&self) -> &UdpCountersWithoutSocket<I> {
131 I::map_ip(
132 (),
133 |()| &self.udpv4.counters_without_socket,
134 |()| &self.udpv6.counters_without_socket,
135 )
136 }
137
138 pub(crate) fn tcp_counters_with_socket<I: Ip>(&self) -> &TcpCountersWithSocket<I> {
139 I::map_ip((), |()| &self.tcpv4.counters_with_socket, |()| &self.tcpv6.counters_with_socket)
140 }
141
142 pub(crate) fn tcp_counters_without_socket<I: Ip>(&self) -> &TcpCountersWithoutSocket<I> {
143 I::map_ip(
144 (),
145 |()| &self.tcpv4.counters_without_socket,
146 |()| &self.tcpv6.counters_without_socket,
147 )
148 }
149}
150
151#[derive(Derivative)]
153#[derivative(
154 Clone(bound = ""),
155 Eq(bound = ""),
156 PartialEq(bound = ""),
157 Hash(bound = ""),
158 Debug(bound = "")
159)]
160pub(crate) enum TransportLayerTimerId<BT: BindingsTypes> {
161 Tcp(TcpTimerId<WeakDeviceId<BT>, BT>),
162}
163
164impl<CC, BT> HandleableTimer<CC, BT> for TransportLayerTimerId<BT>
165where
166 BT: BindingsTypes,
167 CC: TimerHandler<BT, TcpTimerId<WeakDeviceId<BT>, BT>>,
168{
169 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BT, timer: BT::UniqueTimerId) {
170 match self {
171 TransportLayerTimerId::Tcp(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
172 }
173 }
174}
175
176impl<BT: BindingsTypes> From<TcpTimerId<WeakDeviceId<BT>, BT>> for TransportLayerTimerId<BT> {
177 fn from(id: TcpTimerId<WeakDeviceId<BT>, BT>) -> Self {
178 TransportLayerTimerId::Tcp(id)
179 }
180}
181
182#[derive(Derivative)]
184#[derivative(Debug = "transparent", Debug(bound = ""), Default(bound = ""))]
185#[cfg_attr(any(test, feature = "testutils"), derivative(PartialEq(bound = "")))]
186pub struct CoreTxMetadata<BT: BindingsTypes>(TxMetadataInner<BT>);
187
188#[derive(Derivative)]
192#[derivative(Debug(bound = ""), Default(bound = ""))]
193#[cfg_attr(any(test, feature = "testutils"), derivative(PartialEq(bound = "")))]
194enum TxMetadataInner<BT: BindingsTypes> {
195 #[derivative(Default)]
196 None,
197 #[derivative(Debug = "transparent")]
198 Udpv4(UdpSocketTxMetadata<Ipv4, WeakDeviceId<BT>, BT>),
199 #[derivative(Debug = "transparent")]
200 Udpv6(UdpSocketTxMetadata<Ipv6, WeakDeviceId<BT>, BT>),
201 #[derivative(Debug = "transparent")]
202 Icmpv4(IcmpSocketTxMetadata<Ipv4, WeakDeviceId<BT>, BT>),
203 #[derivative(Debug = "transparent")]
204 Icmpv6(IcmpSocketTxMetadata<Ipv6, WeakDeviceId<BT>, BT>),
205 #[derivative(Debug = "transparent")]
206 Tcpv4(TcpSocketTxMetadata<Ipv4, WeakDeviceId<BT>, BT>),
207 #[derivative(Debug = "transparent")]
208 Tcpv6(TcpSocketTxMetadata<Ipv6, WeakDeviceId<BT>, BT>),
209}
210
211impl<I: IpExt, L, BT: BindingsTypes>
212 CoreTxMetadataContext<UdpSocketTxMetadata<I, WeakDeviceId<BT>, BT>, BT> for CoreCtx<'_, BT, L>
213{
214 fn convert_tx_meta(
215 &self,
216 tx_meta: UdpSocketTxMetadata<I, WeakDeviceId<BT>, BT>,
217 ) -> CoreTxMetadata<BT> {
218 CoreTxMetadata(I::map_ip_in(tx_meta, TxMetadataInner::Udpv4, TxMetadataInner::Udpv6))
219 }
220}
221
222impl<I: IpExt, L, BT: BindingsTypes>
223 CoreTxMetadataContext<IcmpSocketTxMetadata<I, WeakDeviceId<BT>, BT>, BT>
224 for CoreCtx<'_, BT, L>
225{
226 fn convert_tx_meta(
227 &self,
228 tx_meta: IcmpSocketTxMetadata<I, WeakDeviceId<BT>, BT>,
229 ) -> CoreTxMetadata<BT> {
230 CoreTxMetadata(I::map_ip_in(tx_meta, TxMetadataInner::Icmpv4, TxMetadataInner::Icmpv6))
231 }
232}
233
234impl<I: IpExt, L, BT: BindingsTypes>
235 CoreTxMetadataContext<TcpSocketTxMetadata<I, WeakDeviceId<BT>, BT>, BT> for CoreCtx<'_, BT, L>
236{
237 fn convert_tx_meta(
238 &self,
239 tx_meta: TcpSocketTxMetadata<I, WeakDeviceId<BT>, BT>,
240 ) -> CoreTxMetadata<BT> {
241 CoreTxMetadata(I::map_ip_in(tx_meta, TxMetadataInner::Tcpv4, TxMetadataInner::Tcpv6))
242 }
243}
244
245impl<BT: BindingsTypes> TxMetadata for CoreTxMetadata<BT> {
246 fn socket_info(&self) -> Option<SocketInfo> {
247 let CoreTxMetadata(inner) = self;
248 match inner {
249 TxMetadataInner::None => None,
251 TxMetadataInner::Tcpv4(tx_metadata) => {
252 tx_metadata.socket().upgrade().map(|s| s.socket_info())
253 }
254 TxMetadataInner::Tcpv6(tx_metadata) => {
255 tx_metadata.socket().upgrade().map(|s| s.socket_info())
256 }
257 TxMetadataInner::Udpv4(tx_metadata) => {
258 tx_metadata.socket().upgrade().map(|s| s.socket_info())
259 }
260 TxMetadataInner::Udpv6(tx_metadata) => {
261 tx_metadata.socket().upgrade().map(|s| s.socket_info())
262 }
263 TxMetadataInner::Icmpv4(tx_metadata) => {
264 tx_metadata.socket().upgrade().map(|s| s.socket_info())
265 }
266 TxMetadataInner::Icmpv6(tx_metadata) => {
267 tx_metadata.socket().upgrade().map(|s| s.socket_info())
268 }
269 }
270 }
271
272 fn checksum_offload_result(&self) -> Option<ChecksumOffloadResult> {
273 let CoreTxMetadata(inner) = self;
274 match inner {
275 TxMetadataInner::None => None,
276 TxMetadataInner::Tcpv4(tx_metadata) => tx_metadata.checksum_offload_result(),
277 TxMetadataInner::Tcpv6(tx_metadata) => tx_metadata.checksum_offload_result(),
278 TxMetadataInner::Udpv4(tx_metadata) => tx_metadata.checksum_offload_result(),
279 TxMetadataInner::Udpv6(tx_metadata) => tx_metadata.checksum_offload_result(),
280 TxMetadataInner::Icmpv4(tx_metadata) => tx_metadata.checksum_offload_result(),
281 TxMetadataInner::Icmpv6(tx_metadata) => tx_metadata.checksum_offload_result(),
282 }
283 }
284
285 fn set_checksum_offload_result(&mut self, result: Option<ChecksumOffloadResult>) {
286 let CoreTxMetadata(inner) = self;
287 match inner {
288 TxMetadataInner::None => {}
289 TxMetadataInner::Tcpv4(tx_metadata) => tx_metadata.set_checksum_offload_result(result),
290 TxMetadataInner::Tcpv6(tx_metadata) => tx_metadata.set_checksum_offload_result(result),
291 TxMetadataInner::Udpv4(tx_metadata) => tx_metadata.set_checksum_offload_result(result),
292 TxMetadataInner::Udpv6(tx_metadata) => tx_metadata.set_checksum_offload_result(result),
293 TxMetadataInner::Icmpv4(tx_metadata) => tx_metadata.set_checksum_offload_result(result),
294 TxMetadataInner::Icmpv6(tx_metadata) => tx_metadata.set_checksum_offload_result(result),
295 }
296 }
297}