blob: 0a5a13543076918f87b26efca17a383269a0862a [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{
152 struct mctp_msg_ctx *ctx;
153 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
232unsigned long mctp_register_bus(struct mctp *mctp,
233 struct mctp_binding *binding,
234 mctp_eid_t eid)
235{
236 assert(!mctp->busses[0].binding);
237 mctp->busses[0].binding = binding;
238 mctp->busses[0].eid = eid;
239 return 0;
240}
241
242void mctp_bus_rx(struct mctp *mctp, unsigned long bus_id,
243 struct mctp_pktbuf *pkt)
244{
245 struct mctp_bus *bus = &mctp->busses[bus_id];
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800246 struct mctp_msg_ctx *ctx;
247 struct mctp_hdr *hdr;
248 uint8_t flags, seq, tag;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800249 size_t len;
250 void *p;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800251 int rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800252
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800253 hdr = mctp_pktbuf_hdr(pkt);
254
255 if (hdr->dest != bus->eid)
256 /* @todo: non-local packet routing */
257 return;
258
259 flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
260 tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK;
261 seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK;
262
263 switch (flags) {
264 case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM:
265 /* single-packet message - send straight up to rx function,
266 * no need to create a message context */
267 len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr);
268 p = pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr),
269 mctp->message_rx(bus->eid, mctp->message_rx_data, p, len);
270 break;
271
272 case MCTP_HDR_FLAG_SOM:
273 /* start of a new message - start the new context for
274 * future message reception. If an existing context is
275 * already present, drop it. */
276 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, tag);
277 if (ctx) {
278 mctp_msg_ctx_reset(ctx);
279 } else {
280 ctx = mctp_msg_ctx_create(mctp, hdr->src, tag);
281 if (((ctx->last_seq + 1) % 4) != seq) {
282 mctp_msg_ctx_drop(ctx);
283 return;
284 }
285 }
286
287 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
288 if (rc) {
289 mctp_msg_ctx_drop(ctx);
290 } else {
291 ctx->last_seq = seq;
292 }
293
294 break;
295
296 case MCTP_HDR_FLAG_EOM:
297 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, tag);
298 if (!ctx)
299 return;
300
301 if (((ctx->last_seq + 1) % 4) != seq) {
302 mctp_msg_ctx_drop(ctx);
303 return;
304 }
305
306 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
307 if (!rc) {
308 mctp->message_rx(bus->eid, mctp->message_rx_data,
309 ctx->buf, ctx->buf_size);
310 }
311
312 mctp_msg_ctx_drop(ctx);
313 break;
314 }
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800315}
316
317static int mctp_packet_tx(struct mctp *mctp __attribute__((unused)),
318 struct mctp_bus *bus,
319 struct mctp_pktbuf *pkt)
320{
321 return bus->binding->tx(bus->binding, pkt);
322}
323
324int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
325 void *msg, size_t msg_len)
326{
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800327 struct mctp_pktbuf *pkt, *tmp;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800328 struct mctp_hdr *hdr;
329 struct mctp_bus *bus;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800330 size_t pkt_len, p;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800331
332 bus = find_bus_for_eid(mctp, eid);
333
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800334 /* queue up packets, each of max MCTP_MTU size */
335 for (p = 0; p < msg_len; ) {
336 pkt_len = msg_len - p;
337 if (pkt_len > MCTP_MTU)
338 pkt_len = MCTP_MTU;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800339
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800340 pkt = mctp_pktbuf_alloc(pkt_len + sizeof(*hdr));
341 hdr = mctp_pktbuf_hdr(pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800342
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800343 /* todo: tags */
344 hdr->ver = bus->binding->version & 0xf;
345 hdr->dest = eid;
346 hdr->src = bus->eid;
347 hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
348 MCTP_HDR_FLAG_EOM |
349 (0 << MCTP_HDR_SEQ_SHIFT) |
350 MCTP_HDR_FLAG_TO |
351 (0 << MCTP_HDR_TAG_SHIFT);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800352
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800353 memcpy(mctp_pktbuf_data(pkt), msg + p, pkt_len);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800354
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800355 /* add to tx queue */
356 if (mctp->tx_queue_tail)
357 mctp->tx_queue_tail->next = pkt;
358 else
359 mctp->tx_queue_head = pkt;
360 mctp->tx_queue_tail = pkt;
361
362 p += pkt_len;
363 }
364
365 /* send queued packets */
366 for (pkt = mctp->tx_queue_head; pkt;) {
367 mctp_prdebug("sending pkt, len %d",
368 mctp_pktbuf_size(pkt));
369 mctp_packet_tx(mctp, bus, pkt);
370 tmp = pkt->next;
371 mctp_pktbuf_free(pkt);
372 pkt = tmp;
373 }
374
375 mctp->tx_queue_tail = NULL;
376 mctp->tx_queue_head = NULL;
377
378 return 0;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800379}