strat9_kernel/hardware/nic/
scheme.rs1use super::{get_device, list_interfaces};
6use crate::{
7 syscall::error::SyscallError,
8 vfs::{
9 scheme::{
10 finalize_pseudo_stat, DirEntry, FileFlags, FileStat, OpenFlags, OpenResult, Scheme,
11 DEV_NETFS, DT_REG,
12 },
13 scheme_router,
14 },
15};
16use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
17use core::sync::atomic::{AtomicU64, Ordering};
18use net_core::NetError;
19use spin::RwLock;
20
21#[derive(Clone)]
22enum Handle {
23 Root,
24 Iface(String),
25}
26
27pub struct NetScheme {
28 handles: RwLock<BTreeMap<u64, Handle>>,
29 next: AtomicU64,
30}
31
32impl NetScheme {
33 fn new() -> Self {
35 Self {
36 handles: RwLock::new(BTreeMap::new()),
37 next: AtomicU64::new(1),
38 }
39 }
40 fn alloc_id(&self) -> u64 {
42 self.next.fetch_add(1, Ordering::Relaxed)
43 }
44}
45
46impl Scheme for NetScheme {
47 fn open(&self, path: &str, _flags: OpenFlags) -> Result<OpenResult, SyscallError> {
49 let path = path.trim_start_matches('/');
50 let id = self.alloc_id();
51 if path.is_empty() {
52 self.handles.write().insert(id, Handle::Root);
53 return Ok(OpenResult {
54 file_id: id,
55 size: None,
56 flags: FileFlags::DIRECTORY,
57 });
58 }
59 if !list_interfaces().iter().any(|n| n == path) {
60 return Err(SyscallError::BadHandle);
61 }
62 self.handles
63 .write()
64 .insert(id, Handle::Iface(String::from(path)));
65 Ok(OpenResult {
66 file_id: id,
67 size: None,
68 flags: FileFlags::DEVICE,
69 })
70 }
71
72 fn read(&self, fid: u64, _off: u64, buf: &mut [u8]) -> Result<usize, SyscallError> {
74 let h = self.handles.read();
75 let handle = h.get(&fid).ok_or(SyscallError::BadHandle)?;
76 match handle {
77 Handle::Root => {
78 let list: String = list_interfaces().into_iter().map(|n| n + "\n").collect();
79 let b = list.as_bytes();
80 let n = core::cmp::min(b.len(), buf.len());
81 buf[..n].copy_from_slice(&b[..n]);
82 Ok(n)
83 }
84 Handle::Iface(name) => {
85 let dev = get_device(name).ok_or(SyscallError::BadHandle)?;
86 drop(h);
87 dev.receive(buf).map_err(|e| match e {
88 NetError::NoPacket => SyscallError::Again,
89 _ => SyscallError::IoError,
90 })
91 }
92 }
93 }
94
95 fn write(&self, fid: u64, _off: u64, buf: &[u8]) -> Result<usize, SyscallError> {
97 let h = self.handles.read();
98 let handle = h.get(&fid).ok_or(SyscallError::BadHandle)?;
99 match handle {
100 Handle::Root => Err(SyscallError::PermissionDenied),
101 Handle::Iface(name) => {
102 let dev = get_device(name).ok_or(SyscallError::BadHandle)?;
103 drop(h);
104 dev.transmit(buf).map_err(|e| match e {
105 NetError::TxQueueFull => SyscallError::Again,
106 _ => SyscallError::IoError,
107 })?;
108 Ok(buf.len())
109 }
110 }
111 }
112
113 fn close(&self, fid: u64) -> Result<(), SyscallError> {
115 self.handles.write().remove(&fid);
116 Ok(())
117 }
118
119 fn stat(&self, fid: u64) -> Result<FileStat, SyscallError> {
121 let h = self.handles.read();
122 let handle = h.get(&fid).ok_or(SyscallError::BadHandle)?;
123 Ok(match handle {
124 Handle::Root => finalize_pseudo_stat(
125 FileStat {
126 st_ino: 0,
127 st_mode: 0o040555,
128 st_nlink: 2,
129 st_size: 0,
130 st_blksize: 1514,
131 st_blocks: 0,
132 ..FileStat::zeroed()
133 },
134 DEV_NETFS,
135 0,
136 ),
137 Handle::Iface(_) => finalize_pseudo_stat(
138 FileStat {
139 st_ino: fid,
140 st_mode: 0o020666,
141 st_nlink: 1,
142 st_size: 0,
143 st_blksize: 1514,
144 st_blocks: 0,
145 ..FileStat::zeroed()
146 },
147 DEV_NETFS,
148 fid,
149 ),
150 })
151 }
152
153 fn readdir(&self, fid: u64) -> Result<Vec<DirEntry>, SyscallError> {
155 let h = self.handles.read();
156 if !matches!(h.get(&fid), Some(Handle::Root)) {
157 return Err(SyscallError::InvalidArgument);
158 }
159 Ok(list_interfaces()
160 .into_iter()
161 .enumerate()
162 .map(|(i, name)| DirEntry {
163 ino: (i + 1) as u64,
164 file_type: DT_REG,
165 name,
166 })
167 .collect())
168 }
169}
170
171pub fn register_net_scheme() -> Result<(), SyscallError> {
173 let scheme = Arc::new(NetScheme::new());
174 scheme_router::register_scheme("net", scheme)?;
175 scheme_router::mount_scheme("net", "/dev/net")?;
176 log::info!("[net] Scheme at /dev/net/");
177 Ok(())
178}