1use crate::arp::{ArpCache, ArpPacket};
7use crate::device::NetworkDevice;
8use crate::error::{NetError, NetResult};
9use crate::ethernet::{EtherType, EthernetFrame, MacAddress};
10use crate::icmp::{IcmpEcho, IcmpHeader, IcmpType};
11use crate::ipv4::{Ipv4Addr, Ipv4Header, Protocol};
12use crate::udp::UdpHeader;
13use crate::{ETHERNET_HEADER_SIZE, IPV4_HEADER_MIN_SIZE, MTU, UDP_HEADER_SIZE};
14
15#[derive(Debug, Clone, Copy)]
17pub struct StackConfig {
18 pub ip_addr: Ipv4Addr,
20 pub subnet_mask: Ipv4Addr,
22 pub gateway: Ipv4Addr,
24 pub arp_timeout: u64,
26 pub default_ttl: u8,
28 pub enable_ping: bool,
30}
31
32impl Default for StackConfig {
33 fn default() -> Self {
34 Self {
35 ip_addr: Ipv4Addr::UNSPECIFIED,
36 subnet_mask: Ipv4Addr::new(255, 255, 255, 0),
37 gateway: Ipv4Addr::UNSPECIFIED,
38 arp_timeout: 300,
39 default_ttl: 64,
40 enable_ping: true,
41 }
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum StackState {
48 Uninitialized,
50 Initializing,
52 Ready,
54 Error,
56}
57
58#[derive(Debug, Clone, Copy)]
60pub struct ReceivedPacket {
61 pub src_mac: MacAddress,
63 pub src_ip: Ipv4Addr,
65 pub src_port: u16,
67 pub dst_port: u16,
69 pub protocol: Protocol,
71 pub payload_offset: usize,
73 pub payload_len: usize,
75}
76
77pub struct NetworkStack<D: NetworkDevice> {
86 device: D,
88 config: StackConfig,
90 arp_cache: ArpCache,
92 state: StackState,
94 ip_id: u16,
96 current_time: u64,
98}
99
100impl<D: NetworkDevice> NetworkStack<D> {
101 #[inline]
103 #[must_use]
104 pub fn new(device: D, config: StackConfig) -> Self {
105 Self {
106 device,
107 config,
108 arp_cache: ArpCache::with_timeout(config.arp_timeout),
109 state: StackState::Ready,
110 ip_id: 0,
111 current_time: 0,
112 }
113 }
114
115 #[inline]
117 #[must_use]
118 pub fn mac_address(&self) -> MacAddress {
119 self.device.mac_address()
120 }
121
122 #[inline]
124 #[must_use]
125 pub const fn ip_address(&self) -> Ipv4Addr {
126 self.config.ip_addr
127 }
128
129 #[inline]
131 #[must_use]
132 pub const fn state(&self) -> StackState {
133 self.state
134 }
135
136 #[inline]
138 #[must_use]
139 pub const fn arp_cache(&self) -> &ArpCache {
140 &self.arp_cache
141 }
142
143 #[inline]
145 pub fn tick(&mut self, current_time: u64) {
146 self.current_time = current_time;
147 self.arp_cache.expire_stale(current_time);
148 }
149
150 #[inline]
152 fn next_ip_id(&mut self) -> u16 {
153 let id = self.ip_id;
154 self.ip_id = self.ip_id.wrapping_add(1);
155 id
156 }
157
158 #[inline]
160 #[must_use]
161 pub fn is_local(&self, dest: Ipv4Addr) -> bool {
162 self.config
163 .ip_addr
164 .is_same_subnet(&dest, &self.config.subnet_mask)
165 }
166
167 pub fn resolve_next_hop(&mut self, dest: Ipv4Addr) -> NetResult<Option<MacAddress>> {
172 let next_hop = if self.is_local(dest) {
173 dest
174 } else {
175 self.config.gateway
176 };
177
178 if let Some(mac) = self.arp_cache.resolve(next_hop, self.current_time) {
180 return Ok(Some(mac));
181 }
182
183 self.send_arp_request(next_hop)?;
185
186 Ok(None)
187 }
188
189 pub fn send_arp_request(&mut self, target_ip: Ipv4Addr) -> NetResult<()> {
191 let arp = ArpPacket::request(self.device.mac_address(), self.config.ip_addr, target_ip);
192
193 let mut buf = [0u8; 64];
194
195 let frame = EthernetFrame::new(
197 MacAddress::BROADCAST,
198 self.device.mac_address(),
199 EtherType::Arp,
200 &[], );
202
203 let eth_len = frame.serialize(&mut buf)?;
204
205 let arp_len = arp.serialize(&mut buf[ETHERNET_HEADER_SIZE..])?;
207
208 self.device.send(&buf[..ETHERNET_HEADER_SIZE + arp_len])?;
210
211 self.arp_cache.mark_pending(target_ip, self.current_time)?;
213
214 let _ = eth_len;
216
217 Ok(())
218 }
219
220 pub fn send_udp(
225 &mut self,
226 src_port: u16,
227 dst_ip: Ipv4Addr,
228 dst_port: u16,
229 payload: &[u8],
230 ) -> NetResult<()> {
231 let max_payload = MTU - IPV4_HEADER_MIN_SIZE - UDP_HEADER_SIZE;
233 if payload.len() > max_payload {
234 return Err(NetError::PacketTooLarge);
235 }
236
237 let dst_mac = match self.resolve_next_hop(dst_ip)? {
239 Some(mac) => mac,
240 None => return Err(NetError::ArpNotFound),
241 };
242
243 let mut buf = [0u8; 1536];
244 let mut offset = 0;
245
246 offset += ETHERNET_HEADER_SIZE;
248
249 let ip_payload_len = UDP_HEADER_SIZE + payload.len();
251 let mut ip_header =
252 Ipv4Header::new(self.config.ip_addr, dst_ip, Protocol::Udp, ip_payload_len as u16);
253 ip_header.identification = self.next_ip_id();
254 ip_header.ttl = self.config.default_ttl;
255
256 let ip_len = ip_header.serialize(&mut buf[offset..])?;
257 offset += ip_len;
258
259 let udp_header = UdpHeader::new(src_port, dst_port, payload.len() as u16);
261 let udp_len = udp_header.serialize(&mut buf[offset..])?;
262
263 buf[offset + udp_len..offset + udp_len + payload.len()].copy_from_slice(payload);
265
266 let checksum = UdpHeader::compute_checksum(
268 self.config.ip_addr,
269 dst_ip,
270 &udp_header,
271 payload,
272 );
273 buf[offset + 6..offset + 8].copy_from_slice(&checksum.to_be_bytes());
274
275 offset += udp_len + payload.len();
276
277 let src_mac = self.device.mac_address();
279 buf[0..6].copy_from_slice(&dst_mac.0);
280 buf[6..12].copy_from_slice(&src_mac.0);
281 buf[12..14].copy_from_slice(&EtherType::Ipv4.to_u16().to_be_bytes());
282
283 self.device.send(&buf[..offset])
285 }
286
287 pub fn send_ping(
289 &mut self,
290 dst_ip: Ipv4Addr,
291 identifier: u16,
292 sequence: u16,
293 data: &[u8],
294 ) -> NetResult<()> {
295 let dst_mac = match self.resolve_next_hop(dst_ip)? {
297 Some(mac) => mac,
298 None => return Err(NetError::ArpNotFound),
299 };
300
301 let mut buf = [0u8; 1536];
302 let mut offset = 0;
303
304 offset += ETHERNET_HEADER_SIZE;
306
307 let echo = IcmpEcho {
309 identifier,
310 sequence,
311 data,
312 };
313 let icmp_start = offset + IPV4_HEADER_MIN_SIZE;
314 let icmp_len = echo.serialize(true, &mut buf[icmp_start..])?;
315
316 let mut ip_header =
318 Ipv4Header::new(self.config.ip_addr, dst_ip, Protocol::Icmp, icmp_len as u16);
319 ip_header.identification = self.next_ip_id();
320 ip_header.ttl = self.config.default_ttl;
321
322 ip_header.serialize(&mut buf[offset..])?;
323 offset = icmp_start + icmp_len;
324
325 let src_mac = self.device.mac_address();
327 buf[0..6].copy_from_slice(&dst_mac.0);
328 buf[6..12].copy_from_slice(&src_mac.0);
329 buf[12..14].copy_from_slice(&EtherType::Ipv4.to_u16().to_be_bytes());
330
331 self.device.send(&buf[..offset])
333 }
334
335 pub fn receive(&mut self, buf: &mut [u8]) -> NetResult<Option<ReceivedPacket>> {
340 let frame_len = match self.device.receive(buf)? {
342 Some(len) => len,
343 None => return Ok(None),
344 };
345
346 if frame_len < ETHERNET_HEADER_SIZE {
347 return Ok(None);
348 }
349
350 let dest_mac = MacAddress::parse(&buf[0..6])?;
352 let src_mac = MacAddress::parse(&buf[6..12])?;
353 let ether_type = EtherType::from_u16(u16::from_be_bytes([buf[12], buf[13]]));
354
355 let our_mac = self.device.mac_address();
357 if !dest_mac.is_broadcast()
358 && dest_mac != our_mac
359 && !dest_mac.is_multicast()
360 {
361 return Ok(None);
362 }
363
364 match ether_type {
365 EtherType::Arp => {
366 self.handle_arp(&buf[ETHERNET_HEADER_SIZE..frame_len])?;
367 Ok(None)
368 }
369 EtherType::Ipv4 => self.handle_ipv4_owned(src_mac, buf, frame_len),
370 _ => Ok(None),
371 }
372 }
373
374 fn handle_arp(&mut self, payload: &[u8]) -> NetResult<()> {
376 let arp = ArpPacket::parse(payload)?;
377
378 self.arp_cache
380 .insert(arp.sender_ip, arp.sender_mac, self.current_time)?;
381
382 if arp.is_request() && arp.target_ip == self.config.ip_addr {
384 let reply =
385 ArpPacket::reply(self.device.mac_address(), self.config.ip_addr, arp.sender_mac, arp.sender_ip);
386
387 let mut buf = [0u8; 64];
388
389 let frame = EthernetFrame::new(
391 arp.sender_mac,
392 self.device.mac_address(),
393 EtherType::Arp,
394 &[],
395 );
396 frame.serialize(&mut buf)?;
397
398 let arp_len = reply.serialize(&mut buf[ETHERNET_HEADER_SIZE..])?;
400
401 self.device.send(&buf[..ETHERNET_HEADER_SIZE + arp_len])?;
402 }
403
404 Ok(())
405 }
406
407 fn handle_ipv4_owned(
409 &mut self,
410 src_mac: MacAddress,
411 buf: &mut [u8],
412 frame_len: usize,
413 ) -> NetResult<Option<ReceivedPacket>> {
414 let (ip_header, ip_payload) = Ipv4Header::parse(&buf[ETHERNET_HEADER_SIZE..frame_len])?;
415
416 if ip_header.dst_addr != self.config.ip_addr
418 && !ip_header.dst_addr.is_broadcast()
419 && !ip_header.dst_addr.is_multicast()
420 {
421 return Ok(None);
422 }
423
424 if ip_header.flags.more_fragments || ip_header.fragment_offset != 0 {
426 return Err(NetError::FragmentationNotSupported);
427 }
428
429 match ip_header.protocol {
430 Protocol::Icmp => {
431 self.handle_icmp(src_mac, &ip_header, ip_payload)?;
432 Ok(None)
433 }
434 Protocol::Udp => self.handle_udp(src_mac, &ip_header, ip_payload),
435 _ => Ok(None),
436 }
437 }
438
439 fn handle_icmp(
441 &mut self,
442 _src_mac: MacAddress,
443 ip_header: &Ipv4Header,
444 payload: &[u8],
445 ) -> NetResult<()> {
446 let (icmp_header, icmp_payload) = IcmpHeader::parse(payload)?;
447
448 if !IcmpHeader::verify_checksum(payload) {
450 return Ok(()); }
452
453 if self.config.enable_ping && icmp_header.icmp_type == IcmpType::EchoRequest {
455 let echo = IcmpEcho::parse(&icmp_header, icmp_payload)?;
456
457 self.send_icmp_echo_reply(ip_header.src_addr, echo.identifier, echo.sequence, echo.data)?;
459 }
460
461 Ok(())
462 }
463
464 fn send_icmp_echo_reply(
466 &mut self,
467 dst_ip: Ipv4Addr,
468 identifier: u16,
469 sequence: u16,
470 data: &[u8],
471 ) -> NetResult<()> {
472 let dst_mac = match self.arp_cache.resolve(dst_ip, self.current_time) {
474 Some(mac) => mac,
475 None => return Ok(()), };
477
478 let mut buf = [0u8; 1536];
479 let mut offset = 0;
480
481 offset += ETHERNET_HEADER_SIZE;
483
484 let echo = IcmpEcho {
486 identifier,
487 sequence,
488 data,
489 };
490 let icmp_start = offset + IPV4_HEADER_MIN_SIZE;
491 let icmp_len = echo.serialize(false, &mut buf[icmp_start..])?; let mut ip_header =
495 Ipv4Header::new(self.config.ip_addr, dst_ip, Protocol::Icmp, icmp_len as u16);
496 ip_header.identification = self.next_ip_id();
497 ip_header.ttl = self.config.default_ttl;
498
499 ip_header.serialize(&mut buf[offset..])?;
500 offset = icmp_start + icmp_len;
501
502 let src_mac = self.device.mac_address();
504 buf[0..6].copy_from_slice(&dst_mac.0);
505 buf[6..12].copy_from_slice(&src_mac.0);
506 buf[12..14].copy_from_slice(&EtherType::Ipv4.to_u16().to_be_bytes());
507
508 self.device.send(&buf[..offset])
510 }
511
512 fn handle_udp(
514 &mut self,
515 src_mac: MacAddress,
516 ip_header: &Ipv4Header,
517 payload: &[u8],
518 ) -> NetResult<Option<ReceivedPacket>> {
519 let (udp_header, udp_payload) = UdpHeader::parse(payload)?;
520
521 if udp_header.checksum != 0 {
523 if !UdpHeader::verify_checksum(
524 ip_header.src_addr,
525 ip_header.dst_addr,
526 &udp_header,
527 udp_payload,
528 ) {
529 return Err(NetError::UdpChecksumError);
530 }
531 }
532
533 Ok(Some(ReceivedPacket {
534 src_mac,
535 src_ip: ip_header.src_addr,
536 src_port: udp_header.src_port,
537 dst_port: udp_header.dst_port,
538 protocol: Protocol::Udp,
539 payload_offset: ETHERNET_HEADER_SIZE
540 + ip_header.header_len()
541 + UDP_HEADER_SIZE,
542 payload_len: udp_payload.len(),
543 }))
544 }
545
546 #[inline]
548 #[must_use]
549 pub const fn device(&self) -> &D {
550 &self.device
551 }
552
553 #[inline]
555 pub fn device_mut(&mut self) -> &mut D {
556 &mut self.device
557 }
558}
559
560#[cfg(test)]
561mod tests {
562 use super::*;
563 use crate::device::LoopbackDevice;
564
565 fn create_test_stack() -> NetworkStack<LoopbackDevice> {
566 let device = LoopbackDevice::new();
567 let config = StackConfig {
568 ip_addr: Ipv4Addr::new(192, 168, 1, 1),
569 subnet_mask: Ipv4Addr::new(255, 255, 255, 0),
570 gateway: Ipv4Addr::new(192, 168, 1, 254),
571 ..Default::default()
572 };
573 NetworkStack::new(device, config)
574 }
575
576 #[test]
577 fn test_stack_creation() {
578 let stack = create_test_stack();
579 assert_eq!(stack.ip_address(), Ipv4Addr::new(192, 168, 1, 1));
580 assert_eq!(stack.state(), StackState::Ready);
581 }
582
583 #[test]
584 fn test_is_local() {
585 let stack = create_test_stack();
586
587 assert!(stack.is_local(Ipv4Addr::new(192, 168, 1, 100)));
589
590 assert!(!stack.is_local(Ipv4Addr::new(10, 0, 0, 1)));
592 }
593
594 #[test]
595 fn test_ip_id_counter() {
596 let mut stack = create_test_stack();
597
598 let id1 = stack.next_ip_id();
599 let id2 = stack.next_ip_id();
600 let id3 = stack.next_ip_id();
601
602 assert_eq!(id1, 0);
603 assert_eq!(id2, 1);
604 assert_eq!(id3, 2);
605 }
606
607 #[test]
608 fn test_tick() {
609 let mut stack = create_test_stack();
610
611 stack
613 .arp_cache
614 .insert(
615 Ipv4Addr::new(192, 168, 1, 2),
616 MacAddress::new([0, 1, 2, 3, 4, 5]),
617 0,
618 )
619 .unwrap();
620
621 assert!(stack
623 .arp_cache
624 .resolve(Ipv4Addr::new(192, 168, 1, 2), 0)
625 .is_some());
626
627 stack.tick(1000);
629 assert!(stack
630 .arp_cache
631 .resolve(Ipv4Addr::new(192, 168, 1, 2), 1000)
632 .is_none());
633 }
634
635 #[test]
636 fn test_arp_request_send() {
637 let mut stack = create_test_stack();
638
639 let result = stack.send_arp_request(Ipv4Addr::new(192, 168, 1, 2));
641 assert!(result.is_ok());
642
643 let entry = stack.arp_cache.lookup(Ipv4Addr::new(192, 168, 1, 2));
645 assert!(entry.is_some());
646 }
647
648 #[test]
649 fn test_receive_empty() {
650 let mut stack = create_test_stack();
651 let mut buf = [0u8; 1536];
652
653 let result = stack.receive(&mut buf).unwrap();
655 assert!(result.is_none());
656 }
657
658 #[test]
659 fn test_stack_config_default() {
660 let config = StackConfig::default();
661 assert_eq!(config.default_ttl, 64);
662 assert!(config.enable_ping);
663 assert_eq!(config.arp_timeout, 300);
664 }
665}