Skip to main content

netstack3_tcp/socket/
demux.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Defines the entry point of TCP packets, by directing them into the correct
6//! state machine.
7
8use 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, GsoInfo,
21    IpDeviceAddr, Marks, Mss, NotFoundError, PacketType, Payload, Segment, SegmentHeader, SeqNum,
22    StrongDeviceIdentifier, 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, MaybeSegmentableTransportSerializer,
31    ReceiveIpPacketMeta, 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
74/// Alias for a SocketId that can reference either V4 or V6 socket.
75pub 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, packet_type, gso_info } = 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        // Per RFC 9293, Section 3.9.2.3 (referencing RFC 1122):
151        //   A TCP implementation MUST silently discard an incoming SYN
152        //   segment that is addressed to a broadcast or multicast address
153        //   [(MUST-57)].
154        //
155        // and
156        //
157        //   ... this guidance is applicable to all incoming segments, not just
158        //   SYNs ...
159        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            *packet_type,
253            *gso_info,
254            early_demux_socket,
255        );
256        Ok(())
257    }
258}
259
260fn early_demux_ip_packet<I, BC, CC, B>(
261    core_ctx: &mut CC,
262    device: &CC::DeviceId,
263    src_ip: I::Addr,
264    dst_ip: I::Addr,
265    mut buffer: B,
266) -> Option<DualStackTcpSocketId<I, CC::WeakDeviceId, BC>>
267where
268    I: DualStackIpExt,
269    BC: TcpBindingsContext<CC::DeviceId>,
270    CC: TcpContext<I, BC> + TcpContext<I::OtherVersion, BC>,
271    B: ParseBuffer,
272{
273    let Ok(packet) = buffer.parse_with::<_, TcpSegmentRaw<_>>(()) else {
274        // If we fail to parse the packet then just return None. Invalid
275        // packets are handled later.
276        return None;
277    };
278
279    let src_ip = SocketIpAddr::new(src_ip)?;
280    let dst_ip = SocketIpAddr::new(dst_ip)?;
281    let (src_port, dst_port) = packet.flow_header().src_dst();
282    let src_port = NonZeroU16::new(src_port)?;
283    let dst_port = NonZeroU16::new(dst_port)?;
284    let device = device.downgrade();
285
286    core_ctx.with_demux(|demux: &DemuxState<I, _, _>| {
287        demux
288            .socketmap
289            .lookup_connected((src_ip, src_port), (dst_ip, dst_port), device)
290            .map(|entry| entry.id())
291    })
292}
293
294fn handle_incoming_packet<WireI, BC, CC, H>(
295    core_ctx: &mut CC,
296    bindings_ctx: &mut BC,
297    conn_addr: ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>,
298    incoming_device: &CC::DeviceId,
299    header_info: &H,
300    incoming: &VerifiedTcpSegment<'_>,
301    marks: &Marks,
302    packet_type: PacketType,
303    gso_info: Option<GsoInfo>,
304    mut early_demux_socket: Option<DualStackTcpSocketId<WireI, CC::WeakDeviceId, BC>>,
305) where
306    WireI: DualStackIpExt,
307    BC: TcpBindingsContext<CC::DeviceId>
308        + BufferProvider<
309            BC::ReceiveBuffer,
310            BC::SendBuffer,
311            ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
312            PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
313        >,
314    CC: TcpContext<WireI, BC> + TcpContext<WireI::OtherVersion, BC>,
315    H: IpHeaderInfo<WireI>,
316{
317    trace_duration!("tcp::handle_incoming_packet");
318    let mut tw_reuse = None;
319
320    // If we have an early demux socket, then we don't need to look up
321    // connected sockets again. We may still need to lookup listener sockets
322    // when the socket we found a in the timed wait state.
323    let addr: IpAddrVec<WireI, _> = if early_demux_socket.is_some() {
324        let (ip, port) = conn_addr.local;
325        IpAddrVec::new_listener(ip, port)
326    } else {
327        conn_addr.into()
328    };
329    let mut addrs_to_search = AddrVecIter::<WireI, CC::WeakDeviceId, TcpPortSpec>::with_device(
330        addr,
331        incoming_device.downgrade(),
332    );
333
334    enum FoundSocket<S> {
335        // Typically holds the demux ID of the found socket, but may hold
336        // `None` if the found socket was destroyed as a result of the segment.
337        Yes(Option<S>),
338        No,
339    }
340    let found_socket = loop {
341        let sock = if let Some(early_demux_socket) = early_demux_socket.take() {
342            let device = match WireI::as_dual_stack_ip_socket(&early_demux_socket) {
343                EitherStack::ThisStack(conn_id) => conn_id.get_bound_device(core_ctx),
344                EitherStack::OtherStack(conn_id) => conn_id.get_bound_device(core_ctx),
345            };
346            let conn_addr = ConnAddr { ip: conn_addr, device };
347            Some(SocketLookupResult::Connection(early_demux_socket, conn_addr))
348        } else {
349            core_ctx.with_demux(|demux| lookup_socket::<WireI, CC, BC>(demux, &mut addrs_to_search))
350        };
351        match sock {
352            None => break FoundSocket::No,
353            Some(SocketLookupResult::Connection(demux_conn_id, conn_addr)) => {
354                // It is not possible to have two same connections that
355                // share the same local and remote IPs and ports.
356                assert_eq!(tw_reuse, None);
357                let disposition = match WireI::as_dual_stack_ip_socket(&demux_conn_id) {
358                    EitherStack::ThisStack(conn_id) => {
359                        try_handle_incoming_for_connection_dual_stack(
360                            core_ctx,
361                            bindings_ctx,
362                            conn_id,
363                            incoming_device,
364                            header_info,
365                            &incoming,
366                            marks,
367                            packet_type,
368                            gso_info,
369                        )
370                    }
371                    EitherStack::OtherStack(conn_id) => {
372                        try_handle_incoming_for_connection_dual_stack(
373                            core_ctx,
374                            bindings_ctx,
375                            conn_id,
376                            incoming_device,
377                            header_info,
378                            &incoming,
379                            marks,
380                            packet_type,
381                            gso_info,
382                        )
383                    }
384                };
385                match disposition {
386                    ConnectionIncomingSegmentDisposition::Destroy => {
387                        WireI::destroy_socket_with_demux_id(core_ctx, bindings_ctx, demux_conn_id);
388                        break FoundSocket::Yes(None);
389                    }
390                    ConnectionIncomingSegmentDisposition::FoundSocket
391                    | ConnectionIncomingSegmentDisposition::Filtered => {
392                        break FoundSocket::Yes(Some(demux_conn_id));
393                    }
394                    ConnectionIncomingSegmentDisposition::ReuseCandidateForListener => {
395                        tw_reuse = Some((demux_conn_id, conn_addr));
396                    }
397                }
398            }
399            Some(SocketLookupResult::Listener((demux_listener_id, _listener_addr))) => {
400                match WireI::as_dual_stack_ip_socket(&demux_listener_id) {
401                    EitherStack::ThisStack(listener_id) => {
402                        let disposition = core_ctx.with_socket_mut_generators_transport_demux(
403                            &listener_id,
404                            |core_ctx, socket_state, isn, timestamp_offset| match core_ctx {
405                                MaybeDualStack::NotDualStack((core_ctx, converter)) => {
406                                    try_handle_incoming_for_listener::<WireI, WireI, CC, BC, _, _>(
407                                        core_ctx,
408                                        bindings_ctx,
409                                        &listener_id,
410                                        isn,
411                                        timestamp_offset,
412                                        socket_state,
413                                        header_info,
414                                        incoming,
415                                        conn_addr,
416                                        incoming_device,
417                                        &mut tw_reuse,
418                                        move |conn, addr| converter.convert_back((conn, addr)),
419                                        WireI::into_demux_socket_id,
420                                        marks,
421                                        packet_type,
422                                        gso_info,
423                                    )
424                                }
425                                MaybeDualStack::DualStack((core_ctx, converter)) => {
426                                    try_handle_incoming_for_listener::<_, _, CC, BC, _, _>(
427                                        core_ctx,
428                                        bindings_ctx,
429                                        &listener_id,
430                                        isn,
431                                        timestamp_offset,
432                                        socket_state,
433                                        header_info,
434                                        incoming,
435                                        conn_addr,
436                                        incoming_device,
437                                        &mut tw_reuse,
438                                        move |conn, addr| {
439                                            converter
440                                                .convert_back(EitherStack::ThisStack((conn, addr)))
441                                        },
442                                        WireI::into_demux_socket_id,
443                                        marks,
444                                        packet_type,
445                                        gso_info,
446                                    )
447                                }
448                            },
449                        );
450                        if try_handle_listener_incoming_disposition(
451                            core_ctx,
452                            bindings_ctx,
453                            disposition,
454                            &demux_listener_id,
455                            &mut tw_reuse,
456                            &mut addrs_to_search,
457                            conn_addr,
458                            incoming_device,
459                        ) {
460                            break FoundSocket::Yes(Some(demux_listener_id));
461                        }
462                    }
463                    EitherStack::OtherStack(listener_id) => {
464                        let disposition = core_ctx.with_socket_mut_generators_transport_demux(
465                            &listener_id,
466                            |core_ctx, socket_state, isn, timestamp_offset| {
467                                match core_ctx {
468                                    MaybeDualStack::NotDualStack((_core_ctx, _converter)) => {
469                                        // TODO(https://issues.fuchsia.dev/316408184):
470                                        // Remove this unreachable!.
471                                        unreachable!("OtherStack socket ID with non dual stack");
472                                    }
473                                    MaybeDualStack::DualStack((core_ctx, converter)) => {
474                                        let other_demux_id_converter =
475                                            core_ctx.other_demux_id_converter();
476                                        try_handle_incoming_for_listener::<_, _, CC, BC, _, _>(
477                                            core_ctx,
478                                            bindings_ctx,
479                                            &listener_id,
480                                            isn,
481                                            timestamp_offset,
482                                            socket_state,
483                                            header_info,
484                                            incoming,
485                                            conn_addr,
486                                            incoming_device,
487                                            &mut tw_reuse,
488                                            move |conn, addr| {
489                                                converter.convert_back(EitherStack::OtherStack((
490                                                    conn, addr,
491                                                )))
492                                            },
493                                            move |id| other_demux_id_converter.convert(id),
494                                            marks,
495                                            packet_type,
496                                            gso_info,
497                                        )
498                                    }
499                                }
500                            },
501                        );
502                        if try_handle_listener_incoming_disposition::<_, _, CC, BC, _>(
503                            core_ctx,
504                            bindings_ctx,
505                            disposition,
506                            &demux_listener_id,
507                            &mut tw_reuse,
508                            &mut addrs_to_search,
509                            conn_addr,
510                            incoming_device,
511                        ) {
512                            break FoundSocket::Yes(Some(demux_listener_id));
513                        }
514                    }
515                };
516            }
517        }
518    };
519
520    let demux_id = match found_socket {
521        FoundSocket::No => {
522            CounterContext::<TcpCountersWithoutSocket<WireI>>::counters(core_ctx)
523                .received_segments_no_dispatch
524                .increment();
525
526            // There is no existing TCP state, pretend it is closed
527            // and generate a RST if needed.
528            // Per RFC 793 (https://tools.ietf.org/html/rfc793#page-21):
529            // CLOSED is fictional because it represents the state when
530            // there is no TCB, and therefore, no connection.
531            if let Some(seg) =
532                (Closed { reason: None::<Option<ConnectionError>> }.on_segment(&incoming.into()))
533            {
534                socket::send_tcp_segment::<WireI, WireI, _, _, _>(
535                    core_ctx,
536                    bindings_ctx,
537                    None,
538                    None,
539                    conn_addr,
540                    seg.into_empty(),
541                    &TcpIpSockOptions { marks: *marks },
542                );
543            }
544            None
545        }
546        FoundSocket::Yes(demux_id) => {
547            counters::increment_counter_with_optional_demux_id::<WireI, _, _, _, _>(
548                core_ctx,
549                demux_id.as_ref(),
550                |c| &c.received_segments_dispatched,
551            );
552            demux_id
553        }
554    };
555
556    if let Some(control) = incoming.control() {
557        counters::increment_counter_with_optional_demux_id::<WireI, _, _, _, _>(
558            core_ctx,
559            demux_id.as_ref(),
560            |c| match control {
561                Control::RST => &c.resets_received,
562                Control::SYN => &c.syns_received,
563                Control::FIN => &c.fins_received,
564            },
565        )
566    }
567}
568
569enum SocketLookupResult<I: DualStackIpExt, D: WeakDeviceIdentifier, BT: TcpBindingsTypes> {
570    Connection(I::DemuxSocketId<D, BT>, ConnAddr<ConnIpAddr<I::Addr, NonZeroU16, NonZeroU16>, D>),
571    Listener((I::DemuxSocketId<D, BT>, ListenerAddr<ListenerIpAddr<I::Addr, NonZeroU16>, D>)),
572}
573
574fn lookup_socket<I, CC, BC>(
575    DemuxState { socketmap, .. }: &DemuxState<I, CC::WeakDeviceId, BC>,
576    addrs_to_search: &mut AddrVecIter<I, CC::WeakDeviceId, TcpPortSpec>,
577) -> Option<SocketLookupResult<I, CC::WeakDeviceId, BC>>
578where
579    I: DualStackIpExt,
580    BC: TcpBindingsContext<CC::DeviceId>,
581    CC: TcpContext<I, BC>,
582{
583    addrs_to_search.find_map(|addr| {
584        match addr {
585            // Connections are always searched before listeners because they
586            // are more specific.
587            AddrVec::Conn(conn_addr) => {
588                socketmap.conns().get_by_addr(&conn_addr).map(|conn_addr_state| {
589                    SocketLookupResult::Connection(conn_addr_state.id(), conn_addr)
590                })
591            }
592            AddrVec::Listen(listener_addr) => {
593                // If we have a listener and the incoming segment is a SYN, we
594                // allocate a new connection entry in the demuxer.
595                // TODO(https://fxbug.dev/42052878): Support SYN cookies.
596
597                socketmap
598                    .listeners()
599                    .get_by_addr(&listener_addr)
600                    .and_then(|addr_state| match addr_state {
601                        ListenerAddrState::ExclusiveListener(id) => Some(id.clone()),
602                        ListenerAddrState::Shared { listener: Some(id), bound: _ } => {
603                            Some(id.clone())
604                        }
605                        ListenerAddrState::ExclusiveBound(_)
606                        | ListenerAddrState::Shared { listener: None, bound: _ } => None,
607                    })
608                    .map(|id| SocketLookupResult::Listener((id, listener_addr)))
609            }
610        }
611    })
612}
613
614#[derive(PartialEq, Eq)]
615enum ConnectionIncomingSegmentDisposition {
616    FoundSocket,
617    Filtered,
618    ReuseCandidateForListener,
619    Destroy,
620}
621
622enum ListenerIncomingSegmentDisposition<S> {
623    FoundSocket,
624    Filtered,
625    ConflictingConnection,
626    NoMatchingSocket,
627    NewConnection(S),
628}
629
630fn try_handle_incoming_for_connection_dual_stack<SockI, WireI, CC, BC, H>(
631    core_ctx: &mut CC,
632    bindings_ctx: &mut BC,
633    conn_id: &TcpSocketId<SockI, CC::WeakDeviceId, BC>,
634    incoming_device: &CC::DeviceId,
635    header_info: &H,
636    incoming: &VerifiedTcpSegment<'_>,
637    packet_marks: &Marks,
638    packet_type: PacketType,
639    gso_info: Option<GsoInfo>,
640) -> ConnectionIncomingSegmentDisposition
641where
642    SockI: DualStackIpExt,
643    WireI: Ip,
644    BC: TcpBindingsContext<CC::DeviceId>
645        + BufferProvider<
646            BC::ReceiveBuffer,
647            BC::SendBuffer,
648            ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
649            PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
650        >,
651    CC: TcpContext<SockI, BC>,
652    H: IpHeaderInfo<WireI>,
653{
654    core_ctx.with_socket_mut_transport_demux(conn_id, |core_ctx, socket_state| {
655        let TcpSocketState { socket_state, sharing: _, ip_options: _, socket_options } =
656            socket_state;
657
658        match run_socket_ingress_filter(
659            bindings_ctx,
660            incoming_device,
661            conn_id.socket_info(),
662            socket_options,
663            packet_marks,
664            header_info,
665            incoming.tcp_segment(),
666            packet_type,
667            gso_info,
668        ) {
669            SocketIngressFilterResult::Accept => (),
670            SocketIngressFilterResult::Drop => {
671                return ConnectionIncomingSegmentDisposition::Filtered;
672            }
673        }
674
675        let (conn_and_addr, timer) = assert_matches!(
676            socket_state,
677            TcpSocketStateInner::Connected { conn, timer } => (conn, timer),
678            "invalid socket ID"
679        );
680        let this_or_other_stack = match core_ctx {
681            MaybeDualStack::DualStack((core_ctx, converter)) => {
682                match converter.convert(conn_and_addr) {
683                    EitherStack::ThisStack((conn, conn_addr)) => {
684                        // The socket belongs to the current stack, so we
685                        // want to deliver the segment to this stack.
686                        // Use `as_this_stack` to make the context types
687                        // match with the non-dual-stack case.
688                        EitherStack::ThisStack((
689                            core_ctx.as_this_stack(),
690                            conn,
691                            conn_addr,
692                            SockI::into_demux_socket_id(conn_id.clone()),
693                        ))
694                    }
695                    EitherStack::OtherStack((conn, conn_addr)) => {
696                        // We need to deliver from the other stack. i.e. we
697                        // need to deliver an IPv4 packet to the IPv6 stack.
698                        let demux_sock_id = core_ctx.into_other_demux_socket_id(conn_id.clone());
699                        EitherStack::OtherStack((core_ctx, conn, conn_addr, demux_sock_id))
700                    }
701                }
702            }
703            MaybeDualStack::NotDualStack((core_ctx, converter)) => {
704                let (conn, conn_addr) = converter.convert(conn_and_addr);
705                // Similar to the first case, we need deliver to this stack,
706                // but use `as_this_stack` to make the types match.
707                EitherStack::ThisStack((
708                    core_ctx.as_this_stack(),
709                    conn,
710                    conn_addr,
711                    SockI::into_demux_socket_id(conn_id.clone()),
712                ))
713            }
714        };
715
716        match this_or_other_stack {
717            EitherStack::ThisStack((core_ctx, conn, conn_addr, demux_conn_id)) => {
718                try_handle_incoming_for_connection::<_, _, CC, _, _>(
719                    core_ctx,
720                    bindings_ctx,
721                    conn_addr.clone(),
722                    conn_id,
723                    demux_conn_id,
724                    socket_options,
725                    conn,
726                    timer,
727                    incoming.into(),
728                )
729            }
730            EitherStack::OtherStack((core_ctx, conn, conn_addr, demux_conn_id)) => {
731                try_handle_incoming_for_connection::<_, _, CC, _, _>(
732                    core_ctx,
733                    bindings_ctx,
734                    conn_addr.clone(),
735                    conn_id,
736                    demux_conn_id,
737                    socket_options,
738                    conn,
739                    timer,
740                    incoming.into(),
741                )
742            }
743        }
744    })
745}
746
747/// Tries to handle the incoming segment by providing it to a connected socket.
748///
749/// Returns `FoundSocket` if the segment was handled; Otherwise,
750/// `ReuseCandidateForListener` will be returned if there is a defunct socket
751/// that is currently in TIME_WAIT, which is ready to be reused if there is an
752/// active listener listening on the port.
753fn try_handle_incoming_for_connection<SockI, WireI, CC, BC, DC>(
754    core_ctx: &mut DC,
755    bindings_ctx: &mut BC,
756    conn_addr: ConnAddr<ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>, CC::WeakDeviceId>,
757    conn_id: &TcpSocketId<SockI, CC::WeakDeviceId, BC>,
758    demux_id: WireI::DemuxSocketId<CC::WeakDeviceId, BC>,
759    socket_options: &SocketOptions,
760    conn: &mut Connection<SockI, WireI, CC::WeakDeviceId, BC>,
761    timer: &mut BC::Timer,
762    incoming: Segment<&[u8]>,
763) -> ConnectionIncomingSegmentDisposition
764where
765    SockI: DualStackIpExt,
766    WireI: DualStackIpExt,
767    BC: TcpBindingsContext<CC::DeviceId>
768        + BufferProvider<
769            BC::ReceiveBuffer,
770            BC::SendBuffer,
771            ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
772            PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
773        >,
774    CC: TcpContext<SockI, BC>,
775    DC: TransportIpContext<WireI, BC, DeviceId = CC::DeviceId, WeakDeviceId = CC::WeakDeviceId>
776        + DeviceIpSocketHandler<SockI, BC>
777        + TcpDemuxContext<WireI, CC::WeakDeviceId, BC>
778        + TcpCounterContext<SockI, CC::WeakDeviceId, BC>
779        + CoreTxMetadataContext<TcpSocketTxMetadata<SockI, CC::WeakDeviceId, BC>, BC>,
780{
781    let Connection { accept_queue, state, ip_sock, defunct, soft_error: _, handshake_status } =
782        conn;
783
784    // Per RFC 9293 Section 3.6.1:
785    //   When a connection is closed actively, it MUST linger in the TIME-WAIT
786    //   state for a time 2xMSL (Maximum Segment Lifetime) (MUST-13). However,
787    //   it MAY accept a new SYN from the remote TCP endpoint to reopen the
788    //   connection directly from TIME-WAIT state (MAY-2), if it:
789    //
790    //   (1) assigns its initial sequence number for the new connection to be
791    //       larger than the largest sequence number it used on the previous
792    //       connection incarnation, and
793    //   (2) returns to TIME-WAIT state if the SYN turns out to be an old
794    //       duplicate.
795    if *defunct
796        && incoming.header().control == Some(Control::SYN)
797        && incoming.header().ack.is_none()
798    {
799        if let State::TimeWait(TimeWait { last_seq: _, closed_rcv, expiry: _, snd_info: _ }) = state
800        {
801            if !incoming.header().seq.before(closed_rcv.ack) {
802                return ConnectionIncomingSegmentDisposition::ReuseCandidateForListener;
803            }
804        }
805    }
806    let (reply, passive_open, data_acked, newly_closed) = state.on_segment::<_, BC>(
807        &conn_id.either(),
808        &TcpCountersRefs::from_ctx(core_ctx, conn_id),
809        incoming,
810        bindings_ctx.now(),
811        socket_options,
812        *defunct,
813    );
814
815    match data_acked {
816        DataAcked::Yes => {
817            core_ctx.confirm_reachable(bindings_ctx, ip_sock, &socket_options.ip_options)
818        }
819        DataAcked::No => {}
820    }
821
822    match state {
823        State::Listen(_) => {
824            unreachable!("has an invalid status: {:?}", conn.state)
825        }
826        State::SynSent(_) | State::SynRcvd(_) => {
827            assert_eq!(*handshake_status, HandshakeStatus::Pending)
828        }
829        State::Established(_)
830        | State::FinWait1(_)
831        | State::FinWait2(_)
832        | State::Closing(_)
833        | State::CloseWait(_)
834        | State::LastAck(_)
835        | State::TimeWait(_) => {
836            if handshake_status
837                .update_if_pending(HandshakeStatus::Completed { reported: accept_queue.is_some() })
838            {
839                core_ctx.confirm_reachable(bindings_ctx, ip_sock, &socket_options.ip_options);
840            }
841        }
842        State::Closed(Closed { reason }) => {
843            // We remove the socket from the socketmap and cancel the timers
844            // regardless of the socket being defunct or not. The justification
845            // is that CLOSED is a synthetic state and it means no connection
846            // exists, thus it should not exist in the demuxer.
847            //
848            // If the socket was already in the closed state we can assume it's
849            // no longer in the demux.
850            socket::handle_newly_closed(
851                core_ctx,
852                bindings_ctx,
853                newly_closed,
854                &demux_id,
855                &conn_addr,
856                timer,
857            );
858            if let Some(accept_queue) = accept_queue {
859                accept_queue.remove(&conn_id);
860                *defunct = true;
861            }
862            if *defunct {
863                // If the client has promised to not touch the socket again,
864                // we can destroy the socket finally.
865                return ConnectionIncomingSegmentDisposition::Destroy;
866            }
867            let _: bool = handshake_status.update_if_pending(match reason {
868                None => HandshakeStatus::Completed { reported: accept_queue.is_some() },
869                Some(_err) => HandshakeStatus::Aborted,
870            });
871        }
872    }
873
874    if let Some(seg) = reply {
875        socket::send_tcp_segment(
876            core_ctx,
877            bindings_ctx,
878            Some(conn_id),
879            Some(&ip_sock),
880            conn_addr.ip,
881            seg.into_empty(),
882            &socket_options.ip_options,
883        );
884    }
885
886    // Send any enqueued data, if there is any.
887    socket::do_send_inner_and_then_handle_newly_closed(
888        conn_id,
889        &demux_id,
890        socket_options,
891        conn,
892        DoSendLimit::MultipleSegments,
893        &conn_addr,
894        timer,
895        core_ctx,
896        bindings_ctx,
897    );
898
899    // Enqueue the connection to the associated listener
900    // socket's accept queue.
901    if let Some(passive_open) = passive_open {
902        let accept_queue = conn.accept_queue.as_ref().expect("no accept queue but passive open");
903        accept_queue.notify_ready(conn_id, passive_open);
904    }
905
906    // We found a valid connection for the segment.
907    ConnectionIncomingSegmentDisposition::FoundSocket
908}
909
910/// Responds to the disposition returned by [`try_handle_incoming_for_listener`].
911///
912/// Returns true if we have found the right socket and there is no need to
913/// continue the iteration for finding the next-best candidate.
914fn try_handle_listener_incoming_disposition<SockI, WireI, CC, BC, Addr>(
915    core_ctx: &mut CC,
916    bindings_ctx: &mut BC,
917    disposition: ListenerIncomingSegmentDisposition<PrimaryRc<SockI, CC::WeakDeviceId, BC>>,
918    demux_listener_id: &WireI::DemuxSocketId<CC::WeakDeviceId, BC>,
919    tw_reuse: &mut Option<(WireI::DemuxSocketId<CC::WeakDeviceId, BC>, Addr)>,
920    addrs_to_search: &mut AddrVecIter<WireI, CC::WeakDeviceId, TcpPortSpec>,
921    conn_addr: ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>,
922    incoming_device: &CC::DeviceId,
923) -> bool
924where
925    SockI: DualStackIpExt,
926    WireI: DualStackIpExt,
927    CC: TcpContext<SockI, BC> + TcpContext<WireI, BC> + TcpContext<WireI::OtherVersion, BC>,
928    BC: TcpBindingsContext<CC::DeviceId>,
929{
930    match disposition {
931        ListenerIncomingSegmentDisposition::FoundSocket => true,
932        ListenerIncomingSegmentDisposition::Filtered => true,
933        ListenerIncomingSegmentDisposition::ConflictingConnection => {
934            // We're about to rewind the lookup. If we got a
935            // conflicting connection it means tw_reuse has been
936            // removed from the demux state and we need to destroy
937            // it.
938            if let Some((tw_reuse, _)) = tw_reuse.take() {
939                WireI::destroy_socket_with_demux_id(core_ctx, bindings_ctx, tw_reuse);
940            }
941
942            // Reset the address vector iterator and go again, a
943            // conflicting connection was found.
944            *addrs_to_search = AddrVecIter::<WireI, CC::WeakDeviceId, TcpPortSpec>::with_device(
945                conn_addr.into(),
946                incoming_device.downgrade(),
947            );
948            false
949        }
950        ListenerIncomingSegmentDisposition::NoMatchingSocket => false,
951        ListenerIncomingSegmentDisposition::NewConnection(primary) => {
952            // If we have a new connection, we need to add it to the
953            // set of all sockets.
954
955            // First things first, if we got here then tw_reuse is
956            // gone so we need to destroy it.
957            if let Some((tw_reuse, _)) = tw_reuse.take() {
958                WireI::destroy_socket_with_demux_id(core_ctx, bindings_ctx, tw_reuse);
959            }
960
961            // Now put the new connection into the socket map.
962            //
963            // Note that there's a possible subtle race here where
964            // another thread could have already operated further on
965            // this connection and marked it for destruction which
966            // puts the entry in the DOA state, if we see that we
967            // must immediately destroy the socket after having put
968            // it in the map.
969            let id = TcpSocketId(PrimaryRc::clone_strong(&primary));
970            let to_destroy = core_ctx.with_all_sockets_mut(move |all_sockets| {
971                let insert_entry = TcpSocketSetEntry::Primary(primary);
972                match all_sockets.entry(id) {
973                    hash_map::Entry::Vacant(v) => {
974                        let _: &mut _ = v.insert(insert_entry);
975                        None
976                    }
977                    hash_map::Entry::Occupied(mut o) => {
978                        // We're holding on to the primary ref, the
979                        // only possible state here should be a DOA
980                        // entry.
981                        assert_matches!(
982                            core::mem::replace(o.get_mut(), insert_entry),
983                            TcpSocketSetEntry::DeadOnArrival
984                        );
985                        Some(o.key().clone())
986                    }
987                }
988            });
989            // NB: we're releasing and reaquiring the
990            // all_sockets_mut lock here for the convenience of not
991            // needing different versions of `destroy_socket`. This
992            // should be fine because the race this is solving
993            // should not be common. If we have correct thread
994            // attribution per flow it should effectively become
995            // impossible so we go for code simplicity here.
996            if let Some(to_destroy) = to_destroy {
997                socket::destroy_socket(core_ctx, bindings_ctx, to_destroy);
998            }
999            counters::increment_counter_for_demux_id::<WireI, _, _, _, _>(
1000                core_ctx,
1001                demux_listener_id,
1002                |c| &c.passive_connection_openings,
1003            );
1004            true
1005        }
1006    }
1007}
1008
1009/// Tries to handle an incoming segment by passing it to a listening socket.
1010///
1011/// Returns `FoundSocket` if the segment was handled, otherwise `NoMatchingSocket`.
1012fn try_handle_incoming_for_listener<SockI, WireI, CC, BC, DC, H>(
1013    core_ctx: &mut DC,
1014    bindings_ctx: &mut BC,
1015    listener_id: &TcpSocketId<SockI, CC::WeakDeviceId, BC>,
1016    isn: &IsnGenerator<BC::Instant>,
1017    timestamp_offset: &TimestampOffsetGenerator<BC::Instant>,
1018    socket_state: &mut TcpSocketState<SockI, CC::WeakDeviceId, BC>,
1019    header_info: &H,
1020    incoming: &VerifiedTcpSegment<'_>,
1021    incoming_addrs: ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>,
1022    incoming_device: &CC::DeviceId,
1023    tw_reuse: &mut Option<(
1024        WireI::DemuxSocketId<CC::WeakDeviceId, BC>,
1025        ConnAddr<ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>, CC::WeakDeviceId>,
1026    )>,
1027    make_connection: impl FnOnce(
1028        Connection<SockI, WireI, CC::WeakDeviceId, BC>,
1029        ConnAddr<ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>, CC::WeakDeviceId>,
1030    ) -> SockI::ConnectionAndAddr<CC::WeakDeviceId, BC>,
1031    make_demux_id: impl Fn(
1032        TcpSocketId<SockI, CC::WeakDeviceId, BC>,
1033    ) -> WireI::DemuxSocketId<CC::WeakDeviceId, BC>,
1034    marks: &Marks,
1035    packet_type: PacketType,
1036    gso_info: Option<GsoInfo>,
1037) -> ListenerIncomingSegmentDisposition<PrimaryRc<SockI, CC::WeakDeviceId, BC>>
1038where
1039    SockI: DualStackIpExt,
1040    WireI: DualStackIpExt,
1041    BC: TcpBindingsContext<CC::DeviceId>
1042        + BufferProvider<
1043            BC::ReceiveBuffer,
1044            BC::SendBuffer,
1045            ActiveOpen = <BC as TcpBindingsTypes>::ListenerNotifierOrProvidedBuffers,
1046            PassiveOpen = <BC as TcpBindingsTypes>::ReturnedBuffers,
1047        >,
1048    CC: TcpContext<SockI, BC>,
1049    DC: TransportIpContext<WireI, BC, DeviceId = CC::DeviceId, WeakDeviceId = CC::WeakDeviceId>
1050        + DeviceIpSocketHandler<WireI, BC>
1051        + TcpDemuxContext<WireI, CC::WeakDeviceId, BC>
1052        + TcpCounterContext<SockI, CC::WeakDeviceId, BC>
1053        + CoreTxMetadataContext<TcpSocketTxMetadata<SockI, CC::WeakDeviceId, BC>, BC>,
1054    H: IpHeaderInfo<WireI>,
1055{
1056    let Listener { addr: listener_addr, accept_queue, backlog, buffer_sizes } =
1057        match &socket_state.socket_state {
1058            TcpSocketStateInner::Bound(_) => {
1059                // If the socket is only bound, but not listening.
1060                return ListenerIncomingSegmentDisposition::NoMatchingSocket;
1061            }
1062            TcpSocketStateInner::Listener(listener) => listener,
1063            _ => panic!("unexpected socket state: {:?}", socket_state.socket_state),
1064        };
1065
1066    let ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) } =
1067        incoming_addrs;
1068
1069    let marks = BC::update_ingress_marks(*marks, &socket_state.socket_options.ip_options.marks);
1070
1071    match run_socket_ingress_filter(
1072        bindings_ctx,
1073        incoming_device,
1074        listener_id.socket_info(),
1075        &socket_state.socket_options,
1076        &marks,
1077        header_info,
1078        incoming.tcp_segment(),
1079        packet_type,
1080        gso_info,
1081    ) {
1082        SocketIngressFilterResult::Accept => (),
1083        SocketIngressFilterResult::Drop => {
1084            return ListenerIncomingSegmentDisposition::Filtered;
1085        }
1086    }
1087
1088    // Note that this checks happens at the very beginning, before we try to
1089    // reuse the connection in TIME-WAIT, this is because we need to store the
1090    // reused connection in the accept queue so we have to respect its limit.
1091    if accept_queue.len() == backlog.get() {
1092        core_ctx.increment_both(listener_id, |counters| &counters.listener_queue_overflow);
1093        core_ctx.increment_both(listener_id, |counters| &counters.failed_connection_attempts);
1094        debug!("incoming SYN dropped because of the full backlog of the listener");
1095        return ListenerIncomingSegmentDisposition::FoundSocket;
1096    }
1097
1098    // Ensure that if the remote address requires a zone, we propagate that to
1099    // the address for the connected socket.
1100    let bound_device = listener_addr.as_ref().clone();
1101    let bound_device = if remote_ip.as_ref().must_have_zone() {
1102        Some(bound_device.map_or(EitherDeviceId::Strong(incoming_device), EitherDeviceId::Weak))
1103    } else {
1104        bound_device.map(EitherDeviceId::Weak)
1105    };
1106
1107    let ip_options = TcpIpSockOptions { marks, ..socket_state.socket_options.ip_options };
1108    let socket_options = SocketOptions { ip_options, ..socket_state.socket_options };
1109
1110    let bound_device = bound_device.as_ref().map(|d| d.as_ref());
1111    let ip_sock = match core_ctx.new_ip_socket(
1112        bindings_ctx,
1113        IpSocketArgs {
1114            device: bound_device,
1115            local_ip: IpDeviceAddr::new_from_socket_ip_addr(local_ip),
1116            remote_ip,
1117            proto: IpProto::Tcp.into(),
1118            options: &ip_options,
1119        },
1120    ) {
1121        Ok(ip_sock) => ip_sock,
1122        err @ Err(IpSockCreationError::Route(_)) => {
1123            core_ctx.increment_both(listener_id, |counters| &counters.passive_open_no_route_errors);
1124            core_ctx.increment_both(listener_id, |counters| &counters.failed_connection_attempts);
1125            debug!("cannot construct an ip socket to the SYN originator: {:?}, ignoring", err);
1126            return ListenerIncomingSegmentDisposition::NoMatchingSocket;
1127        }
1128    };
1129
1130    let isn = isn.generate(
1131        bindings_ctx.now(),
1132        (ip_sock.local_ip().clone().into(), local_port),
1133        (ip_sock.remote_ip().clone(), remote_port),
1134    );
1135    let timestamp_offset = timestamp_offset.generate::<SocketIpAddr<WireI::Addr>, NonZeroU16>(
1136        bindings_ctx.now(),
1137        (ip_sock.local_ip().clone().into(), local_port),
1138        (ip_sock.remote_ip().clone(), remote_port),
1139    );
1140    let device_mms = match core_ctx.get_mms(bindings_ctx, &ip_sock, &socket_options.ip_options) {
1141        Ok(mms) => mms,
1142        Err(err) => {
1143            // If we cannot find a device or the device's MTU is too small,
1144            // there isn't much we can do here since sending a RST back is
1145            // impossible, we just need to silent drop the segment.
1146            error!("Cannot find a device with large enough MTU for the connection");
1147            core_ctx.increment_both(listener_id, |counters| &counters.failed_connection_attempts);
1148            match err {
1149                MmsError::NoDevice(_) | MmsError::MTUTooSmall(_) => {
1150                    return ListenerIncomingSegmentDisposition::FoundSocket;
1151                }
1152            }
1153        }
1154    };
1155    let Some(device_mss) = Mss::from_mms(device_mms) else {
1156        return ListenerIncomingSegmentDisposition::FoundSocket;
1157    };
1158
1159    let mut state = State::Listen(Closed::<Initial>::listen(
1160        isn,
1161        timestamp_offset,
1162        buffer_sizes.clone(),
1163        device_mss,
1164        Mss::default::<WireI>(),
1165        socket_options.user_timeout,
1166    ));
1167
1168    // Prepare a reply to be sent out.
1169    //
1170    // We might end up discarding the reply in case we can't instantiate this
1171    // new connection.
1172    let result = state.on_segment::<_, BC>(
1173        // NB: This is a bit of a lie, we're passing the listener ID to process
1174        // the first segment because we don't have an ID allocated yet. This is
1175        // okay because the state machine ID is only for debugging purposes.
1176        &listener_id.either(),
1177        &TcpCountersRefs::from_ctx(core_ctx, listener_id),
1178        incoming.into(),
1179        bindings_ctx.now(),
1180        &SocketOptions::default(),
1181        false, /* defunct */
1182    );
1183    let reply = assert_matches!(
1184        result,
1185        (reply, None, /* data_acked */ _, NewlyClosed::No /* can't become closed */) => reply
1186    );
1187
1188    let result = if matches!(state, State::SynRcvd(_)) {
1189        let poll_send_at = state.poll_send_at().expect("no retrans timer");
1190        let bound_device = ip_sock.device().cloned();
1191
1192        let addr = ConnAddr {
1193            ip: ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) },
1194            device: bound_device,
1195        };
1196
1197        let new_socket = core_ctx.with_demux_mut(|DemuxState { socketmap, .. }| {
1198            // If we're reusing an entry, remove it from the demux before
1199            // proceeding.
1200            //
1201            // We could just reuse the old allocation for the new connection but
1202            // because of the restrictions on the socket map data structure (for
1203            // good reasons), we can't update the sharing info unconditionally.
1204            // So here we just remove the old connection and create a new one.
1205            // Also this approach has the benefit of not accidentally persisting
1206            // the old state that we don't want.
1207            if let Some((tw_reuse, conn_addr)) = tw_reuse {
1208                match socketmap.conns_mut().remove(tw_reuse, &conn_addr) {
1209                    Ok(()) => {
1210                        // NB: We're removing the tw_reuse connection from the
1211                        // demux here, but not canceling its timer. The timer is
1212                        // canceled via drop when we destroy the socket. Special
1213                        // care is taken when handling timers in the time wait
1214                        // state to account for this.
1215                    }
1216                    Err(NotFoundError) => {
1217                        // We could lose a race trying to reuse the tw_reuse
1218                        // socket, so we just accept the loss and be happy that
1219                        // the conn_addr we want to use is free.
1220                    }
1221                }
1222            }
1223
1224            // Try to create and add the new socket to the demux.
1225            let accept_queue_clone = accept_queue.clone();
1226            let ip_sock = ip_sock.clone();
1227            let bindings_ctx_moved = &mut *bindings_ctx;
1228            let sharing = socket_state.sharing;
1229            match socketmap.conns_mut().try_insert_with(addr, sharing, move |addr, sharing| {
1230                let conn = make_connection(
1231                    Connection {
1232                        accept_queue: Some(accept_queue_clone),
1233                        state,
1234                        ip_sock,
1235                        defunct: false,
1236                        soft_error: None,
1237                        handshake_status: HandshakeStatus::Pending,
1238                    },
1239                    addr,
1240                );
1241
1242                let (id, primary) = TcpSocketId::new_cyclic(
1243                    |weak| {
1244                        let mut timer = CC::new_timer(bindings_ctx_moved, weak);
1245                        // Schedule the timer here because we can't acquire the lock
1246                        // later. This only runs when inserting into the demux
1247                        // succeeds so it's okay.
1248                        assert_eq!(
1249                            bindings_ctx_moved.schedule_timer_instant(poll_send_at, &mut timer),
1250                            None
1251                        );
1252                        TcpSocketStateInner::Connected { conn, timer }
1253                    },
1254                    sharing,
1255                    socket_options,
1256                );
1257                (make_demux_id(id.clone()), (primary, id))
1258            }) {
1259                Ok((_entry, (primary, id))) => {
1260                    // Make sure the new socket is in the pending accept queue
1261                    // before we release the demux lock.
1262                    accept_queue.push_pending(id);
1263                    Some(primary)
1264                }
1265                Err(e) => {
1266                    // The only error we accept here is if the entry exists
1267                    // fully, any indirect conflicts are unexpected because we
1268                    // know the listener is still alive and installed in the
1269                    // demux.
1270                    assert_matches!(e, InsertError::Exists);
1271                    // If we fail to insert it means we lost a race and this
1272                    // packet is destined to a connection that is already
1273                    // established. In that case we should tell the demux code
1274                    // to retry demuxing it all over again.
1275                    None
1276                }
1277            }
1278        });
1279
1280        match new_socket {
1281            Some(new_socket) => ListenerIncomingSegmentDisposition::NewConnection(new_socket),
1282            None => {
1283                // We didn't create a new connection, short circuit early and
1284                // don't send out the pending segment.
1285                core_ctx
1286                    .increment_both(listener_id, |counters| &counters.failed_connection_attempts);
1287                return ListenerIncomingSegmentDisposition::ConflictingConnection;
1288            }
1289        }
1290    } else {
1291        // We found a valid listener for the segment even if the connection
1292        // state is not a newly pending connection.
1293        ListenerIncomingSegmentDisposition::FoundSocket
1294    };
1295
1296    // We can send a reply now if we got here.
1297    if let Some(seg) = reply {
1298        socket::send_tcp_segment(
1299            core_ctx,
1300            bindings_ctx,
1301            Some(&listener_id),
1302            Some(&ip_sock),
1303            incoming_addrs,
1304            seg.into_empty(),
1305            &socket_options.ip_options,
1306        );
1307    }
1308
1309    result
1310}
1311
1312pub(super) fn tcp_serialize_segment<'a, I, P>(
1313    header: &'a SegmentHeader,
1314    data: P,
1315    conn_addr: ConnIpAddr<I::Addr, NonZeroU16, NonZeroU16>,
1316) -> impl TransportPacketSerializer<I, Buffer = EmptyBuf>
1317+ MaybeSegmentableTransportSerializer
1318+ Debug
1319+ 'a
1320where
1321    I: FilterIpExt,
1322    P: InnerPacketBuilder + Copy + Debug + Payload + 'a,
1323{
1324    let SegmentHeader { seq, ack, wnd, control, options, push } = header;
1325    let ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) } = conn_addr;
1326    let mut builder = TcpSegmentBuilder::new(
1327        local_ip.addr(),
1328        remote_ip.addr(),
1329        local_port,
1330        remote_port,
1331        (*seq).into(),
1332        ack.map(Into::into),
1333        u16::from(*wnd),
1334    );
1335    builder.psh(*push);
1336    match control {
1337        None => {}
1338        Some(Control::SYN) => builder.syn(true),
1339        Some(Control::FIN) => builder.fin(true),
1340        Some(Control::RST) => builder.rst(true),
1341    }
1342    TcpSegmentBuilderWithOptions::new(builder, options.builder())
1343        .unwrap_or_else(|TcpOptionsTooLongError| {
1344            panic!("Too many TCP options");
1345        })
1346        .wrap_body(data.into_serializer())
1347}
1348
1349fn run_socket_ingress_filter<I, BC, D>(
1350    bindings_ctx: &BC,
1351    incoming_device: &D,
1352    socket_info: netstack3_base::socket::SocketInfo,
1353    socket_options: &SocketOptions,
1354    packet_marks: &Marks,
1355    header_info: &impl IpHeaderInfo<I>,
1356    tcp_segment: &TcpSegment<&'_ [u8]>,
1357    packet_type: PacketType,
1358    gso_info: Option<GsoInfo>,
1359) -> SocketIngressFilterResult
1360where
1361    I: Ip,
1362    BC: TcpBindingsContext<D>,
1363    D: StrongDeviceIdentifier,
1364{
1365    let [ip_prefix, ip_options] = header_info.as_bytes();
1366    let [tcp_prefix, tcp_options, _data] = tcp_segment.as_bytes();
1367    let mut slices = [ip_prefix, ip_options, tcp_prefix, tcp_options, _data];
1368    let packet = FragmentedByteSlice::new(&mut slices);
1369    let header_len = ip_prefix.len() + ip_options.len() + tcp_prefix.len() + tcp_options.len();
1370
1371    let marks = BC::update_ingress_marks(*packet_marks, &socket_options.ip_options.marks);
1372    bindings_ctx.socket_ops_filter().on_ingress(
1373        I::VERSION,
1374        packet,
1375        header_len,
1376        incoming_device,
1377        socket_info,
1378        &marks,
1379        packet_type,
1380        gso_info,
1381    )
1382}
1383
1384#[cfg(test)]
1385mod test {
1386    use ip_test_macro::ip_test;
1387    use netstack3_base::{
1388        HandshakeOptions, NetworkSerializationContext, Options, ResetOptions, SackBlocks,
1389        SegmentOptions, UnscaledWindowSize,
1390    };
1391    use packet::Serializer as _;
1392    use packet_formats::tcp::options::TcpOptions as _;
1393    use test_case::test_case;
1394
1395    use super::*;
1396
1397    trait TestIpExt: netstack3_base::testutil::TestIpExt + FilterIpExt {}
1398    impl<T> TestIpExt for T where T: netstack3_base::testutil::TestIpExt + FilterIpExt {}
1399
1400    const SEQ: SeqNum = SeqNum::new(12345);
1401    const ACK: SeqNum = SeqNum::new(67890);
1402    const FAKE_DATA: &'static [u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
1403
1404    #[ip_test(I)]
1405    #[test_case(
1406        Segment::syn(SEQ, UnscaledWindowSize::from(u16::MAX),
1407        HandshakeOptions::default()), &[]
1408        ; "syn")]
1409    #[test_case(
1410        Segment::syn(SEQ, UnscaledWindowSize::from(u16::MAX),
1411        HandshakeOptions {
1412            mss: Some(Mss::new(1440).unwrap()),
1413            ..Default::default() }), &[]
1414            ; "syn with mss")]
1415    #[test_case(
1416        Segment::ack(SEQ, ACK, UnscaledWindowSize::from(u16::MAX), SegmentOptions::default()),
1417        &[]; "ack")]
1418    #[test_case(Segment::with_fake_data(SEQ, ACK, FAKE_DATA), FAKE_DATA; "data")]
1419    #[test_case(Segment::new_assert_no_discard(SegmentHeader {
1420            seq: SEQ,
1421            ack: Some(ACK),
1422            push: true,
1423            wnd: UnscaledWindowSize::from(u16::MAX),
1424            ..Default::default()
1425        },
1426        FAKE_DATA
1427    ), FAKE_DATA; "push")]
1428    fn tcp_serialize_segment<I: TestIpExt>(segment: Segment<&[u8]>, expected_body: &[u8]) {
1429        const SOURCE_PORT: NonZeroU16 = NonZeroU16::new(1111).unwrap();
1430        const DEST_PORT: NonZeroU16 = NonZeroU16::new(2222).unwrap();
1431
1432        let (header, data) = segment.into_parts();
1433        let serializer = super::tcp_serialize_segment::<I, _>(
1434            &header,
1435            data,
1436            ConnIpAddr {
1437                local: (SocketIpAddr::try_from(I::TEST_ADDRS.local_ip).unwrap(), SOURCE_PORT),
1438                remote: (SocketIpAddr::try_from(I::TEST_ADDRS.remote_ip).unwrap(), DEST_PORT),
1439            },
1440        );
1441
1442        let mut serialized = serializer
1443            .serialize_vec_outer(&mut NetworkSerializationContext::default())
1444            .unwrap()
1445            .unwrap_b();
1446        let parsed_segment = serialized
1447            .parse_with::<_, TcpSegment<_>>(TcpParseArgs::new(
1448                *I::TEST_ADDRS.remote_ip,
1449                *I::TEST_ADDRS.local_ip,
1450            ))
1451            .expect("is valid segment");
1452
1453        assert_eq!(parsed_segment.src_port(), SOURCE_PORT);
1454        assert_eq!(parsed_segment.dst_port(), DEST_PORT);
1455        assert_eq!(parsed_segment.seq_num(), u32::from(SEQ));
1456        assert_eq!(parsed_segment.psh(), header.push);
1457        assert_eq!(
1458            UnscaledWindowSize::from(parsed_segment.window_size()),
1459            UnscaledWindowSize::from(u16::MAX)
1460        );
1461
1462        let (mss, window_scale, sack_permitted, sack_blocks, timestamp) = match header.options {
1463            Options::Handshake(HandshakeOptions {
1464                mss,
1465                window_scale,
1466                sack_permitted,
1467                timestamp,
1468            }) => (mss, window_scale, sack_permitted, SackBlocks::EMPTY, timestamp),
1469            Options::Segment(SegmentOptions { timestamp, sack_blocks }) => {
1470                (None, None, false, sack_blocks, timestamp)
1471            }
1472            Options::Reset(ResetOptions { timestamp }) => {
1473                (None, None, false, SackBlocks::EMPTY, timestamp)
1474            }
1475        };
1476        assert_eq!(mss.map(|mss| mss.get()), parsed_segment.options().mss());
1477        assert_eq!(window_scale.map(|ws| ws.get()), parsed_segment.options().window_scale());
1478        assert_eq!(sack_permitted, parsed_segment.options().sack_permitted());
1479        assert_eq!(sack_blocks.as_slice(), parsed_segment.options().sack_blocks());
1480        assert_eq!(
1481            timestamp.as_ref().map(Into::into).as_ref(),
1482            parsed_segment.options().timestamp()
1483        );
1484
1485        assert_eq!(parsed_segment.into_body(), expected_body);
1486    }
1487}