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