xref: /aosp_15_r20/bootable/libbootloader/gbl/efi/src/net.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker 
15*5225e6b1SAndroid Build Coastguard Worker use crate::{
16*5225e6b1SAndroid Build Coastguard Worker     error::{listen_to_unified, recv_to_unified, send_to_unified},
17*5225e6b1SAndroid Build Coastguard Worker     utils::{get_device_path, loop_with_timeout},
18*5225e6b1SAndroid Build Coastguard Worker };
19*5225e6b1SAndroid Build Coastguard Worker use alloc::{boxed::Box, vec::Vec};
20*5225e6b1SAndroid Build Coastguard Worker use core::{
21*5225e6b1SAndroid Build Coastguard Worker     fmt::Write,
22*5225e6b1SAndroid Build Coastguard Worker     sync::atomic::{AtomicU64, Ordering},
23*5225e6b1SAndroid Build Coastguard Worker };
24*5225e6b1SAndroid Build Coastguard Worker use efi::{
25*5225e6b1SAndroid Build Coastguard Worker     efi_print, efi_println,
26*5225e6b1SAndroid Build Coastguard Worker     protocol::{simple_network::SimpleNetworkProtocol, Protocol},
27*5225e6b1SAndroid Build Coastguard Worker     utils::{ms_to_100ns, Timeout},
28*5225e6b1SAndroid Build Coastguard Worker     DeviceHandle, EfiEntry, Event, EventNotify, EventType, Tpl,
29*5225e6b1SAndroid Build Coastguard Worker };
30*5225e6b1SAndroid Build Coastguard Worker use efi_types::{EfiEvent, EfiMacAddress, EFI_TIMER_DELAY_TIMER_PERIODIC};
31*5225e6b1SAndroid Build Coastguard Worker use gbl_async::{yield_now, YieldCounter};
32*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result};
33*5225e6b1SAndroid Build Coastguard Worker use libgbl::fastboot::fuchsia_fastboot_mdns_packet;
34*5225e6b1SAndroid Build Coastguard Worker use smoltcp::{
35*5225e6b1SAndroid Build Coastguard Worker     iface::{Config, Interface, SocketSet, SocketStorage},
36*5225e6b1SAndroid Build Coastguard Worker     phy,
37*5225e6b1SAndroid Build Coastguard Worker     phy::{Device, DeviceCapabilities, Medium},
38*5225e6b1SAndroid Build Coastguard Worker     socket::{
39*5225e6b1SAndroid Build Coastguard Worker         tcp::{Socket as TcpSocket, SocketBuffer, State},
40*5225e6b1SAndroid Build Coastguard Worker         udp::{PacketBuffer, Socket as UdpSocket, UdpMetadata},
41*5225e6b1SAndroid Build Coastguard Worker     },
42*5225e6b1SAndroid Build Coastguard Worker     storage::PacketMetadata,
43*5225e6b1SAndroid Build Coastguard Worker     time::Instant,
44*5225e6b1SAndroid Build Coastguard Worker     wire::{EthernetAddress, IpAddress, IpCidr, IpListenEndpoint, Ipv6Address},
45*5225e6b1SAndroid Build Coastguard Worker };
46*5225e6b1SAndroid Build Coastguard Worker 
47*5225e6b1SAndroid Build Coastguard Worker /// Ethernet frame size for frame pool.
48*5225e6b1SAndroid Build Coastguard Worker const ETHERNET_FRAME_SIZE: usize = 1536;
49*5225e6b1SAndroid Build Coastguard Worker // Update period in milliseconds for `NETWORK_TIMESTAMP`.
50*5225e6b1SAndroid Build Coastguard Worker const NETWORK_TIMESTAMP_UPDATE_PERIOD: u64 = 50;
51*5225e6b1SAndroid Build Coastguard Worker // Size of the socket tx/rx application data buffer.
52*5225e6b1SAndroid Build Coastguard Worker const SOCKET_TX_RX_BUFFER: usize = 256 * 1024;
53*5225e6b1SAndroid Build Coastguard Worker 
54*5225e6b1SAndroid Build Coastguard Worker /// Performs a shutdown and restart of the simple network protocol.
reset_simple_network<'a>(snp: &Protocol<'a, SimpleNetworkProtocol>) -> Result<()>55*5225e6b1SAndroid Build Coastguard Worker fn reset_simple_network<'a>(snp: &Protocol<'a, SimpleNetworkProtocol>) -> Result<()> {
56*5225e6b1SAndroid Build Coastguard Worker     match snp.shutdown() {
57*5225e6b1SAndroid Build Coastguard Worker         Err(e) if e != Error::NotStarted => return Err(e),
58*5225e6b1SAndroid Build Coastguard Worker         _ => {}
59*5225e6b1SAndroid Build Coastguard Worker     };
60*5225e6b1SAndroid Build Coastguard Worker 
61*5225e6b1SAndroid Build Coastguard Worker     match snp.start() {
62*5225e6b1SAndroid Build Coastguard Worker         Err(e) if e != Error::AlreadyStarted => return Err(e),
63*5225e6b1SAndroid Build Coastguard Worker         _ => {}
64*5225e6b1SAndroid Build Coastguard Worker     };
65*5225e6b1SAndroid Build Coastguard Worker     snp.initialize(0, 0)?;
66*5225e6b1SAndroid Build Coastguard Worker     Ok(snp.reset(true)?)
67*5225e6b1SAndroid Build Coastguard Worker }
68*5225e6b1SAndroid Build Coastguard Worker 
69*5225e6b1SAndroid Build Coastguard Worker /// `EfiNetworkDevice` manages a frame pool and handles receiving/sending network frames.
70*5225e6b1SAndroid Build Coastguard Worker pub struct EfiNetworkDevice<'a> {
71*5225e6b1SAndroid Build Coastguard Worker     protocol: Protocol<'a, SimpleNetworkProtocol>,
72*5225e6b1SAndroid Build Coastguard Worker     rx_frame: Box<[u8; ETHERNET_FRAME_SIZE]>,
73*5225e6b1SAndroid Build Coastguard Worker     tx_frames: Vec<*mut [u8; ETHERNET_FRAME_SIZE]>,
74*5225e6b1SAndroid Build Coastguard Worker     tx_frame_curr: usize, // Circular next index into tx_frames.
75*5225e6b1SAndroid Build Coastguard Worker     efi_entry: &'a EfiEntry,
76*5225e6b1SAndroid Build Coastguard Worker }
77*5225e6b1SAndroid Build Coastguard Worker 
78*5225e6b1SAndroid Build Coastguard Worker impl<'a> EfiNetworkDevice<'a> {
79*5225e6b1SAndroid Build Coastguard Worker     /// Creates an new instance. Allocates `extra_tx_frames+1` number of TX frames.
new( protocol: Protocol<'a, SimpleNetworkProtocol>, extra_tx_frames: usize, efi_entry: &'a EfiEntry, ) -> Self80*5225e6b1SAndroid Build Coastguard Worker     pub fn new(
81*5225e6b1SAndroid Build Coastguard Worker         protocol: Protocol<'a, SimpleNetworkProtocol>,
82*5225e6b1SAndroid Build Coastguard Worker         extra_tx_frames: usize,
83*5225e6b1SAndroid Build Coastguard Worker         efi_entry: &'a EfiEntry,
84*5225e6b1SAndroid Build Coastguard Worker     ) -> Self {
85*5225e6b1SAndroid Build Coastguard Worker         let mut ret = Self {
86*5225e6b1SAndroid Build Coastguard Worker             protocol: protocol,
87*5225e6b1SAndroid Build Coastguard Worker             rx_frame: Box::new([0u8; ETHERNET_FRAME_SIZE]),
88*5225e6b1SAndroid Build Coastguard Worker             tx_frames: vec![core::ptr::null_mut(); extra_tx_frames + 1],
89*5225e6b1SAndroid Build Coastguard Worker             tx_frame_curr: 0,
90*5225e6b1SAndroid Build Coastguard Worker             efi_entry: efi_entry,
91*5225e6b1SAndroid Build Coastguard Worker         };
92*5225e6b1SAndroid Build Coastguard Worker         ret.tx_frames
93*5225e6b1SAndroid Build Coastguard Worker             .iter_mut()
94*5225e6b1SAndroid Build Coastguard Worker             .for_each(|v| *v = Box::into_raw(Box::new([0u8; ETHERNET_FRAME_SIZE])));
95*5225e6b1SAndroid Build Coastguard Worker         ret
96*5225e6b1SAndroid Build Coastguard Worker     }
97*5225e6b1SAndroid Build Coastguard Worker }
98*5225e6b1SAndroid Build Coastguard Worker 
99*5225e6b1SAndroid Build Coastguard Worker impl Drop for EfiNetworkDevice<'_> {
drop(&mut self)100*5225e6b1SAndroid Build Coastguard Worker     fn drop(&mut self) {
101*5225e6b1SAndroid Build Coastguard Worker         if let Err(e) = self.protocol.shutdown() {
102*5225e6b1SAndroid Build Coastguard Worker             if e != Error::NotStarted {
103*5225e6b1SAndroid Build Coastguard Worker                 // If shutdown fails, the protocol might still be operating on transmit buffers,
104*5225e6b1SAndroid Build Coastguard Worker                 // which can cause undefined behavior. Thus we need to panic.
105*5225e6b1SAndroid Build Coastguard Worker                 panic!("Failed to shutdown EFI network. {:?}", e);
106*5225e6b1SAndroid Build Coastguard Worker             }
107*5225e6b1SAndroid Build Coastguard Worker         }
108*5225e6b1SAndroid Build Coastguard Worker 
109*5225e6b1SAndroid Build Coastguard Worker         // Deallocate TX frames.
110*5225e6b1SAndroid Build Coastguard Worker         self.tx_frames.iter_mut().for_each(|v| {
111*5225e6b1SAndroid Build Coastguard Worker             // SAFETY:
112*5225e6b1SAndroid Build Coastguard Worker             // Each pointer is created by `Box::new()` in `EfiNetworkDevice::new()`. Thus the
113*5225e6b1SAndroid Build Coastguard Worker             // pointer is valid and layout matches.
114*5225e6b1SAndroid Build Coastguard Worker             drop(unsafe { Box::<[u8; ETHERNET_FRAME_SIZE]>::from_raw(*v) });
115*5225e6b1SAndroid Build Coastguard Worker         });
116*5225e6b1SAndroid Build Coastguard Worker     }
117*5225e6b1SAndroid Build Coastguard Worker }
118*5225e6b1SAndroid Build Coastguard Worker 
119*5225e6b1SAndroid Build Coastguard Worker // Implements network device trait backend for the `smoltcp` crate.
120*5225e6b1SAndroid Build Coastguard Worker impl<'a> Device for EfiNetworkDevice<'a> {
121*5225e6b1SAndroid Build Coastguard Worker     type RxToken<'b> = RxToken<'b> where Self: 'b;
122*5225e6b1SAndroid Build Coastguard Worker     type TxToken<'b> = TxToken<'a, 'b> where Self: 'b;
123*5225e6b1SAndroid Build Coastguard Worker 
capabilities(&self) -> DeviceCapabilities124*5225e6b1SAndroid Build Coastguard Worker     fn capabilities(&self) -> DeviceCapabilities {
125*5225e6b1SAndroid Build Coastguard Worker         // Taken from upstream example.
126*5225e6b1SAndroid Build Coastguard Worker         let mut res: DeviceCapabilities = Default::default();
127*5225e6b1SAndroid Build Coastguard Worker         res.max_transmission_unit = 65535;
128*5225e6b1SAndroid Build Coastguard Worker         res.medium = Medium::Ethernet;
129*5225e6b1SAndroid Build Coastguard Worker         res
130*5225e6b1SAndroid Build Coastguard Worker     }
131*5225e6b1SAndroid Build Coastguard Worker 
receive(&mut self, _: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>132*5225e6b1SAndroid Build Coastguard Worker     fn receive(&mut self, _: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
133*5225e6b1SAndroid Build Coastguard Worker         let mut recv_size = self.rx_frame.len();
134*5225e6b1SAndroid Build Coastguard Worker         // Receive the next packet from the device.
135*5225e6b1SAndroid Build Coastguard Worker         self.protocol
136*5225e6b1SAndroid Build Coastguard Worker             .receive(None, Some(&mut recv_size), &mut self.rx_frame[..], None, None, None)
137*5225e6b1SAndroid Build Coastguard Worker             .ok()?;
138*5225e6b1SAndroid Build Coastguard Worker         match recv_size > 0 {
139*5225e6b1SAndroid Build Coastguard Worker             true => Some((
140*5225e6b1SAndroid Build Coastguard Worker                 RxToken(&mut self.rx_frame[..recv_size]),
141*5225e6b1SAndroid Build Coastguard Worker                 TxToken {
142*5225e6b1SAndroid Build Coastguard Worker                     protocol: &self.protocol,
143*5225e6b1SAndroid Build Coastguard Worker                     tx_frames: &mut self.tx_frames[..],
144*5225e6b1SAndroid Build Coastguard Worker                     curr: &mut self.tx_frame_curr,
145*5225e6b1SAndroid Build Coastguard Worker                     efi_entry: self.efi_entry,
146*5225e6b1SAndroid Build Coastguard Worker                 },
147*5225e6b1SAndroid Build Coastguard Worker             )),
148*5225e6b1SAndroid Build Coastguard Worker             _ => None,
149*5225e6b1SAndroid Build Coastguard Worker         }
150*5225e6b1SAndroid Build Coastguard Worker     }
151*5225e6b1SAndroid Build Coastguard Worker 
transmit(&mut self, _: Instant) -> Option<Self::TxToken<'_>>152*5225e6b1SAndroid Build Coastguard Worker     fn transmit(&mut self, _: Instant) -> Option<Self::TxToken<'_>> {
153*5225e6b1SAndroid Build Coastguard Worker         Some(TxToken {
154*5225e6b1SAndroid Build Coastguard Worker             protocol: &self.protocol,
155*5225e6b1SAndroid Build Coastguard Worker             tx_frames: &mut self.tx_frames[..],
156*5225e6b1SAndroid Build Coastguard Worker             curr: &mut self.tx_frame_curr,
157*5225e6b1SAndroid Build Coastguard Worker             efi_entry: self.efi_entry,
158*5225e6b1SAndroid Build Coastguard Worker         })
159*5225e6b1SAndroid Build Coastguard Worker     }
160*5225e6b1SAndroid Build Coastguard Worker }
161*5225e6b1SAndroid Build Coastguard Worker 
162*5225e6b1SAndroid Build Coastguard Worker /// In smoltcp, a `RxToken` is used to receive/process a frame when consumed.
163*5225e6b1SAndroid Build Coastguard Worker pub struct RxToken<'a>(&'a mut [u8]);
164*5225e6b1SAndroid Build Coastguard Worker 
165*5225e6b1SAndroid Build Coastguard Worker impl phy::RxToken for RxToken<'_> {
consume<R, F>(self, f: F) -> R where F: FnOnce(&mut [u8]) -> R,166*5225e6b1SAndroid Build Coastguard Worker     fn consume<R, F>(self, f: F) -> R
167*5225e6b1SAndroid Build Coastguard Worker     where
168*5225e6b1SAndroid Build Coastguard Worker         F: FnOnce(&mut [u8]) -> R,
169*5225e6b1SAndroid Build Coastguard Worker     {
170*5225e6b1SAndroid Build Coastguard Worker         f(self.0)
171*5225e6b1SAndroid Build Coastguard Worker     }
172*5225e6b1SAndroid Build Coastguard Worker }
173*5225e6b1SAndroid Build Coastguard Worker 
174*5225e6b1SAndroid Build Coastguard Worker /// In smoltcp, a `TxToken` is used to transmit a frame when consumed.
175*5225e6b1SAndroid Build Coastguard Worker pub struct TxToken<'a: 'b, 'b> {
176*5225e6b1SAndroid Build Coastguard Worker     tx_frames: &'b mut [*mut [u8; ETHERNET_FRAME_SIZE]],
177*5225e6b1SAndroid Build Coastguard Worker     curr: &'b mut usize,
178*5225e6b1SAndroid Build Coastguard Worker     protocol: &'b Protocol<'a, SimpleNetworkProtocol>,
179*5225e6b1SAndroid Build Coastguard Worker     efi_entry: &'b EfiEntry,
180*5225e6b1SAndroid Build Coastguard Worker }
181*5225e6b1SAndroid Build Coastguard Worker 
182*5225e6b1SAndroid Build Coastguard Worker impl TxToken<'_, '_> {
183*5225e6b1SAndroid Build Coastguard Worker     /// Tries to allocate a send buffer.
try_get_buffer(&mut self) -> Option<*mut [u8; ETHERNET_FRAME_SIZE]>184*5225e6b1SAndroid Build Coastguard Worker     fn try_get_buffer(&mut self) -> Option<*mut [u8; ETHERNET_FRAME_SIZE]> {
185*5225e6b1SAndroid Build Coastguard Worker         let mut ptr: *mut core::ffi::c_void = core::ptr::null_mut();
186*5225e6b1SAndroid Build Coastguard Worker         let mut interrupt_status = 0u32;
187*5225e6b1SAndroid Build Coastguard Worker         // Recyle a buffer or take one from `tx_frames`.
188*5225e6b1SAndroid Build Coastguard Worker         match self.protocol.get_status(Some(&mut interrupt_status), Some(&mut ptr)) {
189*5225e6b1SAndroid Build Coastguard Worker             Ok(()) if self.tx_frames.contains(&(ptr as *mut _)) => Some(ptr as *mut _),
190*5225e6b1SAndroid Build Coastguard Worker             _ if *self.curr < self.tx_frames.len() => {
191*5225e6b1SAndroid Build Coastguard Worker                 // If we can't recycle a buffer, see if we can take one from the pool.
192*5225e6b1SAndroid Build Coastguard Worker                 let res = *self.curr;
193*5225e6b1SAndroid Build Coastguard Worker                 *self.curr = *self.curr + 1;
194*5225e6b1SAndroid Build Coastguard Worker                 Some(self.tx_frames[res])
195*5225e6b1SAndroid Build Coastguard Worker             }
196*5225e6b1SAndroid Build Coastguard Worker             _ => None,
197*5225e6b1SAndroid Build Coastguard Worker         }
198*5225e6b1SAndroid Build Coastguard Worker     }
199*5225e6b1SAndroid Build Coastguard Worker }
200*5225e6b1SAndroid Build Coastguard Worker 
201*5225e6b1SAndroid Build Coastguard Worker impl phy::TxToken for TxToken<'_, '_> {
consume<R, F>(mut self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R,202*5225e6b1SAndroid Build Coastguard Worker     fn consume<R, F>(mut self, len: usize, f: F) -> R
203*5225e6b1SAndroid Build Coastguard Worker     where
204*5225e6b1SAndroid Build Coastguard Worker         F: FnOnce(&mut [u8]) -> R,
205*5225e6b1SAndroid Build Coastguard Worker     {
206*5225e6b1SAndroid Build Coastguard Worker         loop {
207*5225e6b1SAndroid Build Coastguard Worker             match loop_with_timeout(self.efi_entry, 5000, || self.try_get_buffer().ok_or(false)) {
208*5225e6b1SAndroid Build Coastguard Worker                 Ok(Some(send_buffer)) => {
209*5225e6b1SAndroid Build Coastguard Worker                     // SAFETY:
210*5225e6b1SAndroid Build Coastguard Worker                     // * The pointer is confirmed to come from one of `self.tx_frames`. It's
211*5225e6b1SAndroid Build Coastguard Worker                     //   created via `Box::new()` in `EfiNetworkDevice::new()`. Thus it is properly
212*5225e6b1SAndroid Build Coastguard Worker                     //   aligned, dereferenceable and initialized.
213*5225e6b1SAndroid Build Coastguard Worker                     // * The pointer is either recycled from `self.protocol.get_status` or newly
214*5225e6b1SAndroid Build Coastguard Worker                     //   allocated from `self.tx_frames`. Thus There's no other references to it.
215*5225e6b1SAndroid Build Coastguard Worker                     // * The reference is only used for passing to `f` and goes out of scope
216*5225e6b1SAndroid Build Coastguard Worker                     //   immediately after.
217*5225e6b1SAndroid Build Coastguard Worker                     let result = f(&mut unsafe { send_buffer.as_mut() }.unwrap()[..len]);
218*5225e6b1SAndroid Build Coastguard Worker 
219*5225e6b1SAndroid Build Coastguard Worker                     // SAFETY:
220*5225e6b1SAndroid Build Coastguard Worker                     // * `send_buffer` comes from `EfiNetworkDevice::tx_frames`. It has a valid
221*5225e6b1SAndroid Build Coastguard Worker                     //   length at least `len`. `EfiNetworkDevice` shuts down network on drop. Thus
222*5225e6b1SAndroid Build Coastguard Worker                     //   the transmit buffer remains valid throughout the operation of the network
223*5225e6b1SAndroid Build Coastguard Worker                     //   protocol.
224*5225e6b1SAndroid Build Coastguard Worker                     // * `send_buffer` is either recycled from `self.protocol.get_status()` or newly
225*5225e6b1SAndroid Build Coastguard Worker                     //   allocated from `self.tx_frames`. There's no other references to it.
226*5225e6b1SAndroid Build Coastguard Worker                     // * `self.curr` stricly increases for each new allocation until
227*5225e6b1SAndroid Build Coastguard Worker                     //   `reset_simple_network()`. Thus there'll be no other references to the buffer
228*5225e6b1SAndroid Build Coastguard Worker                     //    until it is either recycled or `reset_simple_network()` is called.
229*5225e6b1SAndroid Build Coastguard Worker                     let _ = unsafe {
230*5225e6b1SAndroid Build Coastguard Worker                         self.protocol.transmit(
231*5225e6b1SAndroid Build Coastguard Worker                             0,
232*5225e6b1SAndroid Build Coastguard Worker                             send_buffer.as_mut().unwrap().get_mut(..len).unwrap(),
233*5225e6b1SAndroid Build Coastguard Worker                             Default::default(), // Src mac address don't care
234*5225e6b1SAndroid Build Coastguard Worker                             Default::default(), // Dest mac address don't care
235*5225e6b1SAndroid Build Coastguard Worker                             0,
236*5225e6b1SAndroid Build Coastguard Worker                         )
237*5225e6b1SAndroid Build Coastguard Worker                     };
238*5225e6b1SAndroid Build Coastguard Worker 
239*5225e6b1SAndroid Build Coastguard Worker                     return result;
240*5225e6b1SAndroid Build Coastguard Worker                 }
241*5225e6b1SAndroid Build Coastguard Worker                 Ok(None) => {
242*5225e6b1SAndroid Build Coastguard Worker                     // Some UEFI firmware has internal network service that also recycle buffers,
243*5225e6b1SAndroid Build Coastguard Worker                     // in which case our buffer may be hijacked and will never be returned from our
244*5225e6b1SAndroid Build Coastguard Worker                     // call. If we run into this case, shutdown and restart the network and try
245*5225e6b1SAndroid Build Coastguard Worker                     // again. Shutting down network releases all pending send/receive buffers
246*5225e6b1SAndroid Build Coastguard Worker                     // internally retained.
247*5225e6b1SAndroid Build Coastguard Worker                     efi_println!(
248*5225e6b1SAndroid Build Coastguard Worker                         self.efi_entry,
249*5225e6b1SAndroid Build Coastguard Worker                         "Timeout recycling TX buffers. Resetting network."
250*5225e6b1SAndroid Build Coastguard Worker                     );
251*5225e6b1SAndroid Build Coastguard Worker                     // Panics if this fails, as we have effectively lost control over network's
252*5225e6b1SAndroid Build Coastguard Worker                     // used of buffers.
253*5225e6b1SAndroid Build Coastguard Worker                     reset_simple_network(self.protocol).unwrap();
254*5225e6b1SAndroid Build Coastguard Worker                     *self.curr = 0;
255*5225e6b1SAndroid Build Coastguard Worker                 }
256*5225e6b1SAndroid Build Coastguard Worker                 _ => {} // `loop_with_timeout` failure. Try again.
257*5225e6b1SAndroid Build Coastguard Worker             };
258*5225e6b1SAndroid Build Coastguard Worker         }
259*5225e6b1SAndroid Build Coastguard Worker     }
260*5225e6b1SAndroid Build Coastguard Worker }
261*5225e6b1SAndroid Build Coastguard Worker 
262*5225e6b1SAndroid Build Coastguard Worker /// Find the first available network device.
find_net_device(efi_entry: &EfiEntry) -> Result<DeviceHandle>263*5225e6b1SAndroid Build Coastguard Worker fn find_net_device(efi_entry: &EfiEntry) -> Result<DeviceHandle> {
264*5225e6b1SAndroid Build Coastguard Worker     // Find the device whose path is the "smallest" lexicographically, this ensures that it's not
265*5225e6b1SAndroid Build Coastguard Worker     // any child network device of some other node. e1000 tends to add a child network device for
266*5225e6b1SAndroid Build Coastguard Worker     // ipv4 and ipv6 configuration information.
267*5225e6b1SAndroid Build Coastguard Worker     efi_entry
268*5225e6b1SAndroid Build Coastguard Worker         .system_table()
269*5225e6b1SAndroid Build Coastguard Worker         .boot_services()
270*5225e6b1SAndroid Build Coastguard Worker         .locate_handle_buffer_by_protocol::<SimpleNetworkProtocol>()?
271*5225e6b1SAndroid Build Coastguard Worker         .handles()
272*5225e6b1SAndroid Build Coastguard Worker         .iter()
273*5225e6b1SAndroid Build Coastguard Worker         .map(|handle| (*handle, get_device_path(efi_entry, *handle)))
274*5225e6b1SAndroid Build Coastguard Worker         // Ignore devices that fail to get device path.
275*5225e6b1SAndroid Build Coastguard Worker         .filter_map(|(handle, path)| path.ok().map(|v| (handle, v)))
276*5225e6b1SAndroid Build Coastguard Worker         // Ignore devices that have NULL path.
277*5225e6b1SAndroid Build Coastguard Worker         .filter_map(|(handle, path)| path.text().is_some().then(|| (handle, path)))
278*5225e6b1SAndroid Build Coastguard Worker         // Finds the minimum path lexicographically.
279*5225e6b1SAndroid Build Coastguard Worker         .min_by(|lhs, rhs| Ord::cmp(lhs.1.text().unwrap(), rhs.1.text().unwrap()))
280*5225e6b1SAndroid Build Coastguard Worker         .map(|(h, _)| h)
281*5225e6b1SAndroid Build Coastguard Worker         .ok_or(Error::NotFound.into())
282*5225e6b1SAndroid Build Coastguard Worker }
283*5225e6b1SAndroid Build Coastguard Worker 
284*5225e6b1SAndroid Build Coastguard Worker /// Derives a link local ethernet mac address and IPv6 address from `EfiMacAddress`.
ll_mac_ip6_addr_from_efi_mac(mac: EfiMacAddress) -> (EthernetAddress, IpAddress)285*5225e6b1SAndroid Build Coastguard Worker fn ll_mac_ip6_addr_from_efi_mac(mac: EfiMacAddress) -> (EthernetAddress, IpAddress) {
286*5225e6b1SAndroid Build Coastguard Worker     let ll_mac_bytes = &mac.addr[..6];
287*5225e6b1SAndroid Build Coastguard Worker     let mut ip6_bytes = [0u8; 16];
288*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[0] = 0xfe;
289*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[1] = 0x80;
290*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[8] = ll_mac_bytes[0] ^ 2;
291*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[9] = ll_mac_bytes[1];
292*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[10] = ll_mac_bytes[2];
293*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[11] = 0xff;
294*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[12] = 0xfe;
295*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[13] = ll_mac_bytes[3];
296*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[14] = ll_mac_bytes[4];
297*5225e6b1SAndroid Build Coastguard Worker     ip6_bytes[15] = ll_mac_bytes[5];
298*5225e6b1SAndroid Build Coastguard Worker 
299*5225e6b1SAndroid Build Coastguard Worker     (
300*5225e6b1SAndroid Build Coastguard Worker         EthernetAddress::from_bytes(ll_mac_bytes),
301*5225e6b1SAndroid Build Coastguard Worker         IpAddress::Ipv6(Ipv6Address::from_bytes(&ip6_bytes[..])),
302*5225e6b1SAndroid Build Coastguard Worker     )
303*5225e6b1SAndroid Build Coastguard Worker }
304*5225e6b1SAndroid Build Coastguard Worker 
305*5225e6b1SAndroid Build Coastguard Worker /// `EfiTcpSocket` groups together necessary components for performing TCP.
306*5225e6b1SAndroid Build Coastguard Worker pub struct EfiTcpSocket<'a, 'b> {
307*5225e6b1SAndroid Build Coastguard Worker     pub(crate) efi_entry: &'a EfiEntry,
308*5225e6b1SAndroid Build Coastguard Worker     efi_net_dev: &'b mut EfiNetworkDevice<'a>,
309*5225e6b1SAndroid Build Coastguard Worker     interface: Interface,
310*5225e6b1SAndroid Build Coastguard Worker     socket_set: SocketSet<'b>,
311*5225e6b1SAndroid Build Coastguard Worker     io_yield_counter: YieldCounter,
312*5225e6b1SAndroid Build Coastguard Worker     last_listen_timestamp: Option<u64>,
313*5225e6b1SAndroid Build Coastguard Worker     _time_update_event: Event<'a, 'b>,
314*5225e6b1SAndroid Build Coastguard Worker     timestamp: &'b AtomicU64,
315*5225e6b1SAndroid Build Coastguard Worker     fuchsia_fastboot_mdns_packet: Vec<u8>,
316*5225e6b1SAndroid Build Coastguard Worker }
317*5225e6b1SAndroid Build Coastguard Worker 
318*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'b> EfiTcpSocket<'a, 'b> {
319*5225e6b1SAndroid Build Coastguard Worker     /// Resets the socket and starts listening for new TCP connection.
listen(&mut self, port: u16) -> Result<()>320*5225e6b1SAndroid Build Coastguard Worker     pub fn listen(&mut self, port: u16) -> Result<()> {
321*5225e6b1SAndroid Build Coastguard Worker         self.get_socket().abort();
322*5225e6b1SAndroid Build Coastguard Worker         self.get_socket().listen(port).map_err(listen_to_unified)?;
323*5225e6b1SAndroid Build Coastguard Worker         self.last_listen_timestamp = Some(self.timestamp(0));
324*5225e6b1SAndroid Build Coastguard Worker         Ok(())
325*5225e6b1SAndroid Build Coastguard Worker     }
326*5225e6b1SAndroid Build Coastguard Worker 
327*5225e6b1SAndroid Build Coastguard Worker     // Checks if the socket is listening or performing handshake.
is_listening_or_handshaking(&mut self) -> bool328*5225e6b1SAndroid Build Coastguard Worker     pub fn is_listening_or_handshaking(&mut self) -> bool {
329*5225e6b1SAndroid Build Coastguard Worker         matches!(self.get_socket().state(), State::Listen | State::SynReceived)
330*5225e6b1SAndroid Build Coastguard Worker     }
331*5225e6b1SAndroid Build Coastguard Worker 
332*5225e6b1SAndroid Build Coastguard Worker     /// Returns the amount of time elapsed since last call to `Self::listen()`. If `listen()` has
333*5225e6b1SAndroid Build Coastguard Worker     /// never been called, `u64::MAX` is returned.
time_since_last_listen(&mut self) -> u64334*5225e6b1SAndroid Build Coastguard Worker     pub fn time_since_last_listen(&mut self) -> u64 {
335*5225e6b1SAndroid Build Coastguard Worker         self.last_listen_timestamp.map(|v| self.timestamp(v)).unwrap_or(u64::MAX)
336*5225e6b1SAndroid Build Coastguard Worker     }
337*5225e6b1SAndroid Build Coastguard Worker 
338*5225e6b1SAndroid Build Coastguard Worker     /// Polls network device.
poll(&mut self)339*5225e6b1SAndroid Build Coastguard Worker     pub fn poll(&mut self) {
340*5225e6b1SAndroid Build Coastguard Worker         self.interface.poll(self.instant(), self.efi_net_dev, &mut self.socket_set);
341*5225e6b1SAndroid Build Coastguard Worker     }
342*5225e6b1SAndroid Build Coastguard Worker 
343*5225e6b1SAndroid Build Coastguard Worker     /// Polls network and check if the socket is in an active state.
check_active(&mut self) -> bool344*5225e6b1SAndroid Build Coastguard Worker     pub fn check_active(&mut self) -> bool {
345*5225e6b1SAndroid Build Coastguard Worker         self.poll();
346*5225e6b1SAndroid Build Coastguard Worker         self.get_socket().is_active()
347*5225e6b1SAndroid Build Coastguard Worker     }
348*5225e6b1SAndroid Build Coastguard Worker 
349*5225e6b1SAndroid Build Coastguard Worker     /// Gets a reference to the smoltcp socket object.
get_socket(&mut self) -> &mut TcpSocket<'b>350*5225e6b1SAndroid Build Coastguard Worker     pub fn get_socket(&mut self) -> &mut TcpSocket<'b> {
351*5225e6b1SAndroid Build Coastguard Worker         // We only consider single socket use case for now.
352*5225e6b1SAndroid Build Coastguard Worker         let handle = self.socket_set.iter().next().unwrap().0;
353*5225e6b1SAndroid Build Coastguard Worker         self.socket_set.get_mut::<TcpSocket>(handle)
354*5225e6b1SAndroid Build Coastguard Worker     }
355*5225e6b1SAndroid Build Coastguard Worker 
356*5225e6b1SAndroid Build Coastguard Worker     /// Checks whether a socket is closed.
is_closed(&mut self) -> bool357*5225e6b1SAndroid Build Coastguard Worker     fn is_closed(&mut self) -> bool {
358*5225e6b1SAndroid Build Coastguard Worker         return !self.get_socket().is_open() || self.get_socket().state() == State::CloseWait;
359*5225e6b1SAndroid Build Coastguard Worker     }
360*5225e6b1SAndroid Build Coastguard Worker 
361*5225e6b1SAndroid Build Coastguard Worker     /// Sets the maximum number of bytes to read or write before a force await.
set_io_yield_threshold(&mut self, threshold: u64)362*5225e6b1SAndroid Build Coastguard Worker     pub fn set_io_yield_threshold(&mut self, threshold: u64) {
363*5225e6b1SAndroid Build Coastguard Worker         self.io_yield_counter = YieldCounter::new(threshold)
364*5225e6b1SAndroid Build Coastguard Worker     }
365*5225e6b1SAndroid Build Coastguard Worker 
366*5225e6b1SAndroid Build Coastguard Worker     /// Receives exactly `out.len()` number of bytes to `out`.
receive_exact(&mut self, out: &mut [u8], timeout: u64) -> Result<()>367*5225e6b1SAndroid Build Coastguard Worker     pub async fn receive_exact(&mut self, out: &mut [u8], timeout: u64) -> Result<()> {
368*5225e6b1SAndroid Build Coastguard Worker         let timer = Timeout::new(self.efi_entry, timeout)?;
369*5225e6b1SAndroid Build Coastguard Worker         let mut curr = &mut out[..];
370*5225e6b1SAndroid Build Coastguard Worker         while !curr.is_empty() {
371*5225e6b1SAndroid Build Coastguard Worker             self.poll();
372*5225e6b1SAndroid Build Coastguard Worker             let mut has_progress = false;
373*5225e6b1SAndroid Build Coastguard Worker 
374*5225e6b1SAndroid Build Coastguard Worker             if self.is_closed() {
375*5225e6b1SAndroid Build Coastguard Worker                 return Err(Error::Disconnected);
376*5225e6b1SAndroid Build Coastguard Worker             } else if timer.check()? {
377*5225e6b1SAndroid Build Coastguard Worker                 return Err(Error::Timeout);
378*5225e6b1SAndroid Build Coastguard Worker             } else if self.get_socket().can_recv() {
379*5225e6b1SAndroid Build Coastguard Worker                 let recv_size = self.get_socket().recv_slice(curr).map_err(recv_to_unified)?;
380*5225e6b1SAndroid Build Coastguard Worker                 curr = curr.get_mut(recv_size..).ok_or(Error::BadIndex(recv_size))?;
381*5225e6b1SAndroid Build Coastguard Worker                 has_progress = recv_size > 0;
382*5225e6b1SAndroid Build Coastguard Worker                 // Forces a yield to the executor if the data received/sent reaches a certain
383*5225e6b1SAndroid Build Coastguard Worker                 // threshold. This is to prevent the async code from holding up the CPU for too long
384*5225e6b1SAndroid Build Coastguard Worker                 // in case IO speed is high and the executor uses cooperative scheduling.
385*5225e6b1SAndroid Build Coastguard Worker                 self.io_yield_counter.increment(recv_size.try_into().unwrap()).await;
386*5225e6b1SAndroid Build Coastguard Worker             }
387*5225e6b1SAndroid Build Coastguard Worker 
388*5225e6b1SAndroid Build Coastguard Worker             match has_progress {
389*5225e6b1SAndroid Build Coastguard Worker                 true => timer.reset(timeout)?,
390*5225e6b1SAndroid Build Coastguard Worker                 _ => yield_now().await,
391*5225e6b1SAndroid Build Coastguard Worker             }
392*5225e6b1SAndroid Build Coastguard Worker         }
393*5225e6b1SAndroid Build Coastguard Worker         Ok(())
394*5225e6b1SAndroid Build Coastguard Worker     }
395*5225e6b1SAndroid Build Coastguard Worker 
396*5225e6b1SAndroid Build Coastguard Worker     /// Sends exactly `data.len()` number of bytes from `data`.
send_exact(&mut self, data: &[u8], timeout: u64) -> Result<()>397*5225e6b1SAndroid Build Coastguard Worker     pub async fn send_exact(&mut self, data: &[u8], timeout: u64) -> Result<()> {
398*5225e6b1SAndroid Build Coastguard Worker         let timer = Timeout::new(self.efi_entry, timeout)?;
399*5225e6b1SAndroid Build Coastguard Worker         let mut curr = &data[..];
400*5225e6b1SAndroid Build Coastguard Worker         let mut last_send_queue = self.get_socket().send_queue();
401*5225e6b1SAndroid Build Coastguard Worker         loop {
402*5225e6b1SAndroid Build Coastguard Worker             self.poll();
403*5225e6b1SAndroid Build Coastguard Worker             if curr.is_empty() && self.get_socket().send_queue() == 0 {
404*5225e6b1SAndroid Build Coastguard Worker                 return Ok(());
405*5225e6b1SAndroid Build Coastguard Worker             } else if self.is_closed() {
406*5225e6b1SAndroid Build Coastguard Worker                 return Err(Error::Disconnected.into());
407*5225e6b1SAndroid Build Coastguard Worker             } else if timer.check()? {
408*5225e6b1SAndroid Build Coastguard Worker                 return Err(Error::Timeout.into());
409*5225e6b1SAndroid Build Coastguard Worker             }
410*5225e6b1SAndroid Build Coastguard Worker 
411*5225e6b1SAndroid Build Coastguard Worker             let mut has_progress = false;
412*5225e6b1SAndroid Build Coastguard Worker             // Checks if any data in the queue is sent.
413*5225e6b1SAndroid Build Coastguard Worker             if self.get_socket().send_queue() != last_send_queue {
414*5225e6b1SAndroid Build Coastguard Worker                 last_send_queue = self.get_socket().send_queue();
415*5225e6b1SAndroid Build Coastguard Worker                 has_progress = true;
416*5225e6b1SAndroid Build Coastguard Worker             }
417*5225e6b1SAndroid Build Coastguard Worker             // Checks if there are more data to be queued.
418*5225e6b1SAndroid Build Coastguard Worker             if self.get_socket().can_send() && !curr.is_empty() {
419*5225e6b1SAndroid Build Coastguard Worker                 let sent = self.get_socket().send_slice(curr).map_err(send_to_unified)?;
420*5225e6b1SAndroid Build Coastguard Worker                 curr = curr.get(sent..).ok_or(Error::BadIndex(sent))?;
421*5225e6b1SAndroid Build Coastguard Worker                 // Forces a yield to the executor if the data received/sent reaches a certain
422*5225e6b1SAndroid Build Coastguard Worker                 // threshold. This is to prevent the async code from holding up the CPU for too long
423*5225e6b1SAndroid Build Coastguard Worker                 // in case IO speed is high and the executor uses cooperative scheduling.
424*5225e6b1SAndroid Build Coastguard Worker                 self.io_yield_counter.increment(sent.try_into().unwrap()).await;
425*5225e6b1SAndroid Build Coastguard Worker                 has_progress |= sent > 0;
426*5225e6b1SAndroid Build Coastguard Worker             }
427*5225e6b1SAndroid Build Coastguard Worker 
428*5225e6b1SAndroid Build Coastguard Worker             match has_progress {
429*5225e6b1SAndroid Build Coastguard Worker                 true => timer.reset(timeout)?,
430*5225e6b1SAndroid Build Coastguard Worker                 _ => yield_now().await,
431*5225e6b1SAndroid Build Coastguard Worker             }
432*5225e6b1SAndroid Build Coastguard Worker         }
433*5225e6b1SAndroid Build Coastguard Worker     }
434*5225e6b1SAndroid Build Coastguard Worker 
435*5225e6b1SAndroid Build Coastguard Worker     /// Gets the smoltcp `Interface` for this socket.
interface(&self) -> &Interface436*5225e6b1SAndroid Build Coastguard Worker     pub fn interface(&self) -> &Interface {
437*5225e6b1SAndroid Build Coastguard Worker         &self.interface
438*5225e6b1SAndroid Build Coastguard Worker     }
439*5225e6b1SAndroid Build Coastguard Worker 
440*5225e6b1SAndroid Build Coastguard Worker     /// Returns the number of milliseconds elapsed since the `base` timestamp.
timestamp(&self, base: u64) -> u64441*5225e6b1SAndroid Build Coastguard Worker     pub fn timestamp(&self, base: u64) -> u64 {
442*5225e6b1SAndroid Build Coastguard Worker         let curr = self.timestamp.load(Ordering::Relaxed);
443*5225e6b1SAndroid Build Coastguard Worker         // Assume there can be at most one overflow.
444*5225e6b1SAndroid Build Coastguard Worker         match curr < base {
445*5225e6b1SAndroid Build Coastguard Worker             true => u64::MAX - (base - curr),
446*5225e6b1SAndroid Build Coastguard Worker             false => curr - base,
447*5225e6b1SAndroid Build Coastguard Worker         }
448*5225e6b1SAndroid Build Coastguard Worker     }
449*5225e6b1SAndroid Build Coastguard Worker 
450*5225e6b1SAndroid Build Coastguard Worker     /// Returns a smoltcp time `Instant` value.
instant(&self) -> Instant451*5225e6b1SAndroid Build Coastguard Worker     fn instant(&self) -> Instant {
452*5225e6b1SAndroid Build Coastguard Worker         to_smoltcp_instant(self.timestamp(0))
453*5225e6b1SAndroid Build Coastguard Worker     }
454*5225e6b1SAndroid Build Coastguard Worker 
455*5225e6b1SAndroid Build Coastguard Worker     /// Broadcasts Fuchsia Fastboot MDNS service once.
broadcast_fuchsia_fastboot_mdns(&mut self)456*5225e6b1SAndroid Build Coastguard Worker     pub fn broadcast_fuchsia_fastboot_mdns(&mut self) {
457*5225e6b1SAndroid Build Coastguard Worker         const MDNS_PORT: u16 = 5353;
458*5225e6b1SAndroid Build Coastguard Worker         const IP6_BROADCAST_ADDR: &[u8] =
459*5225e6b1SAndroid Build Coastguard Worker             &[0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB];
460*5225e6b1SAndroid Build Coastguard Worker         let ip6_broadcast = Ipv6Address::from_bytes(&IP6_BROADCAST_ADDR[..]);
461*5225e6b1SAndroid Build Coastguard Worker         let meta =
462*5225e6b1SAndroid Build Coastguard Worker             UdpMetadata { endpoint: (ip6_broadcast, MDNS_PORT).into(), meta: Default::default() };
463*5225e6b1SAndroid Build Coastguard Worker         let handle = self.socket_set.iter().nth(1).unwrap().0;
464*5225e6b1SAndroid Build Coastguard Worker         let socket = self.socket_set.get_mut::<UdpSocket>(handle);
465*5225e6b1SAndroid Build Coastguard Worker         if !socket.is_open() {
466*5225e6b1SAndroid Build Coastguard Worker             match socket.bind(IpListenEndpoint { addr: None, port: MDNS_PORT }) {
467*5225e6b1SAndroid Build Coastguard Worker                 Err(e) => efi_println!(self.efi_entry, "bind error: {:?}", e),
468*5225e6b1SAndroid Build Coastguard Worker                 _ => {}
469*5225e6b1SAndroid Build Coastguard Worker             }
470*5225e6b1SAndroid Build Coastguard Worker         }
471*5225e6b1SAndroid Build Coastguard Worker         if socket.can_send() {
472*5225e6b1SAndroid Build Coastguard Worker             match socket.send_slice(&self.fuchsia_fastboot_mdns_packet, meta) {
473*5225e6b1SAndroid Build Coastguard Worker                 Err(e) => efi_println!(self.efi_entry, "UDP send error: {:?}", e),
474*5225e6b1SAndroid Build Coastguard Worker                 _ => {}
475*5225e6b1SAndroid Build Coastguard Worker             }
476*5225e6b1SAndroid Build Coastguard Worker         }
477*5225e6b1SAndroid Build Coastguard Worker     }
478*5225e6b1SAndroid Build Coastguard Worker }
479*5225e6b1SAndroid Build Coastguard Worker 
480*5225e6b1SAndroid Build Coastguard Worker /// Returns a smoltcp time `Instant` value from a u64 timestamp.
to_smoltcp_instant(ts: u64) -> Instant481*5225e6b1SAndroid Build Coastguard Worker fn to_smoltcp_instant(ts: u64) -> Instant {
482*5225e6b1SAndroid Build Coastguard Worker     Instant::from_millis(i64::try_from(ts).unwrap())
483*5225e6b1SAndroid Build Coastguard Worker }
484*5225e6b1SAndroid Build Coastguard Worker 
485*5225e6b1SAndroid Build Coastguard Worker /// Internal type that contains net driver interfaces and buffers for creating GBL network and
486*5225e6b1SAndroid Build Coastguard Worker /// sockets.
487*5225e6b1SAndroid Build Coastguard Worker ///
488*5225e6b1SAndroid Build Coastguard Worker /// # Lifetimes
489*5225e6b1SAndroid Build Coastguard Worker ///
490*5225e6b1SAndroid Build Coastguard Worker /// * `'a`: Lifetime of [EfiEntry] borrowed.
491*5225e6b1SAndroid Build Coastguard Worker /// * `'b`: Lifetime of [SocketStorage<'b>], which eventually refers to Self.
492*5225e6b1SAndroid Build Coastguard Worker /// * `'c`: Lifetime of [AtomicU64] borrowed.
493*5225e6b1SAndroid Build Coastguard Worker struct EfiGblNetworkInternal<'a, 'b, 'c> {
494*5225e6b1SAndroid Build Coastguard Worker     efi_entry: &'a EfiEntry,
495*5225e6b1SAndroid Build Coastguard Worker     tcp_tx_buffer: Vec<u8>,
496*5225e6b1SAndroid Build Coastguard Worker     tcp_rx_buffer: Vec<u8>,
497*5225e6b1SAndroid Build Coastguard Worker     udp_tx_payload_buffer: Vec<u8>,
498*5225e6b1SAndroid Build Coastguard Worker     udp_rx_payload_buffer: Vec<u8>,
499*5225e6b1SAndroid Build Coastguard Worker     udp_tx_metadata_buffer: Vec<PacketMetadata<UdpMetadata>>,
500*5225e6b1SAndroid Build Coastguard Worker     udp_rx_metadata_buffer: Vec<PacketMetadata<UdpMetadata>>,
501*5225e6b1SAndroid Build Coastguard Worker     socket_storage: [SocketStorage<'b>; 2],
502*5225e6b1SAndroid Build Coastguard Worker     efi_net_dev: EfiNetworkDevice<'a>,
503*5225e6b1SAndroid Build Coastguard Worker     timestamp: &'c AtomicU64,
504*5225e6b1SAndroid Build Coastguard Worker     notify_fn: Option<Box<dyn FnMut(EfiEvent) + Sync + 'c>>,
505*5225e6b1SAndroid Build Coastguard Worker     notify: Option<EventNotify<'b>>,
506*5225e6b1SAndroid Build Coastguard Worker }
507*5225e6b1SAndroid Build Coastguard Worker 
508*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'b, 'c> EfiGblNetworkInternal<'a, 'b, 'c> {
509*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new instance of [EfiGblNetworkInternal].
new(efi_entry: &'a EfiEntry, timestamp: &'c AtomicU64) -> Result<Self>510*5225e6b1SAndroid Build Coastguard Worker     fn new(efi_entry: &'a EfiEntry, timestamp: &'c AtomicU64) -> Result<Self> {
511*5225e6b1SAndroid Build Coastguard Worker         // Creates and initializes simple network protocol.
512*5225e6b1SAndroid Build Coastguard Worker         let snp_dev = find_net_device(efi_entry)?;
513*5225e6b1SAndroid Build Coastguard Worker         let snp = efi_entry
514*5225e6b1SAndroid Build Coastguard Worker             .system_table()
515*5225e6b1SAndroid Build Coastguard Worker             .boot_services()
516*5225e6b1SAndroid Build Coastguard Worker             .open_protocol::<SimpleNetworkProtocol>(snp_dev)?;
517*5225e6b1SAndroid Build Coastguard Worker         reset_simple_network(&snp)?;
518*5225e6b1SAndroid Build Coastguard Worker 
519*5225e6b1SAndroid Build Coastguard Worker         // The TCP stack requires ICMP6 solicitation for discovery. Enable promiscuous mode so that
520*5225e6b1SAndroid Build Coastguard Worker         // all uni/multicast packets can be captured.
521*5225e6b1SAndroid Build Coastguard Worker         match snp.set_promiscuous_mode() {
522*5225e6b1SAndroid Build Coastguard Worker             Err(e) => efi_println!(
523*5225e6b1SAndroid Build Coastguard Worker                 efi_entry,
524*5225e6b1SAndroid Build Coastguard Worker                 "Warning: Failed to set promiscuous mode {e:?}. Device may be undiscoverable",
525*5225e6b1SAndroid Build Coastguard Worker             ),
526*5225e6b1SAndroid Build Coastguard Worker             _ => {}
527*5225e6b1SAndroid Build Coastguard Worker         }
528*5225e6b1SAndroid Build Coastguard Worker 
529*5225e6b1SAndroid Build Coastguard Worker         Ok(Self {
530*5225e6b1SAndroid Build Coastguard Worker             efi_entry,
531*5225e6b1SAndroid Build Coastguard Worker             tcp_tx_buffer: vec![0u8; SOCKET_TX_RX_BUFFER],
532*5225e6b1SAndroid Build Coastguard Worker             tcp_rx_buffer: vec![0u8; SOCKET_TX_RX_BUFFER],
533*5225e6b1SAndroid Build Coastguard Worker             udp_tx_payload_buffer: vec![0u8; ETHERNET_FRAME_SIZE],
534*5225e6b1SAndroid Build Coastguard Worker             udp_rx_payload_buffer: vec![0u8; ETHERNET_FRAME_SIZE],
535*5225e6b1SAndroid Build Coastguard Worker             udp_tx_metadata_buffer: vec![PacketMetadata::EMPTY; 1],
536*5225e6b1SAndroid Build Coastguard Worker             udp_rx_metadata_buffer: vec![PacketMetadata::EMPTY; 1],
537*5225e6b1SAndroid Build Coastguard Worker             socket_storage: Default::default(),
538*5225e6b1SAndroid Build Coastguard Worker             // Allocates 7(chosen randomly) extra TX frames. Revisits if it is not enough.
539*5225e6b1SAndroid Build Coastguard Worker             efi_net_dev: EfiNetworkDevice::new(snp, 7, &efi_entry),
540*5225e6b1SAndroid Build Coastguard Worker             timestamp,
541*5225e6b1SAndroid Build Coastguard Worker             notify_fn: None,
542*5225e6b1SAndroid Build Coastguard Worker             notify: None,
543*5225e6b1SAndroid Build Coastguard Worker         })
544*5225e6b1SAndroid Build Coastguard Worker     }
545*5225e6b1SAndroid Build Coastguard Worker 
546*5225e6b1SAndroid Build Coastguard Worker     /// Creates an instance of [EfiTcpSocket].
create_socket(&'b mut self) -> Result<EfiTcpSocket<'a, 'b>>547*5225e6b1SAndroid Build Coastguard Worker     fn create_socket(&'b mut self) -> Result<EfiTcpSocket<'a, 'b>> {
548*5225e6b1SAndroid Build Coastguard Worker         // Resets network timestamp to 0.
549*5225e6b1SAndroid Build Coastguard Worker         let _ = self.timestamp.swap(0, Ordering::Relaxed);
550*5225e6b1SAndroid Build Coastguard Worker 
551*5225e6b1SAndroid Build Coastguard Worker         // Initializes notification functions.
552*5225e6b1SAndroid Build Coastguard Worker         if self.notify_fn.is_none() {
553*5225e6b1SAndroid Build Coastguard Worker             self.notify_fn = Some(Box::new(|_: EfiEvent| {
554*5225e6b1SAndroid Build Coastguard Worker                 self.timestamp.fetch_add(NETWORK_TIMESTAMP_UPDATE_PERIOD, Ordering::Relaxed);
555*5225e6b1SAndroid Build Coastguard Worker             }));
556*5225e6b1SAndroid Build Coastguard Worker             self.notify = Some(EventNotify::new(Tpl::Callback, self.notify_fn.as_mut().unwrap()));
557*5225e6b1SAndroid Build Coastguard Worker         }
558*5225e6b1SAndroid Build Coastguard Worker 
559*5225e6b1SAndroid Build Coastguard Worker         // Creates a timer event for updating the global timestamp.
560*5225e6b1SAndroid Build Coastguard Worker         let bs = self.efi_entry.system_table().boot_services();
561*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: the notification callback in `notify_fn` initialized above never allocates,
562*5225e6b1SAndroid Build Coastguard Worker         // deallocates, or panics.
563*5225e6b1SAndroid Build Coastguard Worker         let _time_update_event = unsafe {
564*5225e6b1SAndroid Build Coastguard Worker             bs.create_event_with_notification(
565*5225e6b1SAndroid Build Coastguard Worker                 EventType::TimerNotifySignal,
566*5225e6b1SAndroid Build Coastguard Worker                 self.notify.as_mut().unwrap(),
567*5225e6b1SAndroid Build Coastguard Worker             )
568*5225e6b1SAndroid Build Coastguard Worker         }?;
569*5225e6b1SAndroid Build Coastguard Worker         bs.set_timer(
570*5225e6b1SAndroid Build Coastguard Worker             &_time_update_event,
571*5225e6b1SAndroid Build Coastguard Worker             EFI_TIMER_DELAY_TIMER_PERIODIC,
572*5225e6b1SAndroid Build Coastguard Worker             ms_to_100ns(NETWORK_TIMESTAMP_UPDATE_PERIOD)?,
573*5225e6b1SAndroid Build Coastguard Worker         )?;
574*5225e6b1SAndroid Build Coastguard Worker 
575*5225e6b1SAndroid Build Coastguard Worker         // Gets our MAC address and IPv6 address.
576*5225e6b1SAndroid Build Coastguard Worker         // We can also consider getting this from vendor configuration.
577*5225e6b1SAndroid Build Coastguard Worker         let (ll_mac, ll_ip6_addr) =
578*5225e6b1SAndroid Build Coastguard Worker             ll_mac_ip6_addr_from_efi_mac(self.efi_net_dev.protocol.mode()?.current_address);
579*5225e6b1SAndroid Build Coastguard Worker         // Configures smoltcp network interface.
580*5225e6b1SAndroid Build Coastguard Worker         let mut interface = Interface::new(
581*5225e6b1SAndroid Build Coastguard Worker             Config::new(ll_mac.into()),
582*5225e6b1SAndroid Build Coastguard Worker             &mut self.efi_net_dev,
583*5225e6b1SAndroid Build Coastguard Worker             to_smoltcp_instant(0),
584*5225e6b1SAndroid Build Coastguard Worker         );
585*5225e6b1SAndroid Build Coastguard Worker         interface.update_ip_addrs(|ip_addrs| ip_addrs.push(IpCidr::new(ll_ip6_addr, 64)).unwrap());
586*5225e6b1SAndroid Build Coastguard Worker 
587*5225e6b1SAndroid Build Coastguard Worker         // Generates Fuchsia Fastboot MDNS packet.
588*5225e6b1SAndroid Build Coastguard Worker         let eth_mac = ll_mac.as_bytes();
589*5225e6b1SAndroid Build Coastguard Worker         let fuchsia_node_name = format!(
590*5225e6b1SAndroid Build Coastguard Worker             "fuchsia-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}",
591*5225e6b1SAndroid Build Coastguard Worker             eth_mac[0], eth_mac[1], eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5]
592*5225e6b1SAndroid Build Coastguard Worker         );
593*5225e6b1SAndroid Build Coastguard Worker         let fuchsia_fastboot_mdns_packet =
594*5225e6b1SAndroid Build Coastguard Worker             fuchsia_fastboot_mdns_packet(fuchsia_node_name.as_str(), ll_ip6_addr.as_bytes())?
595*5225e6b1SAndroid Build Coastguard Worker                 .into();
596*5225e6b1SAndroid Build Coastguard Worker 
597*5225e6b1SAndroid Build Coastguard Worker         // Creates sockets.
598*5225e6b1SAndroid Build Coastguard Worker         let mut socket_set = SocketSet::new(&mut self.socket_storage[..]);
599*5225e6b1SAndroid Build Coastguard Worker         // Creates a TCP socket for fastboot over TCP.
600*5225e6b1SAndroid Build Coastguard Worker         let tx_socket_buffer = SocketBuffer::new(&mut self.tcp_tx_buffer[..]);
601*5225e6b1SAndroid Build Coastguard Worker         let rx_socket_buffer = SocketBuffer::new(&mut self.tcp_rx_buffer[..]);
602*5225e6b1SAndroid Build Coastguard Worker         let tcp_socket = TcpSocket::new(rx_socket_buffer, tx_socket_buffer);
603*5225e6b1SAndroid Build Coastguard Worker         let _ = socket_set.add(tcp_socket);
604*5225e6b1SAndroid Build Coastguard Worker         // Creates a UDP socket for MDNS broadcast.
605*5225e6b1SAndroid Build Coastguard Worker         let udp_tx_packet_buffer = PacketBuffer::new(
606*5225e6b1SAndroid Build Coastguard Worker             &mut self.udp_tx_metadata_buffer[..],
607*5225e6b1SAndroid Build Coastguard Worker             &mut self.udp_tx_payload_buffer[..],
608*5225e6b1SAndroid Build Coastguard Worker         );
609*5225e6b1SAndroid Build Coastguard Worker         let udp_rx_packet_buffer = PacketBuffer::new(
610*5225e6b1SAndroid Build Coastguard Worker             &mut self.udp_rx_metadata_buffer[..],
611*5225e6b1SAndroid Build Coastguard Worker             &mut self.udp_rx_payload_buffer[..],
612*5225e6b1SAndroid Build Coastguard Worker         );
613*5225e6b1SAndroid Build Coastguard Worker         let udp_socket = UdpSocket::new(udp_rx_packet_buffer, udp_tx_packet_buffer);
614*5225e6b1SAndroid Build Coastguard Worker         let _ = socket_set.add(udp_socket);
615*5225e6b1SAndroid Build Coastguard Worker         Ok(EfiTcpSocket {
616*5225e6b1SAndroid Build Coastguard Worker             efi_entry: self.efi_entry,
617*5225e6b1SAndroid Build Coastguard Worker             efi_net_dev: &mut self.efi_net_dev,
618*5225e6b1SAndroid Build Coastguard Worker             interface,
619*5225e6b1SAndroid Build Coastguard Worker             socket_set,
620*5225e6b1SAndroid Build Coastguard Worker             io_yield_counter: YieldCounter::new(u64::MAX),
621*5225e6b1SAndroid Build Coastguard Worker             last_listen_timestamp: None,
622*5225e6b1SAndroid Build Coastguard Worker             _time_update_event,
623*5225e6b1SAndroid Build Coastguard Worker             timestamp: self.timestamp,
624*5225e6b1SAndroid Build Coastguard Worker             fuchsia_fastboot_mdns_packet,
625*5225e6b1SAndroid Build Coastguard Worker         })
626*5225e6b1SAndroid Build Coastguard Worker     }
627*5225e6b1SAndroid Build Coastguard Worker }
628*5225e6b1SAndroid Build Coastguard Worker 
629*5225e6b1SAndroid Build Coastguard Worker /// The GBL network stack.
630*5225e6b1SAndroid Build Coastguard Worker ///
631*5225e6b1SAndroid Build Coastguard Worker /// # Lifetimes
632*5225e6b1SAndroid Build Coastguard Worker ///
633*5225e6b1SAndroid Build Coastguard Worker /// * `'a`: Lifetime of `efi_entry` borrowed.
634*5225e6b1SAndroid Build Coastguard Worker /// * `'b`: Lifetime of Self.
635*5225e6b1SAndroid Build Coastguard Worker /// * `'c`: Lifetime of external timestamp borrowed.
636*5225e6b1SAndroid Build Coastguard Worker #[derive(Default)]
637*5225e6b1SAndroid Build Coastguard Worker pub struct EfiGblNetwork<'a, 'b, 'c>(Option<EfiGblNetworkInternal<'a, 'b, 'c>>);
638*5225e6b1SAndroid Build Coastguard Worker 
639*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'b, 'c: 'b> EfiGblNetwork<'a, 'b, 'c> {
640*5225e6b1SAndroid Build Coastguard Worker     /// Initializes GBL network and creates GBL sockets.
641*5225e6b1SAndroid Build Coastguard Worker     ///
642*5225e6b1SAndroid Build Coastguard Worker     /// # Args:
643*5225e6b1SAndroid Build Coastguard Worker     ///
644*5225e6b1SAndroid Build Coastguard Worker     /// * `efi_entry`: A [EfiEntry].
645*5225e6b1SAndroid Build Coastguard Worker     /// * `ts`: A reference to an [AtomicU64].
init( &'b mut self, efi_entry: &'a EfiEntry, timestamp: &'c AtomicU64, ) -> Result<EfiTcpSocket<'a, 'b>>646*5225e6b1SAndroid Build Coastguard Worker     pub fn init(
647*5225e6b1SAndroid Build Coastguard Worker         &'b mut self,
648*5225e6b1SAndroid Build Coastguard Worker         efi_entry: &'a EfiEntry,
649*5225e6b1SAndroid Build Coastguard Worker         timestamp: &'c AtomicU64,
650*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<EfiTcpSocket<'a, 'b>> {
651*5225e6b1SAndroid Build Coastguard Worker         // Drops any existing network first to release the global event notify function.
652*5225e6b1SAndroid Build Coastguard Worker         self.0 = None;
653*5225e6b1SAndroid Build Coastguard Worker         self.0 = Some(EfiGblNetworkInternal::new(efi_entry, timestamp)?);
654*5225e6b1SAndroid Build Coastguard Worker         self.0.as_mut().unwrap().create_socket()
655*5225e6b1SAndroid Build Coastguard Worker     }
656*5225e6b1SAndroid Build Coastguard Worker }
657