xref: /aosp_15_r20/bootable/libbootloader/gbl/libefi/src/protocol/simple_network.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
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 //! Rust wrapper for `EFI_SIMPLE_NETWORK_PROTOCOL`.
16 
17 use crate::efi_call;
18 use crate::protocol::{Protocol, ProtocolInfo};
19 use core::ffi::c_void;
20 use core::ptr::null_mut;
21 use efi_types::{
22     EfiGuid, EfiMacAddress, EfiSimpleNetworkMode, EfiSimpleNetworkProtocol,
23     EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS, EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST,
24     EFI_SIMPLE_NETWORK_RECEIVE_UNICAST,
25 };
26 use liberror::{Error, Result};
27 
28 /// EFI_SIMPLE_NETWORK_PROTOCOL
29 pub struct SimpleNetworkProtocol;
30 
31 impl ProtocolInfo for SimpleNetworkProtocol {
32     type InterfaceType = EfiSimpleNetworkProtocol;
33 
34     const GUID: EfiGuid =
35         EfiGuid::new(0xa19832b9, 0xac25, 0x11d3, [0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d]);
36 }
37 
38 impl<'a> Protocol<'a, SimpleNetworkProtocol> {
39     /// Wrapper of `EFI_SIMPLE_NETWORK.Start()`
start(&self) -> Result<()>40     pub fn start(&self) -> Result<()> {
41         // SAFETY:
42         // `self.interface()?` guarantees to return a valid object pointer as established by
43         // `Protocol::new()`.
44         // `self.interface` outlives the call and will not be retained.
45         unsafe { efi_call!(self.interface()?.start, self.interface) }
46     }
47 
48     /// Wrapper of `EFI_SIMPLE_NETWORK.Stop()`
stop(&self) -> Result<()>49     pub fn stop(&self) -> Result<()> {
50         // SAFETY: See safety reasoning of `start()`.
51         unsafe { efi_call!(self.interface()?.stop, self.interface) }
52     }
53 
54     /// Wrapper of `EFI_SIMPLE_NETWORK.Initialize()`
initialize(&self, extra_rx_buf_size: usize, extra_tx_buf_size: usize) -> Result<()>55     pub fn initialize(&self, extra_rx_buf_size: usize, extra_tx_buf_size: usize) -> Result<()> {
56         // SAFETY: See safety reasoning of `start()`.
57         unsafe {
58             efi_call!(
59                 self.interface()?.initialize,
60                 self.interface,
61                 extra_rx_buf_size,
62                 extra_tx_buf_size
63             )
64         }
65     }
66 
67     /// Wrapper of `EFI_SIMPLE_NETWORK.Reset()`
reset(&self, extended_verification: bool) -> Result<()>68     pub fn reset(&self, extended_verification: bool) -> Result<()> {
69         // SAFETY: See safety reasoning of `start()`.
70         unsafe { efi_call!(self.interface()?.reset, self.interface, extended_verification) }
71     }
72 
73     /// Wrapper of `EFI_SIMPLE_NETWORK.Shutdown()`
shutdown(&self) -> Result<()>74     pub fn shutdown(&self) -> Result<()> {
75         // SAFETY: See safety reasoning of `start()`.
76         unsafe { efi_call!(self.interface()?.shutdown, self.interface) }
77     }
78 
79     /// Wrapper of `EFI_SIMPLE_NETWORK.ReceiveFilters()`
receive_filters( &self, enable: u32, disable: u32, reset_mcast_filter: bool, mcast_filter: &mut [EfiMacAddress], ) -> Result<()>80     pub fn receive_filters(
81         &self,
82         enable: u32,
83         disable: u32,
84         reset_mcast_filter: bool,
85         mcast_filter: &mut [EfiMacAddress],
86     ) -> Result<()> {
87         // SAFETY:
88         // `self.interface()?` guarantees to return a valid object pointer as established by
89         // `Protocol::new()`.
90         // `self.interface` outlives the call and will not be retained.
91         // `mcast_filter` is for input only. It outlives the call and will not be retained.
92         unsafe {
93             efi_call!(
94                 self.interface()?.receive_filters,
95                 self.interface,
96                 enable,
97                 disable,
98                 reset_mcast_filter,
99                 mcast_filter.len(),
100                 mcast_filter.as_mut_ptr()
101             )
102         }
103     }
104 
105     /// Wrapper of `EFI_SIMPLE_NETWORK.GetStatus()`
get_status( &self, interrupt_status: Option<&mut u32>, recycle_buffer: Option<&mut *mut c_void>, ) -> Result<()>106     pub fn get_status(
107         &self,
108         interrupt_status: Option<&mut u32>,
109         recycle_buffer: Option<&mut *mut c_void>,
110     ) -> Result<()> {
111         // SAFETY:
112         // See safety reasoning of `start()`.
113         // Pointers to `interrupt_status`, `recycled_buffer` are valid during the call and for
114         // writing output values only.
115         unsafe {
116             efi_call!(
117                 self.interface()?.get_status,
118                 self.interface,
119                 option_ref_mut_to_pointer(interrupt_status),
120                 option_ref_mut_to_pointer(recycle_buffer)
121             )?;
122         }
123         Ok(())
124     }
125 
126     /// Wrapper of `EFI_SIMPLE_NETWORK.Transmit()`
127     ///
128     /// # Safety
129     ///
130     /// * `buf` needs to be a valid buffer.
131     /// * There should not be any existing references to memory pointed by `buf`.
132     /// * Because `buf` is internally retained by the network. `buf` should remain valid and not
133     ///   dereferenced until either 1) the buffer address re-appears in `recycled_buffer` from
134     ///   `Self::get_status()` or 2) Self::Shutdown() is called and returns either Ok(()) or
135     ///   EFI_STATUS_NOT_STARTED.
transmit( &self, header_size: usize, buf: *mut [u8], mut src: EfiMacAddress, mut dest: EfiMacAddress, mut protocol: u16, ) -> Result<()>136     pub unsafe fn transmit(
137         &self,
138         header_size: usize,
139         buf: *mut [u8],
140         mut src: EfiMacAddress,
141         mut dest: EfiMacAddress,
142         mut protocol: u16,
143     ) -> Result<()> {
144         // SAFETY: function safety docs require valid `buf`.
145         let buf = unsafe { buf.as_mut() }.unwrap();
146         // SAFETY:
147         // See safety reasoning of `start()`.
148         // All pointers passed are valid, outlive the call and are not retained by the call.
149         unsafe {
150             efi_call!(
151                 self.interface()?.transmit,
152                 self.interface,
153                 header_size,
154                 buf.len(),
155                 buf.as_mut_ptr() as *mut _,
156                 &mut src,
157                 &mut dest,
158                 &mut protocol
159             )
160         }
161     }
162 
163     /// 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>, ) -> Result<()>164     pub fn receive(
165         &self,
166         header_size: Option<&mut usize>,
167         buf_size: Option<&mut usize>,
168         buf: &mut [u8],
169         src: Option<&mut EfiMacAddress>,
170         dest: Option<&mut EfiMacAddress>,
171         protocol: Option<&mut u16>,
172     ) -> Result<()> {
173         // SAFETY:
174         // See safety reasoning of `start()`.
175         // All pointers passed are valid, outlive the call and are not retained by the call.
176         unsafe {
177             efi_call!(
178                 self.interface()?.receive,
179                 self.interface,
180                 option_ref_mut_to_pointer(header_size),
181                 option_ref_mut_to_pointer(buf_size),
182                 buf.as_mut_ptr() as *mut _,
183                 option_ref_mut_to_pointer(src),
184                 option_ref_mut_to_pointer(dest),
185                 option_ref_mut_to_pointer(protocol)
186             )?;
187         }
188         Ok(())
189     }
190 
191     /// Returns `EFI_SIMPLE_NETWORK.Mode` structure
mode(&self) -> Result<EfiSimpleNetworkMode>192     pub fn mode(&self) -> Result<EfiSimpleNetworkMode> {
193         // SAFETY: Non-null pointer from UEFI interface points to valid object.
194         unsafe { self.interface()?.mode.as_ref() }.ok_or(Error::NotFound).copied()
195     }
196 
197     /// Sets to promiscuous mode to receive all packets over the network.
set_promiscuous_mode(&self) -> Result<()>198     pub fn set_promiscuous_mode(&self) -> Result<()> {
199         self.receive_filters(
200             EFI_SIMPLE_NETWORK_RECEIVE_UNICAST
201                 | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS
202                 | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST,
203             0,
204             false,
205             &mut [],
206         )
207     }
208 }
209 
210 /// 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 T211 fn option_ref_mut_to_pointer<T>(option: Option<&mut T>) -> *mut T {
212     option.map(|t| t as *mut _).unwrap_or(null_mut())
213 }
214