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