11// SPDX-License-Identifier: MIT OR Apache-2.0
22
3- use uefi:: proto:: network:: snp:: { InterruptStatus , ReceiveFlags , SimpleNetwork } ;
4- use uefi:: proto:: network:: MacAddress ;
3+ use crate :: proto:: network:: build_ipv4_udp_packet;
4+ use alloc:: string:: ToString ;
5+ use core:: net:: Ipv4Addr ;
6+ use uefi:: boot:: { OpenProtocolAttributes , OpenProtocolParams } ;
7+ use uefi:: proto:: device_path:: text:: { AllowShortcuts , DisplayOnly } ;
8+ use uefi:: proto:: device_path:: DevicePath ;
9+ use uefi:: proto:: network:: snp:: { InterruptStatus , NetworkState , ReceiveFlags , SimpleNetwork } ;
510use uefi:: { boot, Status } ;
611
12+ fn compute_ipv4_checksum ( header : & [ u8 ] ) -> u16 {
13+ assert_eq ! ( header. len( ) % 2 , 0 ) ;
14+ let sum = header
15+ . chunks ( 2 )
16+ . map ( |chunk| u16:: from_be_bytes ( [ chunk[ 0 ] , chunk[ 1 ] ] ) as u32 )
17+ . sum :: < u32 > ( ) ;
18+
19+ let carry_add = ( sum & 0xFFFF ) + ( sum >> 16 ) ;
20+ !( carry_add as u16 )
21+ }
22+
23+ fn build_ipv4_packet_with_payload (
24+ src_ip : Ipv4Addr ,
25+ dest_ip : Ipv4Addr ,
26+ payload : [ u8 ; 2 ] ,
27+ ) -> [ u8 ; 22 ] {
28+ let mut packet = [ 0u8 ; 22 ] ;
29+ let len = packet. len ( ) as u16 ;
30+
31+ // IPv4 header
32+ // Version = 4, IHL = 5
33+ packet[ 0 ] = 0x45 ;
34+ // DSCP/ECN
35+ packet[ 1 ] = 0x00 ;
36+ // Total length
37+ packet[ 2 ..4 ] . copy_from_slice ( & ( len. to_be_bytes ( ) ) ) ;
38+ // Identification
39+ packet[ 4 ..6 ] . copy_from_slice ( & 0u16 . to_be_bytes ( ) ) ;
40+ // Flags (DF), Fragment offset
41+ packet[ 6 ..8 ] . copy_from_slice ( & 0x4000u16 . to_be_bytes ( ) ) ;
42+ // TTL
43+ packet[ 8 ] = 0x40 ;
44+ // Protocol (UDP)
45+ packet[ 9 ] = 0x11 ;
46+ // Checksum placeholder at [10..12]
47+ packet[ 12 ..16 ] . copy_from_slice ( & src_ip. octets ( ) ) ; // Source IP
48+ packet[ 16 ..20 ] . copy_from_slice ( & dest_ip. octets ( ) ) ; // Destination IP
49+
50+ // Calculate checksum
51+ let checksum = compute_ipv4_checksum ( & packet[ 0 ..20 ] ) ;
52+ packet[ 10 ..12 ] . copy_from_slice ( & checksum. to_be_bytes ( ) ) ;
53+
54+ // Payload
55+ packet[ 20 ] = payload[ 0 ] ;
56+ packet[ 21 ] = payload[ 1 ] ;
57+
58+ packet
59+ }
60+
761pub fn test ( ) {
862 info ! ( "Testing the simple network protocol" ) ;
963
10- let handles = boot:: find_handles :: < SimpleNetwork > ( ) . unwrap_or_default ( ) ;
64+ let handles = boot:: find_handles :: < SimpleNetwork > ( ) . unwrap ( ) ;
1165
1266 for handle in handles {
13- let simple_network = boot:: open_protocol_exclusive :: < SimpleNetwork > ( handle) ;
14- if simple_network. is_err ( ) {
15- continue ;
16- }
17- let simple_network = simple_network. unwrap ( ) ;
67+ // Buggy firmware; although it should be there, we have to test if the
68+ // protocol is actually installed.
69+ let simple_network = match boot:: open_protocol_exclusive :: < SimpleNetwork > ( handle) {
70+ Ok ( snp) => snp,
71+ Err ( e) => {
72+ log:: debug!( "Handle {handle:?} doesn't actually support SNP; skipping" ) ;
73+ continue ;
74+ }
75+ } ;
76+ let simple_network_dvp = boot:: open_protocol_exclusive :: < DevicePath > ( handle) . unwrap ( ) ;
77+ debug ! (
78+ "Testing network device: {}" ,
79+ simple_network_dvp
80+ . to_string( DisplayOnly ( false ) , AllowShortcuts ( false ) )
81+ . unwrap( )
82+ ) ;
1883
19- // Check shutdown
20- let res = simple_network. shutdown ( ) ;
21- assert ! ( res == Ok ( ( ) ) || res == Err ( Status :: NOT_STARTED . into( ) ) ) ;
84+ // Check media
85+ assert ! (
86+ simple_network. mode( ) . media_present && simple_network. mode( ) . media_present_supported
87+ ) ;
2288
23- // Check stop
24- let res = simple_network . stop ( ) ;
25- assert ! ( res == Ok ( ( ) ) || res == Err ( Status :: NOT_STARTED . into ( ) ) ) ;
89+ // Ensure network is not started yet. If it is started, another test
90+ // didn't clean up properly.
91+ assert_eq ! ( simple_network . mode ( ) . state , NetworkState :: STOPPED ) ;
2692
2793 // Check start
2894 simple_network
@@ -52,41 +118,32 @@ pub fn test() {
52118 )
53119 . expect ( "Failed to set receive filters" ) ;
54120
55- // Check media
56- if !simple_network. mode ( ) . media_present_supported || !simple_network. mode ( ) . media_present {
57- continue ;
58- }
59-
60- let payload = b"\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \
61- \x45 \x00 \
62- \x00 \x21 \
63- \x00 \x01 \
64- \x00 \x00 \
65- \x10 \
66- \x11 \
67- \x07 \x6a \
68- \xc0 \xa8 \x11 \x0f \
69- \xc0 \xa8 \x11 \x02 \
70- \x54 \x45 \
71- \x54 \x44 \
72- \x00 \x0d \
73- \xa9 \xe4 \
74- \x04 \x01 \x02 \x03 \x04 ";
75-
76- let dest_addr = MacAddress ( [ 0xffu8 ; 32 ] ) ;
77121 assert ! ( !simple_network
78122 . get_interrupt_status( )
79123 . unwrap( )
80124 . contains( InterruptStatus :: TRANSMIT ) ) ;
81125
82- // Send the frame
126+ // Broadcast address (send to self)
127+ let src_addr = simple_network. mode ( ) . current_address ;
128+ let dest_addr = simple_network. mode ( ) . broadcast_address ;
129+ const ETHER_TYPE_IPV4 : u16 = 0x0800 ;
130+
131+ // IPv4 can be arbitrary, not used for routing here.
132+ let src_ip = Ipv4Addr :: new ( 192 , 168 , 17 , 15 ) ;
133+ let dst_ip = Ipv4Addr :: new ( 192 , 168 , 17 , 2 ) ;
134+ let src_port = 0x5445 ; // "TE"
135+ let dst_port = 0x5444 ; // "TD"
136+ let payload = 0x1337_u16 . to_ne_bytes ( ) ;
137+ let packet = build_ipv4_udp_packet ( src_ip, dst_ip, src_port, dst_port, & payload) ;
138+
139+ // Send the frame to ourselves
83140 simple_network
84141 . transmit (
85142 simple_network. mode ( ) . media_header_size as usize ,
86- payload ,
87- None ,
143+ & packet ,
144+ Some ( src_addr ) ,
88145 Some ( dest_addr) ,
89- Some ( 0x0800 ) ,
146+ Some ( ETHER_TYPE_IPV4 ) ,
90147 )
91148 . expect ( "Failed to transmit frame" ) ;
92149
@@ -98,21 +155,19 @@ pub fn test() {
98155 { }
99156
100157 // Attempt to receive a frame
101- let mut buffer = [ 0u8 ; 1500 ] ;
158+ let mut recv_buffer = [ 0u8 ; 1500 ] ;
102159
103160 info ! ( "Waiting for the reception" ) ;
104- if simple_network. receive ( & mut buffer , None , None , None , None )
161+ if simple_network. receive ( & mut recv_buffer , None , None , None , None )
105162 == Err ( Status :: NOT_READY . into ( ) )
106163 {
107164 boot:: stall ( 1_000_000 ) ;
108165
109166 simple_network
110- . receive ( & mut buffer , None , None , None , None )
167+ . receive ( & mut recv_buffer , None , None , None , None )
111168 . unwrap ( ) ;
112169 }
113170
114- assert_eq ! ( buffer[ 42 ..47 ] , [ 4 , 4 , 3 , 2 , 1 ] ) ;
115-
116171 // Get stats
117172 let res = simple_network. collect_statistics ( ) ;
118173 match res {
0 commit comments