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}