blob: a46a733355dfe2e0c3f2915ce6013a48c988d29e [file] [log] [blame]
Jeremy Kerr3d36ee22019-05-30 11:15:37 +08001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +08002
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"
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +010017#include "libmctp-cmds.h"
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080018
19/* Internal data structures */
20
21struct mctp_bus {
22 mctp_eid_t eid;
23 struct mctp_binding *binding;
Jeremy Kerr1cd31182019-02-27 18:01:00 +080024 bool tx_enabled;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080025
Jeremy Kerrcc2458d2019-03-01 08:23:33 +080026 struct mctp_pktbuf *tx_queue_head;
27 struct mctp_pktbuf *tx_queue_tail;
28
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080029 /* todo: routing */
30};
31
Jeremy Kerr24db71f2019-02-07 21:37:35 +080032struct mctp_msg_ctx {
33 uint8_t src;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +080034 uint8_t dest;
Jeremy Kerr24db71f2019-02-07 21:37:35 +080035 uint8_t tag;
36 uint8_t last_seq;
37 void *buf;
38 size_t buf_size;
39 size_t buf_alloc_size;
40};
41
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080042struct mctp {
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +080043 int n_busses;
44 struct mctp_bus *busses;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080045
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080046 /* Message RX callback */
47 mctp_rx_fn message_rx;
48 void *message_rx_data;
Jeremy Kerr24db71f2019-02-07 21:37:35 +080049
50 /* Message reassembly.
51 * @todo: flexible context count
52 */
53 struct mctp_msg_ctx msg_ctxs[16];
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +080054
55 enum {
56 ROUTE_ENDPOINT,
57 ROUTE_BRIDGE,
58 } route_policy;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080059};
60
61#ifndef BUILD_ASSERT
62#define BUILD_ASSERT(x) \
63 do { (void)sizeof(char[0-(!(x))]); } while (0)
64#endif
65
Jeremy Kerr24db71f2019-02-07 21:37:35 +080066#ifndef ARRAY_SIZE
67#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
68#endif
69
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +080070static int mctp_message_tx_on_bus(struct mctp *mctp, struct mctp_bus *bus,
71 mctp_eid_t src, mctp_eid_t dest, void *msg, size_t msg_len);
72
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +080073struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080074{
75 struct mctp_pktbuf *buf;
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +080076 size_t size;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080077
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +080078 size = binding->pkt_size + binding->pkt_pad;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080079
80 /* todo: pools */
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +080081 buf = __mctp_alloc(sizeof(*buf) + size);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080082
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +080083 buf->size = size;
84 buf->start = binding->pkt_pad;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080085 buf->end = buf->start + len;
86 buf->mctp_hdr_off = buf->start;
Jeremy Kerrdd109f12019-04-04 11:46:49 +080087 buf->next = NULL;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080088
89 return buf;
90}
91
92void mctp_pktbuf_free(struct mctp_pktbuf *pkt)
93{
94 __mctp_free(pkt);
95}
96
97struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt)
98{
99 return (void *)pkt->data + pkt->mctp_hdr_off;
100}
101
102void *mctp_pktbuf_data(struct mctp_pktbuf *pkt)
103{
104 return (void *)pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr);
105}
106
107uint8_t mctp_pktbuf_size(struct mctp_pktbuf *pkt)
108{
109 return pkt->end - pkt->start;
110}
111
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800112void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800113{
114 assert(size <= pkt->start);
115 pkt->start -= size;
116 return pkt->data + pkt->start;
117}
118
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800119void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800120{
121 void *buf;
122
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800123 assert(size < (pkt->size - pkt->end));
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800124 buf = pkt->data + pkt->end;
125 pkt->end += size;
126 return buf;
127}
128
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800129int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, size_t len)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800130{
131 void *p;
132
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800133 if (pkt->end + len > pkt->size)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800134 return -1;
135
136 p = pkt->data + pkt->end;
137
138 pkt->end += len;
139 memcpy(p, data, len);
140
141 return 0;
142}
143
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800144/* Message reassembly */
145static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp,
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800146 uint8_t src, uint8_t dest, uint8_t tag)
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800147{
148 unsigned int i;
149
150 /* @todo: better lookup, if we add support for more outstanding
151 * message contexts */
152 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
153 struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i];
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800154 if (ctx->src == src && ctx->dest == dest && ctx->tag == tag)
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800155 return ctx;
156 }
157
158 return NULL;
159}
160
161static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp,
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800162 uint8_t src, uint8_t dest, uint8_t tag)
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800163{
Jeremy Kerr11a234e2019-02-27 17:59:53 +0800164 struct mctp_msg_ctx *ctx = NULL;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800165 unsigned int i;
166
167 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
168 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
169 if (!tmp->src) {
170 ctx = tmp;
171 break;
172 }
173 }
174
175 if (!ctx)
176 return NULL;
177
178 ctx->src = src;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800179 ctx->dest = dest;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800180 ctx->tag = tag;
Jeremy Kerr9a3da812019-08-02 15:57:53 +0800181 ctx->buf_size = 0;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800182
183 return ctx;
184}
185
186static void mctp_msg_ctx_drop(struct mctp_msg_ctx *ctx)
187{
188 ctx->src = 0;
189}
190
191static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx)
192{
193 ctx->buf_size = 0;
194}
195
196static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx,
197 struct mctp_pktbuf *pkt)
198{
199 size_t len;
200
201 len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr);
202
203 if (ctx->buf_size + len > ctx->buf_alloc_size) {
204 size_t new_alloc_size;
Andrew Jeffery00ecc6c2020-03-10 23:16:53 +1030205 void *lbuf;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800206
207 /* @todo: finer-grained allocation, size limits */
208 if (!ctx->buf_alloc_size) {
209 new_alloc_size = 4096;
210 } else {
211 new_alloc_size = ctx->buf_alloc_size * 2;
212 }
Andrew Jeffery00ecc6c2020-03-10 23:16:53 +1030213
214 lbuf = __mctp_realloc(ctx->buf, new_alloc_size);
215 if (lbuf) {
216 ctx->buf = lbuf;
217 ctx->buf_alloc_size = new_alloc_size;
218 } else {
219 __mctp_free(ctx->buf);
220 return -1;
221 }
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800222 }
223
224 memcpy(ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len);
225 ctx->buf_size += len;
226
227 return 0;
228}
229
230/* Core API functions */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800231struct mctp *mctp_init(void)
232{
233 struct mctp *mctp;
234
235 mctp = __mctp_alloc(sizeof(*mctp));
236 memset(mctp, 0, sizeof(*mctp));
237
238 return mctp;
239}
240
Andrew Jefferyfa56ca52020-03-10 23:18:22 +1030241void mctp_destroy(struct mctp *mctp)
242{
243 int i;
244
245 /* Cleanup message assembly contexts */
246 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
247 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
248 if (tmp->buf)
249 __mctp_free(tmp->buf);
250 }
251
252 __mctp_free(mctp->busses);
253 __mctp_free(mctp);
254}
255
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800256int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data)
257{
258 mctp->message_rx = fn;
259 mctp->message_rx_data = data;
260 return 0;
261}
262
263static struct mctp_bus *find_bus_for_eid(struct mctp *mctp,
264 mctp_eid_t dest __attribute__((unused)))
265{
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800266 /* for now, just use the first bus. For full routing support,
267 * we will need a table of neighbours */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800268 return &mctp->busses[0];
269}
270
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800271int mctp_register_bus(struct mctp *mctp,
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800272 struct mctp_binding *binding,
273 mctp_eid_t eid)
274{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800275 /* todo: multiple busses */
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800276 assert(mctp->n_busses == 0);
277 mctp->n_busses = 1;
278 mctp->busses = __mctp_alloc(sizeof(struct mctp_bus));
James Feist62d72362019-12-13 13:43:32 -0800279 memset(mctp->busses, 0, sizeof(struct mctp_bus));
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800280 mctp->busses[0].binding = binding;
281 mctp->busses[0].eid = eid;
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800282 binding->bus = &mctp->busses[0];
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800283 binding->mctp = mctp;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800284 mctp->route_policy = ROUTE_ENDPOINT;
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800285
286 if (binding->start)
Andrew Jeffery0dc13752020-05-23 21:23:15 +0930287 return binding->start(binding);
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800288
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800289 return 0;
290}
291
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800292int mctp_bridge_busses(struct mctp *mctp,
293 struct mctp_binding *b1, struct mctp_binding *b2)
294{
295 assert(mctp->n_busses == 0);
296 mctp->busses = __mctp_alloc(2 * sizeof(struct mctp_bus));
James Feist62d72362019-12-13 13:43:32 -0800297 memset(mctp->busses, 0, 2 * sizeof(struct mctp_bus));
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800298 mctp->n_busses = 2;
299 mctp->busses[0].binding = b1;
300 b1->bus = &mctp->busses[0];
301 b1->mctp = mctp;
302 mctp->busses[1].binding = b2;
303 b2->bus = &mctp->busses[1];
304 b2->mctp = mctp;
305
306 mctp->route_policy = ROUTE_BRIDGE;
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800307
308 if (b1->start)
309 b1->start(b1);
310
311 if (b2->start)
312 b2->start(b2);
313
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800314 return 0;
315}
316
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100317static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr)
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800318{
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100319 return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) &&
320 (hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT));
321}
322
323static bool mctp_ctrl_handle_msg(struct mctp *mctp, struct mctp_bus *bus,
324 mctp_eid_t src, mctp_eid_t dest, void *buffer,
325 size_t length)
326{
327 struct mctp_ctrl_msg_hdr *msg_hdr = buffer;
328
329 /*
330 * Control message is received. If a transport control message handler
331 * is provided, it will called. If there is no dedicated handler, this
332 * function returns false and data can be handled by the generic
333 * message handler. The transport control message handler will be
334 * provided with messages in the command range 0xF0 - 0xFF.
335 */
336 if (mctp_ctrl_cmd_is_transport(msg_hdr)) {
337 if (bus->binding->control_rx != NULL) {
338 /* MCTP bus binding handler */
339 bus->binding->control_rx(src,
340 bus->binding->control_rx_data,
341 buffer, length);
342 return true;
343 }
344 }
345
346 /*
347 * Command was not handled, due to lack of specific callback.
348 * It will be passed to regular message_rx handler.
349 */
350 return false;
351}
352
353static inline bool mctp_rx_dest_is_local(struct mctp_bus *bus, mctp_eid_t dest)
354{
355 return dest == bus->eid || dest == MCTP_EID_NULL ||
356 dest == MCTP_EID_BROADCAST;
357}
358
359static inline bool mctp_ctrl_cmd_is_request(struct mctp_ctrl_msg_hdr *hdr)
360{
361 return hdr->ic_msg_type == MCTP_CTRL_HDR_MSG_TYPE &&
362 hdr->rq_dgram_inst & MCTP_CTRL_HDR_FLAG_REQUEST;
363}
364
365/*
366 * Receive the complete MCTP message and route it.
367 * Asserts:
368 * 'buf' is not NULL.
369 */
370static void mctp_rx(struct mctp *mctp, struct mctp_bus *bus, mctp_eid_t src,
371 mctp_eid_t dest, void *buf, size_t len)
372{
373 assert(buf != NULL);
374
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800375 if (mctp->route_policy == ROUTE_ENDPOINT &&
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100376 mctp_rx_dest_is_local(bus, dest)) {
377 /* Handle MCTP Control Messages: */
378 if (len >= sizeof(struct mctp_ctrl_msg_hdr)) {
379 struct mctp_ctrl_msg_hdr *msg_hdr = buf;
380
381 /*
382 * Identify if this is a control request message.
383 * See DSP0236 v1.3.0 sec. 11.5.
384 */
385 if (mctp_ctrl_cmd_is_request(msg_hdr)) {
386 bool handled;
387 handled = mctp_ctrl_handle_msg(mctp, bus, src,
388 dest, buf, len);
389 if (handled)
390 return;
391 }
392 }
393 if (mctp->message_rx)
394 mctp->message_rx(src, mctp->message_rx_data, buf, len);
395 }
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800396
397 if (mctp->route_policy == ROUTE_BRIDGE) {
398 int i;
399
400 for (i = 0; i < mctp->n_busses; i++) {
401 struct mctp_bus *dest_bus = &mctp->busses[i];
402 if (dest_bus == bus)
403 continue;
404
405 mctp_message_tx_on_bus(mctp, dest_bus,
406 src, dest, buf, len);
407 }
408
409 }
410}
411
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800412void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800413{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800414 struct mctp_bus *bus = binding->bus;
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800415 struct mctp *mctp = binding->mctp;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800416 uint8_t flags, exp_seq, seq, tag;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800417 struct mctp_msg_ctx *ctx;
418 struct mctp_hdr *hdr;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800419 size_t len;
420 void *p;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800421 int rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800422
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800423 assert(bus);
424
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800425 hdr = mctp_pktbuf_hdr(pkt);
426
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800427 /* small optimisation: don't bother reassembly if we're going to
428 * drop the packet in mctp_rx anyway */
429 if (mctp->route_policy == ROUTE_ENDPOINT && hdr->dest != bus->eid)
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800430 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800431
432 flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
433 tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK;
434 seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK;
435
436 switch (flags) {
437 case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM:
438 /* single-packet message - send straight up to rx function,
439 * no need to create a message context */
440 len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr);
441 p = pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr),
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800442 mctp_rx(mctp, bus, hdr->src, hdr->dest, p, len);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800443 break;
444
445 case MCTP_HDR_FLAG_SOM:
446 /* start of a new message - start the new context for
447 * future message reception. If an existing context is
448 * already present, drop it. */
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800449 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800450 if (ctx) {
451 mctp_msg_ctx_reset(ctx);
452 } else {
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800453 ctx = mctp_msg_ctx_create(mctp,
454 hdr->src, hdr->dest, tag);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800455 }
456
457 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
458 if (rc) {
459 mctp_msg_ctx_drop(ctx);
460 } else {
461 ctx->last_seq = seq;
462 }
463
464 break;
465
466 case MCTP_HDR_FLAG_EOM:
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800467 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800468 if (!ctx)
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800469 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800470
Ed Tanousc2def9f2019-02-21 08:33:08 -0800471 exp_seq = (ctx->last_seq + 1) % 4;
472
473 if (exp_seq != seq) {
474 mctp_prdebug(
475 "Sequence number %d does not match expected %d",
476 seq, exp_seq);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800477 mctp_msg_ctx_drop(ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800478 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800479 }
480
481 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800482 if (!rc)
483 mctp_rx(mctp, bus, ctx->src, ctx->dest,
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800484 ctx->buf, ctx->buf_size);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800485
486 mctp_msg_ctx_drop(ctx);
487 break;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800488
489 case 0:
490 /* Neither SOM nor EOM */
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800491 ctx = mctp_msg_ctx_lookup(mctp, hdr->src,hdr->dest, tag);
Ed Tanousc2def9f2019-02-21 08:33:08 -0800492 if (!ctx)
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800493 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800494
495 exp_seq = (ctx->last_seq + 1) % 4;
496 if (exp_seq != seq) {
497 mctp_prdebug(
498 "Sequence number %d does not match expected %d",
499 seq, exp_seq);
500 mctp_msg_ctx_drop(ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800501 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800502 }
503
504 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
505 if (rc) {
506 mctp_msg_ctx_drop(ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800507 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800508 }
509 ctx->last_seq = seq;
510
511 break;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800512 }
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800513out:
514 mctp_pktbuf_free(pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800515}
516
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800517static int mctp_packet_tx(struct mctp_bus *bus,
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800518 struct mctp_pktbuf *pkt)
519{
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800520 if (!bus->tx_enabled)
521 return -1;
522
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800523 return bus->binding->tx(bus->binding, pkt);
524}
525
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800526static void mctp_send_tx_queue(struct mctp_bus *bus)
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800527{
528 struct mctp_pktbuf *pkt;
529
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800530 while ((pkt = bus->tx_queue_head)) {
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800531 int rc;
532
533 rc = mctp_packet_tx(bus, pkt);
534 if (rc)
535 break;
536
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800537 bus->tx_queue_head = pkt->next;
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800538 mctp_pktbuf_free(pkt);
539 }
540
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800541 if (!bus->tx_queue_head)
542 bus->tx_queue_tail = NULL;
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800543
544}
545
546void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable)
547{
548 struct mctp_bus *bus = binding->bus;
549 bus->tx_enabled = enable;
550 if (enable)
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800551 mctp_send_tx_queue(bus);
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800552}
553
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800554static int mctp_message_tx_on_bus(struct mctp *mctp, struct mctp_bus *bus,
555 mctp_eid_t src, mctp_eid_t dest, void *msg, size_t msg_len)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800556{
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800557 size_t max_payload_len, payload_len, p;
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800558 struct mctp_pktbuf *pkt;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800559 struct mctp_hdr *hdr;
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800560 int i;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800561
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800562 max_payload_len = bus->binding->pkt_size - sizeof(*hdr);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800563
Andrew Jeffery298865f2020-02-06 11:51:29 +1030564 mctp_prdebug("%s: Generating packets for transmission of %zu byte message from %hhu to %hhu",
565 __func__, msg_len, src, dest);
566
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800567 /* queue up packets, each of max MCTP_MTU size */
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800568 for (p = 0, i = 0; p < msg_len; i++) {
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800569 payload_len = msg_len - p;
570 if (payload_len > max_payload_len)
571 payload_len = max_payload_len;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800572
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800573 pkt = mctp_pktbuf_alloc(bus->binding,
574 payload_len + sizeof(*hdr));
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800575 hdr = mctp_pktbuf_hdr(pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800576
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800577 /* todo: tags */
578 hdr->ver = bus->binding->version & 0xf;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800579 hdr->dest = dest;
580 hdr->src = src;
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800581 hdr->flags_seq_tag = MCTP_HDR_FLAG_TO |
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800582 (0 << MCTP_HDR_TAG_SHIFT);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800583
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800584 if (i == 0)
585 hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM;
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800586 if (p + payload_len >= msg_len)
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800587 hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM;
588 hdr->flags_seq_tag |=
589 (i & MCTP_HDR_SEQ_MASK) << MCTP_HDR_SEQ_SHIFT;
590
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800591 memcpy(mctp_pktbuf_data(pkt), msg + p, payload_len);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800592
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800593 /* add to tx queue */
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800594 if (bus->tx_queue_tail)
595 bus->tx_queue_tail->next = pkt;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800596 else
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800597 bus->tx_queue_head = pkt;
598 bus->tx_queue_tail = pkt;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800599
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800600 p += payload_len;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800601 }
602
Andrew Jeffery298865f2020-02-06 11:51:29 +1030603 mctp_prdebug("%s: Enqueued %d packets", __func__, i);
604
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800605 mctp_send_tx_queue(bus);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800606
607 return 0;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800608}
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800609
610int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
611 void *msg, size_t msg_len)
612{
613 struct mctp_bus *bus;
614
615 bus = find_bus_for_eid(mctp, eid);
616 return mctp_message_tx_on_bus(mctp, bus, bus->eid, eid, msg, msg_len);
617}