blob: ebad5f826793c260ad637f77f254590c065db1bb [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;
Jeremy Kerr1cd31182019-02-27 18:01:00 +080023 bool tx_enabled;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080024
Jeremy Kerrcc2458d2019-03-01 08:23:33 +080025 struct mctp_pktbuf *tx_queue_head;
26 struct mctp_pktbuf *tx_queue_tail;
27
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080028 /* todo: routing */
29};
30
Jeremy Kerr24db71f2019-02-07 21:37:35 +080031struct mctp_msg_ctx {
32 uint8_t src;
33 uint8_t tag;
34 uint8_t last_seq;
35 void *buf;
36 size_t buf_size;
37 size_t buf_alloc_size;
38};
39
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080040struct mctp {
41 /* todo: multiple busses */
42 struct mctp_bus busses[1];
43
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080044 /* Message RX callback */
45 mctp_rx_fn message_rx;
46 void *message_rx_data;
Jeremy Kerr24db71f2019-02-07 21:37:35 +080047
48 /* Message reassembly.
49 * @todo: flexible context count
50 */
51 struct mctp_msg_ctx msg_ctxs[16];
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080052};
53
54#ifndef BUILD_ASSERT
55#define BUILD_ASSERT(x) \
56 do { (void)sizeof(char[0-(!(x))]); } while (0)
57#endif
58
Jeremy Kerr24db71f2019-02-07 21:37:35 +080059#ifndef ARRAY_SIZE
60#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
61#endif
62
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080063struct mctp_pktbuf *mctp_pktbuf_alloc(uint8_t len)
64{
65 struct mctp_pktbuf *buf;
66
67 BUILD_ASSERT(MCTP_PKTBUF_SIZE <= 0xff);
68
69 /* todo: pools */
70 buf = __mctp_alloc(sizeof(*buf));
71
72 buf->start = MCTP_PKTBUF_BINDING_PAD;
73 buf->end = buf->start + len;
74 buf->mctp_hdr_off = buf->start;
75
76 return buf;
77}
78
79void mctp_pktbuf_free(struct mctp_pktbuf *pkt)
80{
81 __mctp_free(pkt);
82}
83
84struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt)
85{
86 return (void *)pkt->data + pkt->mctp_hdr_off;
87}
88
89void *mctp_pktbuf_data(struct mctp_pktbuf *pkt)
90{
91 return (void *)pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr);
92}
93
94uint8_t mctp_pktbuf_size(struct mctp_pktbuf *pkt)
95{
96 return pkt->end - pkt->start;
97}
98
99void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, uint8_t size)
100{
101 assert(size <= pkt->start);
102 pkt->start -= size;
103 return pkt->data + pkt->start;
104}
105
106void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, uint8_t size)
107{
108 void *buf;
109
110 assert(size < (MCTP_PKTBUF_SIZE - pkt->end));
111 buf = pkt->data + pkt->end;
112 pkt->end += size;
113 return buf;
114}
115
116int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, uint8_t len)
117{
118 void *p;
119
120 assert(pkt->end + len <= MCTP_PKTBUF_SIZE);
121
122 if (pkt->end + len > MCTP_PKTBUF_SIZE)
123 return -1;
124
125 p = pkt->data + pkt->end;
126
127 pkt->end += len;
128 memcpy(p, data, len);
129
130 return 0;
131}
132
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800133/* Message reassembly */
134static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp,
135 uint8_t src, uint8_t tag)
136{
137 unsigned int i;
138
139 /* @todo: better lookup, if we add support for more outstanding
140 * message contexts */
141 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
142 struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i];
143 if (ctx->src == src && ctx->tag == tag)
144 return ctx;
145 }
146
147 return NULL;
148}
149
150static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp,
151 uint8_t src, uint8_t tag)
152{
Jeremy Kerr11a234e2019-02-27 17:59:53 +0800153 struct mctp_msg_ctx *ctx = NULL;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800154 unsigned int i;
155
156 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
157 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
158 if (!tmp->src) {
159 ctx = tmp;
160 break;
161 }
162 }
163
164 if (!ctx)
165 return NULL;
166
167 ctx->src = src;
168 ctx->tag = tag;
169
170 return ctx;
171}
172
173static void mctp_msg_ctx_drop(struct mctp_msg_ctx *ctx)
174{
175 ctx->src = 0;
176}
177
178static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx)
179{
180 ctx->buf_size = 0;
181}
182
183static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx,
184 struct mctp_pktbuf *pkt)
185{
186 size_t len;
187
188 len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr);
189
190 if (ctx->buf_size + len > ctx->buf_alloc_size) {
191 size_t new_alloc_size;
192
193 /* @todo: finer-grained allocation, size limits */
194 if (!ctx->buf_alloc_size) {
195 new_alloc_size = 4096;
196 } else {
197 new_alloc_size = ctx->buf_alloc_size * 2;
198 }
199 ctx->buf = __mctp_realloc(ctx->buf, new_alloc_size);
200 ctx->buf_alloc_size = new_alloc_size;
201 }
202
203 memcpy(ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len);
204 ctx->buf_size += len;
205
206 return 0;
207}
208
209/* Core API functions */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800210struct mctp *mctp_init(void)
211{
212 struct mctp *mctp;
213
214 mctp = __mctp_alloc(sizeof(*mctp));
215 memset(mctp, 0, sizeof(*mctp));
216
217 return mctp;
218}
219
220int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data)
221{
222 mctp->message_rx = fn;
223 mctp->message_rx_data = data;
224 return 0;
225}
226
227static struct mctp_bus *find_bus_for_eid(struct mctp *mctp,
228 mctp_eid_t dest __attribute__((unused)))
229{
230 return &mctp->busses[0];
231}
232
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800233int mctp_register_bus(struct mctp *mctp,
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800234 struct mctp_binding *binding,
235 mctp_eid_t eid)
236{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800237 /* todo: multiple busses */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800238 assert(!mctp->busses[0].binding);
239 mctp->busses[0].binding = binding;
240 mctp->busses[0].eid = eid;
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800241 binding->bus = &mctp->busses[0];
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800242 binding->mctp = mctp;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800243 return 0;
244}
245
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800246void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800247{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800248 struct mctp_bus *bus = binding->bus;
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800249 struct mctp *mctp = binding->mctp;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800250 struct mctp_msg_ctx *ctx;
251 struct mctp_hdr *hdr;
252 uint8_t flags, seq, tag;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800253 size_t len;
254 void *p;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800255 int rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800256
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800257 assert(bus);
258
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800259 hdr = mctp_pktbuf_hdr(pkt);
260
261 if (hdr->dest != bus->eid)
262 /* @todo: non-local packet routing */
263 return;
264
265 flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
266 tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK;
267 seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK;
268
269 switch (flags) {
270 case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM:
271 /* single-packet message - send straight up to rx function,
272 * no need to create a message context */
273 len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr);
274 p = pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr),
Jeremy Kerra8ec7062019-03-06 09:03:54 +0800275 mctp->message_rx(hdr->src, mctp->message_rx_data, p, len);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800276 break;
277
278 case MCTP_HDR_FLAG_SOM:
279 /* start of a new message - start the new context for
280 * future message reception. If an existing context is
281 * already present, drop it. */
282 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, tag);
283 if (ctx) {
284 mctp_msg_ctx_reset(ctx);
285 } else {
286 ctx = mctp_msg_ctx_create(mctp, hdr->src, tag);
287 if (((ctx->last_seq + 1) % 4) != seq) {
288 mctp_msg_ctx_drop(ctx);
289 return;
290 }
291 }
292
293 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
294 if (rc) {
295 mctp_msg_ctx_drop(ctx);
296 } else {
297 ctx->last_seq = seq;
298 }
299
300 break;
301
302 case MCTP_HDR_FLAG_EOM:
303 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, tag);
304 if (!ctx)
305 return;
306
307 if (((ctx->last_seq + 1) % 4) != seq) {
308 mctp_msg_ctx_drop(ctx);
309 return;
310 }
311
312 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
313 if (!rc) {
314 mctp->message_rx(bus->eid, mctp->message_rx_data,
315 ctx->buf, ctx->buf_size);
316 }
317
318 mctp_msg_ctx_drop(ctx);
319 break;
320 }
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800321}
322
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800323static int mctp_packet_tx(struct mctp_bus *bus,
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800324 struct mctp_pktbuf *pkt)
325{
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800326 if (!bus->tx_enabled)
327 return -1;
328
329 mctp_prdebug("sending pkt, len %d",
330 mctp_pktbuf_size(pkt));
331
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800332 return bus->binding->tx(bus->binding, pkt);
333}
334
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800335static void mctp_send_tx_queue(struct mctp_bus *bus)
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800336{
337 struct mctp_pktbuf *pkt;
338
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800339 while ((pkt = bus->tx_queue_head)) {
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800340 int rc;
341
342 rc = mctp_packet_tx(bus, pkt);
343 if (rc)
344 break;
345
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800346 bus->tx_queue_head = pkt->next;
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800347 mctp_pktbuf_free(pkt);
348 }
349
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800350 if (!bus->tx_queue_head)
351 bus->tx_queue_tail = NULL;
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800352
353}
354
355void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable)
356{
357 struct mctp_bus *bus = binding->bus;
358 bus->tx_enabled = enable;
359 if (enable)
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800360 mctp_send_tx_queue(bus);
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800361}
362
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800363int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
364 void *msg, size_t msg_len)
365{
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800366 struct mctp_pktbuf *pkt;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800367 struct mctp_hdr *hdr;
368 struct mctp_bus *bus;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800369 size_t pkt_len, p;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800370
371 bus = find_bus_for_eid(mctp, eid);
372
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800373 /* queue up packets, each of max MCTP_MTU size */
374 for (p = 0; p < msg_len; ) {
375 pkt_len = msg_len - p;
376 if (pkt_len > MCTP_MTU)
377 pkt_len = MCTP_MTU;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800378
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800379 pkt = mctp_pktbuf_alloc(pkt_len + sizeof(*hdr));
380 hdr = mctp_pktbuf_hdr(pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800381
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800382 /* todo: tags */
383 hdr->ver = bus->binding->version & 0xf;
384 hdr->dest = eid;
385 hdr->src = bus->eid;
386 hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
387 MCTP_HDR_FLAG_EOM |
388 (0 << MCTP_HDR_SEQ_SHIFT) |
389 MCTP_HDR_FLAG_TO |
390 (0 << MCTP_HDR_TAG_SHIFT);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800391
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800392 memcpy(mctp_pktbuf_data(pkt), msg + p, pkt_len);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800393
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800394 /* add to tx queue */
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800395 if (bus->tx_queue_tail)
396 bus->tx_queue_tail->next = pkt;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800397 else
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800398 bus->tx_queue_head = pkt;
399 bus->tx_queue_tail = pkt;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800400
401 p += pkt_len;
402 }
403
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800404 mctp_send_tx_queue(bus);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800405
406 return 0;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800407}