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