1use crate::completers::Completer;
6use fdf::{fdf_arena_t, Arena, ArenaStaticBox};
7use log::error;
8use std::ffi::c_void;
9use std::marker::{PhantomData, PhantomPinned};
10use std::pin::Pin;
11use std::ptr::NonNull;
12use std::{mem, slice};
13use wlan_fidl_ext::{TryUnpack, WithName};
14use {fidl_fuchsia_wlan_softmac as fidl_softmac, fuchsia_trace as trace, wlan_trace as wtrace};
15
16#[repr(C)]
19pub struct FfiEthernetRxCtx {
20 _data: [u8; 0],
21 _marker: PhantomData<(*mut u8, PhantomPinned)>,
22}
23
24#[repr(C)]
25pub struct FfiEthernetRx {
26 ctx: *mut FfiEthernetRxCtx,
27 transfer: unsafe extern "C" fn(
34 ctx: *mut FfiEthernetRxCtx,
35 payload: *const u8,
36 payload_len: usize,
37 ) -> zx::sys::zx_status_t,
38}
39
40unsafe impl Send for FfiEthernetRx {}
43
44pub struct EthernetRx {
45 ffi: FfiEthernetRx,
46}
47
48impl EthernetRx {
49 pub fn new(ffi: FfiEthernetRx) -> Self {
50 Self { ffi }
51 }
52
53 pub fn transfer(
54 &mut self,
55 request: &fidl_softmac::EthernetRxTransferRequest,
56 ) -> Result<(), zx::Status> {
57 wtrace::duration!(c"EthernetRx transfer");
58 let payload = fidl::persist(request);
59 match payload {
60 Err(e) => {
61 error!("Failed to persist EthernetRx.Transfer request: {}", e);
62 Err(zx::Status::INTERNAL)
63 }
64 Ok(payload) => {
65 let payload = payload.as_slice();
66 zx::Status::from_raw(unsafe {
69 (self.ffi.transfer)(self.ffi.ctx, payload.as_ptr(), payload.len())
70 })
71 .into()
72 }
73 }
74 }
75}
76
77#[repr(C)]
80pub struct FfiWlanTxCtx {
81 _data: [u8; 0],
82 _marker: PhantomData<(*mut u8, PhantomPinned)>,
83}
84
85#[repr(C)]
86pub struct FfiWlanTx {
87 ctx: *mut FfiWlanTxCtx,
88 transfer: unsafe extern "C" fn(
95 ctx: *mut FfiWlanTxCtx,
96 payload: *const u8,
97 payload_len: usize,
98 ) -> zx::sys::zx_status_t,
99}
100
101unsafe impl Send for FfiWlanTx {}
105
106pub struct WlanTx {
107 ffi: FfiWlanTx,
108}
109
110impl WlanTx {
111 pub fn new(ffi: FfiWlanTx) -> Self {
112 Self { ffi }
113 }
114
115 pub fn transfer(
116 &mut self,
117 request: &fidl_softmac::WlanTxTransferRequest,
118 ) -> Result<(), zx::Status> {
119 wtrace::duration!(c"WlanTx transfer");
120 let payload = fidl::persist(request);
121 match payload {
122 Err(e) => {
123 error!("Failed to persist WlanTx.Transfer request: {}", e);
124 Err(zx::Status::INTERNAL)
125 }
126 Ok(payload) => {
127 zx::Status::from_raw(unsafe {
130 (self.ffi.transfer)(self.ffi.ctx, payload.as_slice().as_ptr(), payload.len())
131 })
132 .into()
133 }
134 }
135 }
136}
137
138pub trait EthernetTxEventSender {
139 fn unbounded_send(&self, event: EthernetTxEvent) -> Result<(), (String, EthernetTxEvent)>;
140}
141
142#[repr(C)]
143pub struct FfiEthernetTxCtx {
144 sender: Box<dyn EthernetTxEventSender>,
145 pin: PhantomPinned,
146}
147
148#[repr(C)]
149pub struct FfiEthernetTx {
150 ctx: *const FfiEthernetTxCtx,
151 transfer: unsafe extern "C" fn(
152 ctx: *const FfiEthernetTxCtx,
153 request: *const u8,
154 request_size: usize,
155 ) -> zx::sys::zx_status_t,
156}
157
158pub struct EthernetTx {
159 ctx: Pin<Box<FfiEthernetTxCtx>>,
160}
161
162pub struct EthernetTxEvent {
164 pub bytes: NonNull<[u8]>,
165 pub async_id: trace::Id,
166 pub borrowed_operation: Completer<Box<dyn FnOnce(zx::sys::zx_status_t)>>,
167}
168
169impl EthernetTx {
170 pub fn new(sender: Box<dyn EthernetTxEventSender>) -> Self {
175 Self { ctx: Box::pin(FfiEthernetTxCtx { sender, pin: PhantomPinned }) }
176 }
177
178 pub unsafe fn to_ffi(&self) -> FfiEthernetTx {
192 FfiEthernetTx {
193 ctx: &*self.ctx.as_ref() as *const FfiEthernetTxCtx,
194 transfer: Self::ethernet_tx_transfer,
195 }
196 }
197
198 #[no_mangle]
219 unsafe extern "C" fn ethernet_tx_transfer(
220 ctx: *const FfiEthernetTxCtx,
221 payload: *const u8,
222 payload_len: usize,
223 ) -> zx::sys::zx_status_t {
224 wtrace::duration!(c"EthernetTx transfer");
225
226 let payload = unsafe { slice::from_raw_parts(payload, payload_len) };
230 let payload = match fidl::unpersist::<fidl_softmac::EthernetTxTransferRequest>(payload) {
231 Ok(payload) => payload,
232 Err(e) => {
233 error!("Unable to unpersist EthernetTx.Transfer request: {}", e);
234 return zx::Status::BAD_STATE.into_raw();
235 }
236 };
237
238 let borrowed_operation =
239 match payload.borrowed_operation.with_name("borrowed_operation").try_unpack() {
240 Ok(x) => x as *mut c_void,
241 Err(e) => {
242 let e = e.context("Missing required field in EthernetTxTransferRequest.");
243 error!("{}", e);
244 return zx::Status::BAD_STATE.into_raw();
245 }
246 };
247
248 let complete_borrowed_operation: unsafe extern "C" fn(
249 borrowed_operation: *mut c_void,
250 status: zx::sys::zx_status_t,
251 ) = match payload
252 .complete_borrowed_operation
253 .with_name("complete_borrowed_operation")
254 .try_unpack()
255 {
256 Ok(x) => unsafe { mem::transmute(x) },
259 Err(e) => {
260 let e = e.context("Missing required field in EthernetTxTransferRequest.");
261 error!("{}", e);
262 return zx::Status::BAD_STATE.into_raw();
263 }
264 };
265
266 let borrowed_operation: Completer<Box<dyn FnOnce(zx::sys::zx_status_t)>> = {
268 let completer = Box::new(move |status| unsafe {
272 complete_borrowed_operation(borrowed_operation, status);
273 });
274 unsafe { Completer::new_unchecked(completer) }
277 };
278
279 let async_id = match payload.async_id.with_name("async_id").try_unpack() {
280 Ok(x) => x,
281 Err(e) => {
282 let e = e.context("Missing required field in EthernetTxTransferRequest.");
283 error!("{}", e);
284 return zx::Status::INVALID_ARGS.into_raw();
285 }
286 };
287
288 let (packet_address, packet_size) = match (
289 payload.packet_address.with_name("packet_address"),
290 payload.packet_size.with_name("packet_size"),
291 )
292 .try_unpack()
293 {
294 Ok(x) => x,
295 Err(e) => {
296 let e = e.context("Missing required field(s) in EthernetTxTransferRequest.");
297 error!("{}", e);
298 return zx::Status::INVALID_ARGS.into_raw();
299 }
300 };
301
302 let packet_ptr = packet_address as *mut u8;
303 if packet_ptr.is_null() {
304 error!("EthernetTx.Transfer request contained NULL packet_address");
305 return zx::Status::INVALID_ARGS.into_raw();
306 }
307
308 let bytes = unsafe {
311 NonNull::new_unchecked(slice::from_raw_parts_mut(packet_ptr, packet_size as usize))
312 };
313
314 match unsafe {
317 (*ctx).sender.unbounded_send(EthernetTxEvent {
318 bytes,
319 async_id: async_id.into(),
320 borrowed_operation,
321 })
322 } {
323 Err((error, _event)) => {
324 error!("Failed to queue EthernetTx.Transfer request: {}", error);
325 zx::Status::INTERNAL.into_raw()
326 }
327 Ok(()) => zx::Status::OK.into_raw(),
328 }
329 }
330}
331
332pub trait WlanRxEventSender {
333 fn unbounded_send(&self, event: WlanRxEvent) -> Result<(), (String, WlanRxEvent)>;
334}
335
336#[repr(C)]
337pub struct FfiWlanRxCtx {
338 sender: Box<dyn WlanRxEventSender>,
339 pin: PhantomPinned,
340}
341
342#[repr(C)]
343pub struct FfiWlanRx {
344 ctx: *const FfiWlanRxCtx,
345 transfer:
346 unsafe extern "C" fn(ctx: *const FfiWlanRxCtx, request: *const u8, request_size: usize),
347}
348
349pub struct WlanRx {
350 ctx: Pin<Box<FfiWlanRxCtx>>,
351}
352
353pub struct WlanRxEvent {
356 pub bytes: ArenaStaticBox<[u8]>,
357 pub rx_info: fidl_softmac::WlanRxInfo,
358 pub async_id: trace::Id,
359}
360
361impl WlanRx {
362 pub fn new(sender: Box<dyn WlanRxEventSender>) -> Self {
367 Self { ctx: Box::pin(FfiWlanRxCtx { sender, pin: PhantomPinned }) }
368 }
369
370 pub unsafe fn to_ffi(&self) -> FfiWlanRx {
384 FfiWlanRx {
385 ctx: &*self.ctx.as_ref() as *const FfiWlanRxCtx,
386 transfer: Self::wlan_rx_transfer,
387 }
388 }
389
390 #[no_mangle]
398 unsafe extern "C" fn wlan_rx_transfer(
399 ctx: *const FfiWlanRxCtx,
400 payload: *const u8,
401 payload_len: usize,
402 ) {
403 wtrace::duration!(c"WlanRx transfer");
404
405 let payload = unsafe { slice::from_raw_parts(payload, payload_len) };
409 let payload = match fidl::unpersist::<fidl_softmac::WlanRxTransferRequest>(payload) {
410 Ok(payload) => payload,
411 Err(e) => {
412 error!("Unable to unpersist WlanRx.Transfer request: {}", e);
413 return;
414 }
415 };
416
417 let async_id = match payload.async_id.with_name("async_id").try_unpack() {
418 Ok(x) => x,
419 Err(e) => {
420 let e = e.context("Missing required field in WlanRxTransferRequest.");
421 error!("{}", e);
422 return;
423 }
424 };
425
426 let arena = match payload.arena.with_name("arena").try_unpack() {
427 Ok(x) => {
428 if x == 0 {
429 error!("Received arena is null");
430 return;
431 }
432 unsafe { Arena::from_raw(NonNull::new_unchecked(x as *mut fdf_arena_t)) }
434 }
435 Err(e) => {
436 let e = e.context("Missing required field in WlanRxTransferRequest.");
437 error!("{}", e);
438 return;
439 }
440 };
441
442 let (packet_address, packet_size, packet_info) = match (
443 payload.packet_address.with_name("packet_address"),
444 payload.packet_size.with_name("packet_size"),
445 payload.packet_info.with_name("packet_info"),
446 )
447 .try_unpack()
448 {
449 Ok(x) => x,
450 Err(e) => {
451 let e = e.context("Missing required field(s) in WlanRxTransferRequest.");
452 error!("{}", e);
453 wtrace::async_end_wlansoftmac_rx(async_id.into(), &e.to_string());
454 return;
455 }
456 };
457
458 let packet_ptr = packet_address as *mut u8;
459 if packet_ptr.is_null() {
460 let e = "WlanRx.Transfer request contained NULL packet_address";
461 error!("{}", e);
462 wtrace::async_end_wlansoftmac_rx(async_id.into(), e);
463 return;
464 }
465
466 let bytes = unsafe {
470 arena.assume_unchecked(NonNull::new_unchecked(slice::from_raw_parts_mut(
471 packet_ptr,
472 packet_size as usize,
473 )))
474 };
475 let bytes = arena.make_static(bytes);
476
477 let _: Result<(), ()> = unsafe {
480 (*ctx).sender.unbounded_send(WlanRxEvent {
481 bytes,
482 rx_info: packet_info,
483 async_id: async_id.into(),
484 })
485 }
486 .map_err(|(error, _event)| {
487 let e = format!("Failed to queue WlanRx.Transfer request: {}", error);
488 error!("{}", error);
489 wtrace::async_end_wlansoftmac_rx(async_id.into(), &e);
490 });
491 }
492}