kernel/network/
icmp.rs

1//! ICMP protocol layer
2//!
3//! This module provides ICMP handling for network stack.
4//! It implements NetworkLayer trait for ICMP messages.
5
6use alloc::collections::{BTreeMap, VecDeque};
7use alloc::format;
8use alloc::string::String;
9use alloc::sync::{Arc, Weak};
10use alloc::vec::Vec;
11use core::sync::atomic::{AtomicU16, Ordering};
12use spin::{Mutex, RwLock};
13
14use crate::early_println;
15
16use crate::network::ipv4::Ipv4Address;
17use crate::network::protocol_stack::get_network_manager;
18use crate::network::protocol_stack::{LayerContext, NetworkLayer, NetworkLayerStats};
19use crate::network::socket::SocketError;
20use crate::network::socket::{
21    Inet4SocketAddress, SocketAddress, SocketControl, SocketObject, SocketProtocol, SocketState,
22    SocketType,
23};
24
25/// ICMP message types
26pub mod message_type {
27    /// Echo reply
28    pub const ECHO_REPLY: u8 = 0;
29    /// Destination unreachable
30    pub const DESTINATION_UNREACHABLE: u8 = 3;
31    /// Source quench
32    pub const SOURCE_QUENCH: u8 = 4;
33    /// Redirect
34    pub const REDIRECT: u8 = 5;
35    /// Echo request
36    pub const ECHO_REQUEST: u8 = 8;
37    /// Time exceeded
38    pub const TIME_EXCEEDED: u8 = 11;
39    /// Parameter problem
40    pub const PARAMETER_PROBLEM: u8 = 12;
41    /// Timestamp request
42    pub const TIMESTAMP_REQUEST: u8 = 13;
43    /// Timestamp reply
44    pub const TIMESTAMP_REPLY: u8 = 14;
45}
46
47/// ICMP codes
48pub mod code {
49    /// No code
50    pub const NO_CODE: u8 = 0;
51
52    // Destination unreachable codes
53    pub const NET_UNREACHABLE: u8 = 0;
54    pub const HOST_UNREACHABLE: u8 = 1;
55    pub const PROTOCOL_UNREACHABLE: u8 = 2;
56    pub const PORT_UNREACHABLE: u8 = 3;
57    pub const FRAGMENTATION_NEEDED: u8 = 4;
58    pub const SOURCE_ROUTE_FAILED: u8 = 5;
59}
60
61/// ICMP header (4 bytes minimum)
62#[derive(Debug, Clone, Copy)]
63#[repr(C, packed)]
64pub struct IcmpHeader {
65    /// Message type
66    pub message_type: u8,
67    /// Message code
68    pub code: u8,
69    /// Checksum
70    pub checksum: u16,
71    /// Rest of header (varies by type)
72    pub rest: [u8; 4],
73}
74
75impl IcmpHeader {
76    /// Create a new ICMP header
77    pub fn new(message_type: u8, code: u8) -> Self {
78        Self {
79            message_type,
80            code,
81            checksum: 0,
82            rest: [0; 4],
83        }
84    }
85
86    /// Calculate checksum
87    pub fn calculate_checksum(&self, data: &[u8]) -> u16 {
88        let mut sum: u32 = 0;
89
90        // Header
91        let header_bytes =
92            unsafe { core::slice::from_raw_parts(self as *const IcmpHeader as *const u8, 8) };
93        for chunk in header_bytes.chunks(2) {
94            if chunk.len() == 2 {
95                sum += u16::from_be_bytes([chunk[0], chunk[1]]) as u32;
96            } else if chunk.len() == 1 {
97                sum += (chunk[0] as u32) << 8;
98            }
99        }
100
101        // Data
102        for chunk in data.chunks(2) {
103            if chunk.len() == 2 {
104                sum += u16::from_be_bytes([chunk[0], chunk[1]]) as u32;
105            } else if chunk.len() == 1 {
106                sum += (chunk[0] as u32) << 8;
107            }
108        }
109
110        while sum >> 16 != 0 {
111            sum = (sum & 0xFFFF) + (sum >> 16);
112        }
113
114        !sum as u16
115    }
116
117    /// Serialize header to bytes
118    pub fn to_bytes(&self) -> Vec<u8> {
119        let mut bytes = Vec::with_capacity(8);
120        bytes.push(self.message_type);
121        bytes.push(self.code);
122        bytes.extend_from_slice(&self.checksum.to_be_bytes());
123        bytes.extend_from_slice(&self.rest);
124        bytes
125    }
126
127    /// Parse header from bytes
128    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
129        if bytes.len() < 8 {
130            return None;
131        }
132
133        Some(Self {
134            message_type: bytes[0],
135            code: bytes[1],
136            checksum: u16::from_be_bytes([bytes[2], bytes[3]]),
137            rest: [bytes[4], bytes[5], bytes[6], bytes[7]],
138        })
139    }
140}
141
142/// ICMP Echo request/reply header
143#[derive(Debug, Clone, Copy)]
144#[repr(C, packed)]
145pub struct IcmpEcho {
146    /// Identifier
147    pub identifier: u16,
148    /// Sequence number
149    pub sequence: u16,
150}
151
152impl IcmpEcho {
153    /// Create a new ICMP Echo header
154    pub fn new(identifier: u16, sequence: u16) -> Self {
155        Self {
156            identifier,
157            sequence,
158        }
159    }
160
161    /// Serialize to bytes
162    pub fn to_bytes(&self) -> [u8; 4] {
163        let mut bytes = [0u8; 4];
164        bytes[0..2].copy_from_slice(&self.identifier.to_be_bytes());
165        bytes[2..4].copy_from_slice(&self.sequence.to_be_bytes());
166        bytes
167    }
168
169    /// Parse from bytes
170    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
171        if bytes.len() < 4 {
172            return None;
173        }
174
175        Some(Self {
176            identifier: u16::from_be_bytes([bytes[0], bytes[1]]),
177            sequence: u16::from_be_bytes([bytes[2], bytes[3]]),
178        })
179    }
180}
181
182/// ICMP layer
183///
184/// Handles ICMP messages for network diagnostics.
185pub struct IcmpLayer {
186    /// Statistics
187    stats: RwLock<NetworkLayerStats>,
188    /// ICMP sockets by identifier
189    sockets: RwLock<BTreeMap<u16, Weak<IcmpSocket>>>,
190    /// Identifier allocator
191    next_identifier: AtomicU16,
192    self_weak: Weak<IcmpLayer>,
193}
194
195impl IcmpLayer {
196    fn compute_checksum(packet: &[u8]) -> u16 {
197        let mut sum: u32 = 0;
198        let mut chunks = packet.chunks_exact(2);
199        for chunk in &mut chunks {
200            sum += u16::from_be_bytes([chunk[0], chunk[1]]) as u32;
201        }
202        if let Some(&byte) = chunks.remainder().first() {
203            sum += (byte as u32) << 8;
204        }
205        while (sum >> 16) != 0 {
206            sum = (sum & 0xFFFF) + (sum >> 16);
207        }
208        !(sum as u16)
209    }
210
211    fn verify_checksum(packet: &[u8]) -> bool {
212        if packet.len() < 4 {
213            return false;
214        }
215        let expected = u16::from_be_bytes([packet[2], packet[3]]);
216        let mut check = packet.to_vec();
217        check[2] = 0;
218        check[3] = 0;
219        Self::compute_checksum(&check) == expected
220    }
221
222    /// Create a new ICMP layer
223    pub fn new() -> Arc<Self> {
224        Arc::new_cyclic(|weak| Self {
225            stats: RwLock::new(NetworkLayerStats::default()),
226            sockets: RwLock::new(BTreeMap::new()),
227            next_identifier: AtomicU16::new(1),
228            self_weak: weak.clone(),
229        })
230    }
231
232    /// Initialize and register the ICMP layer with NetworkManager
233    ///
234    /// Registers with NetworkManager and registers itself with Ipv4Layer
235    /// for protocol number 1 (ICMP).
236    ///
237    /// # Panics
238    ///
239    /// Panics if Ipv4Layer is not registered (must be initialized first).
240    pub fn init(network_manager: &crate::network::NetworkManager) {
241        let layer = Self::new();
242        network_manager.register_layer("icmp", layer.clone());
243
244        // Register with IPv4 layer for ICMP packets (protocol 1)
245        let ipv4 = network_manager
246            .get_layer("ip")
247            .expect("Ipv4Layer must be initialized before IcmpLayer");
248        ipv4.register_protocol(crate::network::ipv4::protocol::ICMP as u16, layer);
249    }
250
251    pub fn create_socket(&self) -> Arc<IcmpSocket> {
252        let identifier = self.next_identifier.fetch_add(1, Ordering::SeqCst);
253        let socket = IcmpSocket::new(self.self_weak.clone(), identifier);
254        self.sockets
255            .write()
256            .insert(identifier, Arc::downgrade(&socket));
257        socket
258    }
259
260    /// Send an ICMP Echo Request (ping)
261    pub fn send_ping_request(
262        &self,
263        dest_ip: Ipv4Address,
264        identifier: u16,
265        sequence: u16,
266        data: &[u8],
267        next_layers: &[Arc<dyn NetworkLayer>],
268    ) -> Result<(), SocketError> {
269        // Build ICMP Echo Request header
270        let echo = IcmpEcho::new(identifier, sequence);
271        let mut header = IcmpHeader::new(message_type::ECHO_REQUEST, code::NO_CODE);
272        header.rest = echo.to_bytes();
273
274        // Calculate checksum
275        let mut icmp_packet = Vec::with_capacity(8 + data.len());
276        header.checksum = 0;
277        icmp_packet.extend_from_slice(&header.to_bytes());
278        icmp_packet.extend_from_slice(data);
279        let checksum = Self::compute_checksum(&icmp_packet);
280        icmp_packet[2] = (checksum >> 8) as u8;
281        icmp_packet[3] = checksum as u8;
282
283        // Create IP context
284        let mut ip_context = LayerContext::new();
285        ip_context.set("ip_dst", &dest_ip.0);
286        ip_context.set("ip_protocol", &[1]); // ICMP protocol
287
288        let dest_ip_bytes = dest_ip.0;
289        early_println!(
290            "[ICMP] Ping {}.{}.{}.{} (id={}, seq={}, data_len={})",
291            dest_ip_bytes[0],
292            dest_ip_bytes[1],
293            dest_ip_bytes[2],
294            dest_ip_bytes[3],
295            identifier,
296            sequence,
297            data.len()
298        );
299
300        // Send through IP layer
301        if !next_layers.is_empty() {
302            next_layers[0].send(&icmp_packet, &ip_context, &next_layers[1..])?;
303        } else if let Some(ip_layer) = get_network_manager().get_layer("ip") {
304            ip_layer.send(&icmp_packet, &ip_context, &[])?;
305
306            // Update statistics
307            let mut stats = self.stats.write();
308            stats.packets_sent += 1;
309            stats.bytes_sent += icmp_packet.len() as u64;
310        } else {
311            return Err(SocketError::NoRoute);
312        }
313
314        Ok(())
315    }
316
317    /// Send an ICMP Echo Reply
318    pub fn send_ping_reply(
319        &self,
320        dest_ip: Ipv4Address,
321        identifier: u16,
322        sequence: u16,
323        data: &[u8],
324        next_layers: &[Arc<dyn NetworkLayer>],
325    ) -> Result<(), SocketError> {
326        // Build ICMP Echo Reply header
327        let echo = IcmpEcho::new(identifier, sequence);
328        let mut header = IcmpHeader::new(message_type::ECHO_REPLY, code::NO_CODE);
329        header.rest = echo.to_bytes();
330
331        // Calculate checksum
332        let mut icmp_packet = Vec::with_capacity(8 + data.len());
333        header.checksum = 0;
334        icmp_packet.extend_from_slice(&header.to_bytes());
335        icmp_packet.extend_from_slice(data);
336        let checksum = Self::compute_checksum(&icmp_packet);
337        icmp_packet[2] = (checksum >> 8) as u8;
338        icmp_packet[3] = checksum as u8;
339
340        // Create IP context
341        let mut ip_context = LayerContext::new();
342        ip_context.set("ip_dst", &dest_ip.0);
343        ip_context.set("ip_protocol", &[1]); // ICMP protocol
344
345        let dest_ip_bytes = dest_ip.0;
346        early_println!(
347            "[ICMP] Pong {}.{}.{}.{} (id={}, seq={}, data_len={})",
348            dest_ip_bytes[0],
349            dest_ip_bytes[1],
350            dest_ip_bytes[2],
351            dest_ip_bytes[3],
352            identifier,
353            sequence,
354            data.len()
355        );
356
357        // Send through IP layer
358        if !next_layers.is_empty() {
359            next_layers[0].send(&icmp_packet, &ip_context, &next_layers[1..])?;
360        } else if let Some(ip_layer) = get_network_manager().get_layer("ip") {
361            ip_layer.send(&icmp_packet, &ip_context, &[])?;
362
363            // Update statistics
364            let mut stats = self.stats.write();
365            stats.packets_sent += 1;
366            stats.bytes_sent += icmp_packet.len() as u64;
367        } else {
368            return Err(SocketError::NoRoute);
369        }
370
371        Ok(())
372    }
373
374    /// Process received ICMP packet
375    pub fn receive_packet(
376        &self,
377        packet: &[u8],
378        src_ip: Ipv4Address,
379        dst_ip: Ipv4Address,
380    ) -> Result<(), SocketError> {
381        if packet.len() < 8 {
382            return Err(SocketError::InvalidPacket);
383        }
384
385        if !Self::verify_checksum(packet) {
386            let mut stats = self.stats.write();
387            stats.protocol_errors += 1;
388            return Err(SocketError::InvalidPacket);
389        }
390
391        early_println!(
392            "[ICMP] RX: {} bytes src={}.{}.{}.{} dst={}.{}.{}.{}",
393            packet.len(),
394            src_ip.0[0],
395            src_ip.0[1],
396            src_ip.0[2],
397            src_ip.0[3],
398            dst_ip.0[0],
399            dst_ip.0[1],
400            dst_ip.0[2],
401            dst_ip.0[3]
402        );
403
404        // Parse ICMP header
405        let header = IcmpHeader::from_bytes(&packet[..8]).ok_or(SocketError::InvalidPacket)?;
406
407        let data = &packet[8..];
408
409        early_println!(
410            "[ICMP] Recv: type={}, code={}, len={}",
411            header.message_type,
412            header.code,
413            packet.len()
414        );
415
416        // Update statistics
417        let mut stats = self.stats.write();
418        stats.packets_received += 1;
419        stats.bytes_received += packet.len() as u64;
420
421        match header.message_type {
422            message_type::ECHO_REQUEST => {
423                if header.code != code::NO_CODE {
424                    return Ok(());
425                }
426                // Handle ping request - send reply
427                let identifier = u16::from_be_bytes([header.rest[0], header.rest[1]]);
428                let sequence = u16::from_be_bytes([header.rest[2], header.rest[3]]);
429                early_println!(
430                    "[ICMP] Ping request from (id={}, seq={})",
431                    identifier,
432                    sequence
433                );
434
435                if let Some(ip_layer) = get_network_manager().get_layer("ip") {
436                    let mut ctx = LayerContext::new();
437                    ctx.set("ip_dst", &src_ip.0);
438                    ctx.set("ip_src", &dst_ip.0);
439                    ctx.set("ip_protocol", &[1]);
440                    let _ = self.send_ping_reply(src_ip, identifier, sequence, data, &[ip_layer]);
441                }
442            }
443            message_type::ECHO_REPLY => {
444                if header.code != code::NO_CODE {
445                    return Ok(());
446                }
447                let identifier = u16::from_be_bytes([header.rest[0], header.rest[1]]);
448                let sequence = u16::from_be_bytes([header.rest[2], header.rest[3]]);
449                let payload = data.to_vec();
450                self.deliver_echo_reply(identifier, payload, src_ip, sequence);
451            }
452            _ => {}
453        }
454
455        Ok(())
456    }
457
458    fn deliver_echo_reply(
459        &self,
460        identifier: u16,
461        payload: Vec<u8>,
462        src_ip: Ipv4Address,
463        sequence: u16,
464    ) {
465        if let Some(socket) = self
466            .sockets
467            .read()
468            .get(&identifier)
469            .and_then(|weak| weak.upgrade())
470        {
471            socket.deliver_reply(payload, src_ip, sequence);
472        }
473    }
474}
475
476pub struct IcmpSocket {
477    icmp_layer: Weak<IcmpLayer>,
478    identifier: u16,
479    sequence: AtomicU16,
480    expected_sequence: AtomicU16,
481    local_addr: Mutex<Option<SocketAddress>>,
482    remote_addr: RwLock<Option<SocketAddress>>,
483    recv_queue: Mutex<VecDeque<(Vec<u8>, SocketAddress)>>,
484    recv_waker: crate::sync::waker::Waker,
485    nonblocking: RwLock<bool>,
486}
487
488impl IcmpSocket {
489    fn new(icmp_layer: Weak<IcmpLayer>, identifier: u16) -> Arc<Self> {
490        Arc::new(Self {
491            icmp_layer,
492            identifier,
493            sequence: AtomicU16::new(0),
494            expected_sequence: AtomicU16::new(0),
495            local_addr: Mutex::new(None),
496            remote_addr: RwLock::new(None),
497            recv_queue: Mutex::new(VecDeque::new()),
498            recv_waker: crate::sync::waker::Waker::new_interruptible("icmp_recv"),
499            nonblocking: RwLock::new(false),
500        })
501    }
502
503    fn deliver_reply(&self, payload: Vec<u8>, src_ip: Ipv4Address, sequence: u16) {
504        let expected = self.expected_sequence.load(Ordering::SeqCst);
505        if sequence != expected {
506            return;
507        }
508        let addr = SocketAddress::Inet(Inet4SocketAddress::new(src_ip.0, 0));
509        self.recv_queue.lock().push_back((payload, addr));
510        self.recv_waker.wake_one();
511    }
512}
513
514impl SocketObject for IcmpSocket {
515    fn socket_type(&self) -> SocketType {
516        SocketType::Datagram
517    }
518
519    fn socket_domain(&self) -> crate::network::socket::SocketDomain {
520        crate::network::socket::SocketDomain::Inet4
521    }
522
523    fn socket_protocol(&self) -> SocketProtocol {
524        SocketProtocol::Icmp
525    }
526
527    fn as_any(&self) -> &dyn core::any::Any {
528        self
529    }
530
531    fn as_control_ops(&self) -> Option<&dyn crate::object::capability::ControlOps> {
532        Some(self)
533    }
534
535    fn sendto(
536        &self,
537        data: &[u8],
538        address: &SocketAddress,
539        _flags: u32,
540    ) -> Result<usize, SocketError> {
541        let target = match address {
542            SocketAddress::Inet(inet) => *inet,
543            SocketAddress::Unspecified => match self.remote_addr.read().clone() {
544                Some(SocketAddress::Inet(inet)) => inet,
545                _ => return Err(SocketError::InvalidAddress),
546            },
547            _ => return Err(SocketError::InvalidAddress),
548        };
549
550        let sequence = self.sequence.fetch_add(1, Ordering::SeqCst);
551        self.expected_sequence.store(sequence, Ordering::SeqCst);
552        let dest_ip = Ipv4Address::from_bytes(target.addr);
553
554        if let Some(ip_layer) = get_network_manager().get_layer("ip") {
555            if let Some(ipv4) = ip_layer
556                .as_any()
557                .downcast_ref::<crate::network::ipv4::Ipv4Layer>()
558            {
559                // Check if we have a configured IP on any interface
560                let has_ip = get_network_manager()
561                    .get_default_interface()
562                    .and_then(|iface| ipv4.get_primary_ip(iface.name()))
563                    .map(|ip| ip.0 != [0, 0, 0, 0])
564                    .unwrap_or(false);
565                if !has_ip {
566                    early_println!("[ICMP] send blocked: local IP unset");
567                    return Err(SocketError::NotConnected);
568                }
569            }
570            if let Some(icmp_layer) = self.icmp_layer.upgrade() {
571                match icmp_layer.send_ping_request(
572                    dest_ip,
573                    self.identifier,
574                    sequence,
575                    data,
576                    &[ip_layer],
577                ) {
578                    Ok(()) => return Ok(data.len()),
579                    Err(SocketError::WouldBlock) => {
580                        // Packet queued for ARP resolution - treat as success
581                        return Ok(data.len());
582                    }
583                    Err(e) => return Err(e),
584                }
585            } else {
586                early_println!("[ICMP] send failed: ICMP layer unavailable");
587            }
588        } else {
589            early_println!("[ICMP] send failed: IP layer unavailable");
590        }
591
592        Err(SocketError::NoRoute)
593    }
594
595    fn recvfrom(
596        &self,
597        buffer: &mut [u8],
598        _flags: u32,
599    ) -> Result<(usize, SocketAddress), SocketError> {
600        use crate::task::mytask;
601
602        loop {
603            if let Some((data, addr)) = self.recv_queue.lock().pop_front() {
604                let len = buffer.len().min(data.len());
605                buffer[..len].copy_from_slice(&data[..len]);
606                return Ok((len, addr));
607            }
608
609            if *self.nonblocking.read() {
610                return Err(SocketError::WouldBlock);
611            }
612
613            if let Some(task) = mytask() {
614                self.recv_waker.wait(task.get_id(), task.get_trapframe());
615            } else {
616                return Err(SocketError::WouldBlock);
617            }
618        }
619    }
620}
621
622impl crate::object::capability::ControlOps for IcmpSocket {
623    fn control(&self, command: u32, arg: usize) -> Result<i32, &'static str> {
624        match command {
625            crate::network::socket::socket_ctl::SCTL_SOCKET_SET_NONBLOCK => {
626                *self.nonblocking.write() = arg != 0;
627                Ok(0)
628            }
629            crate::network::socket::socket_ctl::SCTL_SOCKET_GET_NONBLOCK => {
630                Ok(if *self.nonblocking.read() { 1 } else { 0 })
631            }
632            _ => Err("Unsupported socket control command"),
633        }
634    }
635
636    fn supported_control_commands(&self) -> alloc::vec::Vec<(u32, &'static str)> {
637        alloc::vec![
638            (
639                crate::network::socket::socket_ctl::SCTL_SOCKET_SET_NONBLOCK,
640                "Set non-blocking mode",
641            ),
642            (
643                crate::network::socket::socket_ctl::SCTL_SOCKET_GET_NONBLOCK,
644                "Get non-blocking mode",
645            ),
646        ]
647    }
648}
649
650impl SocketControl for IcmpSocket {
651    fn bind(&self, address: &SocketAddress) -> Result<(), SocketError> {
652        match address {
653            SocketAddress::Inet(_) => {
654                *self.local_addr.lock() = Some(address.clone());
655                Ok(())
656            }
657            SocketAddress::Unspecified => Ok(()),
658            _ => Err(SocketError::InvalidAddress),
659        }
660    }
661
662    fn connect(&self, address: &SocketAddress) -> Result<(), SocketError> {
663        match address {
664            SocketAddress::Inet(_) => {
665                *self.remote_addr.write() = Some(address.clone());
666                Ok(())
667            }
668            _ => Err(SocketError::InvalidAddress),
669        }
670    }
671
672    fn listen(&self, _backlog: usize) -> Result<(), SocketError> {
673        Err(SocketError::NotSupported)
674    }
675
676    fn accept(&self) -> Result<Arc<dyn SocketObject>, SocketError> {
677        Err(SocketError::NotSupported)
678    }
679
680    fn getpeername(&self) -> Result<SocketAddress, SocketError> {
681        self.remote_addr
682            .read()
683            .clone()
684            .ok_or(SocketError::NotConnected)
685    }
686
687    fn getsockname(&self) -> Result<SocketAddress, SocketError> {
688        self.local_addr
689            .lock()
690            .clone()
691            .ok_or(SocketError::InvalidAddress)
692    }
693
694    fn shutdown(&self, _how: crate::network::socket::ShutdownHow) -> Result<(), SocketError> {
695        Ok(())
696    }
697
698    fn is_connected(&self) -> bool {
699        self.remote_addr.read().is_some()
700    }
701
702    fn state(&self) -> SocketState {
703        if self.is_connected() {
704            SocketState::Connected
705        } else {
706            SocketState::Unconnected
707        }
708    }
709}
710
711impl crate::ipc::StreamIpcOps for IcmpSocket {
712    fn is_connected(&self) -> bool {
713        SocketControl::is_connected(self)
714    }
715
716    fn peer_count(&self) -> usize {
717        if SocketControl::is_connected(self) {
718            1
719        } else {
720            0
721        }
722    }
723
724    fn description(&self) -> String {
725        alloc::format!("ICMP socket")
726    }
727}
728
729impl crate::object::capability::StreamOps for IcmpSocket {
730    fn read(&self, buffer: &mut [u8]) -> Result<usize, crate::object::capability::StreamError> {
731        let (len, _) = self.recvfrom(buffer, 0).map_err(|err| {
732            crate::object::capability::StreamError::Other(format!("icmp recv error: {:?}", err))
733        })?;
734        Ok(len)
735    }
736
737    fn write(&self, data: &[u8]) -> Result<usize, crate::object::capability::StreamError> {
738        let addr = self.remote_addr.read().clone().ok_or_else(|| {
739            crate::object::capability::StreamError::Other("icmp not connected".into())
740        })?;
741        self.sendto(data, &addr, 0).map_err(|err| {
742            crate::object::capability::StreamError::Other(format!("icmp send error: {:?}", err))
743        })?;
744        Ok(data.len())
745    }
746}
747
748impl NetworkLayer for IcmpLayer {
749    fn register_protocol(&self, _proto_num: u16, _handler: Arc<dyn NetworkLayer>) {
750        // ICMP is typically a leaf protocol
751    }
752
753    fn send(
754        &self,
755        _packet: &[u8],
756        _context: &LayerContext,
757        _next_layers: &[Arc<dyn NetworkLayer>],
758    ) -> Result<(), SocketError> {
759        // ICMP send is handled through specific methods
760        Ok(())
761    }
762
763    fn receive(&self, _packet: &[u8], _context: Option<&LayerContext>) -> Result<(), SocketError> {
764        Ok(())
765    }
766
767    fn name(&self) -> &'static str {
768        "ICMP"
769    }
770
771    fn stats(&self) -> NetworkLayerStats {
772        self.stats.read().clone()
773    }
774
775    fn as_any(&self) -> &dyn core::any::Any {
776        self
777    }
778}
779
780#[cfg(test)]
781mod tests {
782    use super::*;
783
784    #[test_case]
785    fn test_icmp_header_creation() {
786        let header = IcmpHeader::new(message_type::ECHO_REQUEST, code::NO_CODE);
787
788        assert_eq!(header.message_type, message_type::ECHO_REQUEST);
789        assert_eq!(header.code, code::NO_CODE);
790        assert_eq!(header.rest, [0, 0, 0, 0]);
791    }
792
793    #[test_case]
794    fn test_icmp_echo_header() {
795        let echo = IcmpEcho::new(1234, 5678);
796
797        let identifier = unsafe { core::ptr::addr_of!(echo.identifier).read_unaligned() };
798        let sequence = unsafe { core::ptr::addr_of!(echo.sequence).read_unaligned() };
799        assert_eq!(identifier, 1234);
800        assert_eq!(sequence, 5678);
801    }
802
803    #[test_case]
804    fn test_icmp_echo_serialization() {
805        let echo = IcmpEcho::new(1234, 5678);
806        let bytes = echo.to_bytes();
807
808        assert_eq!(bytes.len(), 4);
809        assert_eq!(u16::from_be_bytes([bytes[0], bytes[1]]), 1234);
810        assert_eq!(u16::from_be_bytes([bytes[2], bytes[3]]), 5678);
811    }
812
813    #[test_case]
814    fn test_icmp_echo_parsing() {
815        let mut bytes = [0u8; 4];
816        bytes[0..2].copy_from_slice(&1234u16.to_be_bytes());
817        bytes[2..4].copy_from_slice(&5678u16.to_be_bytes());
818
819        let echo = IcmpEcho::from_bytes(&bytes).unwrap();
820
821        let identifier = unsafe { core::ptr::addr_of!(echo.identifier).read_unaligned() };
822        let sequence = unsafe { core::ptr::addr_of!(echo.sequence).read_unaligned() };
823        assert_eq!(identifier, 1234);
824        assert_eq!(sequence, 5678);
825    }
826
827    #[test_case]
828    fn test_icmp_header_parsing() {
829        let mut bytes = [0u8; 8];
830        bytes[0] = message_type::ECHO_REQUEST;
831        bytes[1] = code::NO_CODE;
832        bytes[2..4].copy_from_slice(&0x1234u16.to_be_bytes()); // Checksum
833        bytes[4..8].copy_from_slice(&[0x00, 0x00, 0x00, 0x00]); // Rest
834
835        let header = IcmpHeader::from_bytes(&bytes).unwrap();
836
837        assert_eq!(header.message_type, message_type::ECHO_REQUEST);
838        assert_eq!(header.code, code::NO_CODE);
839        assert_eq!(header.rest, [0, 0, 0, 0]);
840    }
841
842    #[test_case]
843    fn test_icmp_header_too_short() {
844        let bytes = [0u8; 4];
845        assert!(IcmpHeader::from_bytes(&bytes).is_none());
846    }
847
848    #[test_case]
849    fn test_icmp_echo_checksum_known_vector() {
850        let mut header = IcmpHeader::new(message_type::ECHO_REQUEST, code::NO_CODE);
851        header.rest = IcmpEcho::new(0x1234, 0x0001).to_bytes();
852        let data = b"scarlet";
853
854        let mut packet = header.to_bytes();
855        packet.extend_from_slice(data);
856        header.checksum = IcmpLayer::compute_checksum(&packet);
857
858        let mut checked = header.to_bytes();
859        checked.extend_from_slice(data);
860        assert!(IcmpLayer::verify_checksum(&checked));
861    }
862
863    #[test_case]
864    fn test_message_type_constants() {
865        assert_eq!(message_type::ECHO_REPLY, 0);
866        assert_eq!(message_type::DESTINATION_UNREACHABLE, 3);
867        assert_eq!(message_type::ECHO_REQUEST, 8);
868        assert_eq!(message_type::TIME_EXCEEDED, 11);
869    }
870
871    #[test_case]
872    fn test_code_constants() {
873        assert_eq!(code::NO_CODE, 0);
874        assert_eq!(code::NET_UNREACHABLE, 0);
875        assert_eq!(code::HOST_UNREACHABLE, 1);
876        assert_eq!(code::PORT_UNREACHABLE, 3);
877    }
878}