Skip to main content

uefi_raw/protocol/network/
tcp4.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! TCPv4 Protocol
4//!
5//! This module provides the TCPv4 Protocol interface definitions. The
6//! TCPv4 Protocol provides services to send and receive data streams
7//! over IPv4 networks.
8//!
9//! The protocol is defined in the [UEFI Specification, Section 28.1](https://uefi.org/specs/UEFI/2.11/28_Network_Protocols_TCP_IP_and_Configuration.html#efi-tcpv4-protocol).
10
11use crate::protocol::network::ip4::Ip4ModeData;
12use crate::protocol::network::snp::NetworkMode;
13use crate::{Boolean, Event, Guid, Handle, Ipv4Address, Status, guid, newtype_enum};
14use core::ffi::c_void;
15use core::fmt::{Debug, Formatter};
16
17#[derive(Debug)]
18#[repr(C)]
19pub struct Tcp4Protocol {
20    /// Get the current operational status.
21    ///
22    /// `get_mode_data` copies the current operational settings of
23    /// this instance into user-supplied structs. This function can
24    /// also be used to retrieve the operational setting of underlying
25    /// drivers such as IPv4, MNP, or SNP.
26    #[allow(clippy::type_complexity)]
27    pub get_mode_data: unsafe extern "efiapi" fn(
28        this: *mut Self,
29        connection_state: *mut Tcp4ConnectionState,
30        config_data: *mut Tcp4ConfigData,
31        ip4_mode_data: *mut Ip4ModeData,
32        managed_network_config_data: *mut c_void,
33        simple_network_mode: *mut NetworkMode,
34    ) -> Status,
35
36    /// Initialize or brutally reset the operational parameters for
37    /// this instance.
38    ///
39    /// No other [`Tcp4Protocol`] operation can be executed by this
40    /// instance until it is configured properly. For an active
41    /// [`Tcp4Protocol`] instance, after a proper configuration it may
42    /// call [`Tcp4Protocol::connect`] to initiates the three-way
43    /// handshake. For a passive [`Tcp4Protocol`] instance, its state
44    /// will transition to [`Tcp4ConnectionState::LISTEN`] after
45    /// configuration, and [`accept`][Self::accept] may be called to
46    /// listen for incoming TCP connection requests. If `config_data`
47    /// is set to `NULL`, the instance is reset. Resetting process
48    /// will be done brutally; the state machine will be set to
49    /// [`Tcp4ConnectionState::CLOSED`] directly, the receive queue
50    /// and transmit queue will be flushed, and no traffic will be
51    /// allowed through this instance.
52    pub configure:
53        unsafe extern "efiapi" fn(this: *mut Self, config_data: *const Tcp4ConfigData) -> Status,
54
55    /// Add or delete routing entries.
56    ///
57    /// The most specific route is selected by comparing the
58    /// `subnet_address` with the destination IP address
59    /// arithmetically ANDed with the `subnet_mask`.
60    ///
61    /// The default route is added with both `subnet_address` and
62    /// `subnet_mask` set to `0.0.0.0`. The default route matches all
63    /// destination IP addresses if there is no more specific route.
64    ///
65    /// A direct route is added with `gateway_address` set to
66    /// `0.0.0.0`. Packets are sent to the destination host if its
67    /// address can be found in the Address Resolution Protocol (ARP)
68    /// cache or it is on the local subnet. If the instance is
69    /// configured to use default address, a direct route to the local
70    /// network will be added automatically.
71    ///
72    /// Each TCP instance has its own independent routing table. An
73    /// instance that uses the default IP address will have a copy of
74    /// the
75    /// [`Ipv4Config2Protocol`][super::ip4_config2::Ip4Config2Protocol]'s
76    /// routing table. The copy will be updated automatically whenever
77    /// the IP driver reconfigures its instance. As a result, the
78    /// previous modification to the instance's local copy will be
79    /// lost.
80    ///
81    /// The priority of checking the route table is specific to the IP
82    /// implementation, and every IP implementation must comply with
83    /// RFC 1122.
84    ///
85    /// Note: There is no way to set up routes to other network
86    /// interface cards (NICs) because each NIC has its own
87    /// independent network stack that shares information only through
88    /// EFI TCPv4 variable.
89    pub routes: unsafe extern "efiapi" fn(
90        this: *mut Self,
91        delete_route: Boolean,
92        subnet_address: *const Ipv4Address,
93        subnet_mask: *const Ipv4Address,
94        gateway_address: *const Ipv4Address,
95    ) -> Status,
96
97    /// Initiate a nonblocking TCP connection request for an active
98    /// TCP instance.
99    ///
100    /// `connect` initiates an active open to the remote peer
101    /// configured in the current TCP instance if it is configured as
102    /// active. If the connection succeeds or fails due to any error,
103    /// the [`token.completion_token.event`][Tcp4CompletionToken::event]
104    /// will be signaled and `token.completion_token.status` will be
105    /// updated accordingly. This function can only be called for the
106    /// TCP instance in the [`Tcp4ConnectionState::CLOSED`] state. The
107    /// instance will transition to [`Tcp4ConnectionState::SYN_SENT`]
108    /// if the function returns [`Status::SUCCESS`]. If the TCP
109    /// three-way handshake succeeds, its state will become
110    /// [`Tcp4ConnectionState::ESTABLISHED`], otherwise, the state
111    /// will return to [`Tcp4ConnectionState::CLOSED`].
112    pub connect:
113        unsafe extern "efiapi" fn(this: *mut Self, token: *mut Tcp4ConnectionToken) -> Status,
114
115    /// Listen on the passive instance to accept an incoming
116    /// connection request. This is a nonblocking operation.
117    ///
118    /// The `accept` function initiates an asynchronous accept request
119    /// to wait for an incoming connection on the passive TCP
120    /// instance. If a remote peer successfully establishes a
121    /// connection with this instance, a new TCP instance will be
122    /// created and its handle will be returned in
123    /// [`new_child_handle`][Tcp4ListenToken::new_child_handle]. The
124    /// newly created instance is configured by inheriting the passive
125    /// instance's configuration and is ready for use upon return. The
126    /// instance is in the [`Tcp4ConnectionState::ESTABLISHED`]
127    /// state.
128    ///
129    /// The [`new_child_handle`][Tcp4ListenToken::new_child_handle]
130    /// will be signaled when a new connection is accepted, the user
131    /// aborts the listen, or the connection is reset.
132    ///
133    /// This function can only be called when the current TCP instance
134    /// is in [`Tcp4ConnectionState::LISTEN`] state.
135    pub accept:
136        unsafe extern "efiapi" fn(this: *mut Self, listen_token: *mut Tcp4ListenToken) -> Status,
137
138    /// Queues outgoing data into the transmit queue.
139    ///
140    /// The `transmit` function queues a sending request to this
141    /// instance along with the user data. The status of the token is
142    /// updated and the event in the token will be signaled once the
143    /// data is sent out or some error occurs.
144    pub transmit: unsafe extern "efiapi" fn(this: *mut Self, token: *mut Tcp4IoToken) -> Status,
145
146    /// Places an asynchronous receive request into the receiving
147    /// queue.
148    ///
149    /// `receive` places a completion token into the receive packet
150    /// queue. This function is always asynchronous. The caller must
151    /// allocate the
152    /// [`token.completion_token.event`][Tcp4CompletionToken::event]
153    /// and the `fragment_buffer` used to receive data. They also must
154    /// fill [`data_length`][Tcp4ReceiveData::data_length] which
155    /// represents the whole length of all `fragment_buffer`. When the
156    /// receive operation completes, the driver updates the
157    /// [`token.completion_token.status`][Tcp4CompletionToken::status]
158    /// and [`token.packet.rx_data`][Tcp4Packet::rx_data] fields and
159    /// and the `token.completion_token.event` is signaled. If data
160    /// was received, the data and its length will be copied into the
161    /// `fragment_table`. At the same time, the full length of
162    /// received data will be recorded in the `data_length`
163    /// fields. Providing a proper notification function and context
164    /// for the event will enable the user to receive the notification
165    /// and receiving status. That notification function is guaranteed
166    /// to not be re-entered.
167    pub receive: unsafe extern "efiapi" fn(this: *mut Self, token: *mut Tcp4IoToken) -> Status,
168
169    /// Disconnect a TCP connection gracefully or reset a TCP
170    /// connection. This function is a nonblocking operation.
171    ///
172    /// Initiate an asynchronous close token to TCP driver. After
173    /// `close` is called, any buffered transmission data will be sent
174    /// by TCP driver and the current instance will have a graceful
175    /// close working flow described as RFC 793 if `abort_on_close` is
176    /// set to `false`, otherwise, a reset packet will be sent by the
177    /// TCP driver to quickly disconnect this connection. When the
178    /// close operation completes successfully the TCP instance is in
179    /// [`Tcp4ConnectionState::CLOSED`] state, all pending
180    /// asynchronous operations are signaled, and any buffers used for
181    /// TCP network traffic are flushed.
182    pub close:
183        unsafe extern "efiapi" fn(this: *mut Self, close_token: *mut Tcp4CloseToken) -> Status,
184
185    /// Abort an asynchronous connection, listen, transmission or
186    /// receive request.
187    ///
188    /// The `cancel` function aborts a pending connection, listen,
189    /// transmit or receive request. If `completion_token` is not
190    /// `NULL` and the token is in the connection, listen,
191    /// transmission or receive queue when it is being cancelled, its
192    /// `status` will be set to [`Status::ABORTED`] and then `event`
193    /// will be signaled. If the token is not in one of the queues,
194    /// which usually means that the asynchronous operation has
195    /// completed, [`Status::NOT_FOUND`] is returned. If
196    /// `completion_token` is `NULL`, all asynchronous tokens issued
197    /// by [`Tcp4Protocol::connect`], [`Tcp4Protocol::accept`],
198    /// [`Tcp4Protocol::transmit`] and [`Tcp4Protocol::receive`]
199    /// will be aborted.
200    pub cancel: unsafe extern "efiapi" fn(
201        this: *mut Self,
202        completion_token: *mut Tcp4CompletionToken,
203    ) -> Status,
204
205    /// Poll to receive incoming data and transmit outgoing segments.
206    ///
207    /// The `poll` function increases the rate that data is moved
208    /// between the network and application and can be called when the
209    /// TCP instance is created successfully. Its use is optional.
210    ///
211    /// In some implementations, the periodical timer in the MNP
212    /// driver may not poll the underlying communications device fast
213    /// enough to avoid dropping packets. Drivers and applications
214    /// that are experiencing packet loss should try calling the
215    /// `poll` function at a high frequency.
216    pub poll: unsafe extern "efiapi" fn(this: *mut Self) -> Status,
217}
218
219impl Tcp4Protocol {
220    /// The GUID for the TCPv4 protocol.
221    ///
222    /// Defined in the [UEFI Specification, Section 28.1.4](https://uefi.org/specs/UEFI/2.11/28_Network_Protocols_TCP_IP_and_Configuration.html#efi-tcp4-protocol).
223    pub const GUID: Guid = guid!("65530BC7-A359-410F-B010-5AADC7EC2B62");
224
225    /// The GUID for the TCPv4 service binding protocol.
226    ///
227    /// Defined in the [UEFI Specification, Section 28.1.2](https://uefi.org/specs/UEFI/2.11/28_Network_Protocols_TCP_IP_and_Configuration.html#efi-tcp4-service-binding-protocol).
228    pub const SERVICE_BINDING_GUID: Guid = guid!("00720665-67EB-4a99-BAF7-D3C33A1C7CC9");
229}
230
231newtype_enum! {
232    pub enum Tcp4ConnectionState: i32 => {
233        CLOSED = 0,
234        LISTEN = 1,
235        SYN_SENT = 2,
236        SYN_RECEIVED = 3,
237        ESTABLISHED = 4,
238        FIN_WAIT1 = 5,
239        FIN_WAIT2 = 6,
240        CLOSING = 7,
241        TIME_WAIT = 8,
242        CLOSE_WAIT = 9,
243        LAST_ACK = 10,
244    }
245}
246
247#[derive(Debug)]
248#[repr(C)]
249pub struct Tcp4ConfigData {
250    /// Type of service field in transmitted IPv4 packets.
251    pub type_of_service: u8,
252    /// Time to live field in transmitted IPv4 packets.
253    pub time_to_live: u8,
254    /// Access point configuration.
255    pub access_point: Tcp4AccessPoint,
256    /// Optional TCP configuration parameters.
257    pub control_option: *mut Tcp4Option,
258}
259
260#[derive(Debug, Clone)]
261#[repr(C)]
262pub struct Tcp4AccessPoint {
263    /// Set to `TRUE` to use the default IP address.
264    pub use_default_address: Boolean,
265    /// The local IP address assigned to this TCP instance.
266    pub station_address: Ipv4Address,
267    /// The subnet mask associated with the station address.
268    pub subnet_mask: Ipv4Address,
269    /// The local port number.
270    pub station_port: u16,
271    /// The remote IP address.
272    pub remote_address: Ipv4Address,
273    /// The remote port number.
274    pub remote_port: u16,
275    /// Set to `TRUE` for active open, `FALSE` for passive open.
276    pub active_flag: Boolean,
277}
278
279#[derive(Debug)]
280#[repr(C)]
281pub struct Tcp4Option {
282    /// Size of the TCP receive buffer.
283    pub receive_buffer_size: u32,
284    /// Size of the TCP send buffer.
285    pub send_buffer_size: u32,
286    /// Maximum number of pending connections for passive instances.
287    pub max_syn_back_log: u32,
288    /// Connection timeout in seconds.
289    pub connection_timeout: u32,
290    /// Number of data retransmission attempts.
291    pub data_retries: u32,
292    /// FIN timeout in seconds.
293    pub fin_timeout: u32,
294    /// TIME_WAIT timeout in seconds.
295    pub time_wait_timeout: u32,
296    /// Number of keep-alive probes.
297    pub keep_alive_probes: u32,
298    /// Time before sending keep-alive probes in seconds.
299    pub keep_alive_time: u32,
300    /// Interval between keep-alive probes in seconds.
301    pub keep_alive_interval: u32,
302    /// Set to `TRUE` to enable Nagle algorithm.
303    pub enable_nagle: Boolean,
304    /// Set to `TRUE` to enable TCP timestamps.
305    pub enable_time_stamp: Boolean,
306    /// Set to `TRUE` to enable window scaling.
307    pub enable_window_scaling: Boolean,
308    /// Set to `TRUE` to enable selective acknowledgment.
309    pub enable_selective_ack: Boolean,
310    /// Set to `TRUE` to enable path MTU discovery.
311    pub enable_path_mtu_discovery: Boolean,
312}
313
314#[derive(Debug)]
315#[repr(C)]
316pub struct Tcp4CompletionToken {
317    /// Event to signal when the operation completes.
318    pub event: Event,
319    /// Status of the completed operation.
320    pub status: Status,
321}
322
323#[derive(Debug)]
324#[repr(C)]
325pub struct Tcp4ConnectionToken {
326    pub completion_token: Tcp4CompletionToken,
327}
328
329#[derive(Debug)]
330#[repr(C)]
331pub struct Tcp4ListenToken {
332    /// Completion token for the listen operation.
333    pub completion_token: Tcp4CompletionToken,
334    /// The new TCP instance handle created for the established
335    /// connection.
336    pub new_child_handle: Handle,
337}
338
339#[derive(Debug)]
340#[repr(C)]
341pub struct Tcp4IoToken {
342    /// Completion token for the I/O operation.
343    pub completion_token: Tcp4CompletionToken,
344    /// Packet data for the I/O operation.
345    pub packet: Tcp4Packet,
346}
347
348#[derive(Debug)]
349#[repr(C)]
350pub struct Tcp4CloseToken {
351    /// Completion token for the close operation.
352    pub completion_token: Tcp4CompletionToken,
353    /// Abort the TCP connection on close instead of the standard TCP
354    /// close process when it is set to TRUE. This option can be used
355    /// to satisfy a fast disconnect.
356    pub abort_on_close: Boolean,
357}
358
359#[repr(C)]
360pub union Tcp4Packet {
361    /// Pointer to receive data structure.
362    pub rx_data: *mut Tcp4ReceiveData,
363    /// Pointer to transmit data structure.
364    pub tx_data: *mut Tcp4TransmitData,
365}
366
367impl Debug for Tcp4Packet {
368    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
369        f.debug_struct("Tcp4Packet").finish()
370    }
371}
372
373#[derive(Debug)]
374#[repr(C)]
375pub struct Tcp4FragmentData {
376    /// Length of the fragment in bytes.
377    pub fragment_length: u32,
378    /// Pointer to an array of contiguous bytes, at least
379    /// `fragment_length` in length.
380    pub fragment_buf: *mut u8,
381}
382
383#[derive(Debug)]
384#[repr(C)]
385pub struct Tcp4ReceiveData {
386    /// When `TRUE`, the instance is in urgent mode. The
387    /// implementations of this specification should follow RFC793 to
388    /// process urgent data, and should NOT mix the data across the
389    /// urgent point in one token.
390    pub urgent: Boolean,
391    /// When calling [`receive`][Tcp4Protocol::receive], the caller
392    /// is responsible for setting it to the byte counts of all
393    /// fragment buffers. When the token is signaled by the driver
394    /// it is the length of received data in the fragments.
395    pub data_length: u32,
396    /// Number of fragments in the following fragment table.
397    pub fragment_count: u32,
398    /// Variable-length array of fragment descriptors.
399    ///
400    /// NOTE: this is a flexible array member.
401    pub fragment_table: [Tcp4FragmentData; 0],
402}
403
404#[derive(Debug)]
405#[repr(C)]
406pub struct Tcp4TransmitData {
407    /// If `TRUE`, data must be transmitted promptly, and the PUSH bit
408    /// in the last TCP segment created will be set. If `FALSE`, data
409    /// transmission may be delayed to combine with data from
410    /// subsequent [`transmit`][Tcp4Protocol::transmit] for
411    /// efficiency.
412    pub push: Boolean,
413    /// The data in the fragment table are urgent and urgent point is
414    /// in effect if `TRUE`. Otherwise those data are NOT considered
415    /// urgent.
416    pub urgent: Boolean,
417    /// Total length of data to transmit.
418    pub data_length: u32,
419    /// Number of fragments in the following fragment table.
420    pub fragment_count: u32,
421    /// Variable-length array of fragment descriptors.
422    ///
423    /// NOTE: this is a flexible array member.
424    pub fragment_table: [Tcp4FragmentData; 0],
425}
426
427#[derive(Debug)]
428#[repr(C)]
429pub struct Tcp4ClientConnectionModeParams {
430    /// Remote IP address for the connection.
431    pub remote_ip: Ipv4Address,
432    /// Remote port for the connection.
433    pub remote_port: u16,
434}