strat9_kernel/syscall/
net.rs1use super::error::SyscallError;
6use crate::memory::{UserSliceRead, UserSliceWrite};
7use core::sync::atomic::{AtomicU32, Ordering};
8use smallvec::SmallVec;
9
10const NET_INLINE_BUF_CAPACITY: usize = 2048;
13
14static NET_SEND_ERR_LOG_BUDGET: AtomicU32 = AtomicU32::new(32);
16static NET_RECV_ERR_LOG_BUDGET: AtomicU32 = AtomicU32::new(32);
18static DHCP_TRACE_LOG_BUDGET: AtomicU32 = AtomicU32::new(64);
20
21fn trace_dhcp_frame(tag: &str, frame: &[u8]) {
25 if DHCP_TRACE_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed) == 0 {
26 return;
27 }
28 if frame.len() < 14 {
29 return;
30 }
31 let ethertype = u16::from_be_bytes([frame[12], frame[13]]);
32 if ethertype != 0x0800 {
33 return;
34 }
35 if frame.len() < 34 {
36 return;
37 }
38 let ip_hlen = ((frame[14] & 0x0f) as usize) * 4;
39 if ip_hlen < 20 || frame.len() < 14 + ip_hlen + 8 {
40 return;
41 }
42 if frame[23] != 17 {
43 return;
44 }
45 let udp = 14 + ip_hlen;
46 let src_port = u16::from_be_bytes([frame[udp], frame[udp + 1]]);
47 let dst_port = u16::from_be_bytes([frame[udp + 2], frame[udp + 3]]);
48 let is_dhcp = (src_port == 68 && dst_port == 67) || (src_port == 67 && dst_port == 68);
49 if !is_dhcp {
50 return;
51 }
52 let mut xid: u32 = 0;
53 let bootp = udp + 8;
54 if frame.len() >= bootp + 8 {
55 xid = u32::from_be_bytes([
56 frame[bootp + 4],
57 frame[bootp + 5],
58 frame[bootp + 6],
59 frame[bootp + 7],
60 ]);
61 }
62 crate::serial_println!(
63 "[dhcp-trace] {} src_port={} dst_port={} len={} xid=0x{:08x}",
64 tag,
65 src_port,
66 dst_port,
67 frame.len(),
68 xid
69 );
70}
71
72pub fn sys_net_recv(buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
74 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
75 let buf_len = buf_len as usize;
76 let mut kbuf = SmallVec::<[u8; NET_INLINE_BUF_CAPACITY]>::new();
77 kbuf.resize(buf_len, 0u8);
78
79 let n = match device.receive(&mut kbuf) {
80 Ok(n) => n,
81 Err(e) => {
82 let se = SyscallError::from(e);
83 if se != SyscallError::Again
84 && NET_RECV_ERR_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed) > 0
85 {
86 crate::serial_println!("[net-sys] recv error: {:?} -> {}", e, se.name());
87 }
88 return Err(se);
89 }
90 };
91 crate::serial_println!("[net] recv {} bytes", n);
92 if n > 50 {
93 crate::serial_print!("[net] rx icmp");
94 for i in 34..50 {
95 crate::serial_print!(" {:02x}", kbuf[i]);
96 }
97 crate::serial_println!("");
98 }
99 trace_dhcp_frame("rx", &kbuf[..n]);
100
101 let user = UserSliceWrite::new(buf_ptr, n)?;
102 user.copy_from(&kbuf[..n]);
103 Ok(n as u64)
104}
105
106pub fn sys_net_send(buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
108 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
109 let buf_len = buf_len as usize;
110 let user = UserSliceRead::new(buf_ptr, buf_len)?;
111 let mut kbuf = SmallVec::<[u8; NET_INLINE_BUF_CAPACITY]>::new();
112 kbuf.resize(buf_len, 0u8);
113 let copied = user.copy_to(&mut kbuf);
114 if copied != buf_len {
115 return Err(SyscallError::Fault);
116 }
117 trace_dhcp_frame("tx", &kbuf);
118
119 if let Err(e) = device.transmit(&kbuf) {
120 let se = SyscallError::from(e);
121 if NET_SEND_ERR_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed) > 0 {
122 crate::serial_println!("[net-sys] send error: {:?} -> {}", e, se.name());
123 }
124 return Err(se);
125 }
126
127 crate::serial_println!("[net] tx ok {} bytes", buf_len);
128 Ok(buf_len as u64)
129}
130
131pub fn sys_net_info(info_type: u64, buf_ptr: u64) -> Result<u64, SyscallError> {
135 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
136
137 match info_type {
138 0 => {
139 let mac = device.mac_address();
140 let user = UserSliceWrite::new(buf_ptr, 6)?;
141 user.copy_from(&mac);
142 Ok(6)
143 }
144 _ => Err(SyscallError::InvalidArgument),
145 }
146}