22
33use alloc:: vec:: Vec ;
44use core:: net:: Ipv4Addr ;
5+ use smoltcp:: wire:: { IpAddress , IpProtocol , Ipv4Address , Ipv4Packet , UdpPacket , IPV4_HEADER_LEN , UDP_HEADER_LEN } ;
56
67pub fn test ( ) {
78 info ! ( "Testing Network protocols" ) ;
@@ -18,92 +19,53 @@ pub fn test() {
1819mod pxe;
1920mod 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}
0 commit comments