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::{EfiAppError, Result},
17     utils::{get_device_path, loop_with_timeout, ms_to_100ns},
18 };
19 use alloc::{boxed::Box, vec::Vec};
20 use core::{
21     fmt::Write,
22     sync::atomic::{AtomicU64, Ordering},
23 };
24 use efi::{
25     defs::{
26         EfiEvent, EfiMacAddress, EFI_STATUS_ALREADY_STARTED, EFI_STATUS_NOT_STARTED,
27         EFI_TIMER_DELAY_TIMER_PERIODIC,
28     },
29     efi_print, efi_println,
30     protocol::{simple_network::SimpleNetworkProtocol, Protocol},
31     DeviceHandle, EfiEntry, EventNotify, EventType, Tpl,
32 };
33 use smoltcp::{
34     iface::{Config, Interface, SocketSet},
35     phy,
36     phy::{Device, DeviceCapabilities, Medium},
37     socket::tcp,
38     time::Instant,
39     wire::{EthernetAddress, IpAddress, IpCidr, Ipv6Address},
40 };
41 
42 /// Maintains a timestamp needed by smoltcp network. It's updated periodically during timer event.
43 static NETWORK_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
44 /// Ethernet frame size for frame pool.
45 const ETHERNET_FRAME_SIZE: usize = 1536;
46 // Update period in milliseconds for `NETWORK_TIMESTAMP`.
47 const NETWORK_TIMESTAMP_UPDATE_PERIOD: u64 = 50;
48 // Size of the socket tx/rx application data buffer.
49 const SOCKET_TX_RX_BUFFER: usize = 64 * 1024;
50 
51 /// Performs a shutdown and restart of the simple network protocol.
reset_simple_network<'a>(snp: &Protocol<'a, SimpleNetworkProtocol>) -> Result<()>52 fn reset_simple_network<'a>(snp: &Protocol<'a, SimpleNetworkProtocol>) -> Result<()> {
53     match snp.shutdown() {
54         Err(e) if !e.is_efi_err(EFI_STATUS_NOT_STARTED) => return Err(e.into()),
55         _ => {}
56     };
57 
58     match snp.start() {
59         Err(e) if !e.is_efi_err(EFI_STATUS_ALREADY_STARTED) => {
60             return Err(e.into());
61         }
62         _ => {}
63     };
64     snp.initialize(0, 0).unwrap();
65     Ok(snp.reset(true)?)
66 }
67 
68 /// `EfiNetworkDevice` manages a frame pool and handles receiving/sending network frames.
69 pub struct EfiNetworkDevice<'a> {
70     protocol: Protocol<'a, SimpleNetworkProtocol>,
71     rx_frame: Box<[u8; ETHERNET_FRAME_SIZE]>,
72     tx_frames: Vec<*mut [u8; ETHERNET_FRAME_SIZE]>,
73     tx_frame_curr: usize, // Circular next index into tx_frames.
74     efi_entry: &'a EfiEntry,
75 }
76 
77 impl<'a> EfiNetworkDevice<'a> {
78     /// 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, ) -> Self79     pub fn new(
80         protocol: Protocol<'a, SimpleNetworkProtocol>,
81         extra_tx_frames: usize,
82         efi_entry: &'a EfiEntry,
83     ) -> Self {
84         let mut ret = Self {
85             protocol: protocol,
86             rx_frame: Box::new([0u8; ETHERNET_FRAME_SIZE]),
87             tx_frames: vec![core::ptr::null_mut(); extra_tx_frames + 1],
88             tx_frame_curr: 0,
89             efi_entry: efi_entry,
90         };
91         ret.tx_frames
92             .iter_mut()
93             .for_each(|v| *v = Box::into_raw(Box::new([0u8; ETHERNET_FRAME_SIZE])));
94         ret
95     }
96 }
97 
98 impl Drop for EfiNetworkDevice<'_> {
drop(&mut self)99     fn drop(&mut self) {
100         if let Err(e) = self.protocol.shutdown() {
101             if !e.is_efi_err(EFI_STATUS_NOT_STARTED) {
102                 // If shutdown fails, the protocol might still be operating on transmit buffers,
103                 // which can cause undefined behavior. Thus we need to panic.
104                 panic!("Failed to shutdown EFI network. {:?}", e);
105             }
106         }
107 
108         // Deallocate TX frames.
109         self.tx_frames.iter_mut().for_each(|v| {
110             // SAFETY:
111             // Each pointer is created by `Box::new()` in `EfiNetworkDevice::new()`. Thus the
112             // pointer is valid and layout matches.
113             let _ = unsafe { Box::from_raw(v) };
114         });
115     }
116 }
117 
118 // Implements network device trait backend for the `smoltcp` crate.
119 impl<'a> Device for EfiNetworkDevice<'a> {
120     type RxToken<'b> = RxToken<'b> where Self: 'b;
121     type TxToken<'b> = TxToken<'a, 'b> where Self: 'b;
122 
capabilities(&self) -> DeviceCapabilities123     fn capabilities(&self) -> DeviceCapabilities {
124         // Taken from upstream example.
125         let mut res: DeviceCapabilities = Default::default();
126         res.max_transmission_unit = 65535;
127         res.medium = Medium::Ethernet;
128         res
129     }
130 
receive(&mut self, _: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>131     fn receive(&mut self, _: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
132         let mut recv_size = self.rx_frame.len();
133         // Receive the next packet from the device.
134         self.protocol
135             .receive(None, Some(&mut recv_size), &mut self.rx_frame[..], None, None, None)
136             .ok()?;
137         match recv_size > 0 {
138             true => Some((
139                 RxToken(&mut self.rx_frame[..recv_size]),
140                 TxToken {
141                     protocol: &self.protocol,
142                     tx_frames: &mut self.tx_frames[..],
143                     curr: &mut self.tx_frame_curr,
144                     efi_entry: self.efi_entry,
145                 },
146             )),
147             _ => None,
148         }
149     }
150 
transmit(&mut self, _: Instant) -> Option<Self::TxToken<'_>>151     fn transmit(&mut self, _: Instant) -> Option<Self::TxToken<'_>> {
152         Some(TxToken {
153             protocol: &self.protocol,
154             tx_frames: &mut self.tx_frames[..],
155             curr: &mut self.tx_frame_curr,
156             efi_entry: self.efi_entry,
157         })
158     }
159 }
160 
161 /// In smoltcp, a `RxToken` is used to receive/process a frame when consumed.
162 pub struct RxToken<'a>(&'a mut [u8]);
163 
164 impl phy::RxToken for RxToken<'_> {
consume<R, F>(self, f: F) -> R where F: FnOnce(&mut [u8]) -> R,165     fn consume<R, F>(self, f: F) -> R
166     where
167         F: FnOnce(&mut [u8]) -> R,
168     {
169         f(self.0)
170     }
171 }
172 
173 /// In smoltcp, a `TxToken` is used to transmit a frame when consumed.
174 pub struct TxToken<'a: 'b, 'b> {
175     tx_frames: &'b mut [*mut [u8; ETHERNET_FRAME_SIZE]],
176     curr: &'b mut usize,
177     protocol: &'b Protocol<'a, SimpleNetworkProtocol>,
178     efi_entry: &'b EfiEntry,
179 }
180 
181 impl TxToken<'_, '_> {
182     /// Tries to allocate a send buffer.
try_get_buffer(&mut self) -> Option<*mut [u8; ETHERNET_FRAME_SIZE]>183     fn try_get_buffer(&mut self) -> Option<*mut [u8; ETHERNET_FRAME_SIZE]> {
184         let mut ptr: *mut core::ffi::c_void = core::ptr::null_mut();
185         let mut interrupt_status = 0u32;
186         // Recyle a buffer or take one from `tx_frames`.
187         match self.protocol.get_status(Some(&mut interrupt_status), Some(&mut ptr)) {
188             Ok(()) if self.tx_frames.contains(&(ptr as *mut _)) => Some(ptr as *mut _),
189             _ if *self.curr < self.tx_frames.len() => {
190                 // If we can't recycle a buffer, see if we can take one from the pool.
191                 let res = *self.curr;
192                 *self.curr = *self.curr + 1;
193                 Some(self.tx_frames[res])
194             }
195             _ => None,
196         }
197     }
198 }
199 
200 impl phy::TxToken for TxToken<'_, '_> {
consume<R, F>(mut self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R,201     fn consume<R, F>(mut self, len: usize, f: F) -> R
202     where
203         F: FnOnce(&mut [u8]) -> R,
204     {
205         loop {
206             match loop_with_timeout(self.efi_entry, 5000, || self.try_get_buffer().ok_or(false)) {
207                 Ok(Some(send_buffer)) => {
208                     // SAFETY:
209                     // * The pointer is confirmed to come from one of `self.tx_frames`. It's
210                     //   created via `Box::new()` in `EfiNetworkDevice::new()`. Thus it is properly
211                     //   aligned, dereferenceable and initialized.
212                     // * The pointer is either recycled from `self.protocol.get_status` or newly
213                     //   allocated from `self.tx_frames`. Thus There's no other references to it.
214                     // * The reference is only used for passing to `f` and goes out of scope
215                     //   immediately after.
216                     let result = f(&mut unsafe { send_buffer.as_mut() }.unwrap()[..len]);
217 
218                     // SAFETY:
219                     // * `send_buffer` comes from `EfiNetworkDevice::tx_frames`. It has a valid
220                     //   length at least `len`. `EfiNetworkDevice` shuts down network on drop. Thus
221                     //   the transmit buffer remains valid throughout the operation of the network
222                     //   protocol.
223                     // * `send_buffer` is either recycled from `self.protocol.get_status()` or newly
224                     //   allocated from `self.tx_frames`. There's no other references to it.
225                     // * `self.curr` stricly increases for each new allocation until
226                     //   `reset_simple_network()`. Thus there'll be no other references to the buffer
227                     //    until it is either recycled or `reset_simple_network()` is called.
228                     let _ = unsafe {
229                         self.protocol.transmit(
230                             0,
231                             send_buffer.as_mut().unwrap().get_mut(..len).unwrap(),
232                             Default::default(), // Src mac address don't care
233                             Default::default(), // Dest mac address don't care
234                             0,
235                         )
236                     };
237 
238                     return result;
239                 }
240                 Ok(None) => {
241                     // Some UEFI firmware has internal network service that also recycle buffers,
242                     // in which case our buffer may be hijacked and will never be returned from our
243                     // call. If we run into this case, shutdown and restart the network and try
244                     // again. Shutting down network releases all pending send/receive buffers
245                     // internally retained.
246                     efi_println!(
247                         self.efi_entry,
248                         "Timeout recycling TX buffers. Resetting network."
249                     );
250                     // Panics if this fails, as we have effectively lost control over network's
251                     // used of buffers.
252                     reset_simple_network(self.protocol).unwrap();
253                     *self.curr = 0;
254                 }
255                 _ => {} // `loop_with_timeout` failure. Try again.
256             };
257         }
258     }
259 }
260 
261 /// Returns the current value of timestamp.
timestamp() -> u64262 fn timestamp() -> u64 {
263     NETWORK_TIMESTAMP.load(Ordering::Relaxed)
264 }
265 
266 /// Returns a smoltcp time `Instant` value.
time_instant() -> Instant267 fn time_instant() -> Instant {
268     Instant::from_millis(i64::try_from(timestamp()).unwrap())
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(EfiAppError::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     efi_net_dev: &'b mut EfiNetworkDevice<'a>,
317     interface: &'b mut Interface,
318     sockets: &'b mut SocketSet<'b>,
319     efi_entry: &'a EfiEntry,
320 }
321 
322 impl<'a, 'b> EfiTcpSocket<'a, 'b> {
323     /// Resets the socket and starts listening for new TCP connection.
listen(&mut self, port: u16) -> Result<()>324     pub fn listen(&mut self, port: u16) -> Result<()> {
325         self.get_socket().abort();
326         self.get_socket().listen(port)?;
327         Ok(())
328     }
329 
330     /// Polls network device.
poll(&mut self)331     pub fn poll(&mut self) {
332         self.interface.poll(time_instant(), self.efi_net_dev, self.sockets);
333     }
334 
335     /// Polls network and check if the socket is in an active state.
check_active(&mut self) -> bool336     pub fn check_active(&mut self) -> bool {
337         self.poll();
338         self.get_socket().is_active()
339     }
340 
341     /// Gets a reference to the smoltcp socket object.
get_socket(&mut self) -> &mut tcp::Socket<'b>342     pub fn get_socket(&mut self) -> &mut tcp::Socket<'b> {
343         // We only consider single socket use case for now.
344         let handle = self.sockets.iter().next().unwrap().0;
345         self.sockets.get_mut::<tcp::Socket>(handle)
346     }
347 
348     /// Checks whether a socket is closed.
is_closed(&mut self) -> bool349     fn is_closed(&mut self) -> bool {
350         return !self.get_socket().is_open() || self.get_socket().state() == tcp::State::CloseWait;
351     }
352 
353     /// Receives exactly `out.len()` number of bytes to `out`.
receive_exact(&mut self, out: &mut [u8], timeout: u64) -> Result<()>354     pub fn receive_exact(&mut self, out: &mut [u8], timeout: u64) -> Result<()> {
355         let mut recv_size = 0;
356         loop_with_timeout(self.efi_entry, timeout, || -> core::result::Result<Result<()>, bool> {
357             self.poll();
358             if self.is_closed() {
359                 return Ok(Err(EfiAppError::PeerClosed.into()));
360             } else if self.get_socket().can_recv() {
361                 let this_recv = match self.get_socket().recv_slice(&mut out[recv_size..]) {
362                     Err(e) => return Ok(Err(e.into())),
363                     Ok(v) => v,
364                 };
365                 recv_size += this_recv;
366                 if recv_size == out.len() {
367                     return Ok(Ok(()));
368                 }
369 
370                 return Err(this_recv > 0);
371             }
372             Err(false)
373         })?
374         .ok_or(EfiAppError::Timeout)?
375     }
376 
377     /// Sends exactly `data.len()` number of bytes from `data`.
send_exact(&mut self, data: &[u8], timeout: u64) -> Result<()>378     pub fn send_exact(&mut self, data: &[u8], timeout: u64) -> Result<()> {
379         let mut sent_size = 0;
380         let mut last_send_queue = 0usize;
381         loop_with_timeout(self.efi_entry, timeout, || -> core::result::Result<Result<()>, bool> {
382             self.poll();
383             if sent_size == data.len() && self.get_socket().send_queue() == 0 {
384                 return Ok(Ok(()));
385             } else if self.is_closed() {
386                 return Ok(Err(EfiAppError::PeerClosed.into()));
387             }
388             // As long as some data is sent, reset the timeout.
389             let reset = self.get_socket().send_queue() != last_send_queue;
390             if self.get_socket().can_send() && sent_size < data.len() {
391                 sent_size += match self.get_socket().send_slice(&data[sent_size..]) {
392                     Err(e) => return Ok(Err(e.into())),
393                     Ok(v) => v,
394                 };
395             }
396             last_send_queue = self.get_socket().send_queue();
397             Err(reset)
398         })?
399         .ok_or(EfiAppError::Timeout)?
400     }
401 
402     /// Gets the smoltcp `Interface` for this socket.
interface(&self) -> &Interface403     pub fn interface(&self) -> &Interface {
404         self.interface
405     }
406 
407     /// Returns the number of milliseconds elapsed since the `base` timestamp.
timestamp(base: u64) -> u64408     pub fn timestamp(base: u64) -> u64 {
409         let curr = timestamp();
410         // Assume there can be at most one overflow.
411         match curr < base {
412             true => u64::MAX - (base - curr),
413             false => curr - base,
414         }
415     }
416 }
417 
418 /// Initializes network environment and provides a TCP socket for callers to run a closure. The API
419 /// handles clean up automatically after returning.
with_efi_network<F, R>(efi_entry: &EfiEntry, mut f: F) -> Result<R> where F: FnMut(&mut EfiTcpSocket) -> R,420 pub fn with_efi_network<F, R>(efi_entry: &EfiEntry, mut f: F) -> Result<R>
421 where
422     F: FnMut(&mut EfiTcpSocket) -> R,
423 {
424     let bs = efi_entry.system_table().boot_services();
425 
426     // Creates timestamp update event.
427     let _ = NETWORK_TIMESTAMP.swap(0, Ordering::Relaxed);
428     let mut notify_fn = |_: EfiEvent| {
429         NETWORK_TIMESTAMP.fetch_add(NETWORK_TIMESTAMP_UPDATE_PERIOD, Ordering::Relaxed);
430     };
431     let mut notify = EventNotify::new(Tpl::Callback, &mut notify_fn);
432     let timer = bs.create_event(EventType::TimerNotifySignal, Some(&mut notify))?;
433     bs.set_timer(
434         &timer,
435         EFI_TIMER_DELAY_TIMER_PERIODIC,
436         ms_to_100ns(NETWORK_TIMESTAMP_UPDATE_PERIOD)?,
437     )?;
438 
439     // Creates and initializes simple network protocol.
440     let snp_dev = find_net_device(efi_entry)?;
441     let snp = bs.open_protocol::<SimpleNetworkProtocol>(snp_dev)?;
442     reset_simple_network(&snp)?;
443 
444     // Gets our MAC address and IPv6 address.
445     // We can also consider getting this from vendor configuration.
446     let (ll_mac, ll_ip6_addr) = ll_mac_ip6_addr_from_efi_mac(snp.mode()?.current_address);
447 
448     // Creates an `EfiNetworkDevice`.
449     // Allocates 7(chosen randomly) extra TX frames. Revisits if it is not enough.
450     let mut efi_net_dev = EfiNetworkDevice::new(snp, 7, &efi_entry);
451     // Configures smoltcp network interface.
452     let mut interface =
453         Interface::new(Config::new(ll_mac.into()), &mut efi_net_dev, time_instant());
454     interface.update_ip_addrs(|ip_addrs| ip_addrs.push(IpCidr::new(ll_ip6_addr, 64)).unwrap());
455     // Creates an instance of socket.
456     let mut tx_buffer = vec![0u8; SOCKET_TX_RX_BUFFER];
457     let mut rx_buffer = vec![0u8; SOCKET_TX_RX_BUFFER];
458     let tx_socket_buffer = tcp::SocketBuffer::new(&mut tx_buffer[..]);
459     let rx_socket_buffer = tcp::SocketBuffer::new(&mut rx_buffer[..]);
460     let socket = tcp::Socket::new(rx_socket_buffer, tx_socket_buffer);
461     let mut sockets: [_; 1] = Default::default();
462     let mut sockets = SocketSet::new(&mut sockets[..]);
463     let _ = sockets.add(socket);
464     let mut socket = EfiTcpSocket {
465         efi_net_dev: &mut efi_net_dev,
466         interface: &mut interface,
467         sockets: &mut sockets,
468         efi_entry: efi_entry,
469     };
470 
471     Ok(f(&mut socket))
472 }
473