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