1//! Simple Network Protocol
2//!
3//! Provides a packet level interface to a network adapter.
4//! Once the adapter is initialized, the protocol provides services that allows
5//! packets to be transmitted and received.
6//!
7//! No interface function must be called until `SimpleNetwork.start` is successfully
8//! called first.
9
10use super::{IpAddress, MacAddress};
11use crate::data_types::Event;
12use crate::{Result, Status};
13use bitflags::bitflags;
14use core::ffi::c_void;
15use core::ptr;
16use core::ptr::NonNull;
17use uefi_macros::unsafe_protocol;
18
19/// The Simple Network Protocol
20#[repr(C)]
21#[unsafe_protocol("a19832b9-ac25-11d3-9a2d-0090273fc14d")]
22pub struct SimpleNetwork {
23 revision: u64,
24 start: extern "efiapi" fn(this: &Self) -> Status,
25 stop: extern "efiapi" fn(this: &Self) -> Status,
26 initialize: extern "efiapi" fn(
27 this: &Self,
28 extra_recv_buffer_size: usize,
29 extra_transmit_buffer_size: usize,
30 ) -> Status,
31 reset: extern "efiapi" fn(this: &Self, extended_verification: bool) -> Status,
32 shutdown: extern "efiapi" fn(this: &Self) -> Status,
33 receive_filters: extern "efiapi" fn(
34 this: &Self,
35 enable: u32,
36 disable: u32,
37 reset_mcast_filter: bool,
38 mcast_filter_count: usize,
39 mcast_filter: Option<NonNull<MacAddress>>,
40 ) -> Status,
41 station_address:
42 extern "efiapi" fn(this: &Self, reset: bool, new: Option<&MacAddress>) -> Status,
43 statistics: extern "efiapi" fn(
44 this: &Self,
45 reset: bool,
46 stats_size: Option<&mut usize>,
47 stats_table: Option<&mut NetworkStats>,
48 ) -> Status,
49 mcast_ip_to_mac:
50 extern "efiapi" fn(this: &Self, ipv6: bool, ip: &IpAddress, mac: &mut MacAddress) -> Status,
51 nv_data: extern "efiapi" fn(
52 this: &Self,
53 read_write: bool,
54 offset: usize,
55 buffer_size: usize,
56 buffer: *mut c_void,
57 ) -> Status,
58 get_status: extern "efiapi" fn(
59 this: &Self,
60 interrupt_status: Option<&mut InterruptStatus>,
61 tx_buf: Option<&mut *mut c_void>,
62 ) -> Status,
63 transmit: extern "efiapi" fn(
64 this: &Self,
65 header_size: usize,
66 buffer_size: usize,
67 buffer: *const c_void,
68 src_addr: Option<&MacAddress>,
69 dest_addr: Option<&MacAddress>,
70 protocol: Option<&u16>,
71 ) -> Status,
72 receive: extern "efiapi" fn(
73 this: &Self,
74 header_size: Option<&mut usize>,
75 buffer_size: &mut usize,
76 buffer: *mut c_void,
77 src_addr: Option<&mut MacAddress>,
78 dest_addr: Option<&mut MacAddress>,
79 protocol: Option<&mut u16>,
80 ) -> Status,
81 // On QEMU, this event seems to never fire.
82 wait_for_packet: Event,
83 mode: *const NetworkMode,
84}
85
86impl SimpleNetwork {
87 /// Change the state of a network from "Stopped" to "Started".
88 pub fn start(&self) -> Result {
89 (self.start)(self).into()
90 }
91
92 /// Change the state of a network interface from "Started" to "Stopped".
93 pub fn stop(&self) -> Result {
94 (self.stop)(self).into()
95 }
96
97 /// Reset a network adapter and allocate the transmit and receive buffers
98 /// required by the network interface; optionally, also request allocation of
99 /// additional transmit and receive buffers.
100 pub fn initialize(&self, extra_rx_buffer_size: usize, extra_tx_buffer_size: usize) -> Result {
101 (self.initialize)(self, extra_rx_buffer_size, extra_tx_buffer_size).into()
102 }
103
104 /// Reset a network adapter and reinitialize it with the parameters that were
105 /// provided in the previous call to `initialize`.
106 pub fn reset(&self, extended_verification: bool) -> Result {
107 (self.reset)(self, extended_verification).into()
108 }
109
110 /// Reset a network adapter, leaving it in a state that is safe
111 /// for another driver to initialize
112 pub fn shutdown(&self) -> Result {
113 (self.shutdown)(self).into()
114 }
115
116 /// Manage the multicast receive filters of a network.
117 pub fn receive_filters(
118 &self,
119 enable: ReceiveFlags,
120 disable: ReceiveFlags,
121 reset_mcast_filter: bool,
122 mcast_filter: Option<&[MacAddress]>,
123 ) -> Result {
124 if let Some(mcast_filter) = mcast_filter {
125 (self.receive_filters)(
126 self,
127 enable.bits,
128 disable.bits,
129 reset_mcast_filter,
130 mcast_filter.len(),
131 NonNull::new(mcast_filter.as_ptr() as *mut _),
132 )
133 .into()
134 } else {
135 (self.receive_filters)(self, enable.bits, disable.bits, reset_mcast_filter, 0, None)
136 .into()
137 }
138 }
139
140 /// Modify or reset the current station address, if supported.
141 pub fn station_address(&self, reset: bool, new: Option<&MacAddress>) -> Result {
142 (self.station_address)(self, reset, new).into()
143 }
144
145 /// Reset statistics on a network interface.
146 pub fn reset_statistics(&self) -> Result {
147 (self.statistics)(self, true, None, None).into()
148 }
149
150 /// Collect statistics on a network interface.
151 pub fn collect_statistics(&self) -> Result<NetworkStats> {
152 let mut stats_table: NetworkStats = Default::default();
153 let mut stats_size = core::mem::size_of::<NetworkStats>();
154 let status = (self.statistics)(self, false, Some(&mut stats_size), Some(&mut stats_table));
155 Result::from(status)?;
156 Ok(stats_table)
157 }
158
159 /// Convert a multicast IP address to a multicast HW MAC Address.
160 pub fn mcast_ip_to_mac(&self, ipv6: bool, ip: IpAddress) -> Result<MacAddress> {
161 let mut mac_address = MacAddress([0; 32]);
162 let status = (self.mcast_ip_to_mac)(self, ipv6, &ip, &mut mac_address);
163 Result::from(status)?;
164 Ok(mac_address)
165 }
166
167 /// Perform read operations on the NVRAM device attached to
168 /// a network interface.
169 pub fn read_nv_data(&self, offset: usize, buffer: &[u8]) -> Result {
170 (self.nv_data)(
171 self,
172 true,
173 offset,
174 buffer.len(),
175 buffer.as_ptr() as *mut c_void,
176 )
177 .into()
178 }
179
180 /// Perform write operations on the NVRAM device attached to a network interface.
181 pub fn write_nv_data(&self, offset: usize, buffer: &mut [u8]) -> Result {
182 (self.nv_data)(
183 self,
184 false,
185 offset,
186 buffer.len(),
187 buffer.as_mut_ptr().cast(),
188 )
189 .into()
190 }
191
192 /// Read the current interrupt status and recycled transmit buffer
193 /// status from a network interface.
194 pub fn get_interrupt_status(&self) -> Result<InterruptStatus> {
195 let mut interrupt_status = InterruptStatus::empty();
196 let status = (self.get_status)(self, Some(&mut interrupt_status), None);
197 Result::from(status)?;
198 Ok(interrupt_status)
199 }
200
201 /// Read the current recycled transmit buffer status from a
202 /// network interface.
203 pub fn get_recycled_transmit_buffer_status(&self) -> Result<Option<NonNull<u8>>> {
204 let mut tx_buf: *mut c_void = ptr::null_mut();
205 let status = (self.get_status)(self, None, Some(&mut tx_buf));
206 Result::from(status)?;
207 Ok(NonNull::new(tx_buf.cast()))
208 }
209
210 /// Place a packet in the transmit queue of a network interface.
211 pub fn transmit(
212 &self,
213 header_size: usize,
214 buffer: &[u8],
215 src_addr: Option<MacAddress>,
216 dest_addr: Option<MacAddress>,
217 protocol: Option<u16>,
218 ) -> Result {
219 (self.transmit)(
220 self,
221 header_size,
222 buffer.len() + header_size,
223 buffer.as_ptr().cast(),
224 src_addr.as_ref(),
225 dest_addr.as_ref(),
226 protocol.as_ref(),
227 )
228 .into()
229 }
230
231 /// Receive a packet from a network interface.
232 ///
233 /// On success, returns the size of bytes of the received packet.
234 pub fn receive(
235 &self,
236 buffer: &mut [u8],
237 header_size: Option<&mut usize>,
238 src_addr: Option<&mut MacAddress>,
239 dest_addr: Option<&mut MacAddress>,
240 protocol: Option<&mut u16>,
241 ) -> Result<usize> {
242 let mut buffer_size = buffer.len();
243 let status = (self.receive)(
244 self,
245 header_size,
246 &mut buffer_size,
247 buffer.as_mut_ptr().cast(),
248 src_addr,
249 dest_addr,
250 protocol,
251 );
252 Result::from(status)?;
253 Ok(buffer_size)
254 }
255
256 /// Event that fires once a packet is available to be received.
257 ///
258 /// On QEMU, this event seems to never fire; it is suggested to verify that your implementation
259 /// of UEFI properly implements this event before using it.
260 #[must_use]
261 pub fn wait_for_packet(&self) -> &Event {
262 &self.wait_for_packet
263 }
264
265 /// Returns a reference to the Simple Network mode.
266 #[must_use]
267 pub fn mode(&self) -> &NetworkMode {
268 unsafe { &*self.mode }
269 }
270}
271
272bitflags! {
273 /// Flags to pass to receive_filters to enable/disable reception of some kinds of packets.
274 pub struct ReceiveFlags : u32 {
275 /// Receive unicast packets.
276 const UNICAST = 0x01;
277 /// Receive multicast packets.
278 const MULTICAST = 0x02;
279 /// Receive broadcast packets.
280 const BROADCAST = 0x04;
281 /// Receive packets in promiscuous mode.
282 const PROMISCUOUS = 0x08;
283 /// Receive packets in promiscuous multicast mode.
284 const PROMISCUOUS_MULTICAST = 0x10;
285 }
286}
287
288bitflags! {
289 /// Flags returned by get_interrupt_status to indicate which interrupts have fired on the
290 /// interface since the last call.
291 pub struct InterruptStatus : u32 {
292 /// Packet received.
293 const RECEIVE = 0x01;
294 /// Packet transmitted.
295 const TRANSMIT = 0x02;
296 /// Command interrupt fired.
297 const COMMAND = 0x04;
298 /// Software interrupt fired.
299 const SOFTWARE = 0x08;
300 }
301}
302
303/// Network Statistics
304///
305/// The description of statistics on the network with the SNP's `statistics` function
306/// is returned in this structure
307///
308/// Any of these statistics may or may not be available on the device. So, all the
309/// retriever functions of the statistics return `None` when a statistic is not supported
310#[repr(C)]
311#[derive(Default, Debug)]
312pub struct NetworkStats {
313 rx_total_frames: u64,
314 rx_good_frames: u64,
315 rx_undersize_frames: u64,
316 rx_oversize_frames: u64,
317 rx_dropped_frames: u64,
318 rx_unicast_frames: u64,
319 rx_broadcast_frames: u64,
320 rx_multicast_frames: u64,
321 rx_crc_error_frames: u64,
322 rx_total_bytes: u64,
323 tx_total_frames: u64,
324 tx_good_frames: u64,
325 tx_undersize_frames: u64,
326 tx_oversize_frames: u64,
327 tx_dropped_frames: u64,
328 tx_unicast_frames: u64,
329 tx_broadcast_frames: u64,
330 tx_multicast_frames: u64,
331 tx_crc_error_frames: u64,
332 tx_total_bytes: u64,
333 collisions: u64,
334 unsupported_protocol: u64,
335 rx_duplicated_frames: u64,
336 rx_decrypt_error_frames: u64,
337 tx_error_frames: u64,
338 tx_retry_frames: u64,
339}
340
341impl NetworkStats {
342 /// Any statistic value of -1 is not available
343 fn available(&self, stat: u64) -> bool {
344 stat as i64 != -1
345 }
346
347 /// Takes a statistic and converts it to an option
348 ///
349 /// When the statistic is not available, `None` is returned
350 fn to_option(&self, stat: u64) -> Option<u64> {
351 match self.available(stat) {
352 true => Some(stat),
353 false => None,
354 }
355 }
356
357 /// The total number of frames received, including error frames
358 /// and dropped frames
359 #[must_use]
360 pub fn rx_total_frames(&self) -> Option<u64> {
361 self.to_option(self.rx_total_frames)
362 }
363
364 /// The total number of good frames received and copied
365 /// into receive buffers
366 #[must_use]
367 pub fn rx_good_frames(&self) -> Option<u64> {
368 self.to_option(self.rx_good_frames)
369 }
370
371 /// The number of frames below the minimum length for the
372 /// communications device
373 #[must_use]
374 pub fn rx_undersize_frames(&self) -> Option<u64> {
375 self.to_option(self.rx_undersize_frames)
376 }
377
378 /// The number of frames longer than the maximum length for
379 /// the communications length device
380 #[must_use]
381 pub fn rx_oversize_frames(&self) -> Option<u64> {
382 self.to_option(self.rx_oversize_frames)
383 }
384
385 /// The number of valid frames that were dropped because
386 /// the receive buffers were full
387 #[must_use]
388 pub fn rx_dropped_frames(&self) -> Option<u64> {
389 self.to_option(self.rx_dropped_frames)
390 }
391
392 /// The number of valid unicast frames received and not dropped
393 #[must_use]
394 pub fn rx_unicast_frames(&self) -> Option<u64> {
395 self.to_option(self.rx_unicast_frames)
396 }
397
398 /// The number of valid broadcast frames received and not dropped
399 #[must_use]
400 pub fn rx_broadcast_frames(&self) -> Option<u64> {
401 self.to_option(self.rx_broadcast_frames)
402 }
403
404 /// The number of valid multicast frames received and not dropped
405 #[must_use]
406 pub fn rx_multicast_frames(&self) -> Option<u64> {
407 self.to_option(self.rx_multicast_frames)
408 }
409
410 /// Number of frames with CRC or alignment errors
411 #[must_use]
412 pub fn rx_crc_error_frames(&self) -> Option<u64> {
413 self.to_option(self.rx_crc_error_frames)
414 }
415
416 /// The total number of bytes received including frames with errors
417 /// and dropped frames
418 #[must_use]
419 pub fn rx_total_bytes(&self) -> Option<u64> {
420 self.to_option(self.rx_total_bytes)
421 }
422
423 /// The total number of frames transmitted including frames
424 /// with errors and dropped frames
425 #[must_use]
426 pub fn tx_total_frames(&self) -> Option<u64> {
427 self.to_option(self.tx_total_frames)
428 }
429
430 /// The total number of valid frames transmitted and copied
431 /// into receive buffers
432 #[must_use]
433 pub fn tx_good_frames(&self) -> Option<u64> {
434 self.to_option(self.tx_good_frames)
435 }
436
437 /// The number of frames below the minimum length for
438 /// the media. This would be less than 64 for Ethernet
439 #[must_use]
440 pub fn tx_undersize_frames(&self) -> Option<u64> {
441 self.to_option(self.tx_undersize_frames)
442 }
443
444 /// The number of frames longer than the maximum length for
445 /// the media. This would be 1500 for Ethernet
446 #[must_use]
447 pub fn tx_oversize_frames(&self) -> Option<u64> {
448 self.to_option(self.tx_oversize_frames)
449 }
450
451 /// The number of valid frames that were dropped because
452 /// received buffers were full
453 #[must_use]
454 pub fn tx_dropped_frames(&self) -> Option<u64> {
455 self.to_option(self.tx_dropped_frames)
456 }
457
458 /// The number of valid unicast frames transmitted and not
459 /// dropped
460 #[must_use]
461 pub fn tx_unicast_frames(&self) -> Option<u64> {
462 self.to_option(self.tx_unicast_frames)
463 }
464
465 /// The number of valid broadcast frames transmitted and
466 /// not dropped
467 #[must_use]
468 pub fn tx_broadcast_frames(&self) -> Option<u64> {
469 self.to_option(self.tx_broadcast_frames)
470 }
471
472 /// The number of valid multicast frames transmitted
473 /// and not dropped
474 #[must_use]
475 pub fn tx_multicast_frames(&self) -> Option<u64> {
476 self.to_option(self.tx_multicast_frames)
477 }
478
479 /// The number of transmitted frames with CRC or
480 /// alignment errors
481 #[must_use]
482 pub fn tx_crc_error_frames(&self) -> Option<u64> {
483 self.to_option(self.tx_crc_error_frames)
484 }
485
486 /// The total number of bytes transmitted including
487 /// error frames and dropped frames
488 #[must_use]
489 pub fn tx_total_bytes(&self) -> Option<u64> {
490 self.to_option(self.tx_total_bytes)
491 }
492
493 /// The number of collisions detected on this subnet
494 #[must_use]
495 pub fn collisions(&self) -> Option<u64> {
496 self.to_option(self.collisions)
497 }
498
499 /// The number of frames destined for unsupported protocol
500 #[must_use]
501 pub fn unsupported_protocol(&self) -> Option<u64> {
502 self.to_option(self.unsupported_protocol)
503 }
504
505 /// The number of valid frames received that were duplicated
506 #[must_use]
507 pub fn rx_duplicated_frames(&self) -> Option<u64> {
508 self.to_option(self.rx_duplicated_frames)
509 }
510
511 /// The number of encrypted frames received that failed
512 /// to decrypt
513 #[must_use]
514 pub fn rx_decrypt_error_frames(&self) -> Option<u64> {
515 self.to_option(self.rx_decrypt_error_frames)
516 }
517
518 /// The number of frames that failed to transmit after
519 /// exceeding the retry limit
520 #[must_use]
521 pub fn tx_error_frames(&self) -> Option<u64> {
522 self.to_option(self.tx_error_frames)
523 }
524
525 /// The number of frames that transmitted successfully
526 /// after more than one attempt
527 #[must_use]
528 pub fn tx_retry_frames(&self) -> Option<u64> {
529 self.to_option(self.tx_retry_frames)
530 }
531}
532
533/// The Simple Network Mode
534#[repr(C)]
535pub struct NetworkMode {
536 /// Reports the current state of the network interface
537 pub state: NetworkState,
538 /// The size of the network interface's hardware address in bytes
539 pub hw_address_size: u32,
540 /// The size of the network interface's media header in bytes
541 pub media_header_size: u32,
542 /// The maximum size of the packets supported by the network interface in bytes
543 pub max_packet_size: u32,
544 /// The size of the NVRAM device attached to the network interface in bytes
545 pub nv_ram_size: u32,
546 /// The size that must be used for all NVRAM reads and writes
547 pub nv_ram_access_size: u32,
548 /// The multicast receive filter settings supported by the network interface
549 pub receive_filter_mask: u32,
550 /// The current multicast receive filter settings
551 pub receive_filter_setting: u32,
552 /// The maximum number of multicast address receive filters supported by the driver
553 pub max_mcast_filter_count: u32,
554 /// The current number of multicast address receive filters
555 pub mcast_filter_count: u32,
556 /// The array containing the addresses of the current multicast address receive filters
557 pub mcast_filter: [MacAddress; 16],
558 /// The current hardware MAC address for the network interface
559 pub current_address: MacAddress,
560 /// The current hardware MAC address for broadcast packets
561 pub broadcast_address: MacAddress,
562 /// The permanent hardware MAC address for the network interface
563 pub permanent_address: MacAddress,
564 /// The interface type of the network interface
565 pub if_type: u8,
566 /// Tells if the MAC address can be changed
567 pub mac_address_changeable: bool,
568 /// Tells if the network interface can transmit more than one packet at a time
569 pub multiple_tx_supported: bool,
570 /// Tells if the presence of the media can be determined
571 pub media_present_supported: bool,
572 /// Tells if media are connected to the network interface
573 pub media_present: bool,
574}
575
576newtype_enum! {
577 /// The state of a network interface
578 pub enum NetworkState: u32 => {
579 /// The interface has been stopped
580 STOPPED = 0,
581 /// The interface has been started
582 STARTED = 1,
583 /// The interface has been initialized
584 INITIALIZED = 2,
585 /// No state can have a number higher than this
586 MAX_STATE = 4,
587 }
588}
589