Skip to content

Commit d4c7562

Browse files
committed
xxx
1 parent 7d66ab4 commit d4c7562

File tree

4 files changed

+106
-91
lines changed

4 files changed

+106
-91
lines changed

Cargo.lock

Lines changed: 49 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

uefi-test-runner/Cargo.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,19 @@ edition = "2021"
88
[dependencies]
99
uefi-raw = { path = "../uefi-raw" }
1010
uefi = { path = "../uefi", features = ["alloc", "global_allocator", "panic_handler", "logger", "qemu"] }
11-
1211
log.workspace = true
13-
1412
qemu-exit = "3.0.0"
1513

14+
[dependencies.smoltcp]
15+
version = "0.12.0"
16+
default-features = false
17+
features = [
18+
"proto-ipv4",
19+
"socket-udp",
20+
# "medium-ip",
21+
"medium-ethernet"
22+
]
23+
1624
[features]
1725
# Enable the debug support protocol test.
1826
debug_support = []

uefi-test-runner/src/proto/network/mod.rs

Lines changed: 45 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use alloc::vec::Vec;
44
use core::net::Ipv4Addr;
5+
use smoltcp::wire::{IpAddress, IpProtocol, Ipv4Address, Ipv4Packet, UdpPacket, IPV4_HEADER_LEN, UDP_HEADER_LEN};
56

