@@ -23,24 +23,39 @@ impl ConnectedMessaging for EthernetIpClient {
2323 self . send_rr_data ( cip) . await ?
2424 } ;
2525
26- if res. len ( ) < 10 {
26+ // Minimum: service (0), reserved (1), general status (2), ext count (3)
27+ if res. len ( ) < 4 {
2728 return Err ( ForwardOpenError :: Other (
2829 "ForwardOpen response too short" . into ( ) ,
2930 ) ) ;
3031 }
3132
32- let status = res[ 2 ] ;
33- if status != 0 {
33+ let general = res[ 2 ] ;
34+ let ext_words = res[ 3 ] as usize ;
35+ let ext_bytes = 4 + ext_words * 2 ;
36+
37+ if res. len ( ) < ext_bytes + 4 {
38+ return Err ( ForwardOpenError :: Other (
39+ "ForwardOpen response missing connection ID" . into ( ) ,
40+ ) ) ;
41+ }
42+
43+ if general != 0 {
3444 let ext = decode_extended_status ( & res) ;
3545
3646 if !ext. is_empty ( ) {
3747 return Err ( map_extended_status ( & ext) ) ;
3848 }
39-
40- return Err ( ForwardOpenError :: GeneralStatus ( status) ) ;
49+ return Err ( ForwardOpenError :: GeneralStatus ( general) ) ;
4150 }
4251
43- let conn_id = u32:: from_le_bytes ( [ res[ 6 ] , res[ 7 ] , res[ 8 ] , res[ 9 ] ] ) ;
52+ let conn_id = u32:: from_le_bytes ( [
53+ res[ ext_bytes] ,
54+ res[ ext_bytes + 1 ] ,
55+ res[ ext_bytes + 2 ] ,
56+ res[ ext_bytes + 3 ] ,
57+ ] ) ;
58+
4459 self . connection_id = Some ( conn_id) ;
4560 self . sequence = 1 ;
4661 self . connected = true ;
@@ -76,19 +91,34 @@ impl ConnectedMessaging for EthernetIpClient {
7691 self . send_rr_data ( cip) . await ?
7792 } ;
7893
79- if res. len ( ) < 10 {
94+ if res. len ( ) < 4 {
8095 return Err ( io:: Error :: other ( "LargeForwardOpen response too short" ) ) ;
8196 }
8297
83- let status = res[ 2 ] ;
84- if status != 0 {
98+ let general = res[ 2 ] ;
99+ let ext_words = res[ 3 ] as usize ;
100+ let ext_bytes = 4 + ext_words * 2 ;
101+
102+ if res. len ( ) < ext_bytes + 4 {
103+ return Err ( io:: Error :: other (
104+ "LargeForwardOpen response missing connection ID" ,
105+ ) ) ;
106+ }
107+
108+ if general != 0 {
85109 return Err ( io:: Error :: other ( format ! (
86110 "LargeForwardOpen failed: 0x{:02X}" ,
87- status
111+ general
88112 ) ) ) ;
89113 }
90114
91- let conn_id = u32:: from_le_bytes ( [ res[ 6 ] , res[ 7 ] , res[ 8 ] , res[ 9 ] ] ) ;
115+ let conn_id = u32:: from_le_bytes ( [
116+ res[ ext_bytes] ,
117+ res[ ext_bytes + 1 ] ,
118+ res[ ext_bytes + 2 ] ,
119+ res[ ext_bytes + 3 ] ,
120+ ] ) ;
121+
92122 self . connection_id = Some ( conn_id) ;
93123 self . sequence = 1 ;
94124 self . connected = true ;
@@ -127,7 +157,6 @@ impl ConnectedMessaging for EthernetIpClient {
127157
128158 match res {
129159 Ok ( _) => return Ok ( ( ) ) ,
130-
131160 Err ( e) => {
132161 let msg = e. to_string ( ) ;
133162
@@ -153,9 +182,14 @@ impl ConnectedMessaging for EthernetIpClient {
153182 . ok_or_else ( || io:: Error :: other ( "No active ForwardOpen connection" ) ) ?;
154183
155184 let seq = self . sequence ;
156- self . sequence = self . sequence . wrapping_add ( 1 ) ;
185+ // Avoid sequence 0 on wrap
186+ self . sequence = if self . sequence == u16:: MAX {
187+ 1
188+ } else {
189+ self . sequence . wrapping_add ( 1 )
190+ } ;
157191
158- let mut rr = Vec :: new ( ) ;
192+ let mut rr = Vec :: with_capacity ( 4 + 2 + cip . len ( ) ) ;
159193 rr. extend_from_slice ( & conn_id. to_le_bytes ( ) ) ;
160194 rr. extend_from_slice ( & seq. to_le_bytes ( ) ) ;
161195 rr. extend_from_slice ( & cip) ;
@@ -174,6 +208,12 @@ impl ConnectedMessaging for EthernetIpClient {
174208 let h = EncapsulationHeader :: from_bytes ( & h_buf)
175209 . ok_or_else ( || io:: Error :: other ( "Bad encapsulation header" ) ) ?;
176210
211+ if h. command != COMMAND_SEND_UNIT_DATA {
212+ return Err ( io:: Error :: other (
213+ "Unexpected encapsulation command in response" ,
214+ ) ) ;
215+ }
216+
177217 let mut d = vec ! [ 0u8 ; h. length as usize ] ;
178218 self . stream . read_exact ( & mut d) . await ?;
179219
0 commit comments