libmctp/
mctp_traits.rs

1//! Traits used for the MCTP implementation.
2//!
3//! This is an internal implementation.
4
5use crate::base_packet::{
6    MCTPMessageBody, MCTPMessageBodyHeader, MCTPTransportHeader, MessageType,
7};
8use crate::control_packet::CommandCode;
9use crate::smbus_proto::{MCTPSMBusHeader, MCTPSMBusPacket, HDR_VERSION, MCTP_SMBUS_COMMAND_CODE};
10
11/// The standard trait for all MCTP headers
12pub(crate) trait MCTPHeader {
13    /// Return the number of bytes in the header
14    fn len(&self) -> usize;
15
16    /// Check if the header is empty
17    fn is_empty(&self) -> bool {
18        self.len() == 0
19    }
20
21    /// Store the header packet into a buffer and return
22    /// the number of bytes stored. The return value is the same as
23    /// calling `len()`.
24    ///
25    /// `buffer`: a mutable buffer to store the bytes from the struct.
26    /// `buffer` is formated as valid MCTP data.
27    fn to_raw_bytes(&self, buf: &mut [u8]) -> usize;
28}
29
30/// The standard trait for the MCTP Control Message request type
31pub(crate) trait MCTPControlMessageRequest {
32    fn command_code(&self) -> u8;
33
34    /// Get the length of the request data command
35    fn get_request_data_len(&self) -> usize {
36        match self.command_code().into() {
37            CommandCode::Reserved => 0,
38            CommandCode::SetEndpointID => 2,
39            CommandCode::GetEndpointID => 0,
40            CommandCode::GetEndpointUUID => 0,
41            CommandCode::GetMCTPVersionSupport => 1,
42            CommandCode::GetMessageTypeSupport => 0,
43            CommandCode::GetVendorDefinedMessageSupport => 1,
44            CommandCode::ResolveEndpointID => 1,
45            CommandCode::AllocateEndpointIDs => 3,
46            CommandCode::RoutingInformationUpdate => unimplemented!(),
47            CommandCode::GetRoutingTableEntries => unimplemented!(),
48            CommandCode::PrepareForEndpointDiscovery => unimplemented!(),
49            CommandCode::EndpointDiscovery => unimplemented!(),
50            CommandCode::DiscoveryNotify => unimplemented!(),
51            CommandCode::GetNetworkID => unimplemented!(),
52            CommandCode::QueryHop => unimplemented!(),
53            CommandCode::ResolveUUID => unimplemented!(),
54            CommandCode::QueryRateLimit => unimplemented!(),
55            CommandCode::RequestTXRateLimit => unimplemented!(),
56            CommandCode::UpdateRateLimit => unimplemented!(),
57            CommandCode::QuerySupportedInterfaces => unimplemented!(),
58            CommandCode::Unknown => unimplemented!(),
59        }
60    }
61
62    /// Get the length of the response data command
63    /// A return value of zero indicates a variable length
64    fn get_response_data_len(&self) -> usize {
65        match self.command_code().into() {
66            CommandCode::Reserved => 0,
67            CommandCode::SetEndpointID => 3,
68            CommandCode::GetEndpointID => 4,
69            CommandCode::GetEndpointUUID => 16,
70            CommandCode::GetMCTPVersionSupport => 5,
71            CommandCode::GetMessageTypeSupport => 0,
72            CommandCode::GetVendorDefinedMessageSupport => 0,
73            CommandCode::ResolveEndpointID => unimplemented!(),
74            CommandCode::AllocateEndpointIDs => 4,
75            CommandCode::RoutingInformationUpdate => 1,
76            CommandCode::GetRoutingTableEntries => unimplemented!(),
77            CommandCode::PrepareForEndpointDiscovery => unimplemented!(),
78            CommandCode::EndpointDiscovery => unimplemented!(),
79            CommandCode::DiscoveryNotify => unimplemented!(),
80            CommandCode::GetNetworkID => unimplemented!(),
81            CommandCode::QueryHop => unimplemented!(),
82            CommandCode::ResolveUUID => unimplemented!(),
83            CommandCode::QueryRateLimit => unimplemented!(),
84            CommandCode::RequestTXRateLimit => unimplemented!(),
85            CommandCode::UpdateRateLimit => unimplemented!(),
86            CommandCode::QuerySupportedInterfaces => unimplemented!(),
87            CommandCode::Unknown => unimplemented!(),
88        }
89    }
90}
91
92/// The standard trait for SMBus Request and Response
93pub trait SMBusMCTPRequestResponse {
94    /// Get the address of the device
95    ///
96    /// Returns the address
97    fn get_address(&self) -> u8;
98
99    /// Get the current EID of the device
100    ///
101    /// Returns the EID
102    fn get_eid(&self) -> u8;
103
104    /// Set the EID of the device
105    ///
106    /// `eid`: The new eid to use
107    fn set_eid(&self, eid: u8);
108
109    /// Generate a transport header
110    fn generate_transport_header(&self, dest_addr: u8) -> MCTPTransportHeader<[u8; 4]> {
111        let mut base_header: MCTPTransportHeader<[u8; 4]> = MCTPTransportHeader::new(HDR_VERSION);
112        base_header.set_dest_endpoint_id(dest_addr);
113        base_header.set_source_endpoint_id(self.get_address());
114        base_header.set_som(true as u8);
115        base_header.set_eom(true as u8);
116        base_header.set_pkt_seq(0);
117        base_header.set_to(true as u8);
118        base_header.set_msg_tag(0);
119
120        base_header
121    }
122
123    /// Generate a SMBus header
124    fn generate_smbus_header(&self, dest_addr: u8) -> MCTPSMBusHeader<[u8; 4]> {
125        let mut smbus_header: MCTPSMBusHeader<[u8; 4]> = MCTPSMBusHeader::new();
126        smbus_header.set_dest_read_write(0);
127        smbus_header.set_dest_slave_addr(dest_addr);
128        smbus_header.set_command_code(MCTP_SMBUS_COMMAND_CODE);
129        smbus_header.set_source_slave_addr(self.get_address());
130        smbus_header.set_source_read_write(1);
131
132        smbus_header
133    }
134
135    /// Store a control message packet bytes in the `buf`.
136    fn generate_control_packet_bytes(
137        &self,
138        dest_addr: u8,
139        message_header: &Option<&[u8]>,
140        message_data: &[u8],
141        buf: &mut [u8],
142    ) -> Result<usize, ()> {
143        let mut smbus_header = self.generate_smbus_header(dest_addr);
144        let base_header = self.generate_transport_header(dest_addr);
145
146        let header: MCTPMessageBodyHeader<[u8; 1]> =
147            MCTPMessageBodyHeader::new(false, MessageType::MCtpControl);
148
149        let body = MCTPMessageBody::new(&header, *message_header, message_data, None);
150
151        let packet = MCTPSMBusPacket::new(&mut smbus_header, &base_header, &body);
152
153        Ok(packet.to_raw_bytes(buf))
154    }
155
156    /// Store a PCI Vendor message bytes in `buf`
157    fn generate_pci_msg_packet_bytes(
158        &self,
159        dest_addr: u8,
160        message_header: &Option<&[u8]>,
161        message_data: &[u8],
162        buf: &mut [u8],
163    ) -> Result<usize, ()> {
164        let mut smbus_header = self.generate_smbus_header(dest_addr);
165        let base_header = self.generate_transport_header(dest_addr);
166
167        let header: MCTPMessageBodyHeader<[u8; 1]> =
168            MCTPMessageBodyHeader::new(false, MessageType::VendorDefinedPCI);
169
170        let body = MCTPMessageBody::new(&header, *message_header, message_data, None);
171
172        let packet = MCTPSMBusPacket::new(&mut smbus_header, &base_header, &body);
173
174        Ok(packet.to_raw_bytes(buf))
175    }
176
177    /// Store a SPDM Vendor message bytes in `buf`
178    fn generate_spdm_msg_packet_bytes(
179        &self,
180        dest_addr: u8,
181        message_type: MessageType,
182        message_header: &Option<&[u8]>,
183        message_data: &[u8],
184        buf: &mut [u8],
185    ) -> Result<usize, ()> {
186        let mut smbus_header = self.generate_smbus_header(dest_addr);
187        let base_header = self.generate_transport_header(dest_addr);
188
189        let header: MCTPMessageBodyHeader<[u8; 1]> =
190            MCTPMessageBodyHeader::new(false, message_type);
191
192        let body = MCTPMessageBody::new(&header, *message_header, message_data, None);
193
194        let packet = MCTPSMBusPacket::new(&mut smbus_header, &base_header, &body);
195
196        Ok(packet.to_raw_bytes(buf))
197    }
198
199    /// Store a IANA Vendor message bytes in `buf`
200    fn generate_iana_msg_packet_bytes(
201        &self,
202        dest_addr: u8,
203        message_header: &Option<&[u8]>,
204        message_data: &[u8],
205        buf: &mut [u8],
206    ) -> Result<usize, ()> {
207        let mut smbus_header = self.generate_smbus_header(dest_addr);
208        let base_header = self.generate_transport_header(dest_addr);
209
210        let header: MCTPMessageBodyHeader<[u8; 1]> =
211            MCTPMessageBodyHeader::new(false, MessageType::VendorDefinedIANA);
212
213        let body = MCTPMessageBody::new(&header, *message_header, message_data, None);
214
215        let packet = MCTPSMBusPacket::new(&mut smbus_header, &base_header, &body);
216
217        Ok(packet.to_raw_bytes(buf))
218    }
219}