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 buf_len = buf_len as usize;
75 let mut kbuf = SmallVec::<[u8; NET_INLINE_BUF_CAPACITY]>::new();
76 kbuf.resize(buf_len, 0u8);
77
78 let n = {
82 let from_ring = {
83 let dp_guard = crate::hardware::nic::data_plane().lock();
84 match dp_guard.as_ref() {
85 Some(dp) => match dp.pop_rx(0, &mut kbuf) {
86 Ok(Some(n)) => Some(n),
87 _ => None,
88 },
89 None => None,
90 }
91 };
92 if let Some(n) = from_ring {
93 n
94 } else {
95 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
96 match device.receive(&mut kbuf) {
97 Ok(n) => n,
98 Err(e) => {
99 let se = SyscallError::from(e);
100 if se != SyscallError::Again
101 && NET_RECV_ERR_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed) > 0
102 {
103 crate::serial_println!("[net-sys] recv error: {:?} -> {}", e, se.name());
104 }
105 return Err(se);
106 }
107 }
108 }
109 };
110 crate::serial_println!("[net] recv {} bytes", n);
111 if n > 50 {
112 crate::serial_print!("[net] rx icmp");
113 for i in 34..50 {
114 crate::serial_print!(" {:02x}", kbuf[i]);
115 }
116 crate::serial_println!("");
117 }
118 trace_dhcp_frame("rx", &kbuf[..n]);
119
120 let user = UserSliceWrite::new(buf_ptr, n)?;
121 user.copy_from(&kbuf[..n]);
122 Ok(n as u64)
123}
124
125pub fn sys_net_send(buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
127 let buf_len = buf_len as usize;
128 let user = UserSliceRead::new(buf_ptr, buf_len)?;
129 let mut kbuf = SmallVec::<[u8; NET_INLINE_BUF_CAPACITY]>::new();
130 kbuf.resize(buf_len, 0u8);
131 let copied = user.copy_to(&mut kbuf);
132 if copied != buf_len {
133 return Err(SyscallError::Fault);
134 }
135 trace_dhcp_frame("tx", &kbuf);
136
137 if crate::hardware::nic::nic_irq_ready() {
140 let pushed = {
141 let dp_guard = crate::hardware::nic::data_plane().lock();
142 match dp_guard.as_ref() {
143 Some(dp) => match dp.push_tx(0, &kbuf) {
144 Ok(()) => {
145 dp.notify_tx_producer(0);
146 true
147 }
148 Err(_) => false,
149 },
150 None => false,
151 }
152 };
153 if pushed {
154 crate::serial_println!("[net] tx ok {} bytes (N2 ring)", buf_len);
155 return Ok(buf_len as u64);
156 }
157 }
158
159 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
161 if let Err(e) = device.transmit(&kbuf) {
162 let se = SyscallError::from(e);
163 if NET_SEND_ERR_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed) > 0 {
164 crate::serial_println!("[net-sys] send error: {:?} -> {}", e, se.name());
165 }
166 return Err(se);
167 }
168
169 crate::serial_println!("[net] tx ok {} bytes (direct)", buf_len);
170 Ok(buf_len as u64)
171}
172
173pub fn sys_net_register() -> Result<u64, SyscallError> {
178 let task = crate::process::current_task_clone().ok_or(SyscallError::PermissionDenied)?;
179 crate::hardware::nic::register_strate_net_tid(task.id.as_u64());
180 log::info!("[net] strate-net registered (tid={})", task.id.as_u64());
181 Ok(0)
182}
183
184pub fn sys_net_info(info_type: u64, buf_ptr: u64) -> Result<u64, SyscallError> {
188 let device = crate::hardware::nic::get_default_device().ok_or(SyscallError::Again)?;
189
190 match info_type {
191 0 => {
192 let mac = device.mac_address();
193 let user = UserSliceWrite::new(buf_ptr, 6)?;
194 user.copy_from(&mac);
195 Ok(6)
196 }
197 _ => Err(SyscallError::InvalidArgument),
198 }
199}