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 | |
10 | use super::{IpAddress, MacAddress}; |
11 | use crate::data_types::Event; |
12 | use crate::{Result, Status}; |
13 | use bitflags::bitflags; |
14 | use core::ffi::c_void; |
15 | use core::ptr; |
16 | use core::ptr::NonNull; |
17 | use uefi_macros::unsafe_protocol; |
18 | |
19 | /// The Simple Network Protocol |
20 | #[repr (C)] |
21 | #[unsafe_protocol ("a19832b9-ac25-11d3-9a2d-0090273fc14d" )] |
22 | pub 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 | |
86 | impl 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 | |
272 | bitflags! { |
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 | |
288 | bitflags! { |
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)] |
312 | pub 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 | |
341 | impl 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)] |
535 | pub 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 | |
576 | newtype_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 | |