blob: 71b54ce17a9c6836ea91124c286530a92c716b14 [file] [log] [blame]
Jeremy Kerr4cdc2002019-02-07 16:49:12 +08001/* SPDX-License-Identifier: Apache-2.0 */
2
3#include <assert.h>
4#include <stdarg.h>
5#include <stddef.h>
6#include <stdint.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#undef pr_fmt
12#define pr_fmt(fmt) "core: " fmt
13
14#include "libmctp.h"
15#include "libmctp-alloc.h"
16#include "libmctp-log.h"
17
18/* Internal data structures */
19
20struct mctp_bus {
21 mctp_eid_t eid;
22 struct mctp_binding *binding;
23
24 /* todo: routing */
25};
26
Jeremy Kerr24db71f2019-02-07 21:37:35 +080027struct mctp_msg_ctx {
28 uint8_t src;
29 uint8_t tag;
30 uint8_t last_seq;
31 void *buf;
32 size_t buf_size;
33 size_t buf_alloc_size;
34};
35
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080036struct mctp {
37 /* todo: multiple busses */
38 struct mctp_bus busses[1];
39
Jeremy Kerr24db71f2019-02-07 21:37:35 +080040 struct mctp_pktbuf *tx_queue_head;
41 struct mctp_pktbuf *tx_queue_tail;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080042
43 /* Message RX callback */
44 mctp_rx_fn message_rx;
45 void *message_rx_data;
Jeremy Kerr24db71f2019-02-07 21:37:35 +080046
47 /* Message reassembly.
48 * @todo: flexible context count
49 */
50 struct mctp_msg_ctx msg_ctxs[16];
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080051};
52
53#ifndef BUILD_ASSERT
54#define BUILD_ASSERT(x) \
55 do { (void)sizeof(char[0-(!(x))]); } while (0)
56#endif
57
Jeremy Kerr24db71f2019-02-07 21:37:35 +080058#ifndef ARRAY_SIZE
59#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
60#endif
61
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080062struct mctp_pktbuf *mctp_pktbuf_alloc(uint8_t len)
63{
64 struct mctp_pktbuf *buf;
65
66 BUILD_ASSERT(MCTP_PKTBUF_SIZE <= 0xff);
67
68 /* todo: pools */
69 buf = __mctp_alloc(sizeof(*buf));
70
71 buf->start = MCTP_PKTBUF_BINDING_PAD;
72 buf->end = buf->start + len;
73 buf->mctp_hdr_off = buf->start;
74
75 return buf;
76}
77
78void mctp_pktbuf_free(struct mctp_pktbuf *pkt)
79{
80 __mctp_free(pkt);
81}
82
83struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt)
84{
85 return (void *)pkt->data + pkt->mctp_hdr_off;
86}
87
88void *mctp_pktbuf_data(struct mctp_pktbuf *pkt)
89{
90 return (void *)pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr);
91}
92
93uint8_t mctp_pktbuf_size(struct mctp_pktbuf *pkt)
94{
95 return pkt->end - pkt->start;
96}
97
98void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, uint8_t size)
99{
100 assert(size <= pkt->start);
101 pkt->start -= size;
102 return pkt->data + pkt->start;
103}
104
105void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, uint8_t size)
106{
107 void *buf;
108
109 assert(size < (MCTP_PKTBUF_SIZE - pkt->end));
110 buf = pkt->data + pkt->end;
111 pkt->end += size;
112 return buf;
113}
114
115int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, uint8_t len)
116{
117 void *p;
118
119 assert(pkt->end + len <= MCTP_PKTBUF_SIZE);
120
121 if (pkt->end + len > MCTP_PKTBUF_SIZE)
122 return -1;
123
124 p = pkt->data + pkt->end;
125
126 pkt->end += len;
127 memcpy(p, data, len);
128
129 return 0;
130}
131
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800132/* Message reassembly */
133static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp,
134 uint8_t src, uint8_t tag)
135{
136 unsigned int i;
137
138 /* @todo: better lookup, if we add support for more outstanding
139 * message contexts */
140 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
141 struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i];
142 if (ctx->src == src && ctx->tag == tag)
143 return ctx;
144 }
145
146 return NULL;
147}
148
149static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp,
150 uint8_t src, uint8_t tag)
151{
Jeremy Kerr11a234e2019-02-27 17:59:53 +0800152 struct mctp_msg_ctx *ctx = NULL;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800153 unsigned int i;
154
155 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
156 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
157 if (!tmp->src) {
158 ctx = tmp;
159 break;
160 }
161 }
162
163 if (!ctx)
164 return NULL;
165
166 ctx->src = src;
167 ctx->tag = tag;
168
169 return ctx;
170}
171
172static void mctp_msg_ctx_drop(struct mctp_msg_ctx *ctx)
173{
174 ctx->src = 0;
175}
176
177static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx)
178{
179 ctx->buf_size = 0;
180}
181
182static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx,
183 struct mctp_pktbuf *pkt)
184{
185 size_t len;
186
187 len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr);
188
189 if (ctx->buf_size + len > ctx->buf_alloc_size) {
190 size_t new_alloc_size;
191
192 /* @todo: finer-grained allocation, size limits */
193 if (!ctx->buf_alloc_size) {
194 new_alloc_size = 4096;
195 } else {
196 new_alloc_size = ctx->buf_alloc_size * 2;
197 }
198 ctx->buf = __mctp_realloc(ctx->buf, new_alloc_size);
199 ctx->buf_alloc_size = new_alloc_size;
200 }
201
202 memcpy(ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len);
203 ctx->buf_size += len;
204
205 return 0;
206}
207
208/* Core API functions */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800209struct mctp *mctp_init(void)
210{
211 struct mctp *mctp;
212
213 mctp = __mctp_alloc(sizeof(*mctp));
214 memset(mctp, 0, sizeof(*mctp));
215
216 return mctp;
217}
218
219int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data)
220{
221 mctp->message_rx = fn;
222 mctp->message_rx_data = data;
223 return 0;
224}
225
226static struct mctp_bus *find_bus_for_eid(struct mctp *mctp,
227 mctp_eid_t dest __attribute__((unused)))
228{
229 return &mctp->busses[0];
230}
231
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800232int mctp_register_bus(struct mctp *mctp,
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800233 struct mctp_binding *binding,
234 mctp_eid_t eid)
235{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800236 /* todo: multiple busses */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800237 assert(!mctp->busses[0].binding);
238 mctp->busses[0].binding = binding;
239 mctp->busses[0].eid = eid;
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800240 binding->bus = &mctp->busses[0];
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800241 binding->mctp = mctp;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800242 return 0;
243}
244
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800245void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800246{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800247 struct mctp_bus *bus = binding->bus;
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800248 struct mctp *mctp = binding->mctp;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800249 struct mctp_msg_ctx *ctx;
250 struct mctp_hdr *hdr;
251 uint8_t flags, seq, tag;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800252 size_t len;
253 void *p;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800254 int rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800255
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800256 assert(bus);
257
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800258 hdr = mctp_pktbuf_hdr(pkt);
259
260 if (hdr->dest != bus->eid)
261 /* @todo: non-local packet routing */
262 return;
263
264 flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
265 tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK;
266 seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK;
267
268 switch (flags) {
269 case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM:
270 /* single-packet message - send straight up to rx function,
271 * no need to create a message context */
272 len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr);
273 p = pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr),
Jeremy Kerra8ec7062019-03-06 09:03:54 +0800274 mctp->message_rx(hdr->src, mctp->message_rx_data, p, len);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800275 break;
276
277 case MCTP_HDR_FLAG_SOM:
278 /* start of a new message - start the new context for
279 * future message reception. If an existing context is
280 * already present, drop it. */
281 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, tag);
282 if (ctx) {
283 mctp_msg_ctx_reset(ctx);
284 } else {
285 ctx = mctp_msg_ctx_create(mctp, hdr->src, tag);
286 if (((ctx->last_seq + 1) % 4) != seq) {
287 mctp_msg_ctx_drop(ctx);
288 return;
289 }
290 }
291
292 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
293 if (rc) {
294 mctp_msg_ctx_drop(ctx);
295 } else {
296 ctx->last_seq = seq;
297 }
298
299 break;
300
301 case MCTP_HDR_FLAG_EOM:
302 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, tag);
303 if (!ctx)
304 return;
305
306 if (((ctx->last_seq + 1) % 4) != seq) {
307 mctp_msg_ctx_drop(ctx);
308 return;
309 }
310
311 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
312 if (!rc) {
313 mctp->message_rx(bus->eid, mctp->message_rx_data,
314 ctx->buf, ctx->buf_size);
315 }
316
317 mctp_msg_ctx_drop(ctx);
318 break;
319 }
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800320}
321
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800322static int mctp_packet_tx(struct mctp_bus *bus,
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800323 struct mctp_pktbuf *pkt)
324{
325 return bus->binding->tx(bus->binding, pkt);
326}
327
328int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
329 void *msg, size_t msg_len)
330{
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800331 struct mctp_pktbuf *pkt, *tmp;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800332 struct mctp_hdr *hdr;
333 struct mctp_bus *bus;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800334 size_t pkt_len, p;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800335
336 bus = find_bus_for_eid(mctp, eid);
337
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800338 /* queue up packets, each of max MCTP_MTU size */
339 for (p = 0; p < msg_len; ) {
340 pkt_len = msg_len - p;
341 if (pkt_len > MCTP_MTU)
342 pkt_len = MCTP_MTU;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800343
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800344 pkt = mctp_pktbuf_alloc(pkt_len + sizeof(*hdr));
345 hdr = mctp_pktbuf_hdr(pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800346
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800347 /* todo: tags */
348 hdr->ver = bus->binding->version & 0xf;
349 hdr->dest = eid;
350 hdr->src = bus->eid;
351 hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
352 MCTP_HDR_FLAG_EOM |
353 (0 << MCTP_HDR_SEQ_SHIFT) |
354 MCTP_HDR_FLAG_TO |
355 (0 << MCTP_HDR_TAG_SHIFT);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800356
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800357 memcpy(mctp_pktbuf_data(pkt), msg + p, pkt_len);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800358
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800359 /* add to tx queue */
360 if (mctp->tx_queue_tail)
361 mctp->tx_queue_tail->next = pkt;
362 else
363 mctp->tx_queue_head = pkt;
364 mctp->tx_queue_tail = pkt;
365
366 p += pkt_len;
367 }
368
369 /* send queued packets */
370 for (pkt = mctp->tx_queue_head; pkt;) {
371 mctp_prdebug("sending pkt, len %d",
372 mctp_pktbuf_size(pkt));
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800373 mctp_packet_tx(bus, pkt);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800374 tmp = pkt->next;
375 mctp_pktbuf_free(pkt);
376 pkt = tmp;
377 }
378
379 mctp->tx_queue_tail = NULL;
380 mctp->tx_queue_head = NULL;
381
382 return 0;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800383}