1use crate::error::{Result, SomeIpError};
4use crate::types::{MessageType, ReturnCode, PROTOCOL_VERSION};
5
6pub const HEADER_SIZE: usize = 16;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
11pub struct ServiceId(pub u16);
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
16pub struct MethodId(pub u16);
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
20pub struct ClientId(pub u16);
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
24pub struct SessionId(pub u16);
25
26impl MethodId {
27 pub fn is_event(&self) -> bool {
29 self.0 & 0x8000 != 0
30 }
31
32 pub fn event(id: u16) -> Self {
34 Self(id | 0x8000)
35 }
36
37 pub fn method(id: u16) -> Self {
39 Self(id & 0x7FFF)
40 }
41}
42
43impl std::fmt::Display for ServiceId {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 write!(f, "0x{:04X}", self.0)
46 }
47}
48
49impl std::fmt::Display for MethodId {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 write!(f, "0x{:04X}", self.0)
52 }
53}
54
55impl std::fmt::Display for ClientId {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 write!(f, "0x{:04X}", self.0)
58 }
59}
60
61impl std::fmt::Display for SessionId {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 write!(f, "0x{:04X}", self.0)
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
84pub struct SomeIpHeader {
85 pub service_id: ServiceId,
87 pub method_id: MethodId,
89 pub length: u32,
91 pub client_id: ClientId,
93 pub session_id: SessionId,
95 pub protocol_version: u8,
97 pub interface_version: u8,
99 pub message_type: MessageType,
101 pub return_code: ReturnCode,
103}
104
105impl SomeIpHeader {
106 pub fn new(service_id: ServiceId, method_id: MethodId) -> Self {
108 Self {
109 service_id,
110 method_id,
111 length: 8, client_id: ClientId::default(),
113 session_id: SessionId::default(),
114 protocol_version: PROTOCOL_VERSION,
115 interface_version: 1,
116 message_type: MessageType::Request,
117 return_code: ReturnCode::Ok,
118 }
119 }
120
121 pub fn request(service_id: ServiceId, method_id: MethodId) -> Self {
123 let mut header = Self::new(service_id, method_id);
124 header.message_type = MessageType::Request;
125 header
126 }
127
128 pub fn request_no_return(service_id: ServiceId, method_id: MethodId) -> Self {
130 let mut header = Self::new(service_id, method_id);
131 header.message_type = MessageType::RequestNoReturn;
132 header
133 }
134
135 pub fn notification(service_id: ServiceId, method_id: MethodId) -> Self {
137 let mut header = Self::new(service_id, method_id);
138 header.message_type = MessageType::Notification;
139 header
140 }
141
142 pub fn response_from(request: &Self) -> Self {
144 Self {
145 service_id: request.service_id,
146 method_id: request.method_id,
147 length: 8,
148 client_id: request.client_id,
149 session_id: request.session_id,
150 protocol_version: PROTOCOL_VERSION,
151 interface_version: request.interface_version,
152 message_type: MessageType::Response,
153 return_code: ReturnCode::Ok,
154 }
155 }
156
157 pub fn error_from(request: &Self, return_code: ReturnCode) -> Self {
159 Self {
160 service_id: request.service_id,
161 method_id: request.method_id,
162 length: 8,
163 client_id: request.client_id,
164 session_id: request.session_id,
165 protocol_version: PROTOCOL_VERSION,
166 interface_version: request.interface_version,
167 message_type: MessageType::Error,
168 return_code,
169 }
170 }
171
172 pub fn payload_length(&self) -> u32 {
174 self.length.saturating_sub(8)
175 }
176
177 pub fn set_payload_length(&mut self, payload_len: u32) {
179 self.length = payload_len + 8;
180 }
181
182 pub fn from_bytes(data: &[u8]) -> Result<Self> {
184 if data.len() < HEADER_SIZE {
185 return Err(SomeIpError::MessageTooShort {
186 expected: HEADER_SIZE,
187 actual: data.len(),
188 });
189 }
190
191 let service_id = ServiceId(u16::from_be_bytes([data[0], data[1]]));
192 let method_id = MethodId(u16::from_be_bytes([data[2], data[3]]));
193 let length = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
194 let client_id = ClientId(u16::from_be_bytes([data[8], data[9]]));
195 let session_id = SessionId(u16::from_be_bytes([data[10], data[11]]));
196 let protocol_version = data[12];
197 let interface_version = data[13];
198
199 if protocol_version != PROTOCOL_VERSION {
200 return Err(SomeIpError::WrongProtocolVersion(protocol_version));
201 }
202
203 let message_type = MessageType::from_u8(data[14])
204 .ok_or(SomeIpError::UnknownMessageType(data[14]))?;
205 let return_code =
206 ReturnCode::from_u8(data[15]).ok_or(SomeIpError::UnknownReturnCode(data[15]))?;
207
208 Ok(Self {
209 service_id,
210 method_id,
211 length,
212 client_id,
213 session_id,
214 protocol_version,
215 interface_version,
216 message_type,
217 return_code,
218 })
219 }
220
221 pub fn to_bytes(&self) -> [u8; HEADER_SIZE] {
223 let mut buf = [0u8; HEADER_SIZE];
224
225 buf[0..2].copy_from_slice(&self.service_id.0.to_be_bytes());
226 buf[2..4].copy_from_slice(&self.method_id.0.to_be_bytes());
227 buf[4..8].copy_from_slice(&self.length.to_be_bytes());
228 buf[8..10].copy_from_slice(&self.client_id.0.to_be_bytes());
229 buf[10..12].copy_from_slice(&self.session_id.0.to_be_bytes());
230 buf[12] = self.protocol_version;
231 buf[13] = self.interface_version;
232 buf[14] = self.message_type as u8;
233 buf[15] = self.return_code as u8;
234
235 buf
236 }
237
238 pub fn message_id(&self) -> u32 {
240 ((self.service_id.0 as u32) << 16) | (self.method_id.0 as u32)
241 }
242
243 pub fn request_id(&self) -> u32 {
245 ((self.client_id.0 as u32) << 16) | (self.session_id.0 as u32)
246 }
247}
248
249impl Default for SomeIpHeader {
250 fn default() -> Self {
251 Self::new(ServiceId(0), MethodId(0))
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258
259 #[test]
260 fn test_header_roundtrip() {
261 let header = SomeIpHeader {
262 service_id: ServiceId(0x1234),
263 method_id: MethodId(0x5678),
264 length: 16,
265 client_id: ClientId(0xABCD),
266 session_id: SessionId(0xEF01),
267 protocol_version: PROTOCOL_VERSION,
268 interface_version: 2,
269 message_type: MessageType::Request,
270 return_code: ReturnCode::Ok,
271 };
272
273 let bytes = header.to_bytes();
274 let parsed = SomeIpHeader::from_bytes(&bytes).unwrap();
275
276 assert_eq!(header, parsed);
277 }
278
279 #[test]
280 fn test_header_byte_order() {
281 let header = SomeIpHeader {
282 service_id: ServiceId(0x1234),
283 method_id: MethodId(0x5678),
284 length: 8,
285 client_id: ClientId(0x0000),
286 session_id: SessionId(0x0001),
287 protocol_version: PROTOCOL_VERSION,
288 interface_version: 1,
289 message_type: MessageType::Request,
290 return_code: ReturnCode::Ok,
291 };
292
293 let bytes = header.to_bytes();
294
295 assert_eq!(bytes[0], 0x12); assert_eq!(bytes[1], 0x34); assert_eq!(bytes[2], 0x56); assert_eq!(bytes[3], 0x78); }
301
302 #[test]
303 fn test_method_id_event() {
304 let event = MethodId::event(0x1234);
305 assert!(event.is_event());
306 assert_eq!(event.0, 0x9234);
307
308 let method = MethodId::method(0x9234);
309 assert!(!method.is_event());
310 assert_eq!(method.0, 0x1234);
311 }
312
313 #[test]
314 fn test_response_from() {
315 let request = SomeIpHeader {
316 service_id: ServiceId(0x1234),
317 method_id: MethodId(0x0001),
318 length: 20,
319 client_id: ClientId(0x0100),
320 session_id: SessionId(0x0001),
321 protocol_version: PROTOCOL_VERSION,
322 interface_version: 1,
323 message_type: MessageType::Request,
324 return_code: ReturnCode::Ok,
325 };
326
327 let response = SomeIpHeader::response_from(&request);
328
329 assert_eq!(response.service_id, request.service_id);
330 assert_eq!(response.method_id, request.method_id);
331 assert_eq!(response.client_id, request.client_id);
332 assert_eq!(response.session_id, request.session_id);
333 assert_eq!(response.message_type, MessageType::Response);
334 }
335
336 #[test]
337 fn test_parse_too_short() {
338 let data = [0u8; 10];
339 let result = SomeIpHeader::from_bytes(&data);
340 assert!(matches!(result, Err(SomeIpError::MessageTooShort { .. })));
341 }
342
343 #[test]
344 fn test_parse_wrong_protocol_version() {
345 let mut header = SomeIpHeader::default();
346 header.protocol_version = 0x02;
347 let mut bytes = header.to_bytes();
348 bytes[12] = 0x02; let result = SomeIpHeader::from_bytes(&bytes);
351 assert!(matches!(result, Err(SomeIpError::WrongProtocolVersion(0x02))));
352 }
353}