pub(crate) fn receive_ip_packet<D: EventDispatcher, B: BufferMut, I: Ip>(
    ctx: &mut Context<D>,
    device: DeviceId,
    frame_dst: FrameDestination,
    mut buffer: B,
) {
    trace!("receive_ip_packet({})", device);

    // Snapshot of `buffer`'s current state to revert to if parsing fails.
    // TODO(ghanan): Remove manual restoration of `buffer`'s state once
    //               the packet crate guarantees that if parsing fails,
    //               the buffer's state is left as it was before parsing.
    let p_len = buffer.prefix_len();
    let s_len = buffer.suffix_len();

    let result = buffer.parse_mut::<<I as IpExt<_>>::Packet>();

    if result.is_err() {
        let err = result.unwrap_err();

        // Revert `buffer` to it's original state.
        let n_p_len = buffer.prefix_len();
        let n_s_len = buffer.suffix_len();

        if p_len > n_p_len {
            buffer.grow_front(p_len - n_p_len);
        }

        if s_len > n_s_len {
            buffer.grow_back(s_len - n_s_len);
        }

        match err {
            // Conditionally send an ICMP response if we encountered a parameter
            // problem error when parsing an IP 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`.
            IpParseError::ParameterProblem {
                src_ip,
                dst_ip,
                code,
                pointer,
                must_send_icmp,
                header_len,
            } => {
                if must_send_icmp {
                    icmp::send_icmp_parameter_problem(
                        ctx, device, frame_dst, src_ip, dst_ip, code, pointer, buffer, header_len,
                    );
                }
            }
            // TODO(joshlf): Do something with ICMP here?
            _ => {}
        }

        return;
    }

    // This will never panic because we check if `result` was an error earlier and return
    // before reaching here. That is, it is guaranteed that when we reach here, `result`
    // is not an error.
    let mut packet = result.unwrap();

    trace!("receive_ip_packet: parsed packet: {:?}", packet);

    // TODO(ghanan): For IPv4 packets, act upon options and for IPv6 packets,
    //               act upon extension headers.

    if I::LOOPBACK_SUBNET.contains(packet.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(ctx, device, packet.dst_ip()) {
        trace!("receive_ip_packet: delivering locally");
        // TODO(joshlf):
        // - Do something with ICMP if we don't have a handler for that protocol?
        // - Check for already-expired TTL?
        let (src_ip, dst_ip, proto, meta) = drop_packet!(packet);
        dispatch_receive_ip_packet(
            ctx,
            Some(device),
            frame_dst,
            src_ip,
            dst_ip,
            proto,
            buffer,
            Some(meta),
        );
    } else if let Some(dest) = forward(ctx, packet.dst_ip()) {
        let ttl = packet.ttl();
        if ttl > 1 {
            trace!("receive_ip_packet: forwarding");
            packet.set_ttl(ttl - 1);
            let (src_ip, dst_ip, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
            if let Err((err, ser)) = crate::device::send_ip_frame(
                ctx,
                dest.device,
                dest.next_hop,
                BufferSerializer::new_vec(buffer),
            ) {
                #[specialize_ip_address]
                fn send_packet_too_big<D: EventDispatcher, A: IpAddress, B: BufferMut>(
                    ctx: &mut Context<D>,
                    device: DeviceId,
                    frame_dst: FrameDestination,
                    src_ip: A,
                    dst_ip: A,
                    proto: IpProto,
                    mtu: u32,
                    original_packet: B,
                    header_len: usize,
                ) {
                    #[ipv6addr]
                    crate::ip::icmp::send_icmpv6_packet_too_big(
                        ctx,
                        device,
                        frame_dst,
                        src_ip,
                        dst_ip,
                        proto,
                        mtu,
                        original_packet,
                        header_len,
                    );
                }

                debug!("failed to forward IP packet: {:?}", err);
                if err.is_mtu() {
                    trace!("receive_ip_packet: Sending ICMPv6 Packet Too Big");
                    // TODO(joshlf): Increment the TTL since we just decremented
                    // it. The fact that we don't do this is technically a
                    // violation of the ICMP spec (we're not encapsulating the
                    // original packet that caused the issue, but a slightly
                    // modified version of it), but it's not that big of a deal
                    // because it won't affect the sender's ability to figure
                    // out the minimum path MTU. This may break other logic,
                    // though, so we should still fix it eventually.
                    let mtu = crate::device::get_mtu(ctx, device);
                    send_packet_too_big(
                        ctx,
                        device,
                        frame_dst,
                        src_ip,
                        dst_ip,
                        proto,
                        mtu,
                        ser.into_buffer(),
                        meta.header_len(),
                    );
                }
            }
        } else {
            // TTL is 0 or would become 0 after decrement; see "TTL" section,
            // https://tools.ietf.org/html/rfc791#page-14
            let (src_ip, dst_ip, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
            icmp::send_icmp_ttl_expired(
                ctx,
                device,
                frame_dst,
                src_ip,
                dst_ip,
                proto,
                buffer,
                meta.header_len(),
            );
            debug!("received IP packet dropped due to expired TTL");
        }
    } else {
        let (src_ip, dst_ip, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
        icmp::send_icmp_net_unreachable(
            ctx,
            device,
            frame_dst,
            src_ip,
            dst_ip,
            proto,
            buffer,
            meta.header_len(),
        );
        debug!("received IP packet with no known route to destination {}", dst_ip);
    }
}
/// Receive an IP packet from a device.
///
/// `frame_dst` specifies whether this packet was received in a broadcast or
/// unicast link-layer frame.
Receive an IP packet from a device.
`frame_dst` specifies whether this packet was received in a broadcast or
unicast link-layer frame.
Receive an IP packet from a device . ` frame_dst ` specifies whether this packet was received in a broadcast or unicast link - layer frame .
pub(crate) fn receive_ip_packet<D: EventDispatcher, B: BufferMut, I: Ip>(
    ctx: &mut Context<D>,
    device: DeviceId,
    frame_dst: FrameDestination,
    mut buffer: B,
) {
    trace!("receive_ip_packet({})", device);
    // Snapshot of `buffer`'s current state to revert to if parsing fails.
    // TODO(ghanan): Remove manual restoration of `buffer`'s state once
    //               the packet crate guarantees that if parsing fails,
    //               the buffer's state is left as it was before parsing.
    let p_len = buffer.prefix_len();
    let s_len = buffer.suffix_len();
    let result = buffer.parse_mut::<<I as IpExt<_>>::Packet>();
    if result.is_err() {
        let err = result.unwrap_err();
        // Revert `buffer` to it's original state.
        let n_p_len = buffer.prefix_len();
        let n_s_len = buffer.suffix_len();
        if p_len > n_p_len {
            buffer.grow_front(p_len - n_p_len);
        }
        if s_len > n_s_len {
            buffer.grow_back(s_len - n_s_len);
        }
        match err {
            // Conditionally send an ICMP response if we encountered a parameter
            // problem error when parsing an IP 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`.
            IpParseError::ParameterProblem {
                src_ip,
                dst_ip,
                code,
                pointer,
                must_send_icmp,
                header_len,
            } => {
                if must_send_icmp {
                    icmp::send_icmp_parameter_problem(
                        ctx, device, frame_dst, src_ip, dst_ip, code, pointer, buffer, header_len,
                    );
                }
            }
            // TODO(joshlf): Do something with ICMP here?
            _ => {}
        }
        return;
    }
    // This will never panic because we check if `result` was an error earlier and return
    // before reaching here. That is, it is guaranteed that when we reach here, `result`
    // is not an error.
    let mut packet = result.unwrap();
    trace!("receive_ip_packet: parsed packet: {:?}", packet);
    // TODO(ghanan): For IPv4 packets, act upon options and for IPv6 packets,
    //               act upon extension headers.
    if I::LOOPBACK_SUBNET.contains(packet.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(ctx, device, packet.dst_ip()) {
        trace!("receive_ip_packet: delivering locally");
        // TODO(joshlf):
        // - Do something with ICMP if we don't have a handler for that protocol?
        // - Check for already-expired TTL?
        let (src_ip, dst_ip, proto, meta) = drop_packet!(packet);
        dispatch_receive_ip_packet(
            ctx,
            Some(device),
            frame_dst,
            src_ip,
            dst_ip,
            proto,
            buffer,
            Some(meta),
        );
    } else if let Some(dest) = forward(ctx, packet.dst_ip()) {
        let ttl = packet.ttl();
        if ttl > 1 {
            trace!("receive_ip_packet: forwarding");
            packet.set_ttl(ttl - 1);
            let (src_ip, dst_ip, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
            if let Err((err, ser)) = crate::device::send_ip_frame(
                ctx,
                dest.device,
                dest.next_hop,
                BufferSerializer::new_vec(buffer),
            ) {
                #[specialize_ip_address]
                fn send_packet_too_big<D: EventDispatcher, A: IpAddress, B: BufferMut>(
                    ctx: &mut Context<D>,
                    device: DeviceId,
                    frame_dst: FrameDestination,
                    src_ip: A,
                    dst_ip: A,
                    proto: IpProto,
                    mtu: u32,
                    original_packet: B,
                    header_len: usize,
                ) {
                    #[ipv6addr]
                    crate::ip::icmp::send_icmpv6_packet_too_big(
                        ctx,
                        device,
                        frame_dst,
                        src_ip,
                        dst_ip,
                        proto,
                        mtu,
                        original_packet,
                        header_len,
                    );
                }
                debug!("failed to forward IP packet: {:?}", err);
                if err.is_mtu() {
                    trace!("receive_ip_packet: Sending ICMPv6 Packet Too Big");
                    // TODO(joshlf): Increment the TTL since we just decremented
                    // it. The fact that we don't do this is technically a
                    // violation of the ICMP spec (we're not encapsulating the
                    // original packet that caused the issue, but a slightly
                    // modified version of it), but it's not that big of a deal
                    // because it won't affect the sender's ability to figure
                    // out the minimum path MTU. This may break other logic,
                    // though, so we should still fix it eventually.
                    let mtu = crate::device::get_mtu(ctx, device);
                    send_packet_too_big(
                        ctx,
                        device,
                        frame_dst,
                        src_ip,
                        dst_ip,
                        proto,
                        mtu,
                        ser.into_buffer(),
                        meta.header_len(),
                    );
                }
            }
        } else {
            // TTL is 0 or would become 0 after decrement; see "TTL" section,
            // https://tools.ietf.org/html/rfc791#page-14
            let (src_ip, dst_ip, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
            icmp::send_icmp_ttl_expired(
                ctx,
                device,
                frame_dst,
                src_ip,
                dst_ip,
                proto,
                buffer,
                meta.header_len(),
            );
            debug!("received IP packet dropped due to expired TTL");
        }
    } else {
        let (src_ip, dst_ip, proto, meta) = drop_packet_and_undo_parse!(packet, buffer);
        icmp::send_icmp_net_unreachable(
            ctx,
            device,
            frame_dst,
            src_ip,
            dst_ip,
            proto,
            buffer,
            meta.header_len(),
        );
        debug!("received IP packet with no known route to destination {}", dst_ip);
    }
}
pub ( crate ) fn receive_ip_packet < D : EventDispatcher , B : BufferMut , I : Ip > ( ctx : & mut Context < D > , device : DeviceId , frame_dst : FrameDestination , mut buffer : B , ) { trace ! ( " " device ) ; // Snapshot of `buffer`'s current state to revert to if parsing fails. // TODO(ghanan): Remove manual restoration of `buffer`'s state once //               the packet crate guarantees that if parsing fails, //               the buffer's state is left as it was before parsing. let p_len = buffer . prefix_len ( ) ; let s_len = buffer . suffix_len ( ) ; let result = buffer . parse_mut :: < < I as IpExt < _ > > :: Packet > ( ) ; if result . is_err ( ) { let err = result . unwrap_err ( ) ; // Revert `buffer` to it's original state. let n_p_len = buffer . prefix_len ( ) ; let n_s_len = buffer . suffix_len ( ) ; if p_len > n_p_len { buffer . grow_front ( p_len - n_p_len ) ; } if s_len > n_s_len { buffer . grow_back ( s_len - n_s_len ) ; } match err { // Conditionally send an ICMP response if we encountered a parameter // problem error when parsing an IP 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`. IpParseError :: ParameterProblem { src_ip , dst_ip , code , pointer , must_send_icmp , header_len , } => { if must_send_icmp { icmp :: send_icmp_parameter_problem ( ctx , device , frame_dst , src_ip , dst_ip , code , pointer , buffer , header_len , ) ; } } // TODO(joshlf): Do something with ICMP here? _ => { } } return ; } // This will never panic because we check if `result` was an error earlier and return // before reaching here. That is, it is guaranteed that when we reach here, `result` // is not an error. let mut packet = result . unwrap ( ) ; trace ! ( " " packet ) ; // TODO(ghanan): For IPv4 packets, act upon options and for IPv6 packets, //               act upon extension headers. if I :: LOOPBACK_SUBNET . contains ( packet . 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 ( ctx , device , packet . dst_ip ( ) ) { trace ! ( " " ) ; // TODO(joshlf): // - Do something with ICMP if we don't have a handler for that protocol? // - Check for already-expired TTL? let ( src_ip , dst_ip , proto , meta ) = drop_packet ! ( packet ) ; dispatch_receive_ip_packet ( ctx , Some ( device ) , frame_dst , src_ip , dst_ip , proto , buffer , Some ( meta ) , ) ; } else if let Some ( dest ) = forward ( ctx , packet . dst_ip ( ) ) { let ttl = packet . ttl ( ) ; if ttl > 1 { trace ! ( " " ) ; packet . set_ttl ( ttl - 1 ) ; let ( src_ip , dst_ip , proto , meta ) = drop_packet_and_undo_parse ! ( packet buffer ) ; if let Err ( ( err , ser ) ) = crate :: device :: send_ip_frame ( ctx , dest . device , dest . next_hop , BufferSerializer :: new_vec ( buffer ) , ) { # [ specialize_ip_address ] fn send_packet_too_big < D : EventDispatcher , A : IpAddress , B : BufferMut > ( ctx : & mut Context < D > , device : DeviceId , frame_dst : FrameDestination , src_ip : A , dst_ip : A , proto : IpProto , mtu : u32 , original_packet : B , header_len : usize , ) { # [ ipv6addr ] crate :: ip :: icmp :: send_icmpv6_packet_too_big ( ctx , device , frame_dst , src_ip , dst_ip , proto , mtu , original_packet , header_len , ) ; } debug ! ( " " err ) ; if err . is_mtu ( ) { trace ! ( " " ) ; // TODO(joshlf): Increment the TTL since we just decremented // it. The fact that we don't do this is technically a // violation of the ICMP spec (we're not encapsulating the // original packet that caused the issue, but a slightly // modified version of it), but it's not that big of a deal // because it won't affect the sender's ability to figure // out the minimum path MTU. This may break other logic, // though, so we should still fix it eventually. let mtu = crate :: device :: get_mtu ( ctx , device ) ; send_packet_too_big ( ctx , device , frame_dst , src_ip , dst_ip , proto , mtu , ser . into_buffer ( ) , meta . header_len ( ) , ) ; } } } else { // TTL is 0 or would become 0 after decrement; see "TTL" section, // https://tools.ietf.org/html/rfc791#page-14 let ( src_ip , dst_ip , proto , meta ) = drop_packet_and_undo_parse ! ( packet buffer ) ; icmp :: send_icmp_ttl_expired ( ctx , device , frame_dst , src_ip , dst_ip , proto , buffer , meta . header_len ( ) , ) ; debug ! ( " " ) ; } } else { let ( src_ip , dst_ip , proto , meta ) = drop_packet_and_undo_parse ! ( packet buffer ) ; icmp :: send_icmp_net_unreachable ( ctx , device , frame_dst , src_ip , dst_ip , proto , buffer , meta . header_len ( ) , ) ; debug ! ( " " dst_ip ) ; } }
Receive an IP packet from a device.
Receive an IP packet from a device .
ctx
&mut Context<D>
device
DeviceId
frame_dst
FrameDestination
buffer
B
ctx
&mut Context<D>
device
DeviceId
frame_dst
FrameDestination
buffer
B