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