1use 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
25pub mod message_type {
27 pub const ECHO_REPLY: u8 = 0;
29 pub const DESTINATION_UNREACHABLE: u8 = 3;
31 pub const SOURCE_QUENCH: u8 = 4;
33 pub const REDIRECT: u8 = 5;
35 pub const ECHO_REQUEST: u8 = 8;
37 pub const TIME_EXCEEDED: u8 = 11;
39 pub const PARAMETER_PROBLEM: u8 = 12;
41 pub const TIMESTAMP_REQUEST: u8 = 13;
43 pub const TIMESTAMP_REPLY: u8 = 14;
45}
46
47pub mod code {
49 pub const NO_CODE: u8 = 0;
51
52 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#[derive(Debug, Clone, Copy)]
63#[repr(C, packed)]
64pub struct IcmpHeader {
65 pub message_type: u8,
67 pub code: u8,
69 pub checksum: u16,
71 pub rest: [u8; 4],
73}
74
75impl IcmpHeader {
76 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 pub fn calculate_checksum(&self, data: &[u8]) -> u16 {
88 let mut sum: u32 = 0;
89
90 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 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 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 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#[derive(Debug, Clone, Copy)]
144#[repr(C, packed)]
145pub struct IcmpEcho {
146 pub identifier: u16,
148 pub sequence: u16,
150}
151
152impl IcmpEcho {
153 pub fn new(identifier: u16, sequence: u16) -> Self {
155 Self {
156 identifier,
157 sequence,
158 }
159 }
160
161 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 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
182pub struct IcmpLayer {
186 stats: RwLock<NetworkLayerStats>,
188 sockets: RwLock<BTreeMap<u16, Weak<IcmpSocket>>>,
190 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 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 pub fn init(network_manager: &crate::network::NetworkManager) {
241 let layer = Self::new();
242 network_manager.register_layer("icmp", layer.clone());
243
244 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 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 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 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 let mut ip_context = LayerContext::new();
285 ip_context.set("ip_dst", &dest_ip.0);
286 ip_context.set("ip_protocol", &[1]); 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 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 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 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 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 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 let mut ip_context = LayerContext::new();
342 ip_context.set("ip_dst", &dest_ip.0);
343 ip_context.set("ip_protocol", &[1]); 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 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 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 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 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 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 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 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 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 }
752
753 fn send(
754 &self,
755 _packet: &[u8],
756 _context: &LayerContext,
757 _next_layers: &[Arc<dyn NetworkLayer>],
758 ) -> Result<(), SocketError> {
759 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()); bytes[4..8].copy_from_slice(&[0x00, 0x00, 0x00, 0x00]); 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}