fn dispatch_receive_ipv4_packet<B: BufferMut, D: BufferDispatcher<B>>(
    ctx: &mut Ctx<D>,
    device: Option<DeviceId>,
    frame_dst: FrameDestination,
    src_ip: Ipv4Addr,
    dst_ip: SpecifiedAddr<Ipv4Addr>,
    proto: Ipv4Proto,
    buffer: B,
    parse_metadata: Option<ParseMetadata>,
) {
    increment_counter!(ctx, "dispatch_receive_ipv4_packet");

    macro_rules! mtch {
        ($($cond:pat => $ty:ident),*) => {
            match proto {
                Ipv4Proto::Icmp => <IcmpIpTransportContext as BufferIpTransportContext<Ipv4, _, _>>
                            ::receive_ip_packet(ctx, device, src_ip, dst_ip, buffer),
                Ipv4Proto::Igmp => {
                    IgmpPacketHandler::<(), _, _>::receive_igmp_packet(
                        ctx,
                        device.expect("IGMP messages should come from a device"),
                        src_ip,
                        dst_ip,
                        buffer,
                    );
                    Ok(())
                }
                $($cond => <<Ctx<D> as Ipv4TransportLayerContext>::$ty as BufferIpTransportContext<Ipv4, _, _>>
                            ::receive_ip_packet(ctx, device, src_ip, dst_ip, buffer),)*
                // TODO(joshlf): Once all IP protocol numbers are covered,
                // remove this default case.
                _ => Err((
                    buffer,
                    TransportReceiveError { inner: TransportReceiveErrorInner::ProtocolUnsupported },
                )),
            }
        };
    }

    #[rustfmt::skip]
    let res = mtch!(
        Ipv4Proto::Proto(IpProto::Tcp) => Proto6,
        Ipv4Proto::Proto(IpProto::Udp) => Proto17
    );

    if let Err((mut buffer, err)) = res {
        // All branches promise to return the buffer in the same state it was in
        // when they were executed. Thus, all we have to do is undo the parsing
        // of the IP packet header, and the buffer will be back to containing
        // the entire original IP packet.
        let meta = parse_metadata.unwrap();
        buffer.undo_parse(meta);

        if let Some(src_ip) = SpecifiedAddr::new(src_ip) {
            match err.inner {
                TransportReceiveErrorInner::ProtocolUnsupported => {
                    icmp::send_icmpv4_protocol_unreachable(
                        ctx,
                        device.unwrap(),
                        frame_dst,
                        src_ip,
                        dst_ip,
                        buffer,
                        meta.header_len(),
                    );
                }
                TransportReceiveErrorInner::PortUnreachable => {
                    // TODO(joshlf): What if we're called from a loopback
                    // handler, and device and parse_metadata are None? In other
                    // words, what happens if we attempt to send to a loopback
                    // port which is unreachable? We will eventually need to
                    // restructure the control flow here to handle that case.
                    icmp::send_icmpv4_port_unreachable(
                        ctx,
                        device.unwrap(),
                        frame_dst,
                        src_ip,
                        dst_ip,
                        buffer,
                        meta.header_len(),
                    );
                }
            }
        } else {
            trace!("dispatch_receive_ipv4_packet: Cannot send ICMP error message in response to a packet from the unspecified address");
        }
    }
}
/// Dispatch a received IPv4 packet to the appropriate protocol.
///
/// `device` is the device the packet was received on. `parse_metadata` is the
/// parse metadata associated with parsing the IP headers. It is used to undo
/// that parsing. Both `device` and `parse_metadata` are required in order to
/// send ICMP messages in response to unrecognized protocols or ports. If either
/// of `device` or `parse_metadata` is `None`, the caller promises that the
/// protocol and port are recognized.
///
/// # Panics
///
/// `dispatch_receive_ipv4_packet` panics if the protocol is unrecognized and
/// `parse_metadata` is `None`. If an IGMP message is received but it is not
/// coming from a device, i.e., `device` given is `None`,
/// `dispatch_receive_ip_packet` will also panic.
Dispatch a received IPv4 packet to the appropriate protocol.
`device` is the device the packet was received on. `parse_metadata` is the
parse metadata associated with parsing the IP headers. It is used to undo
that parsing. Both `device` and `parse_metadata` are required in order to
send ICMP messages in response to unrecognized protocols or ports.
Dispatch a received IPv4 packet to the appropriate protocol . ` device ` is the device the packet was received on . ` parse_metadata ` is the parse metadata associated with parsing the IP headers . It is used to undo that parsing . Both ` device ` and ` parse_metadata ` are required in order to send ICMP messages in response to unrecognized protocols or ports .
fn dispatch_receive_ipv4_packet<B: BufferMut, D: BufferDispatcher<B>>(
    ctx: &mut Ctx<D>,
    device: Option<DeviceId>,
    frame_dst: FrameDestination,
    src_ip: Ipv4Addr,
    dst_ip: SpecifiedAddr<Ipv4Addr>,
    proto: Ipv4Proto,
    buffer: B,
    parse_metadata: Option<ParseMetadata>,
) {
    increment_counter!(ctx, "dispatch_receive_ipv4_packet");
    macro_rules! mtch {
        ($($cond:pat => $ty:ident),*) => {
            match proto {
                Ipv4Proto::Icmp => <IcmpIpTransportContext as BufferIpTransportContext<Ipv4, _, _>>
                            ::receive_ip_packet(ctx, device, src_ip, dst_ip, buffer),
                Ipv4Proto::Igmp => {
                    IgmpPacketHandler::<(), _, _>::receive_igmp_packet(
                        ctx,
                        device.expect("IGMP messages should come from a device"),
                        src_ip,
                        dst_ip,
                        buffer,
                    );
                    Ok(())
                }
                $($cond => <<Ctx<D> as Ipv4TransportLayerContext>::$ty as BufferIpTransportContext<Ipv4, _, _>>
                            ::receive_ip_packet(ctx, device, src_ip, dst_ip, buffer),)*
                // TODO(joshlf): Once all IP protocol numbers are covered,
                // remove this default case.
                _ => Err((
                    buffer,
                    TransportReceiveError { inner: TransportReceiveErrorInner::ProtocolUnsupported },
                )),
            }
        };
    }
    #[rustfmt::skip]
    let res = mtch!(
        Ipv4Proto::Proto(IpProto::Tcp) => Proto6,
        Ipv4Proto::Proto(IpProto::Udp) => Proto17
    );
    if let Err((mut buffer, err)) = res {
        // All branches promise to return the buffer in the same state it was in
        // when they were executed. Thus, all we have to do is undo the parsing
        // of the IP packet header, and the buffer will be back to containing
        // the entire original IP packet.
        let meta = parse_metadata.unwrap();
        buffer.undo_parse(meta);
        if let Some(src_ip) = SpecifiedAddr::new(src_ip) {
            match err.inner {
                TransportReceiveErrorInner::ProtocolUnsupported => {
                    icmp::send_icmpv4_protocol_unreachable(
                        ctx,
                        device.unwrap(),
                        frame_dst,
                        src_ip,
                        dst_ip,
                        buffer,
                        meta.header_len(),
                    );
                }
                TransportReceiveErrorInner::PortUnreachable => {
                    // TODO(joshlf): What if we're called from a loopback
                    // handler, and device and parse_metadata are None? In other
                    // words, what happens if we attempt to send to a loopback
                    // port which is unreachable? We will eventually need to
                    // restructure the control flow here to handle that case.
                    icmp::send_icmpv4_port_unreachable(
                        ctx,
                        device.unwrap(),
                        frame_dst,
                        src_ip,
                        dst_ip,
                        buffer,
                        meta.header_len(),
                    );
                }
            }
        } else {
            trace!("dispatch_receive_ipv4_packet: Cannot send ICMP error message in response to a packet from the unspecified address");
        }
    }
}
fn dispatch_receive_ipv4_packet < B : BufferMut , D : BufferDispatcher < B > > ( ctx : & mut Ctx < D > , device : Option < DeviceId > , frame_dst : FrameDestination , src_ip : Ipv4Addr , dst_ip : SpecifiedAddr < Ipv4Addr > , proto : Ipv4Proto , buffer : B , parse_metadata : Option < ParseMetadata > , ) { increment_counter ! ( ctx " " ) ; macro_rules! mtch { ( $ ( $cond : pat $ty : ident ) * ) => { match proto { Ipv4Proto Icmp IcmpIpTransportContext as BufferIpTransportContext Ipv4 receive_ip_packet ( ctx device src_ip dst_ip buffer ) Ipv4Proto Igmp { IgmpPacketHandler ( ) receive_igmp_packet ( ctx device expect ( " " ) src_ip dst_ip buffer ) Ok ( ( ) ) } $ ( $cond Ctx D as Ipv4TransportLayerContext $ty as BufferIpTransportContext Ipv4 receive_ip_packet ( ctx device src_ip dst_ip buffer ) ) * // TODO(joshlf): Once all IP protocol numbers are covered, // remove this default case. Err ( ( buffer TransportReceiveError { inner TransportReceiveErrorInner ProtocolUnsupported } ) ) } } ; } # [ rustfmt :: skip ] let res = mtch ! ( Ipv4Proto Proto ( IpProto Tcp ) Proto6 Ipv4Proto Proto ( IpProto Udp ) Proto17 ) ; if let Err ( ( mut buffer , err ) ) = res { // All branches promise to return the buffer in the same state it was in // when they were executed. Thus, all we have to do is undo the parsing // of the IP packet header, and the buffer will be back to containing // the entire original IP packet. let meta = parse_metadata . unwrap ( ) ; buffer . undo_parse ( meta ) ; if let Some ( src_ip ) = SpecifiedAddr :: new ( src_ip ) { match err . inner { TransportReceiveErrorInner :: ProtocolUnsupported => { icmp :: send_icmpv4_protocol_unreachable ( ctx , device . unwrap ( ) , frame_dst , src_ip , dst_ip , buffer , meta . header_len ( ) , ) ; } TransportReceiveErrorInner :: PortUnreachable => { // TODO(joshlf): What if we're called from a loopback // handler, and device and parse_metadata are None? In other // words, what happens if we attempt to send to a loopback // port which is unreachable? We will eventually need to // restructure the control flow here to handle that case. icmp :: send_icmpv4_port_unreachable ( ctx , device . unwrap ( ) , frame_dst , src_ip , dst_ip , buffer , meta . header_len ( ) , ) ; } } } else { trace ! ( " " ) ; } } }
Dispatch a received IPv4 packet to the appropriate protocol.
Dispatch a received IPv4 packet to the appropriate protocol .
ctx
&mut Ctx<D>
device
Option<DeviceId>
frame_dst
FrameDestination
src_ip
Ipv4Addr
dst_ip
SpecifiedAddr<Ipv4Addr>
proto
Ipv4Proto
buffer
B
parse_metadata
Option<ParseMetadata>
ctx
&mut Ctx<D>
device
Option<DeviceId>
frame_dst
FrameDestination
src_ip
Ipv4Addr
dst_ip
SpecifiedAddr<Ipv4Addr>
proto
Ipv4Proto
buffer
B
parse_metadata
Option<ParseMetadata>
panics
`dispatch_receive_ipv4_packet` panics if the protocol is unrecognized and
`parse_metadata` is `None`. If an IGMP message is received but it is not
coming from a device, i.e., `device` given is `None`,
`dispatch_receive_ip_packet` will also panic.
` dispatch_receive_ipv4_packet ` panics if the protocol is unrecognized and ` parse_metadata ` is ` None ` . If an IGMP message is received but it is not coming from a device i . e . ` device ` given is ` None ` ` dispatch_receive_ip_packet ` will also panic .