xref: /openbmc/libmctp/libmctp.h (revision a3830d259a53269f7b9c8b46129e863ebed1b188)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 
3 #ifndef _LIBMCTP_H
4 #define _LIBMCTP_H
5 
6 #ifdef __cplusplus
7 extern "C" {
8 #endif
9 
10 #include <stdarg.h>
11 #include <stdbool.h>
12 #include <stdint.h>
13 #include <stddef.h>
14 #include <stdalign.h>
15 
16 typedef uint8_t mctp_eid_t;
17 
18 /* Special Endpoint ID values */
19 #define MCTP_EID_NULL	   0
20 #define MCTP_EID_BROADCAST 0xff
21 
22 /* MCTP packet definitions */
23 struct mctp_hdr {
24 	uint8_t ver;
25 	uint8_t dest;
26 	uint8_t src;
27 	uint8_t flags_seq_tag;
28 };
29 
30 /* Definitions for flags_seq_tag field */
31 #define MCTP_HDR_FLAG_SOM  (1 << 7)
32 #define MCTP_HDR_FLAG_EOM  (1 << 6)
33 #define MCTP_HDR_FLAG_TO   (1 << 3)
34 #define MCTP_HDR_TO_SHIFT  (3)
35 #define MCTP_HDR_TO_MASK   (1)
36 #define MCTP_HDR_SEQ_SHIFT (4)
37 #define MCTP_HDR_SEQ_MASK  (0x3)
38 #define MCTP_HDR_TAG_SHIFT (0)
39 #define MCTP_HDR_TAG_MASK  (0x7)
40 
41 #define MCTP_MESSAGE_TO_SRC	      true
42 #define MCTP_MESSAGE_TO_DST	      false
43 #define MCTP_MESSAGE_CAPTURE_OUTGOING true
44 #define MCTP_MESSAGE_CAPTURE_INCOMING false
45 
46 /* Baseline Transmission Unit and packet size */
47 #define MCTP_BTU	       64
48 #define MCTP_PACKET_SIZE(unit) ((unit) + sizeof(struct mctp_hdr))
49 #define MCTP_BODY_SIZE(unit)   ((unit) - sizeof(struct mctp_hdr))
50 
51 /* packet buffers */
52 
53 struct mctp_pktbuf {
54 	size_t start, end, size;
55 	size_t mctp_hdr_off;
56 	bool alloc;
57 	unsigned char data[];
58 };
59 
60 #define MCTP_PKTBUF_SIZE(payload)                                              \
61 	(MCTP_PACKET_SIZE(payload) + sizeof(struct mctp_pktbuf))
62 #define PKTBUF_STORAGE_ALIGN __attribute((aligned(alignof(struct mctp_pktbuf))))
63 
64 struct mctp;
65 struct mctp_bus;
66 struct mctp_binding;
67 
68 /* Initialise a mctp_pktbuf in static storage. Should not be freed.
69  * Storage must be sized to fit the binding,
70  * MCTP_PKTBUF_SIZE(binding->pkt_size + binding->pkt_header + binding->pkt_trailer).
71  * storage must be aligned to alignof(struct mctp_pktbuf),
72  * use PKTBUF_STORAGE_ALIGN macro */
73 struct mctp_pktbuf *mctp_pktbuf_init(struct mctp_binding *binding,
74 				     void *storage);
75 /* Allocate and initialise a mctp_pktbuf. Should be freed with
76  * mctp_pktbuf_free */
77 struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len);
78 void mctp_pktbuf_free(struct mctp_pktbuf *pkt);
79 struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt);
80 void *mctp_pktbuf_data(struct mctp_pktbuf *pkt);
81 size_t mctp_pktbuf_size(const struct mctp_pktbuf *pkt);
82 void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size);
83 void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size);
84 int mctp_pktbuf_push(struct mctp_pktbuf *pkt, const void *data, size_t len);
85 void *mctp_pktbuf_pop(struct mctp_pktbuf *pkt, size_t len);
86 
87 /* MCTP core */
88 
89 /* Allocate and setup a MCTP instance */
90 struct mctp *mctp_init(void);
91 /* Cleanup and deallocate a MCTP instance from mctp_init() */
92 void mctp_destroy(struct mctp *mctp);
93 
94 /* Setup a MCTP instance */
95 int mctp_setup(struct mctp *mctp, size_t struct_mctp_size);
96 /* Release resource of a MCTP instance */
97 void mctp_cleanup(struct mctp *mctp);
98 
99 void mctp_set_max_message_size(struct mctp *mctp, size_t message_size);
100 typedef void (*mctp_capture_fn)(struct mctp_pktbuf *pkt, bool outgoing,
101 				void *user);
102 void mctp_set_capture_handler(struct mctp *mctp, mctp_capture_fn fn,
103 			      void *user);
104 
105 /* Register a binding to the MCTP core, and creates a bus (populating
106  * binding->bus).
107  *
108  * If this function is called, the MCTP stack is initialised as an 'endpoint',
109  * and will deliver local packets to a RX callback - see `mctp_set_rx_all()`
110  * below.
111  */
112 int mctp_register_bus(struct mctp *mctp, struct mctp_binding *binding,
113 		      mctp_eid_t eid);
114 
115 void mctp_unregister_bus(struct mctp *mctp, struct mctp_binding *binding);
116 
117 int mctp_bus_set_eid(struct mctp_binding *binding, mctp_eid_t eid);
118 
119 /* Create a simple bidirectional bridge between busses.
120  *
121  * In this mode, the MCTP stack is initialised as a bridge. There is no EID
122  * defined, so no packets are considered local. Instead, all messages from one
123  * binding are forwarded to the other.
124  */
125 int mctp_bridge_busses(struct mctp *mctp, struct mctp_binding *b1,
126 		       struct mctp_binding *b2);
127 
128 typedef void (*mctp_rx_fn)(uint8_t src_eid, bool tag_owner, uint8_t msg_tag,
129 			   void *data, void *msg, size_t len);
130 
131 int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data);
132 
133 /* Transmit a message.
134  * @msg: The message buffer to send. Must be suitable for
135  * free(), or the custom mctp_set_alloc_ops() m_msg_free.
136  * The mctp stack will take ownership of the buffer
137  * and release it when message transmission is complete or fails.
138  *
139  * If an asynchronous binding is being used, it will return -EBUSY if
140  * a message is already pending for transmission (msg will be freed as usual).
141  * Asynchronous users can test mctp_is_tx_ready() prior to sending.
142  */
143 int mctp_message_tx_alloced(struct mctp *mctp, mctp_eid_t eid, bool tag_owner,
144 			    uint8_t msg_tag, void *msg, size_t msg_len);
145 
146 /* Transmit a message.
147  * @msg: The message buffer to send. Ownership of this buffer
148  * remains with the caller (a copy is made internally with __mctp_msg_alloc).
149  *
150  * If an asynchronous binding is being used, it will return -EBUSY if
151  * a message is already pending for transmission.
152  * Asynchronous users can test mctp_is_tx_ready() prior to sending.
153  *
154  * This is equivalent to duplicating `msg` then calling mctp_message_tx_alloc().
155  */
156 int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, bool tag_owner,
157 		    uint8_t msg_tag, const void *msg, size_t msg_len);
158 
159 /* Transmit a request message.
160  * @msg: The message buffer to send. Must be suitable for
161  * free(), or the custom mctp_set_alloc_ops() m_msg_free.
162  *
163  * A tag with Tag Owner bit set will allocated for the sent message,
164  * and returned to the caller (TO bit is unset in the returned @alloc_msg_tag).
165  * alloc_msg_tag may be NULL to ignore the returned tag.
166  * If no tags are spare -EBUSY will be returned.
167  *
168  * If an asynchronous binding is being used, it will return -EBUSY if
169  * a message is already pending for transmission (msg will be freed).
170  * Asynchronous users can test mctp_is_tx_ready() prior to sending.
171  */
172 int mctp_message_tx_request(struct mctp *mctp, mctp_eid_t eid, void *msg,
173 			    size_t msg_len, uint8_t *alloc_msg_tag);
174 
175 bool mctp_is_tx_ready(struct mctp *mctp, mctp_eid_t eid);
176 
177 /* hardware bindings */
178 
179 /**
180  * @tx: Binding function to transmit one packet on the interface
181  * @tx_storage: A buffer for transmitting packets. Must be sized
182  * as MCTP_PKTBUF_SIZE(mtu) and 8 byte aligned.
183  *      Return:
184  *      * 0 - Success, pktbuf can be released
185  *	* -EMSGSIZE - Packet exceeds binding MTU, pktbuf must be dropped
186  *	* -EBUSY - Packet unable to be transmitted, pktbuf must be retained
187  */
188 struct mctp_binding {
189 	const char *name;
190 	uint8_t version;
191 	struct mctp_bus *bus;
192 	struct mctp *mctp;
193 	size_t pkt_size;
194 	size_t pkt_header;
195 	size_t pkt_trailer;
196 	void *tx_storage;
197 	int (*start)(struct mctp_binding *binding);
198 	int (*tx)(struct mctp_binding *binding, struct mctp_pktbuf *pkt);
199 	mctp_rx_fn control_rx;
200 	void *control_rx_data;
201 };
202 
203 void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable);
204 
205 /*
206  * Receive a packet from binding to core. Takes ownership of pkt, free()-ing it
207  * after use.
208  */
209 void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt);
210 
211 /* environment-specific allocation */
212 void mctp_set_alloc_ops(void *(*m_alloc)(size_t), void (*m_free)(void *),
213 			void *(*m_msg_alloc)(size_t, void *),
214 			void (*m_msg_free)(void *, void *));
215 /* Gets/sets context that will be passed to custom m_msg_ ops */
216 void *mctp_get_alloc_ctx(struct mctp *mctp);
217 void mctp_set_alloc_ctx(struct mctp *mctp, void *ctx);
218 
219 /* environment-specific logging */
220 
221 void mctp_set_log_stdio(int level);
222 void mctp_set_log_syslog(void);
223 void mctp_set_log_custom(void (*fn)(int, const char *, va_list));
224 
225 /* these should match the syslog-standard LOG_* definitions, for
226  * easier use with syslog */
227 #define MCTP_LOG_ERR	 3
228 #define MCTP_LOG_WARNING 4
229 #define MCTP_LOG_NOTICE	 5
230 #define MCTP_LOG_INFO	 6
231 #define MCTP_LOG_DEBUG	 7
232 
233 /* Environment-specific time functionality */
234 /* The `now` callback returns a timestamp in milliseconds.
235  * Timestamps should be monotonically increasing, and can have an arbitrary
236  * origin. (As long as returned timestamps aren't too close to UINT64_MAX, not
237  * a problem forany reasonable implementation). */
238 void mctp_set_now_op(struct mctp *mctp, uint64_t (*now)(void *), void *ctx);
239 /* Returns a timestamp in milliseconds */
240 uint64_t mctp_now(struct mctp *mctp);
241 
242 int mctp_control_handler_enable(struct mctp *mctp);
243 void mctp_control_handler_disable(struct mctp *mctp);
244 
245 /* Add/remove message types to be reported by Get MCTP Version Support.
246  * Control type is added automatically for the control handler */
247 int mctp_control_add_type(struct mctp *mctp, uint8_t msg_type);
248 void mctp_control_remove_type(struct mctp *mctp, uint8_t msg_type);
249 
250 #ifdef __cplusplus
251 }
252 #endif
253 
254 #endif /* _LIBMCTP_H */
255