pub(crate) fn receive_ipv4_packet<B: BufferMut, D: BufferDispatcher<B>>(
    ctx: &mut Ctx<D>,
    device: DeviceId,
    frame_dst: FrameDestination,
    mut buffer: B,
) {
    increment_counter!(ctx, "receive_ipv4_packet");
    trace!("receive_ip_packet({})", device);

    let mut packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
        Ok(packet) => packet,
        // Conditionally send an ICMP response if we encountered a parameter
        // problem error when parsing an IPv4 packet. Note, we do not always
        // send back an ICMP response as it can be used as an attack vector for
        // DDoS attacks. We only send back an ICMP response if the RFC requires
        // that we MUST send one, as noted by `must_send_icmp` and `action`.
        // TODO(https://fxbug.dev/77598): test this code path once
        // `Ipv4Packet::parse` can return an `IpParseError::ParameterProblem`
        // error.
        Err(IpParseError::ParameterProblem {
            src_ip,
            dst_ip,
            code,
            pointer,
            must_send_icmp,
            header_len,
            action,
        }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
            // `should_send_icmp_to_multicast` should never return `true` for IPv4.
            assert!(!action.should_send_icmp_to_multicast());
            let dst_ip = try_unit!(SpecifiedAddr::new(dst_ip), debug!("receive_ipv4_packet: Received packet with unspecified destination IP address; dropping"));
            let src_ip = try_unit!(SpecifiedAddr::new(src_ip), trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address"));
            send_icmpv4_parameter_problem(
                ctx,
                device,
                frame_dst,
                src_ip,
                dst_ip,
                code,
                Icmpv4ParameterProblem::new(pointer),
                buffer,
                header_len,
                // When the call to `action.should_send_icmp` returns true, it always means that
                // the IPv4 packet that failed parsing is an initial fragment.
                Ipv4FragmentType::InitialFragment,
            );
            return;
        }
        _ => return, // TODO(joshlf): Do something with ICMP here?
    };

    let dst_ip = try_unit!(SpecifiedAddr::new(packet.dst_ip()), debug!("receive_ipv4_packet: Received packet with unspecified destination IP address; dropping"));

    // TODO(ghanan): Act upon options.

    if Ipv4::LOOPBACK_SUBNET.contains(&dst_ip) {
        // A packet from outside this host was sent with the destination IP of
        // the loopback address, which is illegal. Loopback traffic is handled
        // explicitly in send_ip_packet.
        //
        // TODO(joshlf): Do something with ICMP here?
        debug!("got packet from remote host for loopback address {}", packet.dst_ip());
    } else if deliver_ipv4(ctx, device, dst_ip) {
        trace!("receive_ipv4_packet: delivering locally");
        let src_ip = packet.src_ip();

        // Process a potential IPv4 fragment if the destination is this host.
        //
        // We process IPv4 packet reassembly here because, for IPv4, the
        // fragment data is in the header itself so we can handle it right away.
        //
        // Note, the `process_fragment` function (which is called by the
        // `process_fragment!` macro) could panic if the packet does not have
        // fragment data. However, we are guaranteed that it will not panic
        // because the fragment data is in the fixed header so it is always
        // present (even if the fragment data has values that implies that the
        // packet is not fragmented).
        process_fragment!(
            ctx,
            dispatch_receive_ipv4_packet,
            device,
            frame_dst,
            buffer,
            packet,
            src_ip,
            dst_ip,
            Ipv4
        );
    } else {
        match forward(ctx, device, dst_ip) {
            ForwardDestination::Destination(dest) => {
                let ttl = packet.ttl();
                if ttl > 1 {
                    trace!("receive_ipv4_packet: forwarding");

                    packet.set_ttl(ttl - 1);
                    let (_, _, _, _) = drop_packet_and_undo_parse!(packet, buffer);
                    if crate::device::send_ip_frame(ctx, dest.device, dest.next_hop, buffer)
                        .is_err()
                    {
                        debug!("failed to forward IPv4 packet: MTU exceeded");
                    }
                } else {
                    // TTL is 0 or would become 0 after decrement; see "TTL"
                    // section, https://tools.ietf.org/html/rfc791#page-14
                    use packet_formats::ipv4::Ipv4Header;
                    debug!("received IPv4 packet dropped due to expired TTL");
                    let fragment_type = packet.fragment_type();
                    let (src_ip, _, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
                    let src_ip = try_unit!(SpecifiedAddr::new(src_ip), trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address"));
                    icmp::send_icmpv4_ttl_expired(
                        ctx,
                        device,
                        frame_dst,
                        src_ip,
                        dst_ip,
                        proto,
                        buffer,
                        meta.header_len(),
                        fragment_type,
                    );
                }
            }
            ForwardDestination::NoRouteToHost => {
                use packet_formats::ipv4::Ipv4Header;
                debug!("received IPv4 packet with no known route to destination {}", dst_ip);
                let fragment_type = packet.fragment_type();
                let (src_ip, _, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
                let src_ip = try_unit!(SpecifiedAddr::new(src_ip), trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address"));
                icmp::send_icmpv4_net_unreachable(
                    ctx,
                    device,
                    frame_dst,
                    src_ip,
                    dst_ip,
                    proto,
                    buffer,
                    meta.header_len(),
                    fragment_type,
                );
            }
            ForwardDestination::ForwardingDisabled => {
                // RFC 1122 § 3.2.1.3 "A host MUST silently discard an incoming
                // datagram that is not destined for the host." If forwarding is
                // disabled (we are not acting as a router) we follow this host
                // rule.
                debug!(
                    "received IPv4 packet to non-local destination {} with forwarding disabled",
                    packet.dst_ip()
                );
            }
        }
    }
}
/// Receive an IPv4 packet from a device.
///
/// `frame_dst` specifies whether this packet was received in a broadcast or
/// unicast link-layer frame.
Receive an IPv4 packet from a device.
`frame_dst` specifies whether this packet was received in a broadcast or
unicast link-layer frame.
Receive an IPv4 packet from a device . ` frame_dst ` specifies whether this packet was received in a broadcast or unicast link - layer frame .
pub(crate) fn receive_ipv4_packet<B: BufferMut, D: BufferDispatcher<B>>(
    ctx: &mut Ctx<D>,
    device: DeviceId,
    frame_dst: FrameDestination,
    mut buffer: B,
) {
    increment_counter!(ctx, "receive_ipv4_packet");
    trace!("receive_ip_packet({})", device);
    let mut packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
        Ok(packet) => packet,
        // Conditionally send an ICMP response if we encountered a parameter
        // problem error when parsing an IPv4 packet. Note, we do not always
        // send back an ICMP response as it can be used as an attack vector for
        // DDoS attacks. We only send back an ICMP response if the RFC requires
        // that we MUST send one, as noted by `must_send_icmp` and `action`.
        // TODO(https://fxbug.dev/77598): test this code path once
        // `Ipv4Packet::parse` can return an `IpParseError::ParameterProblem`
        // error.
        Err(IpParseError::ParameterProblem {
            src_ip,
            dst_ip,
            code,
            pointer,
            must_send_icmp,
            header_len,
            action,
        }) if must_send_icmp && action.should_send_icmp(&dst_ip) => {
            // `should_send_icmp_to_multicast` should never return `true` for IPv4.
            assert!(!action.should_send_icmp_to_multicast());
            let dst_ip = try_unit!(SpecifiedAddr::new(dst_ip), debug!("receive_ipv4_packet: Received packet with unspecified destination IP address; dropping"));
            let src_ip = try_unit!(SpecifiedAddr::new(src_ip), trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address"));
            send_icmpv4_parameter_problem(
                ctx,
                device,
                frame_dst,
                src_ip,
                dst_ip,
                code,
                Icmpv4ParameterProblem::new(pointer),
                buffer,
                header_len,
                // When the call to `action.should_send_icmp` returns true, it always means that
                // the IPv4 packet that failed parsing is an initial fragment.
                Ipv4FragmentType::InitialFragment,
            );
            return;
        }
        _ => return, // TODO(joshlf): Do something with ICMP here?
    };
    let dst_ip = try_unit!(SpecifiedAddr::new(packet.dst_ip()), debug!("receive_ipv4_packet: Received packet with unspecified destination IP address; dropping"));
    // TODO(ghanan): Act upon options.
    if Ipv4::LOOPBACK_SUBNET.contains(&dst_ip) {
        // A packet from outside this host was sent with the destination IP of
        // the loopback address, which is illegal. Loopback traffic is handled
        // explicitly in send_ip_packet.
        //
        // TODO(joshlf): Do something with ICMP here?
        debug!("got packet from remote host for loopback address {}", packet.dst_ip());
    } else if deliver_ipv4(ctx, device, dst_ip) {
        trace!("receive_ipv4_packet: delivering locally");
        let src_ip = packet.src_ip();
        // Process a potential IPv4 fragment if the destination is this host.
        //
        // We process IPv4 packet reassembly here because, for IPv4, the
        // fragment data is in the header itself so we can handle it right away.
        //
        // Note, the `process_fragment` function (which is called by the
        // `process_fragment!` macro) could panic if the packet does not have
        // fragment data. However, we are guaranteed that it will not panic
        // because the fragment data is in the fixed header so it is always
        // present (even if the fragment data has values that implies that the
        // packet is not fragmented).
        process_fragment!(
            ctx,
            dispatch_receive_ipv4_packet,
            device,
            frame_dst,
            buffer,
            packet,
            src_ip,
            dst_ip,
            Ipv4
        );
    } else {
        match forward(ctx, device, dst_ip) {
            ForwardDestination::Destination(dest) => {
                let ttl = packet.ttl();
                if ttl > 1 {
                    trace!("receive_ipv4_packet: forwarding");
                    packet.set_ttl(ttl - 1);
                    let (_, _, _, _) = drop_packet_and_undo_parse!(packet, buffer);
                    if crate::device::send_ip_frame(ctx, dest.device, dest.next_hop, buffer)
                        .is_err()
                    {
                        debug!("failed to forward IPv4 packet: MTU exceeded");
                    }
                } else {
                    // TTL is 0 or would become 0 after decrement; see "TTL"
                    // section, https://tools.ietf.org/html/rfc791#page-14
                    use packet_formats::ipv4::Ipv4Header;
                    debug!("received IPv4 packet dropped due to expired TTL");
                    let fragment_type = packet.fragment_type();
                    let (src_ip, _, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
                    let src_ip = try_unit!(SpecifiedAddr::new(src_ip), trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address"));
                    icmp::send_icmpv4_ttl_expired(
                        ctx,
                        device,
                        frame_dst,
                        src_ip,
                        dst_ip,
                        proto,
                        buffer,
                        meta.header_len(),
                        fragment_type,
                    );
                }
            }
            ForwardDestination::NoRouteToHost => {
                use packet_formats::ipv4::Ipv4Header;
                debug!("received IPv4 packet with no known route to destination {}", dst_ip);
                let fragment_type = packet.fragment_type();
                let (src_ip, _, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
                let src_ip = try_unit!(SpecifiedAddr::new(src_ip), trace!("receive_ipv4_packet: Cannot send ICMP error in response to packet with unspecified source IP address"));
                icmp::send_icmpv4_net_unreachable(
                    ctx,
                    device,
                    frame_dst,
                    src_ip,
                    dst_ip,
                    proto,
                    buffer,
                    meta.header_len(),
                    fragment_type,
                );
            }
            ForwardDestination::ForwardingDisabled => {
                // RFC 1122 § 3.2.1.3 "A host MUST silently discard an incoming
                // datagram that is not destined for the host." If forwarding is
                // disabled (we are not acting as a router) we follow this host
                // rule.
                debug!(
                    "received IPv4 packet to non-local destination {} with forwarding disabled",
                    packet.dst_ip()
                );
            }
        }
    }
}
pub ( crate ) fn receive_ipv4_packet < B : BufferMut , D : BufferDispatcher < B > > ( ctx : & mut Ctx < D > , device : DeviceId , frame_dst : FrameDestination , mut buffer : B , ) { increment_counter ! ( ctx " " ) ; trace ! ( " " device ) ; let mut packet : Ipv4Packet < _ > = match try_parse_ip_packet ! ( buffer ) { Ok ( packet ) => packet , // Conditionally send an ICMP response if we encountered a parameter // problem error when parsing an IPv4 packet. Note, we do not always // send back an ICMP response as it can be used as an attack vector for // DDoS attacks. We only send back an ICMP response if the RFC requires // that we MUST send one, as noted by `must_send_icmp` and `action`. // TODO(https://fxbug.dev/77598): test this code path once // `Ipv4Packet::parse` can return an `IpParseError::ParameterProblem` // error. Err ( IpParseError :: ParameterProblem { src_ip , dst_ip , code , pointer , must_send_icmp , header_len , action , } ) if must_send_icmp && action . should_send_icmp ( & dst_ip ) => { // `should_send_icmp_to_multicast` should never return `true` for IPv4. assert ! ( action should_send_icmp_to_multicast ( ) ) ; let dst_ip = try_unit ! ( SpecifiedAddr new ( dst_ip ) debug ( " " ) ) ; let src_ip = try_unit ! ( SpecifiedAddr new ( src_ip ) trace ( " " ) ) ; send_icmpv4_parameter_problem ( ctx , device , frame_dst , src_ip , dst_ip , code , Icmpv4ParameterProblem :: new ( pointer ) , buffer , header_len , // When the call to `action.should_send_icmp` returns true, it always means that // the IPv4 packet that failed parsing is an initial fragment. Ipv4FragmentType :: InitialFragment , ) ; return ; } _ => return , // TODO(joshlf): Do something with ICMP here? } ; let dst_ip = try_unit ! ( SpecifiedAddr new ( packet dst_ip ( ) ) debug ( " " ) ) ; // TODO(ghanan): Act upon options. if Ipv4 :: LOOPBACK_SUBNET . contains ( & dst_ip ) { // A packet from outside this host was sent with the destination IP of // the loopback address, which is illegal. Loopback traffic is handled // explicitly in send_ip_packet. // // TODO(joshlf): Do something with ICMP here? debug ! ( " " packet dst_ip ( ) ) ; } else if deliver_ipv4 ( ctx , device , dst_ip ) { trace ! ( " " ) ; let src_ip = packet . src_ip ( ) ; // Process a potential IPv4 fragment if the destination is this host. // // We process IPv4 packet reassembly here because, for IPv4, the // fragment data is in the header itself so we can handle it right away. // // Note, the `process_fragment` function (which is called by the // `process_fragment!` macro) could panic if the packet does not have // fragment data. However, we are guaranteed that it will not panic // because the fragment data is in the fixed header so it is always // present (even if the fragment data has values that implies that the // packet is not fragmented). process_fragment ! ( ctx dispatch_receive_ipv4_packet device frame_dst buffer packet src_ip dst_ip Ipv4 ) ; } else { match forward ( ctx , device , dst_ip ) { ForwardDestination :: Destination ( dest ) => { let ttl = packet . ttl ( ) ; if ttl > 1 { trace ! ( " " ) ; packet . set_ttl ( ttl - 1 ) ; let ( _ , _ , _ , _ ) = drop_packet_and_undo_parse ! ( packet buffer ) ; if crate :: device :: send_ip_frame ( ctx , dest . device , dest . next_hop , buffer ) . is_err ( ) { debug ! ( " " ) ; } } else { // TTL is 0 or would become 0 after decrement; see "TTL" // section, https://tools.ietf.org/html/rfc791#page-14 use packet_formats :: ipv4 :: Ipv4Header ; debug ! ( " " ) ; let fragment_type = packet . fragment_type ( ) ; let ( src_ip , _ , proto , meta ) = drop_packet_and_undo_parse ! ( packet buffer ) ; let src_ip = try_unit ! ( SpecifiedAddr new ( src_ip ) trace ( " " ) ) ; icmp :: send_icmpv4_ttl_expired ( ctx , device , frame_dst , src_ip , dst_ip , proto , buffer , meta . header_len ( ) , fragment_type , ) ; } } ForwardDestination :: NoRouteToHost => { use packet_formats :: ipv4 :: Ipv4Header ; debug ! ( " " dst_ip ) ; let fragment_type = packet . fragment_type ( ) ; let ( src_ip , _ , proto , meta ) = drop_packet_and_undo_parse ! ( packet buffer ) ; let src_ip = try_unit ! ( SpecifiedAddr new ( src_ip ) trace ( " " ) ) ; icmp :: send_icmpv4_net_unreachable ( ctx , device , frame_dst , src_ip , dst_ip , proto , buffer , meta . header_len ( ) , fragment_type , ) ; } ForwardDestination :: ForwardingDisabled => { // RFC 1122 § 3.2.1.3 "A host MUST silently discard an incoming // datagram that is not destined for the host." If forwarding is // disabled (we are not acting as a router) we follow this host // rule. debug ! ( " " packet dst_ip ( ) ) ; } } } }
Receive an IPv4 packet from a device.
Receive an IPv4 packet from a device .
ctx
&mut Ctx<D>
device
DeviceId
frame_dst
FrameDestination
buffer
B
ctx
&mut Ctx<D>
device
DeviceId
frame_dst
FrameDestination
buffer
B