1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! A Rust library for parsing the SOME/IP network protocol (without payload interpretation).
//!
//! # Usage
//!
//! Add the following to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! someip_parse = "0.6.1"
//! ```
//!
//! # Example
//! [examples/print_messages.rs](https://github.com/JulianSchmid/someip-parse-rs/blob/0.2.0/examples/print_messages.rs):
//! ```
//! # let mut udp_payload = Vec::<u8>::new();
//! # {
//! #     use someip_parse::*;
//! #     let header = SomeIpHeader{
//! #         message_id: 0x1234_8234,
//! #         length: SOMEIP_LEN_OFFSET_TO_PAYLOAD + 4,
//! #         request_id: 1,
//! #         interface_version: 1,
//! #         message_type: MessageType::Notification,
//! #         return_code: ReturnCode::Ok.into(),
//! #         tp_header: None
//! #     };/*
//! #     header.write_raw(&mut udp_payload).unwrap();
//! #     udp_payload.extend_from_slice(&[1,2,3,4]);*/
//! # }
//! use someip_parse::SomeipMsgsIterator;
//!
//! //trying parsing some ip messages located in a udp payload
//! for someip_message in SomeipMsgsIterator::new(&udp_payload) {
//!     match someip_message {
//!         Ok(value) => {
//!             if value.is_someip_sd() {
//!                 println!("someip service discovery packet");
//!             } else {
//!                 println!("0x{:x} (service id: 0x{:x}, method/event id: 0x{:x})",
//!                          value.message_id(),
//!                          value.service_id(),
//!                          value.event_or_method_id());
//!             }
//!             println!("  with payload {:?}", value.payload())
//!         },
//!         Err(_) => {} //error reading a someip packet (based on size, protocol version value or message type value)
//!     }
//! }
//! ```
//!
//! # References
//! * [AUTOSAR Foundation](https://www.autosar.org/standards/foundation) \(contains SOMEIP Protocol Specification & SOME/IP Service Discovery Protocol Specification\)
//! * [SOME/IP Protocol Specification R22-11](https://www.autosar.org/fileadmin/standards/R22-11/FO/AUTOSAR_PRS_SOMEIPProtocol.pdf)
//! * [SOME/IP Service Discovery Protocol Specification R22-11](https://www.autosar.org/fileadmin/standards/R22-11/FO/AUTOSAR_PRS_SOMEIPServiceDiscoveryProtocol.pdf)

// # Reason for 'bool_comparison' disable:
//
// Clippy triggers triggers errors like the following if the warning stays enabled:
//
//   warning: equality checks against false can be replaced by a negation
//     --> src/packet_decoder.rs:131:20
//      |
//  131 |                 if false == fragmented {
//      |                    ^^^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!fragmented`
//
//
// I prefer to write `false == value` instead of `!value` as it
// is more visually striking and is not as easy to overlook as the single
// character '!'.
#![allow(clippy::bool_comparison)]

#[cfg(test)]
mod proptest_generators;

/// Error types of someip_parse.
pub mod err;

mod message_type;
pub use message_type::*;

mod return_code;
pub use return_code::*;

mod sd;
pub use sd::*;

mod tp_range;
pub use tp_range::*;

mod someip_msgs_iterator;
pub use someip_msgs_iterator::*;

mod someip_header;
pub use someip_header::*;

mod someip_msg_slice;
pub use someip_msg_slice::*;

mod tp_buf_config;
pub use tp_buf_config::*;

mod tp_buf;
pub use tp_buf::*;

mod tp_header;
pub use tp_header::*;

mod tp_pool;
pub use tp_pool::*;

/// Maximum allowed TP segment length.
pub const TP_UDP_MAX_SEGMENT_LEN: usize = 1400;

/// Maximum allowed TP aligned segment length.
///
/// All packets except for the last packet (where
/// the "more segments" flag is set to 0) are required
/// to have a len of multiple of 16 bytes.
pub const TP_UDP_MAX_SEGMENT_LEN_ALIGNED: usize = 1392;

///The currently supported protocol version.
pub const SOMEIP_PROTOCOL_VERSION: u8 = 1;

///Offset that must be substracted from the length field to determine the length of the actual payload.
pub const SOMEIP_LEN_OFFSET_TO_PAYLOAD: u32 = 4 * 2; // 2x 32bits

///Maximum payload length supported by some ip. This is NOT the maximum length that is supported when
///sending packets over UDP. This constant is based on the limitation of the length field data type (uint32).
pub const SOMEIP_MAX_PAYLOAD_LEN: u32 = std::u32::MAX - SOMEIP_LEN_OFFSET_TO_PAYLOAD;

/// The maximum payload size of an SOMEIP UDP message.
///
/// This value comes directly from the SOMEIP specification,
/// which states the following:
///
/// > The size of the SOME/IP payload field depends on the transport
/// > protocol used. With UDP the SOME/IP payload shall be between 0
/// > and 1400 Bytes. The limitation to 1400 Bytes is needed in order
/// > to allow for future changes to protocol stack (e.g. changing to
/// > IPv6 or adding security means). Since TCP supports segmentation
/// > of payloads, larger sizes are automatically supported.
pub const SOMEIP_MAX_PAYLOAD_LEN_UDP: u32 = 1400;

///Length of a someip header.
pub const SOMEIP_HEADER_LENGTH: usize = 4 * 4;

///Length of the tp header that follows a someip header if a someip packet has been flaged as tp.
pub const TP_HEADER_LENGTH: usize = 4;

///Flag in the message type field marking the package a as tp message (transporting large SOME/IP messages of UDP).
pub const SOMEIP_HEADER_MESSAGE_TYPE_TP_FLAG: u8 = 0x20;

///Message id of SOMEIP service discovery messages
pub const SOMEIP_SD_MESSAGE_ID: u32 = 0xffff_8100;

/// Helper function for reading big endian u32 values from a ptr unchecked.
///
/// # Safety
///
/// It is in the responsibility of the caller to ensure there are at least 4
/// bytes accessable via the ptr. If this is not the case undefined behavior
/// will be triggered.
#[inline]
unsafe fn get_unchecked_be_u32(ptr: *const u8) -> u32 {
    u32::from_be_bytes([*ptr, *ptr.add(1), *ptr.add(2), *ptr.add(3)])
}

/// Helper function for reading big endian u16 values from a ptr unchecked.
///
/// # Safety
///
/// It is in the responsibility of the caller to ensure there are at least 2
/// bytes accessable via the ptr. If this is not the case undefined behavior
/// will be triggered.
#[inline]
unsafe fn get_unchecked_be_u16(ptr: *const u8) -> u16 {
    u16::from_be_bytes([*ptr, *ptr.add(1)])
}