Skip to content

Commit f0d161e

Browse files
committed
uefi[-raw]: implement working TCPv4 protocol
1 parent 62b2618 commit f0d161e

File tree

5 files changed

+621
-1
lines changed

5 files changed

+621
-1
lines changed

uefi-raw/src/protocol/network/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ pub mod ip4;
66
pub mod ip4_config2;
77
pub mod pxe;
88
pub mod snp;
9+
pub mod tcpv4;
910
pub mod tls;
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
use crate::{Event, Guid, Ipv4Address, Status, guid};
4+
use core::{
5+
ffi::c_void,
6+
fmt::{Debug, Formatter},
7+
marker::PhantomData,
8+
ptr::NonNull,
9+
};
10+
11+
pub type UnmodelledPtr = NonNull<c_void>;
12+
13+
#[derive(Debug)]
14+
#[repr(C)]
15+
pub struct Tcpv4AccessPoint {
16+
pub use_default_address: bool,
17+
pub station_address: Ipv4Address,
18+
pub subnet_mask: Ipv4Address,
19+
pub station_port: u16,
20+
pub remote_address: Ipv4Address,
21+
pub remote_port: u16,
22+
pub active_flag: bool,
23+
}
24+
25+
impl Tcpv4AccessPoint {
26+
pub fn new(connection_mode: Tcpv4ConnectionMode) -> Tcpv4AccessPoint {
27+
let (remote_ip, remote_port, is_client) = match connection_mode {
28+
Tcpv4ConnectionMode::Client(params) => (params.remote_ip, params.remote_port, true),
29+
Tcpv4ConnectionMode::Server => (Ipv4Address([0, 0, 0, 0]), 0, false),
30+
};
31+
Self {
32+
use_default_address: true,
33+
// These two fields are meaningless because we set use_default_address above
34+
station_address: Ipv4Address([0, 0, 0, 0]),
35+
subnet_mask: Ipv4Address([0, 0, 0, 0]),
36+
// Chosen on-demand
37+
station_port: 0,
38+
remote_address: remote_ip,
39+
remote_port,
40+
active_flag: is_client,
41+
}
42+
}
43+
}
44+
45+
#[derive(Debug)]
46+
#[repr(C)]
47+
pub struct Tcpv4Option {
48+
pub receive_buffer_size: u32,
49+
pub send_buffer_size: u32,
50+
pub max_syn_back_log: u32,
51+
pub connection_timeout: u32,
52+
pub data_retries: u32,
53+
pub fin_timeout: u32,
54+
pub time_wait_timeout: u32,
55+
pub keep_alive_probes: u32,
56+
pub keep_alive_time: u32,
57+
pub keep_alive_interval: u32,
58+
pub enable_nagle: bool,
59+
pub enable_time_stamp: bool,
60+
pub enable_window_scaling: bool,
61+
pub enable_selective_ack: bool,
62+
pub enable_path_mtu_discovery: bool,
63+
}
64+
65+
#[derive(Debug)]
66+
#[repr(C)]
67+
pub struct Tcpv4ConfigData<'a> {
68+
pub type_of_service: u8,
69+
pub time_to_live: u8,
70+
pub access_point: Tcpv4AccessPoint,
71+
pub option: Option<&'a Tcpv4Option>,
72+
}
73+
74+
#[derive(Debug)]
75+
pub struct Tcpv4ClientConnectionModeParams {
76+
pub remote_ip: Ipv4Address,
77+
pub remote_port: u16,
78+
}
79+
80+
impl Tcpv4ClientConnectionModeParams {
81+
pub fn new(remote_ip: Ipv4Address, remote_port: u16) -> Tcpv4ClientConnectionModeParams {
82+
Self {
83+
remote_ip,
84+
remote_port,
85+
}
86+
}
87+
}
88+
89+
#[derive(Debug)]
90+
pub enum Tcpv4ConnectionMode {
91+
Client(Tcpv4ClientConnectionModeParams),
92+
// TODO(PT): There may be parameters we need to model when operating as a server
93+
Server,
94+
}
95+
96+
impl<'a> Tcpv4ConfigData<'a> {
97+
pub fn new(
98+
connection_mode: Tcpv4ConnectionMode,
99+
options: Option<&'a Tcpv4Option>,
100+
) -> Tcpv4ConfigData<'a> {
101+
Tcpv4ConfigData {
102+
type_of_service: 0,
103+
time_to_live: 255,
104+
access_point: Tcpv4AccessPoint::new(connection_mode),
105+
option: options,
106+
}
107+
}
108+
}
109+
110+
#[derive(Debug)]
111+
#[repr(C)]
112+
pub struct Tcpv4IoToken<'a> {
113+
pub completion_token: Tcpv4CompletionToken,
114+
pub packet: Tcpv4Packet<'a>,
115+
}
116+
117+
#[repr(C)]
118+
pub union Tcpv4Packet<'a> {
119+
pub rx_data: Option<&'a Tcpv4ReceiveData<'a>>,
120+
pub tx_data: Option<&'a Tcpv4TransmitData<'a>>,
121+
}
122+
123+
impl Debug for Tcpv4Packet<'_> {
124+
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
125+
f.debug_struct("Tcpv4Packet").finish()
126+
}
127+
}
128+
129+
#[derive(Debug)]
130+
#[repr(C)]
131+
pub struct Tcpv4CompletionToken {
132+
pub event: Event,
133+
pub status: Status,
134+
}
135+
136+
#[derive(Debug)]
137+
#[repr(C)]
138+
pub struct Tcpv4FragmentData<'a> {
139+
pub fragment_length: u32,
140+
pub fragment_buf: *const c_void,
141+
pub _pd: PhantomData<&'a mut [u8]>,
142+
}
143+
144+
impl<'a> Tcpv4FragmentData<'a> {
145+
pub fn with_buf(buf: &'a [u8]) -> Tcpv4FragmentData<'a> {
146+
Self {
147+
fragment_length: buf.len() as u32,
148+
fragment_buf: buf.as_ptr() as *const c_void,
149+
_pd: PhantomData,
150+
}
151+
}
152+
153+
pub fn with_mut_buf(buf: &'a mut [u8]) -> Tcpv4FragmentData<'a> {
154+
Self {
155+
fragment_length: buf.len() as u32,
156+
fragment_buf: buf.as_ptr() as *const c_void,
157+
_pd: PhantomData,
158+
}
159+
}
160+
}
161+
162+
#[derive(Debug)]
163+
#[repr(C)]
164+
pub enum Tcpv4ConnectionState {
165+
Closed = 0,
166+
Listen = 1,
167+
SynSent = 2,
168+
SynReceived = 3,
169+
Established = 4,
170+
FinWait1 = 5,
171+
FinWait2 = 6,
172+
Closing = 7,
173+
TimeWait = 8,
174+
CloseWait = 9,
175+
LastAck = 10,
176+
}
177+
178+
/// Current IPv4 configuration data used by the TCPv4 instance.
179+
#[derive(Debug)]
180+
#[repr(C)]
181+
pub struct Ipv4ModeData<'a> {
182+
pub is_started: bool,
183+
pub max_packet_size: u32,
184+
pub config_data: Ipv4ConfigData,
185+
pub is_configured: bool,
186+
pub group_count: bool,
187+
pub group_table: &'a [Ipv4Address; 0],
188+
pub route_count: u32,
189+
pub ip4_route_table: &'a [Ipv4RouteTable; 0],
190+
pub icmp_type_count: u32,
191+
pub icmp_type_list: &'a [Ipv4IcmpType; 0],
192+
}
193+
194+
#[derive(Debug)]
195+
#[repr(C)]
196+
pub struct Ipv4ConfigData {
197+
pub default_protocol: u8,
198+
pub accept_any_protocol: bool,
199+
pub accept_icmp_errors: bool,
200+
pub accept_broadcast: bool,
201+
pub accept_promiscuous: bool,
202+
pub use_default_address: bool,
203+
pub station_address: Ipv4Address,
204+
pub subnet_mask: Ipv4Address,
205+
pub type_of_service: u8,
206+
pub time_to_live: u8,
207+
pub do_not_fragment: bool,
208+
pub raw_data: bool,
209+
pub receive_timeout: u32,
210+
pub transmit_timeout: u32,
211+
}
212+
213+
#[derive(Debug)]
214+
#[repr(C)]
215+
pub struct Ipv4RouteTable {
216+
pub subnet_address: Ipv4Address,
217+
pub subnet_mask: Ipv4Address,
218+
pub gateway_address: Ipv4Address,
219+
}
220+
221+
#[derive(Debug)]
222+
#[repr(C)]
223+
pub struct Ipv4IcmpType {
224+
pub type_: u8,
225+
pub code: u8,
226+
}
227+
228+
#[derive(Debug)]
229+
#[repr(C)]
230+
pub struct Tcpv4Protocol {
231+
// TODO: should this &mut? It's plain *This in the spec but
232+
// HttpProtocol uses `*const Self` for `get_mode_data`.
233+
#[allow(clippy::type_complexity)]
234+
pub get_mode_data: extern "efiapi" fn(
235+
this: &Self,
236+
out_connection_state: Option<&mut Tcpv4ConnectionState>,
237+
out_config_data: Option<UnmodelledPtr>,
238+
out_ip4_mode_data: Option<&mut Ipv4ModeData>,
239+
out_managed_network_config_data: Option<UnmodelledPtr>,
240+
out_simple_network_mode: Option<UnmodelledPtr>,
241+
) -> Status,
242+
pub configure: extern "efiapi" fn(&mut Self, config_data: Option<&Tcpv4ConfigData>) -> Status,
243+
pub routes: extern "efiapi" fn(
244+
&mut Self,
245+
delete_route: bool,
246+
subnet_address: &Ipv4Address,
247+
subnet_mask: &Ipv4Address,
248+
gateway_address: &Ipv4Address,
249+
) -> Status,
250+
pub connect: extern "efiapi" fn(&mut Self, connection_token: &Tcpv4CompletionToken) -> Status,
251+
pub accept: extern "efiapi" fn(&mut Self, listen_token: UnmodelledPtr) -> Status,
252+
pub transmit: extern "efiapi" fn(&mut Self, token: &Tcpv4IoToken) -> Status,
253+
pub receive: extern "efiapi" fn(&mut Self, token: &Tcpv4IoToken) -> Status,
254+
pub close: extern "efiapi" fn(&mut Self, close_token: UnmodelledPtr) -> Status,
255+
pub cancel: extern "efiapi" fn(&mut Self, completion_token: UnmodelledPtr) -> Status,
256+
pub poll: extern "efiapi" fn(&mut Self) -> Status,
257+
}
258+
259+
impl Tcpv4Protocol {
260+
pub const GUID: Guid = guid!("65530BC7-A359-410F-B010-5AADC7EC2B62");
261+
pub const SERVICE_BINDING_GUID: Guid = guid!("00720665-67EB-4a99-BAF7-D3C33A1C7CC9");
262+
}
263+
264+
#[derive(Debug)]
265+
#[repr(C)]
266+
pub struct Tcpv4ReceiveData<'a> {
267+
pub urgent: bool,
268+
pub data_length: u32,
269+
pub fragment_count: u32,
270+
pub fragment_table: [Tcpv4FragmentData<'a>; 1],
271+
}
272+
273+
#[derive(Debug)]
274+
#[repr(C)]
275+
pub struct Tcpv4TransmitData<'a> {
276+
pub push: bool,
277+
pub urgent: bool,
278+
pub data_length: u32,
279+
pub fragment_count: u32,
280+
pub fragment_table: [Tcpv4FragmentData<'a>; 1],
281+
}

uefi/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ uguid.workspace = true
4343
cfg-if = "1.0.0"
4444
ucs2 = "0.3.3"
4545
uefi-macros = "0.18.1"
46-
uefi-raw = "0.11.0"
46+
uefi-raw.path = "../uefi-raw"
4747
qemu-exit = { version = "3.0.2", optional = true }
4848

4949
[package.metadata.docs.rs]

uefi/src/proto/network/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod http;
88
pub mod ip4config2;
99
pub mod pxe;
1010
pub mod snp;
11+
pub mod tcpv4;
1112

1213
pub use uefi_raw::MacAddress;
1314

0 commit comments

Comments
 (0)