1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::defs::{
16     EfiGuid, EfiMacAddress, EfiSimpleNetworkMode, EfiSimpleNetworkProtocol, EFI_STATUS_NOT_FOUND,
17 };
18 use crate::protocol::{Protocol, ProtocolInfo};
19 use crate::{efi_call, map_efi_err, EfiResult};
20 use core::ffi::c_void;
21 use core::ptr::null_mut;
22 
23 /// EFI_SIMPLE_NETWORK_PROTOCOL
24 pub struct SimpleNetworkProtocol;
25 
26 impl ProtocolInfo for SimpleNetworkProtocol {
27     type InterfaceType = EfiSimpleNetworkProtocol;
28 
29     const GUID: EfiGuid =
30         EfiGuid::new(0xa19832b9, 0xac25, 0x11d3, [0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d]);
31 }
32 
33 impl<'a> Protocol<'a, SimpleNetworkProtocol> {
34     /// Wrapper of `EFI_SIMPLE_NETWORK.Start()`
start(&self) -> EfiResult<()>35     pub fn start(&self) -> EfiResult<()> {
36         // SAFETY:
37         // `self.interface()?` guarantees to return a valid object pointer as established by
38         // `Protocol::new()`.
39         // `self.interface` outlives the call and will not be retained.
40         unsafe { efi_call!(self.interface()?.start, self.interface) }
41     }
42 
43     /// Wrapper of `EFI_SIMPLE_NETWORK.Stop()`
stop(&self) -> EfiResult<()>44     pub fn stop(&self) -> EfiResult<()> {
45         // SAFETY: See safety reasoning of `start()`.
46         unsafe { efi_call!(self.interface()?.stop, self.interface) }
47     }
48 
49     /// Wrapper of `EFI_SIMPLE_NETWORK.Initialize()`
initialize(&self, extra_rx_buf_size: usize, extra_tx_buf_size: usize) -> EfiResult<()>50     pub fn initialize(&self, extra_rx_buf_size: usize, extra_tx_buf_size: usize) -> EfiResult<()> {
51         // SAFETY: See safety reasoning of `start()`.
52         unsafe {
53             efi_call!(
54                 self.interface()?.initialize,
55                 self.interface,
56                 extra_rx_buf_size,
57                 extra_tx_buf_size
58             )
59         }
60     }
61 
62     /// Wrapper of `EFI_SIMPLE_NETWORK.Reset()`
reset(&self, extended_verification: bool) -> EfiResult<()>63     pub fn reset(&self, extended_verification: bool) -> EfiResult<()> {
64         // SAFETY: See safety reasoning of `start()`.
65         unsafe { efi_call!(self.interface()?.reset, self.interface, extended_verification) }
66     }
67 
68     /// Wrapper of `EFI_SIMPLE_NETWORK.Shutdown()`
shutdown(&self) -> EfiResult<()>69     pub fn shutdown(&self) -> EfiResult<()> {
70         // SAFETY: See safety reasoning of `start()`.
71         unsafe { efi_call!(self.interface()?.shutdown, self.interface) }
72     }
73 
74     /// Wrapper of `EFI_SIMPLE_NETWORK.GetStatus()`
get_status( &self, interrupt_status: Option<&mut u32>, recycle_buffer: Option<&mut *mut c_void>, ) -> EfiResult<()>75     pub fn get_status(
76         &self,
77         interrupt_status: Option<&mut u32>,
78         recycle_buffer: Option<&mut *mut c_void>,
79     ) -> EfiResult<()> {
80         // SAFETY:
81         // See safety reasoning of `start()`.
82         // Pointers to `interrupt_status`, `recycled_buffer` are valid during the call and for
83         // writing output values only.
84         unsafe {
85             efi_call!(
86                 self.interface()?.get_status,
87                 self.interface,
88                 option_ref_mut_to_pointer(interrupt_status),
89                 option_ref_mut_to_pointer(recycle_buffer)
90             )?;
91         }
92         Ok(())
93     }
94 
95     /// Wrapper of `EFI_SIMPLE_NETWORK.Transmit()`
96     ///
97     /// # Safety
98     ///
99     /// * `buf` needs to be a valid buffer.
100     /// * There should not be any existing references to memory pointed by `buf`.
101     /// * Because `buf` is internally retained by the network. `buf` should remain valid and not
102     ///   dereferenced until either 1) the buffer address re-appears in `recycled_buffer` from
103     ///   `Self::get_status()` or 2) Self::Shutdown() is called and returns either Ok(()) or
104     ///   EFI_STATUS_NOT_STARTED.
transmit( &self, header_size: usize, buf: *mut [u8], mut src: EfiMacAddress, mut dest: EfiMacAddress, mut protocol: u16, ) -> EfiResult<()>105     pub unsafe fn transmit(
106         &self,
107         header_size: usize,
108         buf: *mut [u8],
109         mut src: EfiMacAddress,
110         mut dest: EfiMacAddress,
111         mut protocol: u16,
112     ) -> EfiResult<()> {
113         let buf = buf.as_mut().unwrap();
114         // SAFETY:
115         // See safety reasoning of `start()`.
116         // All pointers passed are valid, outlive the call and are not retained by the call.
117         unsafe {
118             efi_call!(
119                 self.interface()?.transmit,
120                 self.interface,
121                 header_size,
122                 buf.len(),
123                 buf.as_mut_ptr() as *mut _,
124                 &mut src,
125                 &mut dest,
126                 &mut protocol
127             )
128         }
129     }
130 
131     /// Wrapper of `EFI_SIMPLE_NETWORK.Receive()`.
receive( &self, header_size: Option<&mut usize>, buf_size: Option<&mut usize>, buf: &mut [u8], src: Option<&mut EfiMacAddress>, dest: Option<&mut EfiMacAddress>, protocol: Option<&mut u16>, ) -> EfiResult<()>132     pub fn receive(
133         &self,
134         header_size: Option<&mut usize>,
135         buf_size: Option<&mut usize>,
136         buf: &mut [u8],
137         src: Option<&mut EfiMacAddress>,
138         dest: Option<&mut EfiMacAddress>,
139         protocol: Option<&mut u16>,
140     ) -> EfiResult<()> {
141         // SAFETY:
142         // See safety reasoning of `start()`.
143         // All pointers passed are valid, outlive the call and are not retained by the call.
144         unsafe {
145             efi_call!(
146                 self.interface()?.receive,
147                 self.interface,
148                 option_ref_mut_to_pointer(header_size),
149                 option_ref_mut_to_pointer(buf_size),
150                 buf.as_mut_ptr() as *mut _,
151                 option_ref_mut_to_pointer(src),
152                 option_ref_mut_to_pointer(dest),
153                 option_ref_mut_to_pointer(protocol)
154             )?;
155         }
156         Ok(())
157     }
158 
159     /// Returns `EFI_SIMPLE_NETWORK.Mode` structure
mode(&self) -> EfiResult<EfiSimpleNetworkMode>160     pub fn mode(&self) -> EfiResult<EfiSimpleNetworkMode> {
161         // SAFETY: Non-null pointer from UEFI interface points to valid object.
162         unsafe { self.interface()?.mode.as_ref() }.ok_or(EFI_STATUS_NOT_FOUND.into()).copied()
163     }
164 }
165 
166 /// A helper to convert an `Option<&mut T>` to `*mut T`. None maps to NULL.
option_ref_mut_to_pointer<T>(option: Option<&mut T>) -> *mut T167 fn option_ref_mut_to_pointer<T>(option: Option<&mut T>) -> *mut T {
168     option.map(|t| t as *mut _).unwrap_or(null_mut())
169 }
170