67
pub fn test() {
78
info!("Testing Network protocols");
@@ -18,92 +19,53 @@ pub fn test() {
1819
mod pxe;
1920
mod snp;
2021

21-
/// Computes the standard IPv4 or UDP checksum (one's complement)
22-
fn compute_ipv4_checksum(data: &[u8]) -> u16 {
23-
let mut sum = 0u32;
24-
25-
for chunk in data.chunks(2) {
26-
let word = if chunk.len() == 2 {
27-
u16::from_be_bytes([chunk[0], chunk[1]]) as u32
28-
} else {
29-
(chunk[0] as u32) << 8
30-
};
31-
sum = sum.wrapping_add(word);
32-
}
33-
34-
// Fold carry
35-
while (sum >> 16) != 0 {
36-
sum = (sum & 0xFFFF) + (sum >> 16);
37-
}
38-
39-
!sum as u16
40-
}
41-
42-
/// Builds the UDP pseudo-header used for UDP checksum calculation
43-
fn build_udp_pseudo_header(src_ip: &Ipv4Addr, dst_ip: &Ipv4Addr, udp_segment: &[u8]) -> Vec<u8> {
44-
let mut pseudo = Vec::with_capacity(12 + udp_segment.len());
45-
46-
// Pseudo-header: src IP, dst IP, zero, protocol, UDP length
47-
pseudo.extend_from_slice(&src_ip.octets());
48-
pseudo.extend_from_slice(&dst_ip.octets());
49-
pseudo.push(0);
50-
pseudo.push(0x11); // Protocol = UDP
51-
pseudo.extend_from_slice(&(udp_segment.len() as u16).to_be_bytes());
52-
53-
pseudo.extend_from_slice(udp_segment);
54-
55-
if pseudo.len() % 2 != 0 {
56-
pseudo.push(0); // Pad to even length
57-
}
58-
59-
pseudo
60-
}
61-
62-
fn build_ipv4_udp_packet(
63-
src_ip: Ipv4Addr,
64-
dst_ip: Ipv4Addr,
22+
/// Build an IPv4/UDP packet into a buffer. Must be large enough.
23+
///
24+
/// Returns the full length of the valid data in the buffer.
25+
pub fn build_ipv4_udp_packet_smoltcp(
26+
src_ip: IpAddress,
27+
dst_ip: IpAddress,
6528
src_port: u16,
6629
dst_port: u16,
6730
payload: &[u8],
6831
) -> Vec<u8> {
69-
let ip_header_len = 20;
70-
let udp_header_len = 8;
71-
let total_len = ip_header_len + udp_header_len + payload.len();
72-
73-
let mut packet = Vec::with_capacity(total_len);
74-
75-
// === IPv4 Header ===
76-
packet.push(0x45); // Version (4) + IHL (5)
77-
packet.push(0x00); // DSCP/ECN
78-
packet.extend_from_slice(&(total_len as u16).to_be_bytes()); // Total Length
79-
packet.extend_from_slice(&0x0001u16.to_be_bytes()); // Identification
80-
packet.extend_from_slice(&0x0000u16.to_be_bytes()); // Flags/Fragment offset
81-
packet.push(0x40); // TTL
82-
packet.push(0x11); // Protocol = UDP (17)
83-
packet.extend_from_slice(&[0x00, 0x00]); // Checksum placeholder
84-
packet.extend_from_slice(&src_ip.octets()); // Source IP
85-
packet.extend_from_slice(&dst_ip.octets()); // Destination IP
86-
87-
// Compute IPv4 header checksum
88-
let ip_checksum = compute_ipv4_checksum(&packet[..20]);
89-
packet[10..12].copy_from_slice(&ip_checksum.to_be_bytes());
90-
91-
// === UDP Header ===
92-
packet.extend_from_slice(&src_port.to_be_bytes()); // Source port
93-
packet.extend_from_slice(&dst_port.to_be_bytes()); // Destination port
94-
let udp_len = (udp_header_len + payload.len()) as u16;
95-
packet.extend_from_slice(&udp_len.to_be_bytes()); // UDP length
96-
packet.extend_from_slice(&[0x00, 0x00]); // UDP checksum placeholder
97-
98-
// === Payload ===
99-
packet.extend_from_slice(payload);
100-
101-
// === UDP Checksum ===
102-
let udp_offset = 20;
103-
let udp_packet = &packet[udp_offset..];
104-
let pseudo_header = build_udp_pseudo_header(&src_ip, &dst_ip, udp_packet);
105-
let udp_checksum = compute_ipv4_checksum(&pseudo_header);
106-
packet[udp_offset + 6..udp_offset + 8].copy_from_slice(&udp_checksum.to_be_bytes());
32+
fn extract_ipv4(ip: IpAddress) -> Ipv4Address {
33+
match ip {
34+
IpAddress::Ipv4(v4) => v4,
35+
//IpAddress::Ipv6(_) => panic!("IPv6 not supported"),
36+
}
37+
}
10738

108-
packet
39+
let total_len = IPV4_HEADER_LEN + UDP_HEADER_LEN + payload.len() + 10 /* why additional space necessary? */;
40+
let mut buf = vec![0; total_len];
41+
assert!(buf.len() >= total_len, "buffer too small");
42+
43+
// Write payload first (UDP requires it to be present for checksum)
44+
let udp_payload_start = IPV4_HEADER_LEN + UDP_HEADER_LEN;
45+
const PAYLOAD_BEGIN: usize = IPV4_HEADER_LEN + UDP_HEADER_LEN;
46+
buf[PAYLOAD_BEGIN..PAYLOAD_BEGIN + payload.len()].copy_from_slice(payload);
47+
48+
// --- Build UDP packet ---
49+
let mut udp_packet = UdpPacket::new_checked(&mut buf[IPV4_HEADER_LEN..udp_payload_start]).unwrap();
50+
udp_packet.set_src_port(src_port);
51+
udp_packet.set_dst_port(dst_port);
52+
udp_packet.set_len((UDP_HEADER_LEN + payload.len()) as u16);
53+
udp_packet.fill_checksum(&src_ip, &dst_ip);
54+
55+
// --- Build IPv4 header ---
56+
let mut ip_packet = Ipv4Packet::new_checked(&mut buf[..IPV4_HEADER_LEN]).unwrap();
57+
ip_packet.set_version(4);
58+
ip_packet.set_header_len(5); // 5 * 4 = 20 bytes
59+
ip_packet.set_dscp(0);
60+
ip_packet.set_ecn(0);
61+
ip_packet.set_total_len(total_len as u16);
62+
ip_packet.set_ident(0x1234);
63+
ip_packet.set_dont_frag(true);
64+
ip_packet.set_hop_limit(64);
65+
ip_packet.set_next_header(IpProtocol::Udp);
66+
ip_packet.set_src_addr(extract_ipv4(src_ip));
67+
ip_packet.set_dst_addr(extract_ipv4(src_ip));
68+
ip_packet.fill_checksum();
69+
70+
buf
10971
}

uefi-test-runner/src/proto/network/snp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22

3-
use crate::proto::network::build_ipv4_udp_packet;
3+
use crate::proto::network::{ build_ipv4_udp_packet_smoltcp};
44
use alloc::string::ToString;
55
use core::net::Ipv4Addr;
66
use uefi::boot::{OpenProtocolAttributes, OpenProtocolParams};
@@ -134,7 +134,7 @@ pub fn test() {
134134
let src_port = 0x5445; // "TE"
135135
let dst_port = 0x5444; // "TD"
136136
let payload = 0x1337_u16.to_ne_bytes();
137-
let packet = build_ipv4_udp_packet(src_ip, dst_ip, src_port, dst_port, &payload);
137+
let packet = build_ipv4_udp_packet_smoltcp(src_ip.into(), dst_ip.into(), src_port, dst_port, &payload);
138138

139139
// Send the frame to ourselves
140140
simple_network

0 commit comments

Comments
 (0)