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- simple_network
21- . shutdown ( )
22- . expect ( "Failed to shutdown Simple Network" ) ;
84+ // Check media
85+ assert ! (
86+ simple_network . mode ( ) . media_present && simple_network . mode ( ) . media_present_supported
87+ ) ;
2388
24- // Check stop
25- simple_network
26- . stop ( )
27- . expect ( "Failed to stop Simple Network" ) ;
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 ) ;
2892
2993 // Check start
3094 simple_network
@@ -36,56 +100,50 @@ pub fn test() {
36100 . initialize ( 0 , 0 )
37101 . expect ( "Failed to initialize Simple Network" ) ;
38102
39- simple_network. reset_statistics ( ) . unwrap ( ) ;
103+ // edk2 virtio-net driver does not support statistics, so
104+ // allow UNSUPPORTED (same for collect_statistics below).
105+ let res = simple_network. reset_statistics ( ) ;
106+ assert ! ( res == Ok ( ( ) ) || res == Err ( Status :: UNSUPPORTED . into( ) ) ) ;
40107
41108 // Reading the interrupt status clears it
42109 simple_network. get_interrupt_status ( ) . unwrap ( ) ;
43110
44111 // Set receive filters
45112 simple_network
46113 . receive_filters (
47- ReceiveFlags :: UNICAST | ReceiveFlags :: MULTICAST | ReceiveFlags :: BROADCAST ,
114+ ReceiveFlags :: UNICAST | ReceiveFlags :: BROADCAST ,
48115 ReceiveFlags :: empty ( ) ,
49116 false ,
50117 None ,
51118 )
52119 . expect ( "Failed to set receive filters" ) ;
53120
54- // Check media
55- if !simple_network. mode ( ) . media_present_supported || !simple_network. mode ( ) . media_present {
56- continue ;
57- }
58-
59- let payload = b"\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \
60- \x45 \x00 \
61- \x00 \x21 \
62- \x00 \x01 \
63- \x00 \x00 \
64- \x10 \
65- \x11 \
66- \x07 \x6a \
67- \xc0 \xa8 \x11 \x0f \
68- \xc0 \xa8 \x11 \x02 \
69- \x54 \x45 \
70- \x54 \x44 \
71- \x00 \x0d \
72- \xa9 \xe4 \
73- \x04 \x01 \x02 \x03 \x04 ";
74-
75- let dest_addr = MacAddress ( [ 0xffu8 ; 32 ] ) ;
76121 assert ! ( !simple_network
77122 . get_interrupt_status( )
78123 . unwrap( )
79124 . contains( InterruptStatus :: TRANSMIT ) ) ;
80125
81- // 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
82140 simple_network
83141 . transmit (
84142 simple_network. mode ( ) . media_header_size as usize ,
85- payload ,
86- None ,
143+ & packet ,
144+ Some ( src_addr ) ,
87145 Some ( dest_addr) ,
88- Some ( 0x0800 ) ,
146+ Some ( ETHER_TYPE_IPV4 ) ,
89147 )
90148 . expect ( "Failed to transmit frame" ) ;
91149
@@ -97,29 +155,36 @@ pub fn test() {
97155 { }
98156
99157 // Attempt to receive a frame
100- let mut buffer = [ 0u8 ; 1500 ] ;
158+ let mut recv_buffer = [ 0u8 ; 1500 ] ;
101159
102160 info ! ( "Waiting for the reception" ) ;
103- if simple_network. receive ( & mut buffer , None , None , None , None )
161+ if simple_network. receive ( & mut recv_buffer , None , None , None , None )
104162 == Err ( Status :: NOT_READY . into ( ) )
105163 {
106164 boot:: stall ( 1_000_000 ) ;
107165
108166 simple_network
109- . receive ( & mut buffer , None , None , None , None )
167+ . receive ( & mut recv_buffer , None , None , None , None )
110168 . unwrap ( ) ;
111169 }
112170
113- assert_eq ! ( buffer[ 42 ..47 ] , [ 4 , 4 , 3 , 2 , 1 ] ) ;
114-
115171 // Get stats
116- let stats = simple_network
117- . collect_statistics ( )
118- . expect ( "Failed to collect statistics" ) ;
119- info ! ( "Stats: {:?}" , stats) ;
120-
121- // One frame should have been transmitted and one received
122- assert_eq ! ( stats. tx_total_frames( ) . unwrap( ) , 1 ) ;
123- assert_eq ! ( stats. rx_total_frames( ) . unwrap( ) , 1 ) ;
172+ let res = simple_network. collect_statistics ( ) ;
173+ match res {
174+ Ok ( stats) => {
175+ info ! ( "Stats: {:?}" , stats) ;
176+
177+ // One frame should have been transmitted and one received
178+ assert_eq ! ( stats. tx_total_frames( ) . unwrap( ) , 1 ) ;
179+ assert_eq ! ( stats. rx_total_frames( ) . unwrap( ) , 1 ) ;
180+ }
181+ Err ( e) => {
182+ if e == Status :: UNSUPPORTED . into ( ) {
183+ info ! ( "Stats: unsupported." ) ;
184+ } else {
185+ panic ! ( "{e}" ) ;
186+ }
187+ }
188+ }
124189 }
125190}
0 commit comments