1use core::fmt::Debug;
9use core::num::NonZeroU16;
10
11use assert_matches::assert_matches;
12use log::{debug, error, warn};
13use net_types::ip::Ip;
14use net_types::{MulticastAddress as _, SpecifiedAddr, Witness as _};
15use netstack3_base::socket::{
16 AddrIsMappedError, AddrVec, AddrVecIter, ConnAddr, ConnIpAddr, InsertError, IpAddrVec,
17 ListenerAddr, ListenerIpAddr, SocketIpAddr, SocketIpAddrExt as _,
18};
19use netstack3_base::{
20 BidirectionalConverter as _, Control, CounterContext, CtxPair, EitherDeviceId, IpDeviceAddr,
21 Marks, Mss, NotFoundError, Payload, Segment, SegmentHeader, SeqNum, StrongDeviceIdentifier,
22 VerifiedTcpSegment, WeakDeviceIdentifier,
23};
24use netstack3_filter::{
25 FilterIpExt, SocketIngressFilterResult, SocketOpsFilter, TransportPacketSerializer,
26};
27use netstack3_hashmap::hash_map;
28use netstack3_ip::socket::{IpSockCreationError, IpSocketArgs, MmsError};
29use netstack3_ip::{
30 IpHeaderInfo, IpTransportContext, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
31 TransportIpContext,
32};
33use netstack3_trace::trace_duration;
34use packet::{
35 BufferMut, BufferView as _, EmptyBuf, FragmentedByteSlice, InnerPacketBuilder,
36 NestablePacketBuilder as _, ParseBuffer,
37};
38use packet_formats::error::ParseError;
39use packet_formats::ip::IpProto;
40use packet_formats::tcp::{
41 TcpFlowAndSeqNum, TcpOptionsTooLongError, TcpParseArgs, TcpSegment, TcpSegmentBuilder,
42 TcpSegmentBuilderWithOptions, TcpSegmentRaw,
43};
44
45use crate::internal::base::{BufferSizes, ConnectionError, SocketOptions, TcpIpSockOptions};
46use crate::internal::counters::{
47 self, TcpCounterContext, TcpCountersRefs, TcpCountersWithoutSocket,
48};
49use crate::internal::socket::generators::{IsnGenerator, TimestampOffsetGenerator};
50use crate::internal::socket::{
51 self, AsThisStack as _, Connection, CoreTxMetadataContext, DemuxState, DeviceIpSocketHandler,
52 DoSendLimit, DualStackBaseIpExt, DualStackDemuxIdConverter as _, DualStackIpExt, EitherStack,
53 HandshakeStatus, Listener, ListenerAddrState, MaybeDualStack, PrimaryRc, TcpApi,
54 TcpBindingsContext, TcpBindingsTypes, TcpContext, TcpDemuxContext, TcpDualStackContext,
55 TcpIpTransportContext, TcpPortSpec, TcpSocketId, TcpSocketSetEntry, TcpSocketState,
56 TcpSocketStateInner, TcpSocketTxMetadata,
57};
58use crate::internal::state::{
59 BufferProvider, Closed, DataAcked, Initial, NewlyClosed, State, TimeWait,
60};
61
62impl<BT: TcpBindingsTypes> BufferProvider<BT::ReceiveBuffer, BT::SendBuffer> for BT {
63 type ActiveOpen = BT::ListenerNotifierOrProvidedBuffers;
64
65 type PassiveOpen = BT::ReturnedBuffers;
66
67 fn new_passive_open_buffers(
68 buffer_sizes: BufferSizes,
69 ) -> (BT::ReceiveBuffer, BT::SendBuffer, Self::PassiveOpen) {
70 BT::new_passive_open_buffers(buffer_sizes)
71 }
72}
73
74pub type DualStackTcpSocketId<I, D, BT> = <I as DualStackBaseIpExt>::DemuxSocketId<D, BT>;
76
77impl<I, BC, CC> IpTransportContext<I, BC, CC> for TcpIpTransportContext
78where
79 I: DualStackIpExt,
80 BC: TcpBindingsContext<CC::DeviceId>
81 + BufferProvider<
82 BC::ReceiveBuffer,
83 BC::SendBuffer,
84 ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
85 PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
86 >,
87 CC: TcpContext<I, BC> + TcpContext<I::OtherVersion, BC>,
88{
89 type EarlyDemuxSocket = DualStackTcpSocketId<I, CC::WeakDeviceId, BC>;
90
91 fn early_demux<B: ParseBuffer>(
92 core_ctx: &mut CC,
93 device: &CC::DeviceId,
94 src_ip: I::Addr,
95 dst_ip: I::Addr,
96 buffer: B,
97 ) -> Option<Self::EarlyDemuxSocket> {
98 early_demux_ip_packet::<I, _, _, _>(core_ctx, device, src_ip, dst_ip, buffer)
99 }
100
101 fn receive_icmp_error(
102 core_ctx: &mut CC,
103 bindings_ctx: &mut BC,
104 _device: &CC::DeviceId,
105 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
106 original_dst_ip: SpecifiedAddr<I::Addr>,
107 mut original_body: &[u8],
108 err: I::ErrorCode,
109 ) {
110 let mut buffer = &mut original_body;
111 let Some(flow_and_seqnum) = buffer.take_obj_front::<TcpFlowAndSeqNum>() else {
112 error!("received an ICMP error but its body is less than 8 bytes");
113 return;
114 };
115
116 let Some(original_src_ip) = original_src_ip else { return };
117 let Some(original_src_port) = NonZeroU16::new(flow_and_seqnum.src_port()) else { return };
118 let Some(original_dst_port) = NonZeroU16::new(flow_and_seqnum.dst_port()) else { return };
119 let original_seqnum = SeqNum::new(flow_and_seqnum.sequence_num());
120
121 TcpApi::<I, _>::new(CtxPair { core_ctx, bindings_ctx }).on_icmp_error(
122 original_src_ip,
123 original_dst_ip,
124 original_src_port,
125 original_dst_port,
126 original_seqnum,
127 err.into(),
128 );
129 }
130
131 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
132 core_ctx: &mut CC,
133 bindings_ctx: &mut BC,
134 device: &CC::DeviceId,
135 remote_ip: I::RecvSrcAddr,
136 local_ip: SpecifiedAddr<I::Addr>,
137 mut buffer: B,
138 info: &mut LocalDeliveryPacketInfo<I, H>,
139 early_demux_socket: Option<Self::EarlyDemuxSocket>,
140 ) -> Result<(), (B, I::IcmpError)> {
141 let LocalDeliveryPacketInfo { meta, header_info, marks } = info;
142 let ReceiveIpPacketMeta { broadcast, transparent_override, parsing_context } = meta;
143 if let Some(delivery) = transparent_override {
144 warn!(
145 "TODO(https://fxbug.dev/337009139): transparent proxy not supported for TCP \
146 sockets; will not override dispatch to perform local delivery to {delivery:?}"
147 );
148 }
149
150 if broadcast.is_some() {
160 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
161 .invalid_ip_addrs_received
162 .increment();
163 debug!("tcp: dropping broadcast TCP packet");
164 return Ok(());
165 }
166 if local_ip.is_multicast() {
167 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
168 .invalid_ip_addrs_received
169 .increment();
170 debug!("tcp: dropping multicast TCP packet");
171 return Ok(());
172 }
173
174 let remote_ip = match SpecifiedAddr::new(remote_ip.into_addr()) {
175 None => {
176 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
177 .invalid_ip_addrs_received
178 .increment();
179 debug!("tcp: source address unspecified, dropping the packet");
180 return Ok(());
181 }
182 Some(src_ip) => src_ip,
183 };
184 let remote_ip: SocketIpAddr<_> = match remote_ip.try_into() {
185 Ok(remote_ip) => remote_ip,
186 Err(AddrIsMappedError {}) => {
187 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
188 .invalid_ip_addrs_received
189 .increment();
190 debug!("tcp: source address is mapped (ipv4-mapped-ipv6), dropping the packet");
191 return Ok(());
192 }
193 };
194 let local_ip: SocketIpAddr<_> = match local_ip.try_into() {
195 Ok(local_ip) => local_ip,
196 Err(AddrIsMappedError {}) => {
197 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
198 .invalid_ip_addrs_received
199 .increment();
200 debug!("tcp: local address is mapped (ipv4-mapped-ipv6), dropping the packet");
201 return Ok(());
202 }
203 };
204 let packet = match buffer.parse_with::<_, TcpSegment<_>>(TcpParseArgs::with_context(
205 remote_ip.addr(),
206 local_ip.addr(),
207 parsing_context,
208 )) {
209 Ok(packet) => packet,
210 Err(err) => {
211 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
212 .invalid_segments_received
213 .increment();
214 debug!("tcp: failed parsing incoming packet {:?}", err);
215 match err {
216 ParseError::Checksum => {
217 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
218 .checksum_errors
219 .increment();
220 }
221 ParseError::NotSupported | ParseError::NotExpected | ParseError::Format => {}
222 }
223 return Ok(());
224 }
225 };
226 let local_port = packet.dst_port();
227 let remote_port = packet.src_port();
228 let incoming = match VerifiedTcpSegment::try_from(packet) {
229 Ok(segment) => segment,
230 Err(err) => {
231 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
232 .invalid_segments_received
233 .increment();
234 debug!("tcp: malformed segment {:?}", err);
235 return Ok(());
236 }
237 };
238 let conn_addr =
239 ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) };
240
241 CounterContext::<TcpCountersWithoutSocket<I>>::counters(core_ctx)
242 .valid_segments_received
243 .increment();
244 handle_incoming_packet::<I, _, _, _>(
245 core_ctx,
246 bindings_ctx,
247 conn_addr,
248 device,
249 header_info,
250 &incoming,
251 marks,
252 early_demux_socket,
253 );
254 Ok(())
255 }
256}
257
258fn early_demux_ip_packet<I, BC, CC, B>(
259 core_ctx: &mut CC,
260 device: &CC::DeviceId,
261 src_ip: I::Addr,
262 dst_ip: I::Addr,
263 mut buffer: B,
264) -> Option<DualStackTcpSocketId<I, CC::WeakDeviceId, BC>>
265where
266 I: DualStackIpExt,
267 BC: TcpBindingsContext<CC::DeviceId>,
268 CC: TcpContext<I, BC> + TcpContext<I::OtherVersion, BC>,
269 B: ParseBuffer,
270{
271 let Ok(packet) = buffer.parse_with::<_, TcpSegmentRaw<_>>(()) else {
272 return None;
275 };
276
277 let src_ip = SocketIpAddr::new(src_ip)?;
278 let dst_ip = SocketIpAddr::new(dst_ip)?;
279 let (src_port, dst_port) = packet.flow_header().src_dst();
280 let src_port = NonZeroU16::new(src_port)?;
281 let dst_port = NonZeroU16::new(dst_port)?;
282 let device = device.downgrade();
283
284 core_ctx.with_demux(|demux: &DemuxState<I, _, _>| {
285 demux
286 .socketmap
287 .lookup_connected((src_ip, src_port), (dst_ip, dst_port), device)
288 .map(|entry| entry.id())
289 })
290}
291
292fn handle_incoming_packet<WireI, BC, CC, H>(
293 core_ctx: &mut CC,
294 bindings_ctx: &mut BC,
295 conn_addr: ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>,
296 incoming_device: &CC::DeviceId,
297 header_info: &H,
298 incoming: &VerifiedTcpSegment<'_>,
299 marks: &Marks,
300 mut early_demux_socket: Option<DualStackTcpSocketId<WireI, CC::WeakDeviceId, BC>>,
301) where
302 WireI: DualStackIpExt,
303 BC: TcpBindingsContext<CC::DeviceId>
304 + BufferProvider<
305 BC::ReceiveBuffer,
306 BC::SendBuffer,
307 ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
308 PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
309 >,
310 CC: TcpContext<WireI, BC> + TcpContext<WireI::OtherVersion, BC>,
311 H: IpHeaderInfo<WireI>,
312{
313 trace_duration!("tcp::handle_incoming_packet");
314 let mut tw_reuse = None;
315
316 let addr: IpAddrVec<WireI, _> = if early_demux_socket.is_some() {
320 let (ip, port) = conn_addr.local;
321 IpAddrVec::new_listener(ip, port)
322 } else {
323 conn_addr.into()
324 };
325 let mut addrs_to_search = AddrVecIter::<WireI, CC::WeakDeviceId, TcpPortSpec>::with_device(
326 addr,
327 incoming_device.downgrade(),
328 );
329
330 enum FoundSocket<S> {
331 Yes(Option<S>),
334 No,
335 }
336 let found_socket = loop {
337 let sock = if let Some(early_demux_socket) = early_demux_socket.take() {
338 let device = match WireI::as_dual_stack_ip_socket(&early_demux_socket) {
339 EitherStack::ThisStack(conn_id) => conn_id.get_bound_device(core_ctx),
340 EitherStack::OtherStack(conn_id) => conn_id.get_bound_device(core_ctx),
341 };
342 let conn_addr = ConnAddr { ip: conn_addr, device };
343 Some(SocketLookupResult::Connection(early_demux_socket, conn_addr))
344 } else {
345 core_ctx.with_demux(|demux| lookup_socket::<WireI, CC, BC>(demux, &mut addrs_to_search))
346 };
347 match sock {
348 None => break FoundSocket::No,
349 Some(SocketLookupResult::Connection(demux_conn_id, conn_addr)) => {
350 assert_eq!(tw_reuse, None);
353 let disposition = match WireI::as_dual_stack_ip_socket(&demux_conn_id) {
354 EitherStack::ThisStack(conn_id) => {
355 try_handle_incoming_for_connection_dual_stack(
356 core_ctx,
357 bindings_ctx,
358 conn_id,
359 incoming_device,
360 header_info,
361 &incoming,
362 marks,
363 )
364 }
365 EitherStack::OtherStack(conn_id) => {
366 try_handle_incoming_for_connection_dual_stack(
367 core_ctx,
368 bindings_ctx,
369 conn_id,
370 incoming_device,
371 header_info,
372 &incoming,
373 marks,
374 )
375 }
376 };
377 match disposition {
378 ConnectionIncomingSegmentDisposition::Destroy => {
379 WireI::destroy_socket_with_demux_id(core_ctx, bindings_ctx, demux_conn_id);
380 break FoundSocket::Yes(None);
381 }
382 ConnectionIncomingSegmentDisposition::FoundSocket
383 | ConnectionIncomingSegmentDisposition::Filtered => {
384 break FoundSocket::Yes(Some(demux_conn_id));
385 }
386 ConnectionIncomingSegmentDisposition::ReuseCandidateForListener => {
387 tw_reuse = Some((demux_conn_id, conn_addr));
388 }
389 }
390 }
391 Some(SocketLookupResult::Listener((demux_listener_id, _listener_addr))) => {
392 match WireI::as_dual_stack_ip_socket(&demux_listener_id) {
393 EitherStack::ThisStack(listener_id) => {
394 let disposition = core_ctx.with_socket_mut_generators_transport_demux(
395 &listener_id,
396 |core_ctx, socket_state, isn, timestamp_offset| match core_ctx {
397 MaybeDualStack::NotDualStack((core_ctx, converter)) => {
398 try_handle_incoming_for_listener::<WireI, WireI, CC, BC, _, _>(
399 core_ctx,
400 bindings_ctx,
401 &listener_id,
402 isn,
403 timestamp_offset,
404 socket_state,
405 header_info,
406 incoming,
407 conn_addr,
408 incoming_device,
409 &mut tw_reuse,
410 move |conn, addr| converter.convert_back((conn, addr)),
411 WireI::into_demux_socket_id,
412 marks,
413 )
414 }
415 MaybeDualStack::DualStack((core_ctx, converter)) => {
416 try_handle_incoming_for_listener::<_, _, CC, BC, _, _>(
417 core_ctx,
418 bindings_ctx,
419 &listener_id,
420 isn,
421 timestamp_offset,
422 socket_state,
423 header_info,
424 incoming,
425 conn_addr,
426 incoming_device,
427 &mut tw_reuse,
428 move |conn, addr| {
429 converter
430 .convert_back(EitherStack::ThisStack((conn, addr)))
431 },
432 WireI::into_demux_socket_id,
433 marks,
434 )
435 }
436 },
437 );
438 if try_handle_listener_incoming_disposition(
439 core_ctx,
440 bindings_ctx,
441 disposition,
442 &demux_listener_id,
443 &mut tw_reuse,
444 &mut addrs_to_search,
445 conn_addr,
446 incoming_device,
447 ) {
448 break FoundSocket::Yes(Some(demux_listener_id));
449 }
450 }
451 EitherStack::OtherStack(listener_id) => {
452 let disposition = core_ctx.with_socket_mut_generators_transport_demux(
453 &listener_id,
454 |core_ctx, socket_state, isn, timestamp_offset| {
455 match core_ctx {
456 MaybeDualStack::NotDualStack((_core_ctx, _converter)) => {
457 unreachable!("OtherStack socket ID with non dual stack");
460 }
461 MaybeDualStack::DualStack((core_ctx, converter)) => {
462 let other_demux_id_converter =
463 core_ctx.other_demux_id_converter();
464 try_handle_incoming_for_listener::<_, _, CC, BC, _, _>(
465 core_ctx,
466 bindings_ctx,
467 &listener_id,
468 isn,
469 timestamp_offset,
470 socket_state,
471 header_info,
472 incoming,
473 conn_addr,
474 incoming_device,
475 &mut tw_reuse,
476 move |conn, addr| {
477 converter.convert_back(EitherStack::OtherStack((
478 conn, addr,
479 )))
480 },
481 move |id| other_demux_id_converter.convert(id),
482 marks,
483 )
484 }
485 }
486 },
487 );
488 if try_handle_listener_incoming_disposition::<_, _, CC, BC, _>(
489 core_ctx,
490 bindings_ctx,
491 disposition,
492 &demux_listener_id,
493 &mut tw_reuse,
494 &mut addrs_to_search,
495 conn_addr,
496 incoming_device,
497 ) {
498 break FoundSocket::Yes(Some(demux_listener_id));
499 }
500 }
501 };
502 }
503 }
504 };
505
506 let demux_id = match found_socket {
507 FoundSocket::No => {
508 CounterContext::<TcpCountersWithoutSocket<WireI>>::counters(core_ctx)
509 .received_segments_no_dispatch
510 .increment();
511
512 if let Some(seg) =
518 (Closed { reason: None::<Option<ConnectionError>> }.on_segment(&incoming.into()))
519 {
520 socket::send_tcp_segment::<WireI, WireI, _, _, _>(
521 core_ctx,
522 bindings_ctx,
523 None,
524 None,
525 conn_addr,
526 seg.into_empty(),
527 &TcpIpSockOptions { marks: *marks },
528 );
529 }
530 None
531 }
532 FoundSocket::Yes(demux_id) => {
533 counters::increment_counter_with_optional_demux_id::<WireI, _, _, _, _>(
534 core_ctx,
535 demux_id.as_ref(),
536 |c| &c.received_segments_dispatched,
537 );
538 demux_id
539 }
540 };
541
542 if let Some(control) = incoming.control() {
543 counters::increment_counter_with_optional_demux_id::<WireI, _, _, _, _>(
544 core_ctx,
545 demux_id.as_ref(),
546 |c| match control {
547 Control::RST => &c.resets_received,
548 Control::SYN => &c.syns_received,
549 Control::FIN => &c.fins_received,
550 },
551 )
552 }
553}
554
555enum SocketLookupResult<I: DualStackIpExt, D: WeakDeviceIdentifier, BT: TcpBindingsTypes> {
556 Connection(I::DemuxSocketId<D, BT>, ConnAddr<ConnIpAddr<I::Addr, NonZeroU16, NonZeroU16>, D>),
557 Listener((I::DemuxSocketId<D, BT>, ListenerAddr<ListenerIpAddr<I::Addr, NonZeroU16>, D>)),
558}
559
560fn lookup_socket<I, CC, BC>(
561 DemuxState { socketmap, .. }: &DemuxState<I, CC::WeakDeviceId, BC>,
562 addrs_to_search: &mut AddrVecIter<I, CC::WeakDeviceId, TcpPortSpec>,
563) -> Option<SocketLookupResult<I, CC::WeakDeviceId, BC>>
564where
565 I: DualStackIpExt,
566 BC: TcpBindingsContext<CC::DeviceId>,
567 CC: TcpContext<I, BC>,
568{
569 addrs_to_search.find_map(|addr| {
570 match addr {
571 AddrVec::Conn(conn_addr) => {
574 socketmap.conns().get_by_addr(&conn_addr).map(|conn_addr_state| {
575 SocketLookupResult::Connection(conn_addr_state.id(), conn_addr)
576 })
577 }
578 AddrVec::Listen(listener_addr) => {
579 socketmap
584 .listeners()
585 .get_by_addr(&listener_addr)
586 .and_then(|addr_state| match addr_state {
587 ListenerAddrState::ExclusiveListener(id) => Some(id.clone()),
588 ListenerAddrState::Shared { listener: Some(id), bound: _ } => {
589 Some(id.clone())
590 }
591 ListenerAddrState::ExclusiveBound(_)
592 | ListenerAddrState::Shared { listener: None, bound: _ } => None,
593 })
594 .map(|id| SocketLookupResult::Listener((id, listener_addr)))
595 }
596 }
597 })
598}
599
600#[derive(PartialEq, Eq)]
601enum ConnectionIncomingSegmentDisposition {
602 FoundSocket,
603 Filtered,
604 ReuseCandidateForListener,
605 Destroy,
606}
607
608enum ListenerIncomingSegmentDisposition<S> {
609 FoundSocket,
610 Filtered,
611 ConflictingConnection,
612 NoMatchingSocket,
613 NewConnection(S),
614}
615
616fn try_handle_incoming_for_connection_dual_stack<SockI, WireI, CC, BC, H>(
617 core_ctx: &mut CC,
618 bindings_ctx: &mut BC,
619 conn_id: &TcpSocketId<SockI, CC::WeakDeviceId, BC>,
620 incoming_device: &CC::DeviceId,
621 header_info: &H,
622 incoming: &VerifiedTcpSegment<'_>,
623 packet_marks: &Marks,
624) -> ConnectionIncomingSegmentDisposition
625where
626 SockI: DualStackIpExt,
627 WireI: Ip,
628 BC: TcpBindingsContext<CC::DeviceId>
629 + BufferProvider<
630 BC::ReceiveBuffer,
631 BC::SendBuffer,
632 ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
633 PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
634 >,
635 CC: TcpContext<SockI, BC>,
636 H: IpHeaderInfo<WireI>,
637{
638 core_ctx.with_socket_mut_transport_demux(conn_id, |core_ctx, socket_state| {
639 let TcpSocketState { socket_state, sharing: _, ip_options: _, socket_options } =
640 socket_state;
641
642 match run_socket_ingress_filter(
643 bindings_ctx,
644 incoming_device,
645 conn_id.socket_info(),
646 socket_options,
647 packet_marks,
648 header_info,
649 incoming.tcp_segment(),
650 ) {
651 SocketIngressFilterResult::Accept => (),
652 SocketIngressFilterResult::Drop => {
653 return ConnectionIncomingSegmentDisposition::Filtered;
654 }
655 }
656
657 let (conn_and_addr, timer) = assert_matches!(
658 socket_state,
659 TcpSocketStateInner::Connected { conn, timer } => (conn, timer),
660 "invalid socket ID"
661 );
662 let this_or_other_stack = match core_ctx {
663 MaybeDualStack::DualStack((core_ctx, converter)) => {
664 match converter.convert(conn_and_addr) {
665 EitherStack::ThisStack((conn, conn_addr)) => {
666 EitherStack::ThisStack((
671 core_ctx.as_this_stack(),
672 conn,
673 conn_addr,
674 SockI::into_demux_socket_id(conn_id.clone()),
675 ))
676 }
677 EitherStack::OtherStack((conn, conn_addr)) => {
678 let demux_sock_id = core_ctx.into_other_demux_socket_id(conn_id.clone());
681 EitherStack::OtherStack((core_ctx, conn, conn_addr, demux_sock_id))
682 }
683 }
684 }
685 MaybeDualStack::NotDualStack((core_ctx, converter)) => {
686 let (conn, conn_addr) = converter.convert(conn_and_addr);
687 EitherStack::ThisStack((
690 core_ctx.as_this_stack(),
691 conn,
692 conn_addr,
693 SockI::into_demux_socket_id(conn_id.clone()),
694 ))
695 }
696 };
697
698 match this_or_other_stack {
699 EitherStack::ThisStack((core_ctx, conn, conn_addr, demux_conn_id)) => {
700 try_handle_incoming_for_connection::<_, _, CC, _, _>(
701 core_ctx,
702 bindings_ctx,
703 conn_addr.clone(),
704 conn_id,
705 demux_conn_id,
706 socket_options,
707 conn,
708 timer,
709 incoming.into(),
710 )
711 }
712 EitherStack::OtherStack((core_ctx, conn, conn_addr, demux_conn_id)) => {
713 try_handle_incoming_for_connection::<_, _, CC, _, _>(
714 core_ctx,
715 bindings_ctx,
716 conn_addr.clone(),
717 conn_id,
718 demux_conn_id,
719 socket_options,
720 conn,
721 timer,
722 incoming.into(),
723 )
724 }
725 }
726 })
727}
728
729fn try_handle_incoming_for_connection<SockI, WireI, CC, BC, DC>(
736 core_ctx: &mut DC,
737 bindings_ctx: &mut BC,
738 conn_addr: ConnAddr<ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>, CC::WeakDeviceId>,
739 conn_id: &TcpSocketId<SockI, CC::WeakDeviceId, BC>,
740 demux_id: WireI::DemuxSocketId<CC::WeakDeviceId, BC>,
741 socket_options: &SocketOptions,
742 conn: &mut Connection<SockI, WireI, CC::WeakDeviceId, BC>,
743 timer: &mut BC::Timer,
744 incoming: Segment<&[u8]>,
745) -> ConnectionIncomingSegmentDisposition
746where
747 SockI: DualStackIpExt,
748 WireI: DualStackIpExt,
749 BC: TcpBindingsContext<CC::DeviceId>
750 + BufferProvider<
751 BC::ReceiveBuffer,
752 BC::SendBuffer,
753 ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
754 PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
755 >,
756 CC: TcpContext<SockI, BC>,
757 DC: TransportIpContext<WireI, BC, DeviceId = CC::DeviceId, WeakDeviceId = CC::WeakDeviceId>
758 + DeviceIpSocketHandler<SockI, BC>
759 + TcpDemuxContext<WireI, CC::WeakDeviceId, BC>
760 + TcpCounterContext<SockI, CC::WeakDeviceId, BC>
761 + CoreTxMetadataContext<TcpSocketTxMetadata<SockI, CC::WeakDeviceId, BC>, BC>,
762{
763 let Connection { accept_queue, state, ip_sock, defunct, soft_error: _, handshake_status } =
764 conn;
765
766 if *defunct
778 && incoming.header().control == Some(Control::SYN)
779 && incoming.header().ack.is_none()
780 {
781 if let State::TimeWait(TimeWait { last_seq: _, closed_rcv, expiry: _, snd_info: _ }) = state
782 {
783 if !incoming.header().seq.before(closed_rcv.ack) {
784 return ConnectionIncomingSegmentDisposition::ReuseCandidateForListener;
785 }
786 }
787 }
788 let (reply, passive_open, data_acked, newly_closed) = state.on_segment::<_, BC>(
789 &conn_id.either(),
790 &TcpCountersRefs::from_ctx(core_ctx, conn_id),
791 incoming,
792 bindings_ctx.now(),
793 socket_options,
794 *defunct,
795 );
796
797 match data_acked {
798 DataAcked::Yes => {
799 core_ctx.confirm_reachable(bindings_ctx, ip_sock, &socket_options.ip_options)
800 }
801 DataAcked::No => {}
802 }
803
804 match state {
805 State::Listen(_) => {
806 unreachable!("has an invalid status: {:?}", conn.state)
807 }
808 State::SynSent(_) | State::SynRcvd(_) => {
809 assert_eq!(*handshake_status, HandshakeStatus::Pending)
810 }
811 State::Established(_)
812 | State::FinWait1(_)
813 | State::FinWait2(_)
814 | State::Closing(_)
815 | State::CloseWait(_)
816 | State::LastAck(_)
817 | State::TimeWait(_) => {
818 if handshake_status
819 .update_if_pending(HandshakeStatus::Completed { reported: accept_queue.is_some() })
820 {
821 core_ctx.confirm_reachable(bindings_ctx, ip_sock, &socket_options.ip_options);
822 }
823 }
824 State::Closed(Closed { reason }) => {
825 socket::handle_newly_closed(
833 core_ctx,
834 bindings_ctx,
835 newly_closed,
836 &demux_id,
837 &conn_addr,
838 timer,
839 );
840 if let Some(accept_queue) = accept_queue {
841 accept_queue.remove(&conn_id);
842 *defunct = true;
843 }
844 if *defunct {
845 return ConnectionIncomingSegmentDisposition::Destroy;
848 }
849 let _: bool = handshake_status.update_if_pending(match reason {
850 None => HandshakeStatus::Completed { reported: accept_queue.is_some() },
851 Some(_err) => HandshakeStatus::Aborted,
852 });
853 }
854 }
855
856 if let Some(seg) = reply {
857 socket::send_tcp_segment(
858 core_ctx,
859 bindings_ctx,
860 Some(conn_id),
861 Some(&ip_sock),
862 conn_addr.ip,
863 seg.into_empty(),
864 &socket_options.ip_options,
865 );
866 }
867
868 socket::do_send_inner_and_then_handle_newly_closed(
870 conn_id,
871 &demux_id,
872 socket_options,
873 conn,
874 DoSendLimit::MultipleSegments,
875 &conn_addr,
876 timer,
877 core_ctx,
878 bindings_ctx,
879 );
880
881 if let Some(passive_open) = passive_open {
884 let accept_queue = conn.accept_queue.as_ref().expect("no accept queue but passive open");
885 accept_queue.notify_ready(conn_id, passive_open);
886 }
887
888 ConnectionIncomingSegmentDisposition::FoundSocket
890}
891
892fn try_handle_listener_incoming_disposition<SockI, WireI, CC, BC, Addr>(
897 core_ctx: &mut CC,
898 bindings_ctx: &mut BC,
899 disposition: ListenerIncomingSegmentDisposition<PrimaryRc<SockI, CC::WeakDeviceId, BC>>,
900 demux_listener_id: &WireI::DemuxSocketId<CC::WeakDeviceId, BC>,
901 tw_reuse: &mut Option<(WireI::DemuxSocketId<CC::WeakDeviceId, BC>, Addr)>,
902 addrs_to_search: &mut AddrVecIter<WireI, CC::WeakDeviceId, TcpPortSpec>,
903 conn_addr: ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>,
904 incoming_device: &CC::DeviceId,
905) -> bool
906where
907 SockI: DualStackIpExt,
908 WireI: DualStackIpExt,
909 CC: TcpContext<SockI, BC> + TcpContext<WireI, BC> + TcpContext<WireI::OtherVersion, BC>,
910 BC: TcpBindingsContext<CC::DeviceId>,
911{
912 match disposition {
913 ListenerIncomingSegmentDisposition::FoundSocket => true,
914 ListenerIncomingSegmentDisposition::Filtered => true,
915 ListenerIncomingSegmentDisposition::ConflictingConnection => {
916 if let Some((tw_reuse, _)) = tw_reuse.take() {
921 WireI::destroy_socket_with_demux_id(core_ctx, bindings_ctx, tw_reuse);
922 }
923
924 *addrs_to_search = AddrVecIter::<WireI, CC::WeakDeviceId, TcpPortSpec>::with_device(
927 conn_addr.into(),
928 incoming_device.downgrade(),
929 );
930 false
931 }
932 ListenerIncomingSegmentDisposition::NoMatchingSocket => false,
933 ListenerIncomingSegmentDisposition::NewConnection(primary) => {
934 if let Some((tw_reuse, _)) = tw_reuse.take() {
940 WireI::destroy_socket_with_demux_id(core_ctx, bindings_ctx, tw_reuse);
941 }
942
943 let id = TcpSocketId(PrimaryRc::clone_strong(&primary));
952 let to_destroy = core_ctx.with_all_sockets_mut(move |all_sockets| {
953 let insert_entry = TcpSocketSetEntry::Primary(primary);
954 match all_sockets.entry(id) {
955 hash_map::Entry::Vacant(v) => {
956 let _: &mut _ = v.insert(insert_entry);
957 None
958 }
959 hash_map::Entry::Occupied(mut o) => {
960 assert_matches!(
964 core::mem::replace(o.get_mut(), insert_entry),
965 TcpSocketSetEntry::DeadOnArrival
966 );
967 Some(o.key().clone())
968 }
969 }
970 });
971 if let Some(to_destroy) = to_destroy {
979 socket::destroy_socket(core_ctx, bindings_ctx, to_destroy);
980 }
981 counters::increment_counter_for_demux_id::<WireI, _, _, _, _>(
982 core_ctx,
983 demux_listener_id,
984 |c| &c.passive_connection_openings,
985 );
986 true
987 }
988 }
989}
990
991fn try_handle_incoming_for_listener<SockI, WireI, CC, BC, DC, H>(
995 core_ctx: &mut DC,
996 bindings_ctx: &mut BC,
997 listener_id: &TcpSocketId<SockI, CC::WeakDeviceId, BC>,
998 isn: &IsnGenerator<BC::Instant>,
999 timestamp_offset: &TimestampOffsetGenerator<BC::Instant>,
1000 socket_state: &mut TcpSocketState<SockI, CC::WeakDeviceId, BC>,
1001 header_info: &H,
1002 incoming: &VerifiedTcpSegment<'_>,
1003 incoming_addrs: ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>,
1004 incoming_device: &CC::DeviceId,
1005 tw_reuse: &mut Option<(
1006 WireI::DemuxSocketId<CC::WeakDeviceId, BC>,
1007 ConnAddr<ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>, CC::WeakDeviceId>,
1008 )>,
1009 make_connection: impl FnOnce(
1010 Connection<SockI, WireI, CC::WeakDeviceId, BC>,
1011 ConnAddr<ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>, CC::WeakDeviceId>,
1012 ) -> SockI::ConnectionAndAddr<CC::WeakDeviceId, BC>,
1013 make_demux_id: impl Fn(
1014 TcpSocketId<SockI, CC::WeakDeviceId, BC>,
1015 ) -> WireI::DemuxSocketId<CC::WeakDeviceId, BC>,
1016 marks: &Marks,
1017) -> ListenerIncomingSegmentDisposition<PrimaryRc<SockI, CC::WeakDeviceId, BC>>
1018where
1019 SockI: DualStackIpExt,
1020 WireI: DualStackIpExt,
1021 BC: TcpBindingsContext<CC::DeviceId>
1022 + BufferProvider<
1023 BC::ReceiveBuffer,
1024 BC::SendBuffer,
1025 ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
1026 PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
1027 >,
1028 CC: TcpContext<SockI, BC>,
1029 DC: TransportIpContext<WireI, BC, DeviceId = CC::DeviceId, WeakDeviceId = CC::WeakDeviceId>
1030 + DeviceIpSocketHandler<WireI, BC>
1031 + TcpDemuxContext<WireI, CC::WeakDeviceId, BC>
1032 + TcpCounterContext<SockI, CC::WeakDeviceId, BC>
1033 + CoreTxMetadataContext<TcpSocketTxMetadata<SockI, CC::WeakDeviceId, BC>, BC>,
1034 H: IpHeaderInfo<WireI>,
1035{
1036 let Listener { addr: listener_addr, accept_queue, backlog, buffer_sizes } =
1037 match &socket_state.socket_state {
1038 TcpSocketStateInner::Bound(_) => {
1039 return ListenerIncomingSegmentDisposition::NoMatchingSocket;
1041 }
1042 TcpSocketStateInner::Listener(listener) => listener,
1043 _ => panic!("unexpected socket state: {:?}", socket_state.socket_state),
1044 };
1045
1046 let ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) } =
1047 incoming_addrs;
1048
1049 let marks = BC::update_ingress_marks(*marks, &socket_state.socket_options.ip_options.marks);
1050
1051 match run_socket_ingress_filter(
1052 bindings_ctx,
1053 incoming_device,
1054 listener_id.socket_info(),
1055 &socket_state.socket_options,
1056 &marks,
1057 header_info,
1058 incoming.tcp_segment(),
1059 ) {
1060 SocketIngressFilterResult::Accept => (),
1061 SocketIngressFilterResult::Drop => {
1062 return ListenerIncomingSegmentDisposition::Filtered;
1063 }
1064 }
1065
1066 if accept_queue.len() == backlog.get() {
1070 core_ctx.increment_both(listener_id, |counters| &counters.listener_queue_overflow);
1071 core_ctx.increment_both(listener_id, |counters| &counters.failed_connection_attempts);
1072 debug!("incoming SYN dropped because of the full backlog of the listener");
1073 return ListenerIncomingSegmentDisposition::FoundSocket;
1074 }
1075
1076 let bound_device = listener_addr.as_ref().clone();
1079 let bound_device = if remote_ip.as_ref().must_have_zone() {
1080 Some(bound_device.map_or(EitherDeviceId::Strong(incoming_device), EitherDeviceId::Weak))
1081 } else {
1082 bound_device.map(EitherDeviceId::Weak)
1083 };
1084
1085 let ip_options = TcpIpSockOptions { marks, ..socket_state.socket_options.ip_options };
1086 let socket_options = SocketOptions { ip_options, ..socket_state.socket_options };
1087
1088 let bound_device = bound_device.as_ref().map(|d| d.as_ref());
1089 let ip_sock = match core_ctx.new_ip_socket(
1090 bindings_ctx,
1091 IpSocketArgs {
1092 device: bound_device,
1093 local_ip: IpDeviceAddr::new_from_socket_ip_addr(local_ip),
1094 remote_ip,
1095 proto: IpProto::Tcp.into(),
1096 options: &ip_options,
1097 },
1098 ) {
1099 Ok(ip_sock) => ip_sock,
1100 err @ Err(IpSockCreationError::Route(_)) => {
1101 core_ctx.increment_both(listener_id, |counters| &counters.passive_open_no_route_errors);
1102 core_ctx.increment_both(listener_id, |counters| &counters.failed_connection_attempts);
1103 debug!("cannot construct an ip socket to the SYN originator: {:?}, ignoring", err);
1104 return ListenerIncomingSegmentDisposition::NoMatchingSocket;
1105 }
1106 };
1107
1108 let isn = isn.generate(
1109 bindings_ctx.now(),
1110 (ip_sock.local_ip().clone().into(), local_port),
1111 (ip_sock.remote_ip().clone(), remote_port),
1112 );
1113 let timestamp_offset = timestamp_offset.generate::<SocketIpAddr<WireI::Addr>, NonZeroU16>(
1114 bindings_ctx.now(),
1115 (ip_sock.local_ip().clone().into(), local_port),
1116 (ip_sock.remote_ip().clone(), remote_port),
1117 );
1118 let device_mms = match core_ctx.get_mms(bindings_ctx, &ip_sock, &socket_options.ip_options) {
1119 Ok(mms) => mms,
1120 Err(err) => {
1121 error!("Cannot find a device with large enough MTU for the connection");
1125 core_ctx.increment_both(listener_id, |counters| &counters.failed_connection_attempts);
1126 match err {
1127 MmsError::NoDevice(_) | MmsError::MTUTooSmall(_) => {
1128 return ListenerIncomingSegmentDisposition::FoundSocket;
1129 }
1130 }
1131 }
1132 };
1133 let Some(device_mss) = Mss::from_mms(device_mms) else {
1134 return ListenerIncomingSegmentDisposition::FoundSocket;
1135 };
1136
1137 let mut state = State::Listen(Closed::<Initial>::listen(
1138 isn,
1139 timestamp_offset,
1140 buffer_sizes.clone(),
1141 device_mss,
1142 Mss::default::<WireI>(),
1143 socket_options.user_timeout,
1144 ));
1145
1146 let result = state.on_segment::<_, BC>(
1151 &listener_id.either(),
1155 &TcpCountersRefs::from_ctx(core_ctx, listener_id),
1156 incoming.into(),
1157 bindings_ctx.now(),
1158 &SocketOptions::default(),
1159 false, );
1161 let reply = assert_matches!(
1162 result,
1163 (reply, None, _, NewlyClosed::No ) => reply
1164 );
1165
1166 let result = if matches!(state, State::SynRcvd(_)) {
1167 let poll_send_at = state.poll_send_at().expect("no retrans timer");
1168 let bound_device = ip_sock.device().cloned();
1169
1170 let addr = ConnAddr {
1171 ip: ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) },
1172 device: bound_device,
1173 };
1174
1175 let new_socket = core_ctx.with_demux_mut(|DemuxState { socketmap, .. }| {
1176 if let Some((tw_reuse, conn_addr)) = tw_reuse {
1186 match socketmap.conns_mut().remove(tw_reuse, &conn_addr) {
1187 Ok(()) => {
1188 }
1194 Err(NotFoundError) => {
1195 }
1199 }
1200 }
1201
1202 let accept_queue_clone = accept_queue.clone();
1204 let ip_sock = ip_sock.clone();
1205 let bindings_ctx_moved = &mut *bindings_ctx;
1206 let sharing = socket_state.sharing;
1207 match socketmap.conns_mut().try_insert_with(addr, sharing, move |addr, sharing| {
1208 let conn = make_connection(
1209 Connection {
1210 accept_queue: Some(accept_queue_clone),
1211 state,
1212 ip_sock,
1213 defunct: false,
1214 soft_error: None,
1215 handshake_status: HandshakeStatus::Pending,
1216 },
1217 addr,
1218 );
1219
1220 let (id, primary) = TcpSocketId::new_cyclic(
1221 |weak| {
1222 let mut timer = CC::new_timer(bindings_ctx_moved, weak);
1223 assert_eq!(
1227 bindings_ctx_moved.schedule_timer_instant(poll_send_at, &mut timer),
1228 None
1229 );
1230 TcpSocketStateInner::Connected { conn, timer }
1231 },
1232 sharing,
1233 socket_options,
1234 );
1235 (make_demux_id(id.clone()), (primary, id))
1236 }) {
1237 Ok((_entry, (primary, id))) => {
1238 accept_queue.push_pending(id);
1241 Some(primary)
1242 }
1243 Err(e) => {
1244 assert_matches!(e, InsertError::Exists);
1249 None
1254 }
1255 }
1256 });
1257
1258 match new_socket {
1259 Some(new_socket) => ListenerIncomingSegmentDisposition::NewConnection(new_socket),
1260 None => {
1261 core_ctx
1264 .increment_both(listener_id, |counters| &counters.failed_connection_attempts);
1265 return ListenerIncomingSegmentDisposition::ConflictingConnection;
1266 }
1267 }
1268 } else {
1269 ListenerIncomingSegmentDisposition::FoundSocket
1272 };
1273
1274 if let Some(seg) = reply {
1276 socket::send_tcp_segment(
1277 core_ctx,
1278 bindings_ctx,
1279 Some(&listener_id),
1280 Some(&ip_sock),
1281 incoming_addrs,
1282 seg.into_empty(),
1283 &socket_options.ip_options,
1284 );
1285 }
1286
1287 result
1288}
1289
1290pub(super) fn tcp_serialize_segment<'a, I, P>(
1291 header: &'a SegmentHeader,
1292 data: P,
1293 conn_addr: ConnIpAddr<I::Addr, NonZeroU16, NonZeroU16>,
1294) -> impl TransportPacketSerializer<I, Buffer = EmptyBuf> + Debug + 'a
1295where
1296 I: FilterIpExt,
1297 P: InnerPacketBuilder + Debug + Payload + 'a,
1298{
1299 let SegmentHeader { seq, ack, wnd, control, options, push } = header;
1300 let ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) } = conn_addr;
1301 let mut builder = TcpSegmentBuilder::new(
1302 local_ip.addr(),
1303 remote_ip.addr(),
1304 local_port,
1305 remote_port,
1306 (*seq).into(),
1307 ack.map(Into::into),
1308 u16::from(*wnd),
1309 );
1310 builder.psh(*push);
1311 match control {
1312 None => {}
1313 Some(Control::SYN) => builder.syn(true),
1314 Some(Control::FIN) => builder.fin(true),
1315 Some(Control::RST) => builder.rst(true),
1316 }
1317 TcpSegmentBuilderWithOptions::new(builder, options.builder())
1318 .unwrap_or_else(|TcpOptionsTooLongError| {
1319 panic!("Too many TCP options");
1320 })
1321 .wrap_body(data.into_serializer())
1322}
1323
1324fn run_socket_ingress_filter<I, BC, D>(
1325 bindings_ctx: &BC,
1326 incoming_device: &D,
1327 socket_info: netstack3_base::socket::SocketInfo,
1328 socket_options: &SocketOptions,
1329 packet_marks: &Marks,
1330 header_info: &impl IpHeaderInfo<I>,
1331 tcp_segment: &TcpSegment<&'_ [u8]>,
1332) -> SocketIngressFilterResult
1333where
1334 I: Ip,
1335 BC: TcpBindingsContext<D>,
1336 D: StrongDeviceIdentifier,
1337{
1338 let [ip_prefix, ip_options] = header_info.as_bytes();
1339 let [tcp_prefix, tcp_options, _data] = tcp_segment.as_bytes();
1340 let mut slices = [ip_prefix, ip_options, tcp_prefix, tcp_options, _data];
1341 let packet = FragmentedByteSlice::new(&mut slices);
1342 let header_len = ip_prefix.len() + ip_options.len() + tcp_prefix.len() + tcp_options.len();
1343
1344 let marks = BC::update_ingress_marks(*packet_marks, &socket_options.ip_options.marks);
1345 bindings_ctx.socket_ops_filter().on_ingress(
1346 I::VERSION,
1347 packet,
1348 header_len,
1349 incoming_device,
1350 socket_info,
1351 &marks,
1352 )
1353}
1354
1355#[cfg(test)]
1356mod test {
1357 use ip_test_macro::ip_test;
1358 use netstack3_base::{
1359 HandshakeOptions, NetworkSerializationContext, Options, ResetOptions, SackBlocks,
1360 SegmentOptions, UnscaledWindowSize,
1361 };
1362 use packet::Serializer as _;
1363 use packet_formats::tcp::options::TcpOptions as _;
1364 use test_case::test_case;
1365
1366 use super::*;
1367
1368 trait TestIpExt: netstack3_base::testutil::TestIpExt + FilterIpExt {}
1369 impl<T> TestIpExt for T where T: netstack3_base::testutil::TestIpExt + FilterIpExt {}
1370
1371 const SEQ: SeqNum = SeqNum::new(12345);
1372 const ACK: SeqNum = SeqNum::new(67890);
1373 const FAKE_DATA: &'static [u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
1374
1375 #[ip_test(I)]
1376 #[test_case(
1377 Segment::syn(SEQ, UnscaledWindowSize::from(u16::MAX),
1378 HandshakeOptions::default()), &[]
1379 ; "syn")]
1380 #[test_case(
1381 Segment::syn(SEQ, UnscaledWindowSize::from(u16::MAX),
1382 HandshakeOptions {
1383 mss: Some(Mss::new(1440).unwrap()),
1384 ..Default::default() }), &[]
1385 ; "syn with mss")]
1386 #[test_case(
1387 Segment::ack(SEQ, ACK, UnscaledWindowSize::from(u16::MAX), SegmentOptions::default()),
1388 &[]; "ack")]
1389 #[test_case(Segment::with_fake_data(SEQ, ACK, FAKE_DATA), FAKE_DATA; "data")]
1390 #[test_case(Segment::new_assert_no_discard(SegmentHeader {
1391 seq: SEQ,
1392 ack: Some(ACK),
1393 push: true,
1394 wnd: UnscaledWindowSize::from(u16::MAX),
1395 ..Default::default()
1396 },
1397 FAKE_DATA
1398 ), FAKE_DATA; "push")]
1399 fn tcp_serialize_segment<I: TestIpExt>(segment: Segment<&[u8]>, expected_body: &[u8]) {
1400 const SOURCE_PORT: NonZeroU16 = NonZeroU16::new(1111).unwrap();
1401 const DEST_PORT: NonZeroU16 = NonZeroU16::new(2222).unwrap();
1402
1403 let (header, data) = segment.into_parts();
1404 let serializer = super::tcp_serialize_segment::<I, _>(
1405 &header,
1406 data,
1407 ConnIpAddr {
1408 local: (SocketIpAddr::try_from(I::TEST_ADDRS.local_ip).unwrap(), SOURCE_PORT),
1409 remote: (SocketIpAddr::try_from(I::TEST_ADDRS.remote_ip).unwrap(), DEST_PORT),
1410 },
1411 );
1412
1413 let mut serialized = serializer
1414 .serialize_vec_outer(&mut NetworkSerializationContext::default())
1415 .unwrap()
1416 .unwrap_b();
1417 let parsed_segment = serialized
1418 .parse_with::<_, TcpSegment<_>>(TcpParseArgs::new(
1419 *I::TEST_ADDRS.remote_ip,
1420 *I::TEST_ADDRS.local_ip,
1421 ))
1422 .expect("is valid segment");
1423
1424 assert_eq!(parsed_segment.src_port(), SOURCE_PORT);
1425 assert_eq!(parsed_segment.dst_port(), DEST_PORT);
1426 assert_eq!(parsed_segment.seq_num(), u32::from(SEQ));
1427 assert_eq!(parsed_segment.psh(), header.push);
1428 assert_eq!(
1429 UnscaledWindowSize::from(parsed_segment.window_size()),
1430 UnscaledWindowSize::from(u16::MAX)
1431 );
1432
1433 let (mss, window_scale, sack_permitted, sack_blocks, timestamp) = match header.options {
1434 Options::Handshake(HandshakeOptions {
1435 mss,
1436 window_scale,
1437 sack_permitted,
1438 timestamp,
1439 }) => (mss, window_scale, sack_permitted, SackBlocks::EMPTY, timestamp),
1440 Options::Segment(SegmentOptions { timestamp, sack_blocks }) => {
1441 (None, None, false, sack_blocks, timestamp)
1442 }
1443 Options::Reset(ResetOptions { timestamp }) => {
1444 (None, None, false, SackBlocks::EMPTY, timestamp)
1445 }
1446 };
1447 assert_eq!(mss.map(|mss| mss.get()), parsed_segment.options().mss());
1448 assert_eq!(window_scale.map(|ws| ws.get()), parsed_segment.options().window_scale());
1449 assert_eq!(sack_permitted, parsed_segment.options().sack_permitted());
1450 assert_eq!(sack_blocks.as_slice(), parsed_segment.options().sack_blocks());
1451 assert_eq!(
1452 timestamp.as_ref().map(Into::into).as_ref(),
1453 parsed_segment.options().timestamp()
1454 );
1455
1456 assert_eq!(parsed_segment.into_body(), expected_body);
1457 }
1458}