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