1#![no_std]
2#![no_main]
3#![feature(alloc_error_handler)]
4
5extern crate alloc;
6
7use alloc::{collections::BTreeMap, string::String};
8use core::{
9 alloc::Layout,
10 panic::PanicInfo,
11 sync::atomic::{AtomicUsize, Ordering},
12};
13use strate_net::{syscalls::*, IpcMessage, OPCODE_CLOSE, OPCODE_OPEN, OPCODE_READ, OPCODE_WRITE};
14
15alloc_freelist::define_freelist_brk_allocator!(
16 pub struct BumpAllocator;
17 brk = strat9_syscall::call::brk;
18 heap_max = 16 * 1024 * 1024;
19);
20
21#[global_allocator]
22static GLOBAL_ALLOCATOR: BumpAllocator = BumpAllocator;
23
24#[alloc_error_handler]
25fn alloc_error(_layout: Layout) -> ! {
27 let _ = call::debug_log(b"[strate-net] OOM\n");
28 exit(12);
29}
30
31#[panic_handler]
32fn panic(info: &PanicInfo) -> ! {
34 let _ = call::debug_log(b"[strate-net] PANIC: ");
35 let msg = info.message();
36 let mut buf = [0u8; 256];
37 use core::fmt::Write;
38 let mut cursor = BufWriter {
39 buf: &mut buf,
40 pos: 0,
41 };
42 let _ = write!(cursor, "{}", msg);
43 let written = cursor.pos;
44 if written > 0 {
45 let _ = call::debug_log(&buf[..written]);
46 }
47 let _ = call::debug_log(b"\n");
48 exit(255);
49}
50
51struct BufWriter<'a> {
53 buf: &'a mut [u8],
54 pos: usize,
55}
56
57impl core::fmt::Write for BufWriter<'_> {
58 fn write_str(&mut self, s: &str) -> core::fmt::Result {
60 let bytes = s.as_bytes();
61 let avail = self.buf.len().saturating_sub(self.pos);
62 let n = bytes.len().min(avail);
63 self.buf[self.pos..self.pos + n].copy_from_slice(&bytes[..n]);
64 self.pos += n;
65 Ok(())
66 }
67}
68
69use smoltcp::{
74 iface::{Config, Interface, SocketHandle, SocketSet},
75 phy::{self, Device, DeviceCapabilities, Medium},
76 socket::{dhcpv4, dns, icmp, tcp, udp},
77 time::Instant,
78 wire::{DnsQueryType, EthernetAddress, IpAddress, IpCidr, IpEndpoint, Ipv4Address},
79};
80
81fn icmp_checksum(data: &[u8]) -> u16 {
83 let mut sum: u32 = 0;
84 let mut i = 0;
85 while i + 1 < data.len() {
86 sum += u16::from_be_bytes([data[i], data[i + 1]]) as u32;
87 i += 2;
88 }
89 if i < data.len() {
90 sum += (data[i] as u32) << 8;
91 }
92 while sum >> 16 != 0 {
93 sum = (sum & 0xFFFF) + (sum >> 16);
94 }
95 !(sum as u16)
96}
97
98const MAX_FRAME_SIZE: usize = 1514;
99const NANOS_PER_SEC: u64 = 1_000_000_000;
100const NANOS_PER_MICRO: u64 = 1_000;
101static RX_ERR_LOG_BUDGET: AtomicUsize = AtomicUsize::new(16);
102static TX_ERR_LOG_BUDGET: AtomicUsize = AtomicUsize::new(16);
103
104fn log_errno(prefix: &str, err: strate_net::syscalls::Error) {
106 use core::fmt::Write;
107 let mut buf = [0u8; 96];
108 let len = {
109 let mut w = BufWriter {
110 buf: &mut buf,
111 pos: 0,
112 };
113 let _ = write!(w, "{}{}\n", prefix, err.to_errno());
114 w.pos
115 };
116 if let Ok(s) = core::str::from_utf8(&buf[..len]) {
117 debug_log(s);
118 }
119}
120
121fn now_instant() -> Instant {
123 match clock_gettime_ns() {
124 Ok(ns) => Instant::from_micros((ns / NANOS_PER_MICRO) as i64),
125 Err(_) => Instant::from_micros(0),
126 }
127}
128
129fn sleep_micros(micros: u64) {
131 if micros == 0 {
132 return;
133 }
134 let nanos = micros.saturating_mul(NANOS_PER_MICRO);
135 let req = TimeSpec {
136 tv_sec: (nanos / NANOS_PER_SEC) as i64,
137 tv_nsec: (nanos % NANOS_PER_SEC) as i64,
138 };
139 let _ = nanosleep(&req);
140}
141
142struct Strat9NetDevice;
143
144impl Device for Strat9NetDevice {
145 type RxToken<'a> = Strat9RxToken;
146 type TxToken<'a> = Strat9TxToken;
147
148 fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
150 let mut buf = [0u8; MAX_FRAME_SIZE];
151 match net_recv(&mut buf) {
152 Ok(n) if n > 0 => {
153 let len = core::cmp::min(n, MAX_FRAME_SIZE);
154 Some((Strat9RxToken { buf, len }, Strat9TxToken))
155 }
156 Err(e) => {
157 if e.to_errno() != 11 {
158 if RX_ERR_LOG_BUDGET.load(Ordering::Relaxed) > 0 {
159 RX_ERR_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed);
160 log_errno("[strate-net] net_recv errno=", e);
161 }
162 }
163 None
164 }
165 _ => None,
166 }
167 }
168
169 fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
171 Some(Strat9TxToken)
172 }
173
174 fn capabilities(&self) -> DeviceCapabilities {
176 let mut caps = DeviceCapabilities::default();
177 caps.max_transmission_unit = MAX_FRAME_SIZE;
178 caps.medium = Medium::Ethernet;
179 caps
180 }
181}
182
183struct Strat9RxToken {
184 buf: [u8; MAX_FRAME_SIZE],
185 len: usize,
186}
187
188impl phy::RxToken for Strat9RxToken {
189 fn consume<R, F>(self, f: F) -> R
190 where
191 F: FnOnce(&[u8]) -> R,
192 {
193 f(&self.buf[..self.len])
194 }
195}
196
197struct Strat9TxToken;
198
199impl phy::TxToken for Strat9TxToken {
200 fn consume<R, F>(self, len: usize, f: F) -> R
201 where
202 F: FnOnce(&mut [u8]) -> R,
203 {
204 if len > MAX_FRAME_SIZE {
205 log("[strate-net] TX frame too large\n");
206 return f(&mut []);
207 }
208 let mut buf = [0u8; MAX_FRAME_SIZE];
209 let ret = f(&mut buf[..len]);
210 if let Err(e) = net_send(&buf[..len]) {
211 if TX_ERR_LOG_BUDGET.load(Ordering::Relaxed) > 0 {
212 TX_ERR_LOG_BUDGET.fetch_sub(1, Ordering::Relaxed);
213 log_errno("[strate-net] net_send errno=", e);
214 }
215 }
216 ret
217 }
218}
219
220#[derive(Debug, Clone)]
225struct IpConfig {
226 address: smoltcp::wire::Ipv4Cidr,
228 host: Ipv4Address,
230 prefix_len: u8,
232 netmask: Ipv4Address,
234 broadcast: Ipv4Address,
236 gateway: Option<Ipv4Address>,
238 dns: [Option<Ipv4Address>; 3],
240}
241
242fn ipv4_cidr_to_str(cidr: &smoltcp::wire::Ipv4Cidr, buf: &mut [u8]) -> usize {
244 use core::fmt::Write;
245 let mut w = BufWriter { buf, pos: 0 };
246 let a = cidr.address().octets();
247 let _ = write!(
248 w,
249 "{}.{}.{}.{}/{}\n",
250 a[0],
251 a[1],
252 a[2],
253 a[3],
254 cidr.prefix_len()
255 );
256 w.pos
257}
258
259fn ipv4_addr_to_str(addr: &Ipv4Address, buf: &mut [u8]) -> usize {
261 use core::fmt::Write;
262 let mut w = BufWriter { buf, pos: 0 };
263 let a = addr.octets();
264 let _ = write!(w, "{}.{}.{}.{}\n", a[0], a[1], a[2], a[3]);
265 w.pos
266}
267
268fn u8_to_str(v: u8, buf: &mut [u8]) -> usize {
270 use core::fmt::Write;
271 let mut w = BufWriter { buf, pos: 0 };
272 let _ = write!(w, "{}\n", v);
273 w.pos
274}
275
276fn mask_from_prefix(prefix: u8) -> Ipv4Address {
278 let mask: u32 = if prefix == 0 {
279 0
280 } else if prefix >= 32 {
281 u32::MAX
282 } else {
283 u32::MAX << (32 - prefix)
284 };
285 let b = mask.to_be_bytes();
286 Ipv4Address::new(b[0], b[1], b[2], b[3])
287}
288
289fn broadcast_from_host_prefix(host: Ipv4Address, prefix: u8) -> Ipv4Address {
291 let h = u32::from_be_bytes(host.octets());
292 let m = u32::from_be_bytes(mask_from_prefix(prefix).octets());
293 let b = (h & m) | (!m);
294 let o = b.to_be_bytes();
295 Ipv4Address::new(o[0], o[1], o[2], o[3])
296}
297
298fn route_to_str(gateway: &Ipv4Address, buf: &mut [u8]) -> usize {
300 use core::fmt::Write;
301 let mut w = BufWriter { buf, pos: 0 };
302 let a = gateway.octets();
303 let _ = write!(w, "default via {}.{}.{}.{}\n", a[0], a[1], a[2], a[3]);
304 w.pos
305}
306
307fn dns_list_to_str(dns: &[Option<Ipv4Address>; 3], buf: &mut [u8]) -> usize {
309 use core::fmt::Write;
310 let mut w = BufWriter { buf, pos: 0 };
311 let mut wrote_any = false;
312 for server in dns.iter().flatten() {
313 let a = server.octets();
314 let _ = write!(w, "{}.{}.{}.{}\n", a[0], a[1], a[2], a[3]);
315 wrote_any = true;
316 }
317 if !wrote_any {
318 let _ = write!(w, "0.0.0.0\n");
319 }
320 w.pos
321}
322
323fn parse_ipv4_cidr(s: &str) -> Option<smoltcp::wire::Ipv4Cidr> {
325 let slash = s.find('/')?;
326 let ip = parse_ipv4(&s[..slash])?;
327 let prefix = s[slash + 1..].parse::<u8>().ok()?;
328 if prefix > 32 {
329 return None;
330 }
331 Some(smoltcp::wire::Ipv4Cidr::new(ip, prefix))
332}
333
334fn reply_open(sender: u64, file_id: u64, size: u64, flags: u32) -> IpcMessage {
354 let mut msg = IpcMessage::new(0x80);
355 msg.sender = sender;
356 msg.payload[0..4].copy_from_slice(&0u32.to_le_bytes());
357 msg.payload[4..12].copy_from_slice(&file_id.to_le_bytes());
358 msg.payload[12..20].copy_from_slice(&size.to_le_bytes());
359 msg.payload[20..24].copy_from_slice(&flags.to_le_bytes());
360 msg
361}
362
363fn reply_read(sender: u64, data: &[u8]) -> IpcMessage {
365 let mut msg = IpcMessage::new(0x80);
366 msg.sender = sender;
367 msg.payload[0..4].copy_from_slice(&0u32.to_le_bytes());
368 let n = data.len().min(40);
370 msg.payload[4..8].copy_from_slice(&(n as u32).to_le_bytes());
371 msg.payload[8..8 + n].copy_from_slice(&data[..n]);
372 msg
373}
374
375fn reply_write(sender: u64, n: usize) -> IpcMessage {
377 let mut msg = IpcMessage::new(0x80);
378 msg.sender = sender;
379 msg.payload[0..4].copy_from_slice(&0u32.to_le_bytes());
380 msg.payload[4..8].copy_from_slice(&(n as u32).to_le_bytes());
381 msg
382}
383
384fn reply_ok(sender: u64) -> IpcMessage {
386 let mut msg = IpcMessage::new(0x80);
387 msg.sender = sender;
388 msg.payload[0..4].copy_from_slice(&0u32.to_le_bytes());
389 msg
390}
391
392fn parse_ipv4(s: &str) -> Option<Ipv4Address> {
394 let mut octets = [0u8; 4];
395 let mut idx = 0;
396 let mut val: u16 = 0;
397 let mut has_digit = false;
398 for &b in s.as_bytes() {
399 if b == b'.' {
400 if !has_digit || idx >= 3 {
401 return None;
402 }
403 if val > 255 {
404 return None;
405 }
406 octets[idx] = val as u8;
407 idx += 1;
408 val = 0;
409 has_digit = false;
410 } else if b >= b'0' && b <= b'9' {
411 val = val * 10 + (b - b'0') as u16;
412 has_digit = true;
413 } else {
414 break;
415 }
416 }
417 if !has_digit || idx != 3 || val > 255 {
418 return None;
419 }
420 octets[3] = val as u8;
421 Some(Ipv4Address::new(octets[0], octets[1], octets[2], octets[3]))
422}
423
424struct PendingPing {
429 seq: u16,
430 send_ts_ns: u64,
431}
432
433#[derive(Clone, Copy)]
434struct TcpListenerState {
435 socket: SocketHandle,
436 port: u16,
437 auto_relisten: bool,
438}
439
440#[derive(Copy, Clone)]
442struct TcpConnState {
443 socket: SocketHandle,
444 local_port: u16,
445 remote: IpEndpoint,
446}
447
448#[derive(Copy, Clone)]
450struct UdpBoundState {
451 socket: SocketHandle,
452 local_port: u16,
453}
454
455#[derive(Copy, Clone)]
458struct UdpConnState {
459 socket: SocketHandle,
460 local_port: u16,
461 remote: IpEndpoint,
462}
463
464struct NetworkStrate {
465 device: Strat9NetDevice,
466 interface: Interface,
467 sockets: SocketSet<'static>,
468 dhcp_handle: SocketHandle,
469 dns_handle: SocketHandle,
470 icmp_handle: SocketHandle,
471 ip_config: Option<IpConfig>,
472 open_handles: BTreeMap<u64, String>,
474 tcp_listeners: BTreeMap<u64, TcpListenerState>,
475 tcp_connections: BTreeMap<u64, TcpConnState>,
476 udp_bound: BTreeMap<u64, UdpBoundState>,
477 udp_connections: BTreeMap<u64, UdpConnState>,
478 next_fid: u64,
479 pending_ping: Option<PendingPing>,
481 ping_reply: Option<(u16, u64)>,
483 ping_ident: u16,
484 dhcp_enabled: bool,
485}
486
487impl NetworkStrate {
488 fn new(mac: [u8; 6]) -> Self {
490 let mut device = Strat9NetDevice;
491 let config = Config::new(EthernetAddress(mac).into());
492 let interface = Interface::new(config, &mut device, Instant::from_micros(0));
493 let mut sockets = SocketSet::new(alloc::vec![]);
494
495 let dhcp_socket = dhcpv4::Socket::new();
496 let dhcp_handle = sockets.add(dhcp_socket);
497
498 let dns_socket = dns::Socket::new(&[], alloc::vec![]);
499 let dns_handle = sockets.add(dns_socket);
500
501 let icmp_rx_buf = icmp::PacketBuffer::new(
502 alloc::vec![icmp::PacketMetadata::EMPTY; 4],
503 alloc::vec![0u8; 1024],
504 );
505 let icmp_tx_buf = icmp::PacketBuffer::new(
506 alloc::vec![icmp::PacketMetadata::EMPTY; 4],
507 alloc::vec![0u8; 1024],
508 );
509 let icmp_socket = icmp::Socket::new(icmp_rx_buf, icmp_tx_buf);
510 let icmp_handle = sockets.add(icmp_socket);
511
512 Self {
513 device,
514 interface,
515 sockets,
516 dhcp_handle,
517 dns_handle,
518 icmp_handle,
519 ip_config: None,
520 open_handles: BTreeMap::new(),
521 tcp_listeners: BTreeMap::new(),
522 tcp_connections: BTreeMap::new(),
523 udp_bound: BTreeMap::new(),
524 udp_connections: BTreeMap::new(),
525 next_fid: 1,
526 pending_ping: None,
527 ping_reply: None,
528 ping_ident: 0x9001,
529 dhcp_enabled: true,
530 }
531 }
532
533 fn udp_port_in_use(&self, port: u16) -> bool {
535 self.udp_bound.values().any(|s| s.local_port == port)
536 || self.udp_connections.values().any(|s| s.local_port == port)
537 }
538
539 fn alloc_udp_ephemeral_port(&self) -> Option<u16> {
541 const BASE: u16 = 49_152;
542 const COUNT: usize = 16_384;
543 let start = (self.next_fid as usize) % COUNT;
544 for step in 0..COUNT {
545 let port = BASE + ((start + step) % COUNT) as u16;
546 if !self.udp_port_in_use(port) {
547 return Some(port);
548 }
549 }
550 None
551 }
552
553 fn create_udp_socket(&mut self, local_port: u16) -> core::result::Result<SocketHandle, i32> {
556 let rx_buf = udp::PacketBuffer::new(
557 alloc::vec![udp::PacketMetadata::EMPTY; 16],
558 alloc::vec![0u8; 4096],
559 );
560 let tx_buf = udp::PacketBuffer::new(
561 alloc::vec![udp::PacketMetadata::EMPTY; 16],
562 alloc::vec![0u8; 4096],
563 );
564 let mut socket = udp::Socket::new(rx_buf, tx_buf);
565 if socket.bind(local_port).is_err() {
566 return Err(-98); }
568 Ok(self.sockets.add(socket))
569 }
570
571 fn tcp_state_name(state: tcp::State) -> &'static str {
573 match state {
574 tcp::State::Closed => "CLOSED",
575 tcp::State::Listen => "LISTEN",
576 tcp::State::SynSent => "SYN-SENT",
577 tcp::State::SynReceived => "SYN-RECEIVED",
578 tcp::State::Established => "ESTABLISHED",
579 tcp::State::FinWait1 => "FIN-WAIT-1",
580 tcp::State::FinWait2 => "FIN-WAIT-2",
581 tcp::State::CloseWait => "CLOSE-WAIT",
582 tcp::State::Closing => "CLOSING",
583 tcp::State::LastAck => "LAST-ACK",
584 tcp::State::TimeWait => "TIME-WAIT",
585 }
586 }
587
588 fn process_dhcp(&mut self) {
594 if !self.dhcp_enabled {
595 return;
596 }
597 let event = self
598 .sockets
599 .get_mut::<dhcpv4::Socket>(self.dhcp_handle)
600 .poll();
601
602 match event {
603 Some(dhcpv4::Event::Configured(config)) => {
604 log("[strate-net] DHCP: address acquired\n");
605
606 self.interface.update_ip_addrs(|addrs| {
608 let cidr = IpCidr::new(
609 IpAddress::Ipv4(config.address.address()),
610 config.address.prefix_len(),
611 );
612 if let Some(slot) = addrs.iter_mut().next() {
613 *slot = cidr;
614 } else {
615 let _ = addrs.push(cidr);
617 }
618 });
619
620 let _ = self.interface.routes_mut().remove_default_ipv4_route();
622 if let Some(gw) = config.router {
623 self.interface.routes_mut().add_default_ipv4_route(gw).ok();
624 }
625
626 let mut dns = [None::<Ipv4Address>; 3];
628 for (slot, &server) in dns.iter_mut().zip(config.dns_servers.iter()) {
629 *slot = Some(server);
630 }
631
632 let host = config.address.address();
633 let prefix_len = config.address.prefix_len();
634 let netmask = mask_from_prefix(prefix_len);
635 let broadcast = broadcast_from_host_prefix(host, prefix_len);
636 self.ip_config = Some(IpConfig {
637 address: config.address,
638 host,
639 prefix_len,
640 netmask,
641 broadcast,
642 gateway: config.router,
643 dns,
644 });
645 self.refresh_dns_servers();
646 }
647 Some(dhcpv4::Event::Deconfigured) => {
648 log("[strate-net] DHCP: deconfigured (lease expired?)\n");
649 self.ip_config = None;
650 self.interface.update_ip_addrs(|addrs| addrs.clear());
652 let _ = self.interface.routes_mut().remove_default_ipv4_route();
653 self.refresh_dns_servers();
654 }
655 None => {}
656 }
657 }
658
659 fn refresh_dns_servers(&mut self) {
661 let mut servers = [IpAddress::Ipv4(Ipv4Address::new(0, 0, 0, 0)); 3];
662 let mut count = 0usize;
663
664 if let Some(ref cfg) = self.ip_config {
665 for s in cfg.dns.iter().flatten() {
666 if *s != Ipv4Address::new(0, 0, 0, 0) && count < servers.len() {
667 servers[count] = IpAddress::Ipv4(*s);
668 count += 1;
669 }
670 }
671 if count == 0 {
672 if let Some(gw) = cfg.gateway {
673 servers[0] = IpAddress::Ipv4(gw);
674 count = 1;
675 }
676 }
677 }
678
679 let socket = self.sockets.get_mut::<dns::Socket>(self.dns_handle);
680 socket.update_servers(&servers[..count]);
681 }
682
683 fn apply_ipv4_config(
685 &mut self,
686 address: smoltcp::wire::Ipv4Cidr,
687 gateway: Option<Ipv4Address>,
688 dns: [Option<Ipv4Address>; 3],
689 ) {
690 let host = address.address();
691 let prefix_len = address.prefix_len();
692 let netmask = mask_from_prefix(prefix_len);
693 let broadcast = broadcast_from_host_prefix(host, prefix_len);
694
695 self.interface.update_ip_addrs(|addrs| {
696 let cidr = IpCidr::new(IpAddress::Ipv4(host), prefix_len);
697 if let Some(slot) = addrs.iter_mut().next() {
698 *slot = cidr;
699 } else {
700 let _ = addrs.push(cidr);
701 }
702 });
703
704 let _ = self.interface.routes_mut().remove_default_ipv4_route();
705 if let Some(gw) = gateway {
706 let _ = self.interface.routes_mut().add_default_ipv4_route(gw);
707 }
708
709 self.ip_config = Some(IpConfig {
710 address,
711 host,
712 prefix_len,
713 netmask,
714 broadcast,
715 gateway,
716 dns,
717 });
718 self.refresh_dns_servers();
719 }
720
721 fn resolve_hostname_blocking(&mut self, name: &str) -> core::result::Result<Ipv4Address, i32> {
723 if let Some(ip) = parse_ipv4(name) {
724 return Ok(ip);
725 }
726 if self.ip_config.is_none() {
727 return Err(-11);
728 }
729
730 let query = {
731 let cx = self.interface.context();
732 let socket = self.sockets.get_mut::<dns::Socket>(self.dns_handle);
733 match socket.start_query(cx, name, DnsQueryType::A) {
734 Ok(q) => q,
735 Err(_) => return Err(-22),
736 }
737 };
738
739 let deadline_ns = clock_gettime_ns()
740 .unwrap_or(0)
741 .saturating_add(3_000_000_000);
742 loop {
743 let now = now_instant();
744 let _ = self
745 .interface
746 .poll(now, &mut self.device, &mut self.sockets);
747 self.process_dhcp();
748 self.process_icmp();
749
750 let res = self
751 .sockets
752 .get_mut::<dns::Socket>(self.dns_handle)
753 .get_query_result(query);
754 match res {
755 Ok(addrs) => {
756 for addr in addrs {
757 let IpAddress::Ipv4(v4) = addr;
758 return Ok(v4);
759 }
760 return Err(-2);
761 }
762 Err(dns::GetQueryResultError::Failed) => return Err(-2),
763 Err(dns::GetQueryResultError::Pending) => {
764 if clock_gettime_ns().unwrap_or(0) >= deadline_ns {
765 return Err(-110);
766 }
767 sleep_micros(10_000);
768 }
769 }
770 }
771 }
772
773 fn process_icmp(&mut self) {
779 let socket = self.sockets.get_mut::<icmp::Socket>(self.icmp_handle);
780 if !socket.can_recv() {
781 return;
782 }
783 let now_ns = clock_gettime_ns().unwrap_or(0);
784 while socket.can_recv() {
785 let Ok((data, _addr)) = socket.recv() else {
786 break;
787 };
788 if data.len() < 8 {
790 continue;
791 }
792 if data[0] != 0 {
794 continue;
795 }
796 let ident = u16::from_be_bytes([data[4], data[5]]);
797 let seq = u16::from_be_bytes([data[6], data[7]]);
798 if ident != self.ping_ident {
799 continue;
800 }
801 if let Some(ref pending) = self.pending_ping {
802 if seq == pending.seq {
803 let rtt_us = now_ns.saturating_sub(pending.send_ts_ns) / 1000;
804 self.ping_reply = Some((seq, rtt_us));
805 self.pending_ping = None;
806 }
807 }
808 }
809 }
810
811 fn send_ping(&mut self, target: Ipv4Address, seq: u16) -> bool {
813 if self.pending_ping.is_some() || self.ping_reply.is_some() {
815 return false;
816 }
817 let socket = self.sockets.get_mut::<icmp::Socket>(self.icmp_handle);
818 if !socket.is_open() {
819 socket.bind(icmp::Endpoint::Ident(self.ping_ident)).ok();
820 }
821 if !socket.can_send() {
822 return false;
823 }
824 let payload_len = 40;
826 let icmp_len = 8 + payload_len;
827 let Ok(buf) = socket.send(icmp_len, IpAddress::Ipv4(target)) else {
828 return false;
829 };
830 buf[0] = 8; buf[1] = 0; buf[2] = 0; buf[3] = 0;
834 buf[4..6].copy_from_slice(&self.ping_ident.to_be_bytes());
835 buf[6..8].copy_from_slice(&seq.to_be_bytes());
836 for i in 8..icmp_len {
837 buf[i] = 0xAA;
838 }
839 let cksum = icmp_checksum(buf);
841 buf[2..4].copy_from_slice(&cksum.to_be_bytes());
842
843 let now_ns = clock_gettime_ns().unwrap_or(0);
844 self.pending_ping = Some(PendingPing {
845 seq,
846 send_ts_ns: now_ns,
847 });
848 true
849 }
850
851 fn handle_open(&mut self, msg: &IpcMessage) -> IpcMessage {
857 let path_len = u16::from_le_bytes([msg.payload[4], msg.payload[5]]) as usize;
858 if path_len > 42 {
859 return IpcMessage::error_reply(msg.sender, -22);
860 }
861 let path_bytes = &msg.payload[6..6 + path_len];
862 let path = match core::str::from_utf8(path_bytes) {
863 Ok(p) => p.trim_start_matches('/'),
864 Err(_) => return IpcMessage::error_reply(msg.sender, -22),
865 };
866
867 match path {
868 "" => {
869 let fid = self.alloc_fid();
870 self.open_handles.insert(fid, String::from(""));
871 reply_open(msg.sender, fid, u64::MAX, 1)
872 }
873 "ip" | "address" | "prefix" | "netmask" | "broadcast" | "gateway" | "route"
874 | "routes" | "dns" | "resolve" | "ping" | "tcp" | "tcp/listeners"
875 | "tcp/connections" | "tcp/stats" | "udp" | "dhcp" => {
876 let fid = self.alloc_fid();
877 self.open_handles.insert(fid, String::from(path));
878 reply_open(msg.sender, fid, u64::MAX, 0)
879 }
880 p if p.starts_with("resolve/") => {
881 if p.len() <= 8 {
882 return IpcMessage::error_reply(msg.sender, -22);
883 }
884 let fid = self.alloc_fid();
885 self.open_handles.insert(fid, String::from(path));
886 reply_open(msg.sender, fid, u64::MAX, 0)
887 }
888 p if p.starts_with("ping/") => {
889 let fid = self.alloc_fid();
890 self.open_handles.insert(fid, String::from(path));
891 reply_open(msg.sender, fid, u64::MAX, 0)
892 }
893 p if p.starts_with("tcp/connect/") => {
894 let rest = &p[12..];
895 let parts: alloc::vec::Vec<&str> = rest.split('/').collect();
896 if parts.len() < 2 || parts.len() > 3 {
897 return IpcMessage::error_reply(msg.sender, -22);
898 }
899 let Some(ip) = parse_ipv4(parts[0]) else {
900 return IpcMessage::error_reply(msg.sender, -22);
901 };
902 let Some(port) = parts[1].parse::<u16>().ok() else {
903 return IpcMessage::error_reply(msg.sender, -22);
904 };
905 if port == 0 {
906 return IpcMessage::error_reply(msg.sender, -22);
907 }
908
909 let rx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 4096]);
910 let tx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 4096]);
911 let sock = tcp::Socket::new(rx_buf, tx_buf);
912 let handle = self.sockets.add(sock);
913
914 let local_port = if parts.len() == 3 {
915 let Some(lp) = parts[2].parse::<u16>().ok() else {
916 self.sockets.remove(handle);
917 return IpcMessage::error_reply(msg.sender, -22);
918 };
919 if lp == 0 {
920 self.sockets.remove(handle);
921 return IpcMessage::error_reply(msg.sender, -22);
922 }
923 lp
924 } else {
925 49152 + (self.next_fid as u16 % 16384)
926 };
927 let remote = (smoltcp::wire::IpAddress::Ipv4(ip), port);
928 let conn_socket = self.sockets.get_mut::<tcp::Socket>(handle);
929 if conn_socket
930 .connect(self.interface.context(), remote, local_port)
931 .is_err()
932 {
933 self.sockets.remove(handle);
934 return IpcMessage::error_reply(msg.sender, -111);
935 }
936
937 let fid = self.alloc_fid();
938 self.open_handles.insert(fid, String::from(path));
939 self.tcp_connections.insert(
940 fid,
941 TcpConnState {
942 socket: handle,
943 local_port,
944 remote: IpEndpoint::new(IpAddress::Ipv4(ip), port),
945 },
946 );
947 reply_open(msg.sender, fid, u64::MAX, 0)
948 }
949 p if p.starts_with("tcp/listen-once/") => {
950 let port_str = &p[16..];
951 let Some(port) = port_str.parse::<u16>().ok() else {
952 return IpcMessage::error_reply(msg.sender, -22);
953 };
954 if port == 0 {
955 return IpcMessage::error_reply(msg.sender, -22);
956 }
957
958 let rx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 4096]);
959 let tx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 4096]);
960 let mut sock = tcp::Socket::new(rx_buf, tx_buf);
961 if sock.listen(port).is_err() {
962 return IpcMessage::error_reply(msg.sender, -98);
963 }
964 let socket = self.sockets.add(sock);
965
966 let fid = self.alloc_fid();
967 self.open_handles.insert(fid, String::from(path));
968 self.tcp_listeners.insert(
969 fid,
970 TcpListenerState {
971 socket,
972 port,
973 auto_relisten: false,
974 },
975 );
976 reply_open(msg.sender, fid, u64::MAX, 0)
977 }
978 p if p.starts_with("tcp/listen/") => {
979 let port_str = &p[11..];
980 let Some(port) = port_str.parse::<u16>().ok() else {
981 return IpcMessage::error_reply(msg.sender, -22);
982 };
983 if port == 0 {
984 return IpcMessage::error_reply(msg.sender, -22);
985 }
986
987 let rx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 4096]);
988 let tx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 4096]);
989 let mut sock = tcp::Socket::new(rx_buf, tx_buf);
990 if sock.listen(port).is_err() {
991 return IpcMessage::error_reply(msg.sender, -98);
992 }
993 let socket = self.sockets.add(sock);
994
995 let fid = self.alloc_fid();
996 self.open_handles.insert(fid, String::from(path));
997 self.tcp_listeners.insert(
998 fid,
999 TcpListenerState {
1000 socket,
1001 port,
1002 auto_relisten: true,
1003 },
1004 );
1005 reply_open(msg.sender, fid, u64::MAX, 0)
1006 }
1007 p if p.starts_with("udp/bind/") => {
1008 let port_str = &p[9..];
1009 let Some(port) = port_str.parse::<u16>().ok() else {
1010 return IpcMessage::error_reply(msg.sender, -22);
1011 };
1012 if port == 0 || self.udp_port_in_use(port) {
1013 return IpcMessage::error_reply(msg.sender, -98);
1014 }
1015 let Ok(socket) = self.create_udp_socket(port) else {
1016 return IpcMessage::error_reply(msg.sender, -98);
1017 };
1018
1019 let fid = self.alloc_fid();
1020 self.open_handles.insert(fid, String::from(path));
1021 self.udp_bound.insert(
1022 fid,
1023 UdpBoundState {
1024 socket,
1025 local_port: port,
1026 },
1027 );
1028 reply_open(msg.sender, fid, u64::MAX, 0)
1029 }
1030 p if p.starts_with("udp/connect/") => {
1031 let rest = &p[12..];
1032 let parts: alloc::vec::Vec<&str> = rest.splitn(2, '/').collect();
1033 if parts.len() != 2 {
1034 return IpcMessage::error_reply(msg.sender, -22);
1035 }
1036 let Some(ip) = parse_ipv4(parts[0]) else {
1037 return IpcMessage::error_reply(msg.sender, -22);
1038 };
1039 let Some(remote_port) = parts[1].parse::<u16>().ok() else {
1040 return IpcMessage::error_reply(msg.sender, -22);
1041 };
1042 if remote_port == 0 {
1043 return IpcMessage::error_reply(msg.sender, -22);
1044 }
1045
1046 let Some(local_port) = self.alloc_udp_ephemeral_port() else {
1047 return IpcMessage::error_reply(msg.sender, -28); };
1049 let Ok(socket) = self.create_udp_socket(local_port) else {
1050 return IpcMessage::error_reply(msg.sender, -98);
1051 };
1052
1053 let fid = self.alloc_fid();
1054 self.open_handles.insert(fid, String::from(path));
1055 self.udp_connections.insert(
1056 fid,
1057 UdpConnState {
1058 socket,
1059 local_port,
1060 remote: IpEndpoint::new(IpAddress::Ipv4(ip), remote_port),
1061 },
1062 );
1063 reply_open(msg.sender, fid, u64::MAX, 0)
1064 }
1065 p if p.starts_with("udp/send/") => {
1066 let rest = &p[9..];
1067 let parts: alloc::vec::Vec<&str> = rest.splitn(2, '/').collect();
1068 if parts.len() != 2 {
1069 return IpcMessage::error_reply(msg.sender, -22);
1070 }
1071 let Some(ip) = parse_ipv4(parts[0]) else {
1072 return IpcMessage::error_reply(msg.sender, -22);
1073 };
1074 let Some(remote_port) = parts[1].parse::<u16>().ok() else {
1075 return IpcMessage::error_reply(msg.sender, -22);
1076 };
1077 if remote_port == 0 {
1078 return IpcMessage::error_reply(msg.sender, -22);
1079 }
1080
1081 let Some(local_port) = self.alloc_udp_ephemeral_port() else {
1082 return IpcMessage::error_reply(msg.sender, -28); };
1084 let Ok(socket) = self.create_udp_socket(local_port) else {
1085 return IpcMessage::error_reply(msg.sender, -98);
1086 };
1087
1088 let fid = self.alloc_fid();
1089 self.open_handles.insert(fid, String::from(path));
1090 self.udp_connections.insert(
1091 fid,
1092 UdpConnState {
1093 socket,
1094 local_port,
1095 remote: IpEndpoint::new(IpAddress::Ipv4(ip), remote_port),
1096 },
1097 );
1098 reply_open(msg.sender, fid, u64::MAX, 0)
1099 }
1100 p if p.starts_with("route/add/")
1101 || p.starts_with("route/del/")
1102 || p.starts_with("route/default/set/")
1103 || p == "route/default/clear" =>
1104 {
1105 let fid = self.alloc_fid();
1106 self.open_handles.insert(fid, String::from(path));
1107 reply_open(msg.sender, fid, u64::MAX, 0)
1108 }
1109 p if p.starts_with("ip/set/")
1110 || p.starts_with("dns/set/")
1111 || p == "dhcp/enable"
1112 || p == "dhcp/disable" =>
1113 {
1114 let fid = self.alloc_fid();
1115 self.open_handles.insert(fid, String::from(path));
1116 reply_open(msg.sender, fid, u64::MAX, 0)
1117 }
1118 _ => IpcMessage::error_reply(msg.sender, -2),
1119 }
1120 }
1121
1122 fn handle_tcp_read(&mut self, sender: u64, listener: TcpListenerState) -> IpcMessage {
1124 let socket = self.sockets.get_mut::<tcp::Socket>(listener.socket);
1125 if !socket.is_open() || (!socket.is_listening() && !socket.is_active()) {
1126 if listener.auto_relisten {
1127 let _ = socket.listen(listener.port);
1128 } else {
1129 return IpcMessage::error_reply(sender, -104);
1130 }
1131 }
1132
1133 let mut data = [0u8; 40];
1134 if socket.can_recv() {
1135 match socket.recv_slice(&mut data) {
1136 Ok(n) => return reply_read(sender, &data[..n]),
1137 Err(_) => return IpcMessage::error_reply(sender, -5),
1138 }
1139 }
1140
1141 if socket.is_open() && !socket.may_recv() && !socket.may_send() {
1142 socket.abort();
1143 if listener.auto_relisten {
1144 let _ = socket.listen(listener.port);
1145 } else {
1146 return IpcMessage::error_reply(sender, -104);
1147 }
1148 }
1149 IpcMessage::error_reply(sender, -11)
1150 }
1151
1152 fn handle_tcp_write(
1154 &mut self,
1155 sender: u64,
1156 listener: TcpListenerState,
1157 msg: &IpcMessage,
1158 ) -> IpcMessage {
1159 let socket = self.sockets.get_mut::<tcp::Socket>(listener.socket);
1160 if !socket.is_open() || (!socket.is_listening() && !socket.is_active()) {
1161 if listener.auto_relisten {
1162 let _ = socket.listen(listener.port);
1163 } else {
1164 return IpcMessage::error_reply(sender, -104);
1165 }
1166 }
1167
1168 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1169 let data_len = core::cmp::min(data_len, msg.payload.len().saturating_sub(18));
1170 let data = &msg.payload[18..18 + data_len];
1171
1172 if !socket.can_send() {
1173 return IpcMessage::error_reply(sender, -11);
1174 }
1175
1176 match socket.send_slice(data) {
1177 Ok(n) => reply_write(sender, n),
1178 Err(_) => IpcMessage::error_reply(sender, -11),
1179 }
1180 }
1181
1182 fn handle_tcp_conn_read(&mut self, sender: u64, conn: TcpConnState) -> IpcMessage {
1184 let socket = self.sockets.get_mut::<tcp::Socket>(conn.socket);
1185 if !socket.is_open() {
1186 return IpcMessage::error_reply(sender, -104); }
1188 let state = socket.state();
1189 if state == tcp::State::SynSent || state == tcp::State::SynReceived {
1190 return IpcMessage::error_reply(sender, -115); }
1192 let mut data = [0u8; 40];
1193 if socket.can_recv() {
1194 match socket.recv_slice(&mut data) {
1195 Ok(n) => reply_read(sender, &data[..n]),
1196 Err(_) => IpcMessage::error_reply(sender, -5),
1197 }
1198 } else {
1199 IpcMessage::error_reply(sender, -11) }
1201 }
1202
1203 fn handle_tcp_conn_write(
1205 &mut self,
1206 sender: u64,
1207 conn: TcpConnState,
1208 msg: &IpcMessage,
1209 ) -> IpcMessage {
1210 let socket = self.sockets.get_mut::<tcp::Socket>(conn.socket);
1211 if !socket.is_open() {
1212 return IpcMessage::error_reply(sender, -104);
1213 }
1214 let state = socket.state();
1215 if state == tcp::State::SynSent || state == tcp::State::SynReceived {
1216 return IpcMessage::error_reply(sender, -115); }
1218 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1219 let data_len = core::cmp::min(data_len, msg.payload.len().saturating_sub(18));
1220 let data = &msg.payload[18..18 + data_len];
1221
1222 if !socket.can_send() {
1223 return IpcMessage::error_reply(sender, -11);
1224 }
1225 match socket.send_slice(data) {
1226 Ok(n) => reply_write(sender, n),
1227 Err(_) => IpcMessage::error_reply(sender, -11),
1228 }
1229 }
1230
1231 fn handle_udp_bound_read(&mut self, sender: u64, state: UdpBoundState) -> IpcMessage {
1238 let socket = self.sockets.get_mut::<udp::Socket>(state.socket);
1239 let Ok((data, meta)) = socket.recv() else {
1240 return IpcMessage::error_reply(sender, -11); };
1242
1243 let IpAddress::Ipv4(src_ip) = meta.endpoint.addr;
1244
1245 let mut out = [0u8; 1478];
1247 out[0..4].copy_from_slice(&src_ip.octets());
1248 out[4..6].copy_from_slice(&meta.endpoint.port.to_be_bytes());
1249 let data_n = core::cmp::min(data.len(), out.len().saturating_sub(6));
1250 out[6..6 + data_n].copy_from_slice(&data[..data_n]);
1251 reply_read(sender, &out[..6 + data_n])
1252 }
1253
1254 fn handle_udp_bound_write(
1259 &mut self,
1260 sender: u64,
1261 state: UdpBoundState,
1262 msg: &IpcMessage,
1263 ) -> IpcMessage {
1264 let _ = state;
1265 let _ = msg;
1266 IpcMessage::error_reply(sender, -95) }
1268
1269 fn handle_udp_conn_read(&mut self, sender: u64, conn: UdpConnState) -> IpcMessage {
1271 let socket = self.sockets.get_mut::<udp::Socket>(conn.socket);
1272 while socket.can_recv() {
1273 let Ok((data, meta)) = socket.recv() else {
1274 break;
1275 };
1276 if meta.endpoint.addr == conn.remote.addr && meta.endpoint.port == conn.remote.port {
1277 let n = core::cmp::min(data.len(), 1472); return reply_read(sender, &data[..n]);
1279 }
1280 }
1281 IpcMessage::error_reply(sender, -11) }
1283
1284 fn handle_udp_conn_write(
1286 &mut self,
1287 sender: u64,
1288 conn: UdpConnState,
1289 msg: &IpcMessage,
1290 ) -> IpcMessage {
1291 let socket = self.sockets.get_mut::<udp::Socket>(conn.socket);
1292 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1293 let data_len = core::cmp::min(data_len, msg.payload.len().saturating_sub(18));
1294 let data = &msg.payload[18..18 + data_len];
1295 if !socket.can_send() {
1296 return IpcMessage::error_reply(sender, -11);
1297 }
1298 match socket.send_slice(data, conn.remote) {
1299 Ok(()) => reply_write(sender, data_len),
1300 Err(udp::SendError::BufferFull) => IpcMessage::error_reply(sender, -11),
1301 Err(udp::SendError::Unaddressable) => IpcMessage::error_reply(sender, -22),
1302 }
1303 }
1304
1305 fn handle_read(&mut self, msg: &IpcMessage) -> IpcMessage {
1307 let file_id = u64::from_le_bytes(msg.payload[0..8].try_into().unwrap_or([0u8; 8]));
1308 let offset = u64::from_le_bytes(msg.payload[8..16].try_into().unwrap_or([0u8; 8]));
1309
1310 if let Some(listener) = self.tcp_listeners.get(&file_id).copied() {
1311 return self.handle_tcp_read(msg.sender, listener);
1312 }
1313 if let Some(conn) = self.tcp_connections.get(&file_id).copied() {
1314 return self.handle_tcp_conn_read(msg.sender, conn);
1315 }
1316 if let Some(state) = self.udp_bound.get(&file_id).copied() {
1317 return self.handle_udp_bound_read(msg.sender, state);
1318 }
1319 if let Some(conn) = self.udp_connections.get(&file_id).copied() {
1320 return self.handle_udp_conn_read(msg.sender, conn);
1321 }
1322
1323 let path = match self.open_handles.get(&file_id) {
1324 Some(p) => p.clone(),
1325 None => return IpcMessage::error_reply(msg.sender, -9),
1326 };
1327
1328 let mut tmp = [0u8; 64];
1329
1330 match path.as_str() {
1331 "" => {
1332 let listing =
1333 b"ip\naddress\nprefix\nnetmask\nbroadcast\ngateway\nroute\nroutes\ndns\ndhcp\nresolve\nping\ntcp\nudp\n";
1334 let start = (offset as usize).min(listing.len());
1335 reply_read(msg.sender, &listing[start..])
1336 }
1337 "ip" => {
1338 if let Some(ref cfg) = self.ip_config {
1339 let n = ipv4_cidr_to_str(&cfg.address, &mut tmp);
1340 let start = (offset as usize).min(n);
1341 reply_read(msg.sender, &tmp[start..n])
1342 } else {
1343 reply_read(msg.sender, b"0.0.0.0/0\n")
1344 }
1345 }
1346 "address" => {
1347 if let Some(ref cfg) = self.ip_config {
1348 let n = ipv4_addr_to_str(&cfg.host, &mut tmp);
1349 let start = (offset as usize).min(n);
1350 reply_read(msg.sender, &tmp[start..n])
1351 } else {
1352 reply_read(msg.sender, b"0.0.0.0\n")
1353 }
1354 }
1355 "prefix" => {
1356 if let Some(ref cfg) = self.ip_config {
1357 let n = u8_to_str(cfg.prefix_len, &mut tmp);
1358 let start = (offset as usize).min(n);
1359 reply_read(msg.sender, &tmp[start..n])
1360 } else {
1361 reply_read(msg.sender, b"0\n")
1362 }
1363 }
1364 "netmask" => {
1365 if let Some(ref cfg) = self.ip_config {
1366 let n = ipv4_addr_to_str(&cfg.netmask, &mut tmp);
1367 let start = (offset as usize).min(n);
1368 reply_read(msg.sender, &tmp[start..n])
1369 } else {
1370 reply_read(msg.sender, b"0.0.0.0\n")
1371 }
1372 }
1373 "broadcast" => {
1374 if let Some(ref cfg) = self.ip_config {
1375 let n = ipv4_addr_to_str(&cfg.broadcast, &mut tmp);
1376 let start = (offset as usize).min(n);
1377 reply_read(msg.sender, &tmp[start..n])
1378 } else {
1379 reply_read(msg.sender, b"0.0.0.0\n")
1380 }
1381 }
1382 "gateway" => {
1383 if let Some(ref cfg) = self.ip_config {
1384 if let Some(gw) = cfg.gateway {
1385 let n = ipv4_addr_to_str(&gw, &mut tmp);
1386 let start = (offset as usize).min(n);
1387 return reply_read(msg.sender, &tmp[start..n]);
1388 }
1389 }
1390 reply_read(msg.sender, b"0.0.0.0\n")
1391 }
1392 "dns" => {
1393 if let Some(ref cfg) = self.ip_config {
1394 let n = dns_list_to_str(&cfg.dns, &mut tmp);
1395 let start = (offset as usize).min(n);
1396 return reply_read(msg.sender, &tmp[start..n]);
1397 }
1398 reply_read(msg.sender, b"0.0.0.0\n")
1399 }
1400 "dhcp" => {
1401 if self.dhcp_enabled {
1402 reply_read(msg.sender, b"on\n")
1403 } else {
1404 reply_read(msg.sender, b"off\n")
1405 }
1406 }
1407 "route" => {
1408 if let Some(ref cfg) = self.ip_config {
1409 if let Some(gw) = cfg.gateway {
1410 let n = route_to_str(&gw, &mut tmp);
1411 let start = (offset as usize).min(n);
1412 return reply_read(msg.sender, &tmp[start..n]);
1413 }
1414 }
1415 reply_read(msg.sender, b"none\n")
1416 }
1417 "routes" => {
1418 use core::fmt::Write;
1419 let mut out = [0u8; 256];
1420 let n = {
1421 let mut w = BufWriter {
1422 buf: &mut out,
1423 pos: 0,
1424 };
1425 let mut any = false;
1426 self.interface.routes_mut().update(|table| {
1427 for r in table.iter() {
1428 let (IpCidr::Ipv4(c), IpAddress::Ipv4(gw)) = (r.cidr, r.via_router);
1429 let ca = c.address().octets();
1430 let ga = gw.octets();
1431 let _ = write!(
1432 w,
1433 "{}.{}.{}.{}/{} via {}.{}.{}.{}\n",
1434 ca[0],
1435 ca[1],
1436 ca[2],
1437 ca[3],
1438 c.prefix_len(),
1439 ga[0],
1440 ga[1],
1441 ga[2],
1442 ga[3]
1443 );
1444 any = true;
1445 }
1446 });
1447 if !any {
1448 let _ = write!(w, "none\n");
1449 }
1450 w.pos
1451 };
1452 let start = (offset as usize).min(n);
1453 reply_read(msg.sender, &out[start..n])
1454 }
1455 "resolve" => reply_read(msg.sender, b"use /net/resolve/<hostname>\n"),
1456 "tcp" => reply_read(
1457 msg.sender,
1458 b"use /net/tcp/listen/<port>, /net/tcp/listen-once/<port>, /net/tcp/connect/<ip>/<port>[/<local_port>], /net/tcp/listeners, /net/tcp/connections, /net/tcp/stats\n",
1459 ),
1460 "tcp/listeners" => {
1461 use core::fmt::Write;
1462 let mut out = [0u8; 512];
1463 let n = {
1464 let mut w = BufWriter {
1465 buf: &mut out,
1466 pos: 0,
1467 };
1468 if self.tcp_listeners.is_empty() {
1469 let _ = write!(w, "none\n");
1470 } else {
1471 for (fid, listener) in self.tcp_listeners.iter() {
1472 let socket = self.sockets.get::<tcp::Socket>(listener.socket);
1473 let mode = if listener.auto_relisten { "auto" } else { "once" };
1474 let _ = write!(
1475 w,
1476 "fid={} port={} state={} mode={}\n",
1477 fid,
1478 listener.port,
1479 Self::tcp_state_name(socket.state()),
1480 mode
1481 );
1482 }
1483 }
1484 w.pos
1485 };
1486 let start = (offset as usize).min(n);
1487 reply_read(msg.sender, &out[start..n])
1488 }
1489 "tcp/connections" => {
1490 use core::fmt::Write;
1491 let mut out = [0u8; 768];
1492 let n = {
1493 let mut w = BufWriter {
1494 buf: &mut out,
1495 pos: 0,
1496 };
1497 if self.tcp_connections.is_empty() {
1498 let _ = write!(w, "none\n");
1499 } else {
1500 for (fid, conn) in self.tcp_connections.iter() {
1501 let socket = self.sockets.get::<tcp::Socket>(conn.socket);
1502 let local = socket.local_endpoint();
1503 let remote = socket.remote_endpoint();
1504 match (local, remote) {
1505 (Some(l), Some(r)) => {
1506 let _ = write!(
1507 w,
1508 "fid={} local={} remote={} state={}\n",
1509 fid,
1510 l,
1511 r,
1512 Self::tcp_state_name(socket.state())
1513 );
1514 }
1515 _ => {
1516 let _ = write!(
1517 w,
1518 "fid={} local_port={} remote={} state={}\n",
1519 fid,
1520 conn.local_port,
1521 conn.remote,
1522 Self::tcp_state_name(socket.state())
1523 );
1524 }
1525 }
1526 }
1527 }
1528 w.pos
1529 };
1530 let start = (offset as usize).min(n);
1531 reply_read(msg.sender, &out[start..n])
1532 }
1533 "tcp/stats" => {
1534 use core::fmt::Write;
1535 let mut out = [0u8; 256];
1536 let n = {
1537 let mut w = BufWriter {
1538 buf: &mut out,
1539 pos: 0,
1540 };
1541 let listeners = self.tcp_listeners.len();
1542 let connections = self.tcp_connections.len();
1543 let mut established = 0usize;
1544 let mut connecting = 0usize;
1545 let mut closing = 0usize;
1546 for conn in self.tcp_connections.values() {
1547 let socket = self.sockets.get::<tcp::Socket>(conn.socket);
1548 match socket.state() {
1549 tcp::State::Established => established += 1,
1550 tcp::State::SynSent | tcp::State::SynReceived => connecting += 1,
1551 tcp::State::Closed => {}
1552 _ => closing += 1,
1553 }
1554 }
1555 let _ = write!(
1556 w,
1557 "listeners={}\nconnections={}\nestablished={}\nconnecting={}\nclosing={}\n",
1558 listeners,
1559 connections,
1560 established,
1561 connecting,
1562 closing
1563 );
1564 w.pos
1565 };
1566 let start = (offset as usize).min(n);
1567 reply_read(msg.sender, &out[start..n])
1568 }
1569 "udp" => reply_read(
1570 msg.sender,
1571 b"use /net/udp/bind/<port>, /net/udp/connect/<ip>/<port> or /net/udp/send/<ip>/<port>\n",
1572 ),
1573 p if p.starts_with("resolve/") => {
1574 let name = &p[8..];
1575 match self.resolve_hostname_blocking(name) {
1576 Ok(addr) => {
1577 let n = ipv4_addr_to_str(&addr, &mut tmp);
1578 let start = (offset as usize).min(n);
1579 reply_read(msg.sender, &tmp[start..n])
1580 }
1581 Err(e) => IpcMessage::error_reply(msg.sender, e),
1582 }
1583 }
1584 p if p.starts_with("ping/") => {
1585 if let Some((seq, rtt_us)) = self.ping_reply.take() {
1586 let mut buf = [0u8; 10];
1587 buf[0..2].copy_from_slice(&seq.to_le_bytes());
1588 buf[2..10].copy_from_slice(&rtt_us.to_le_bytes());
1589 let start = (offset as usize).min(buf.len());
1590 reply_read(msg.sender, &buf[start..])
1591 } else {
1592 reply_read(msg.sender, &[])
1593 }
1594 }
1595 _ => IpcMessage::error_reply(msg.sender, -9),
1596 }
1597 }
1598
1599 fn handle_write(&mut self, msg: &IpcMessage) -> IpcMessage {
1601 let file_id = u64::from_le_bytes(msg.payload[0..8].try_into().unwrap_or([0u8; 8]));
1602
1603 if let Some(listener) = self.tcp_listeners.get(&file_id).copied() {
1604 return self.handle_tcp_write(msg.sender, listener, msg);
1605 }
1606 if let Some(conn) = self.tcp_connections.get(&file_id).copied() {
1607 return self.handle_tcp_conn_write(msg.sender, conn, msg);
1608 }
1609 if let Some(state) = self.udp_bound.get(&file_id).copied() {
1610 return self.handle_udp_bound_write(msg.sender, state, msg);
1611 }
1612 if let Some(conn) = self.udp_connections.get(&file_id).copied() {
1613 return self.handle_udp_conn_write(msg.sender, conn, msg);
1614 }
1615
1616 let path = match self.open_handles.get(&file_id) {
1617 Some(p) => p.clone(),
1618 None => return IpcMessage::error_reply(msg.sender, -9),
1619 };
1620
1621 if path.starts_with("ping/") {
1622 let ip_str = &path[5..];
1623 if let Some(target) = parse_ipv4(ip_str) {
1624 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1625 let seq = if data_len >= 2 {
1626 u16::from_le_bytes([msg.payload[18], msg.payload[19]])
1627 } else {
1628 0
1629 };
1630 if self.send_ping(target, seq) {
1631 return reply_write(msg.sender, data_len);
1632 }
1633 return IpcMessage::error_reply(msg.sender, -11); }
1635 return IpcMessage::error_reply(msg.sender, -22);
1636 }
1637
1638 if let Some(cidr_s) = path.strip_prefix("ip/set/") {
1639 let Some(cidr) = parse_ipv4_cidr(cidr_s) else {
1640 return IpcMessage::error_reply(msg.sender, -22);
1641 };
1642 self.dhcp_enabled = false;
1643 let (gateway, dns) = if let Some(ref cfg) = self.ip_config {
1644 (cfg.gateway, cfg.dns)
1645 } else {
1646 (None, [None; 3])
1647 };
1648 self.apply_ipv4_config(cidr, gateway, dns);
1649 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1650 return reply_write(msg.sender, data_len);
1651 }
1652
1653 if let Some(rest) = path.strip_prefix("dns/set/") {
1654 let mut parts = rest.split('/');
1655 let Some(idx_s) = parts.next() else {
1656 return IpcMessage::error_reply(msg.sender, -22);
1657 };
1658 let Some(ip_s) = parts.next() else {
1659 return IpcMessage::error_reply(msg.sender, -22);
1660 };
1661 if parts.next().is_some() {
1662 return IpcMessage::error_reply(msg.sender, -22);
1663 }
1664 let Some(idx) = idx_s.parse::<usize>().ok() else {
1665 return IpcMessage::error_reply(msg.sender, -22);
1666 };
1667 if idx >= 3 {
1668 return IpcMessage::error_reply(msg.sender, -22);
1669 }
1670 let Some(ip) = parse_ipv4(ip_s) else {
1671 return IpcMessage::error_reply(msg.sender, -22);
1672 };
1673 let Some(ref mut cfg) = self.ip_config else {
1674 return IpcMessage::error_reply(msg.sender, -11);
1675 };
1676 self.dhcp_enabled = false;
1677 cfg.dns[idx] = if ip == Ipv4Address::new(0, 0, 0, 0) {
1678 None
1679 } else {
1680 Some(ip)
1681 };
1682 self.refresh_dns_servers();
1683 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1684 return reply_write(msg.sender, data_len);
1685 }
1686
1687 if path == "dhcp/enable" {
1688 self.dhcp_enabled = true;
1689 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1690 return reply_write(msg.sender, data_len);
1691 }
1692
1693 if path == "dhcp/disable" {
1694 self.dhcp_enabled = false;
1695 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1696 return reply_write(msg.sender, data_len);
1697 }
1698
1699 if let Some(rest) = path.strip_prefix("route/add/") {
1700 let mut parts = rest.split('/');
1701 let Some(cidr_s) = parts.next() else {
1702 return IpcMessage::error_reply(msg.sender, -22);
1703 };
1704 let Some(gw_s) = parts.next() else {
1705 return IpcMessage::error_reply(msg.sender, -22);
1706 };
1707 if parts.next().is_some() {
1708 return IpcMessage::error_reply(msg.sender, -22);
1709 }
1710 let Some(cidr) = parse_ipv4_cidr(cidr_s) else {
1711 return IpcMessage::error_reply(msg.sender, -22);
1712 };
1713 let Some(gw) = parse_ipv4(gw_s) else {
1714 return IpcMessage::error_reply(msg.sender, -22);
1715 };
1716 let mut full = false;
1717 self.interface.routes_mut().update(|table| {
1718 if let Some((idx, _)) = table
1719 .iter()
1720 .enumerate()
1721 .find(|(_, r)| r.cidr == IpCidr::Ipv4(cidr))
1722 {
1723 let _ = table.remove(idx);
1724 }
1725 if table
1726 .push(smoltcp::iface::Route {
1727 cidr: IpCidr::Ipv4(cidr),
1728 via_router: IpAddress::Ipv4(gw),
1729 preferred_until: None,
1730 expires_at: None,
1731 })
1732 .is_err()
1733 {
1734 full = true;
1735 }
1736 });
1737 if full {
1738 return IpcMessage::error_reply(msg.sender, -28);
1739 }
1740 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1741 return reply_write(msg.sender, data_len);
1742 }
1743
1744 if let Some(rest) = path.strip_prefix("route/del/") {
1745 let Some(cidr) = parse_ipv4_cidr(rest) else {
1746 return IpcMessage::error_reply(msg.sender, -22);
1747 };
1748 let mut removed = false;
1749 self.interface.routes_mut().update(|table| {
1750 if let Some((idx, _)) = table
1751 .iter()
1752 .enumerate()
1753 .find(|(_, r)| r.cidr == IpCidr::Ipv4(cidr))
1754 {
1755 let _ = table.remove(idx);
1756 removed = true;
1757 }
1758 });
1759 if !removed {
1760 return IpcMessage::error_reply(msg.sender, -2);
1761 }
1762 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1763 return reply_write(msg.sender, data_len);
1764 }
1765
1766 if let Some(gw_s) = path.strip_prefix("route/default/set/") {
1767 let Some(gw) = parse_ipv4(gw_s) else {
1768 return IpcMessage::error_reply(msg.sender, -22);
1769 };
1770 if self
1771 .interface
1772 .routes_mut()
1773 .add_default_ipv4_route(gw)
1774 .is_err()
1775 {
1776 return IpcMessage::error_reply(msg.sender, -28);
1777 }
1778 if let Some(ref mut cfg) = self.ip_config {
1779 cfg.gateway = Some(gw);
1780 }
1781 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1782 return reply_write(msg.sender, data_len);
1783 }
1784
1785 if path == "route/default/clear" {
1786 let _ = self.interface.routes_mut().remove_default_ipv4_route();
1787 if let Some(ref mut cfg) = self.ip_config {
1788 cfg.gateway = None;
1789 }
1790 let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
1791 return reply_write(msg.sender, data_len);
1792 }
1793
1794 IpcMessage::error_reply(msg.sender, -1) }
1796
1797 fn handle_close(&mut self, msg: &IpcMessage) -> IpcMessage {
1799 let file_id = u64::from_le_bytes(msg.payload[0..8].try_into().unwrap_or([0u8; 8]));
1800 self.open_handles.remove(&file_id);
1801 if let Some(listener) = self.tcp_listeners.remove(&file_id) {
1802 let _ = self.sockets.remove(listener.socket);
1803 }
1804 if let Some(conn) = self.tcp_connections.remove(&file_id) {
1805 let sock = self.sockets.get_mut::<tcp::Socket>(conn.socket);
1806 sock.close();
1807 self.sockets.remove(conn.socket);
1808 }
1809 if let Some(state) = self.udp_bound.remove(&file_id) {
1810 let sock = self.sockets.get_mut::<udp::Socket>(state.socket);
1811 sock.close();
1812 self.sockets.remove(state.socket);
1813 }
1814 if let Some(conn) = self.udp_connections.remove(&file_id) {
1815 let sock = self.sockets.get_mut::<udp::Socket>(conn.socket);
1816 sock.close();
1817 self.sockets.remove(conn.socket);
1818 }
1819 reply_ok(msg.sender)
1820 }
1821
1822 fn alloc_fid(&mut self) -> u64 {
1824 let id = self.next_fid;
1825 self.next_fid += 1;
1826 id
1827 }
1828
1829 fn serve(&mut self, port: u64) -> ! {
1835 log("[strate-net] Starting DHCP...\n");
1836
1837 loop {
1838 let now = now_instant();
1840 let poll_result = self
1841 .interface
1842 .poll(now, &mut self.device, &mut self.sockets);
1843
1844 self.process_dhcp();
1846 self.process_icmp();
1847
1848 let mut msg = IpcMessage::new(0);
1850 let mut got_ipc = false;
1851 if ipc_try_recv(port, &mut msg).is_ok() {
1852 got_ipc = true;
1853 let reply = match msg.msg_type {
1854 OPCODE_OPEN => self.handle_open(&msg),
1855 OPCODE_READ => self.handle_read(&msg),
1856 OPCODE_WRITE => self.handle_write(&msg),
1857 OPCODE_CLOSE => self.handle_close(&msg),
1858 _ => IpcMessage::error_reply(msg.sender, -22), };
1860 let _ = call::ipc_reply(&reply);
1861 }
1862
1863 if !got_ipc && poll_result == smoltcp::iface::PollResult::None {
1865 const MAX_SLEEP_US: u64 = 10_000; if let Some(delay) = self.interface.poll_delay(now, &self.sockets) {
1867 let micros = delay.total_micros().min(MAX_SLEEP_US);
1868 if micros > 0 {
1869 sleep_micros(micros);
1870 } else {
1871 let _ = proc_yield();
1872 }
1873 } else {
1874 sleep_micros(MAX_SLEEP_US);
1875 }
1876 }
1877 }
1878 }
1879}
1880
1881fn log(msg: &str) {
1883 let _ = call::debug_log(msg.as_bytes());
1884}
1885
1886#[unsafe(no_mangle)]
1887pub extern "C" fn _start() -> ! {
1889 log("[strate-net] Starting network silo\n");
1890
1891 let port = match call::ipc_create_port(0) {
1892 Ok(p) => p as u64,
1893 Err(e) => {
1894 log("[strate-net] Failed to create port: ");
1895 log_error_code(e);
1896 log("\n");
1897 exit(1);
1898 }
1899 };
1900
1901 if let Err(e) = call::ipc_bind_port(port as usize, b"/net") {
1902 log("[strate-net] Failed to bind to /net: ");
1903 log_error_code(e);
1904 log("\n");
1905 exit(2);
1906 }
1907
1908 log("[strate-net] Bound to /net\n");
1909
1910 let mut mac = [0u8; 6];
1911 if net_info(0, &mut mac).is_err() {
1912 log("[strate-net] No NIC found, using fallback MAC\n");
1913 mac = [0x52, 0x54, 0x00, 0x12, 0x34, 0x56];
1914 } else {
1915 log("[strate-net] MAC acquired from kernel\n");
1916 }
1917
1918 let mut strate = NetworkStrate::new(mac);
1919 strate.serve(port);
1920}
1921
1922fn log_error_code(e: strate_net::syscalls::Error) {
1924 use core::fmt::Write;
1925 let mut buf = [0u8; 32];
1926 let n = {
1927 let mut w = BufWriter {
1928 buf: &mut buf,
1929 pos: 0,
1930 };
1931 let _ = write!(w, "{}", e.to_errno());
1932 w.pos
1933 };
1934 if let Ok(s) = core::str::from_utf8(&buf[..n]) {
1935 log(s);
1936 }
1937}