1use crate::wifi::{len, Client, Device, Passphrase, Security, Ssid};
6use enum_primitive::cast::FromPrimitive;
7use kernel::errorcode::into_statuscode;
8use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
9use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
10use kernel::syscall::{self, CommandReturn, SyscallDriver};
11use kernel::{process, utilities::cells::OptionalCell, ErrorCode, ProcessId};
12
13mod ro_allow {
15 pub const SSID: usize = 0;
16 pub const PASS: usize = 1;
17
18 pub const COUNT: u8 = 2;
20}
21
22mod rw_allow {
24 pub const MAC: usize = 0;
25 pub const SCAN_SSID: usize = 1;
26
27 pub const MAC_LEN: usize = 6;
29 pub const COUNT: u8 = 2;
31}
32
33mod upcall {
35 pub const INIT: usize = 0;
36 pub const JOIN: usize = 1;
37 pub const LEAVE: usize = 2;
38 pub const AP: usize = 3;
39 pub const STA: usize = 4;
40 pub const SCAN: usize = 5;
41 pub const STOP_SCAN: usize = 6;
42
43 pub const SCAN_RES: usize = 7;
45
46 pub const COUNT: u8 = 8;
48}
49
50mod security {
52 pub const OPEN: usize = 0;
53 pub const WPA: usize = 1;
54 pub const WPA2: usize = 2;
55 pub const WPA2_WPA3: usize = 3;
56 pub const WPA3: usize = 4;
57}
58
59#[repr(usize)]
60#[derive(Clone, Copy, Debug)]
61pub enum Command {
62 Init = upcall::INIT,
63 Join = upcall::JOIN,
64 Leave = upcall::LEAVE,
65 Ap = upcall::AP,
66 Sta = upcall::STA,
67 Scan = upcall::SCAN,
68 StopScan = upcall::STOP_SCAN,
69}
70
71impl Command {
72 #[inline]
73 fn to_upcall(self) -> usize {
74 self as _
75 }
76}
77
78#[derive(Default)]
79pub struct App;
80
81pub struct WifiDriver<'a, D: Device<'a>> {
82 device: &'a D,
83 process_id: OptionalCell<ProcessId>,
84 command: OptionalCell<Command>,
85 grants: Grant<
86 App,
87 UpcallCount<{ upcall::COUNT }>,
88 AllowRoCount<{ ro_allow::COUNT }>,
89 AllowRwCount<{ rw_allow::COUNT }>,
90 >,
91}
92
93impl<'a, D: Device<'a>> WifiDriver<'a, D> {
94 pub fn new(
95 device: &'a D,
96 grants: Grant<
97 App,
98 UpcallCount<{ upcall::COUNT }>,
99 AllowRoCount<{ ro_allow::COUNT }>,
100 AllowRwCount<{ rw_allow::COUNT }>,
101 >,
102 ) -> Self {
103 WifiDriver {
104 device,
105 process_id: OptionalCell::empty(),
106 command: OptionalCell::empty(),
107 grants,
108 }
109 }
110
111 fn credentials(
112 &self,
113 process_id: ProcessId,
114 security: usize,
115 ) -> Result<(Ssid, Option<(Security, Passphrase)>), ErrorCode> {
116 self.grants.enter(process_id, |_, kernel_data| {
117 let ssid = kernel_data
118 .get_readonly_processbuffer(ro_allow::SSID)
119 .and_then(|buf| {
120 buf.enter(|buf| -> Result<Ssid, ErrorCode> {
121 let mut ssid = Ssid::try_new(buf.len() as _)?;
122 buf.copy_to_slice(&mut ssid.buf[..buf.len()]);
123 Ok(ssid)
124 })
125 })
126 .map_err(ErrorCode::from)??;
127 let security = match security {
128 security::OPEN => None,
129 wpa @ (security::WPA | security::WPA3 | security::WPA2 | security::WPA2_WPA3) => {
130 Some(
131 kernel_data
132 .get_readonly_processbuffer(ro_allow::PASS)
133 .and_then(|buf| {
134 buf.enter(|buf| {
135 if buf.len() < len::WPA_PASSPHRASE_MIN {
136 return Err(ErrorCode::INVAL);
137 }
138 let mut passphrase = Passphrase::try_new(buf.len() as _)?;
139 buf.copy_to_slice(&mut passphrase.buf[..buf.len()]);
140 let security =
141 Security::from_usize(wpa).ok_or(ErrorCode::INVAL)?;
142
143 Ok((security, passphrase))
144 })
145 })??,
146 )
147 }
148 _ => Err(ErrorCode::INVAL)?,
149 };
150 Ok((ssid, security))
151 })?
152 }
153}
154
155impl<'a, D: Device<'a>> SyscallDriver for WifiDriver<'a, D> {
156 fn command(
157 &self,
158 command_num: usize,
159 security: usize,
160 channel: usize,
161 process_id: ProcessId,
162 ) -> syscall::CommandReturn {
163 match command_num {
164 0 => CommandReturn::success(),
165 1 => {
167 let rval = self.device.init();
168 if rval.is_ok() {
169 self.command.set(Command::Init);
170 self.process_id.set(process_id);
171 }
172 rval.into()
173 }
174 2 => self.device.mac().map_or_else(
177 |err| Err(err).into(),
178 |mac| {
179 self.grants
180 .enter(process_id, |_, kernel_data| {
181 kernel_data
182 .get_readwrite_processbuffer(rw_allow::MAC)
183 .and_then(|buf| {
184 buf.mut_enter(|buf| {
185 let len = usize::min(rw_allow::MAC_LEN, buf.len());
186 buf[..len].copy_from_slice(&mac[..len]);
187 })
188 })
189 .map_err(ErrorCode::from)
190 })
191 .unwrap_or_else(|err| Err(err.into()))
192 .into()
193 },
194 ),
195 3 => {
197 if channel > u8::MAX as _ {
198 return Err(ErrorCode::INVAL).into();
199 }
200 let rval = self
201 .credentials(process_id, security)
202 .and_then(|(ssid, security)| {
203 self.device.access_point(ssid, security, channel as _)
204 });
205 if rval.is_ok() {
206 self.command.set(Command::Ap);
207 self.process_id.set(process_id);
208 }
209 rval.into()
210 }
211 4 => {
213 let rval = self.device.station();
214 if rval.is_ok() {
215 self.command.set(Command::Sta);
216 self.process_id.set(process_id);
217 }
218 rval.into()
219 }
220 5 => {
222 let rval = self
223 .credentials(process_id, security)
224 .and_then(|(ssid, security)| self.device.join(ssid, security));
225 if rval.is_ok() {
226 self.command.set(Command::Join);
227 self.process_id.set(process_id);
228 }
229 rval.into()
230 }
231 6 => {
233 let rval = self.device.leave();
234 if rval.is_ok() {
235 self.command.set(Command::Leave);
236 self.process_id.set(process_id);
237 }
238 rval.into()
239 }
240 7 => {
242 let rval = self.device.scan();
243 if rval.is_ok() {
244 self.command.set(Command::Scan);
245 self.process_id.set(process_id);
246 }
247 rval.into()
248 }
249 8 => {
251 let rval = self.device.stop_scan();
252 if rval.is_ok() {
253 self.command.set(Command::StopScan);
254 self.process_id.set(process_id);
255 }
256 rval.into()
257 }
258 _ => syscall::CommandReturn::failure(ErrorCode::INVAL),
259 }
260 }
261
262 fn allocate_grant(&self, process_id: ProcessId) -> Result<(), process::Error> {
263 self.grants.enter(process_id, |_, _| {})
264 }
265}
266
267impl<'a, D: Device<'a>> Client for WifiDriver<'a, D> {
268 fn command_done(&self, rval: Result<(), ErrorCode>) {
269 Option::zip(self.process_id.get(), self.command.take()).map(|(process_id, command)| {
270 let _ = self.grants.enter(process_id, |_, kernel_data| {
271 let _ =
272 kernel_data.schedule_upcall(command.to_upcall(), (into_statuscode(rval), 0, 0));
273 if let Command::Scan = command {
274 self.process_id.set(process_id);
275 }
276 });
277 });
278 }
279
280 fn scan_done(&self) {
281 self.process_id.map(|process_id| {
282 self.grants.enter(process_id, |_, kernel_data| {
283 let _ = kernel_data.schedule_upcall(upcall::SCAN_RES, (0, 0, 0));
284 })
285 });
286 }
287
288 fn scanned_network(&self, ssid: Ssid) {
289 self.process_id.get().map(|process_id| {
290 self.grants
291 .enter(process_id, |_, kernel_data| {
292 let _ = kernel_data
293 .get_readwrite_processbuffer(rw_allow::SCAN_SSID)
294 .and_then(|buf| {
295 buf.mut_enter(|buf| {
296 let len = usize::min(ssid.len.get() as _, buf.len());
297 buf[..len].copy_from_slice(&ssid.buf[..len]);
298 })
299 });
300 let _ =
301 kernel_data.schedule_upcall(upcall::SCAN_RES, (ssid.len.get() as _, 0, 0));
302 })
303 .unwrap();
304 });
305 }
306}