blob: 95c38aabed1a36458de8dd7416b5f15319334ed4 [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
Andrew Jefferyb93b6112020-06-05 14:13:44 +093070static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src,
71 mctp_eid_t dest, void *msg, size_t msg_len);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +080072
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{
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930243 size_t i;
Andrew Jefferyfa56ca52020-03-10 23:18:22 +1030244
245 /* Cleanup message assembly contexts */
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930246 BUILD_ASSERT(ARRAY_SIZE(mctp->msg_ctxs) < SIZE_MAX);
Andrew Jefferyfa56ca52020-03-10 23:18:22 +1030247 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
248 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
249 if (tmp->buf)
250 __mctp_free(tmp->buf);
251 }
252
253 __mctp_free(mctp->busses);
254 __mctp_free(mctp);
255}
256
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800257int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data)
258{
259 mctp->message_rx = fn;
260 mctp->message_rx_data = data;
261 return 0;
262}
263
264static struct mctp_bus *find_bus_for_eid(struct mctp *mctp,
265 mctp_eid_t dest __attribute__((unused)))
266{
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800267 /* for now, just use the first bus. For full routing support,
268 * we will need a table of neighbours */
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800269 return &mctp->busses[0];
270}
271
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800272int mctp_register_bus(struct mctp *mctp,
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800273 struct mctp_binding *binding,
274 mctp_eid_t eid)
275{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800276 /* todo: multiple busses */
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800277 assert(mctp->n_busses == 0);
278 mctp->n_busses = 1;
279 mctp->busses = __mctp_alloc(sizeof(struct mctp_bus));
James Feist62d72362019-12-13 13:43:32 -0800280 memset(mctp->busses, 0, sizeof(struct mctp_bus));
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800281 mctp->busses[0].binding = binding;
282 mctp->busses[0].eid = eid;
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800283 binding->bus = &mctp->busses[0];
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800284 binding->mctp = mctp;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800285 mctp->route_policy = ROUTE_ENDPOINT;
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800286
287 if (binding->start)
Andrew Jeffery0dc13752020-05-23 21:23:15 +0930288 return binding->start(binding);
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800289
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800290 return 0;
291}
292
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800293int mctp_bridge_busses(struct mctp *mctp,
294 struct mctp_binding *b1, struct mctp_binding *b2)
295{
296 assert(mctp->n_busses == 0);
297 mctp->busses = __mctp_alloc(2 * sizeof(struct mctp_bus));
James Feist62d72362019-12-13 13:43:32 -0800298 memset(mctp->busses, 0, 2 * sizeof(struct mctp_bus));
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800299 mctp->n_busses = 2;
300 mctp->busses[0].binding = b1;
301 b1->bus = &mctp->busses[0];
302 b1->mctp = mctp;
303 mctp->busses[1].binding = b2;
304 b2->bus = &mctp->busses[1];
305 b2->mctp = mctp;
306
307 mctp->route_policy = ROUTE_BRIDGE;
Jeremy Kerr3b36d172019-09-04 11:56:09 +0800308
309 if (b1->start)
310 b1->start(b1);
311
312 if (b2->start)
313 b2->start(b2);
314
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800315 return 0;
316}
317
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100318static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr)
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800319{
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100320 return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) &&
321 (hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT));
322}
323
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930324static bool mctp_ctrl_handle_msg(struct mctp_bus *bus, mctp_eid_t src,
325 void *buffer, size_t length)
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100326{
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;
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930387 handled = mctp_ctrl_handle_msg(bus, src, buf,
388 len);
Wiktor GoĊ‚gowskiba6727e2020-03-13 18:25:01 +0100389 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
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930405 mctp_message_tx_on_bus(dest_bus, src, dest, buf, len);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800406 }
407
408 }
409}
410
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800411void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800412{
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800413 struct mctp_bus *bus = binding->bus;
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800414 struct mctp *mctp = binding->mctp;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800415 uint8_t flags, exp_seq, seq, tag;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800416 struct mctp_msg_ctx *ctx;
417 struct mctp_hdr *hdr;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800418 size_t len;
419 void *p;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800420 int rc;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800421
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800422 assert(bus);
423
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800424 hdr = mctp_pktbuf_hdr(pkt);
425
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800426 /* small optimisation: don't bother reassembly if we're going to
427 * drop the packet in mctp_rx anyway */
428 if (mctp->route_policy == ROUTE_ENDPOINT && hdr->dest != bus->eid)
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800429 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800430
431 flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
432 tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK;
433 seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK;
434
435 switch (flags) {
436 case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM:
437 /* single-packet message - send straight up to rx function,
438 * no need to create a message context */
439 len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr);
440 p = pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr),
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800441 mctp_rx(mctp, bus, hdr->src, hdr->dest, p, len);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800442 break;
443
444 case MCTP_HDR_FLAG_SOM:
445 /* start of a new message - start the new context for
446 * future message reception. If an existing context is
447 * already present, drop it. */
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800448 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800449 if (ctx) {
450 mctp_msg_ctx_reset(ctx);
451 } else {
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800452 ctx = mctp_msg_ctx_create(mctp,
453 hdr->src, hdr->dest, tag);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800454 }
455
456 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
457 if (rc) {
458 mctp_msg_ctx_drop(ctx);
459 } else {
460 ctx->last_seq = seq;
461 }
462
463 break;
464
465 case MCTP_HDR_FLAG_EOM:
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800466 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800467 if (!ctx)
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800468 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800469
Ed Tanousc2def9f2019-02-21 08:33:08 -0800470 exp_seq = (ctx->last_seq + 1) % 4;
471
472 if (exp_seq != seq) {
473 mctp_prdebug(
474 "Sequence number %d does not match expected %d",
475 seq, exp_seq);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800476 mctp_msg_ctx_drop(ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800477 goto out;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800478 }
479
480 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800481 if (!rc)
482 mctp_rx(mctp, bus, ctx->src, ctx->dest,
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800483 ctx->buf, ctx->buf_size);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800484
485 mctp_msg_ctx_drop(ctx);
486 break;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800487
488 case 0:
489 /* Neither SOM nor EOM */
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800490 ctx = mctp_msg_ctx_lookup(mctp, hdr->src,hdr->dest, tag);
Ed Tanousc2def9f2019-02-21 08:33:08 -0800491 if (!ctx)
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800492 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800493
494 exp_seq = (ctx->last_seq + 1) % 4;
495 if (exp_seq != seq) {
496 mctp_prdebug(
497 "Sequence number %d does not match expected %d",
498 seq, exp_seq);
499 mctp_msg_ctx_drop(ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800500 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800501 }
502
503 rc = mctp_msg_ctx_add_pkt(ctx, pkt);
504 if (rc) {
505 mctp_msg_ctx_drop(ctx);
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800506 goto out;
Ed Tanousc2def9f2019-02-21 08:33:08 -0800507 }
508 ctx->last_seq = seq;
509
510 break;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800511 }
Jeremy Kerrc1693af2019-08-05 14:30:59 +0800512out:
513 mctp_pktbuf_free(pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800514}
515
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800516static int mctp_packet_tx(struct mctp_bus *bus,
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800517 struct mctp_pktbuf *pkt)
518{
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800519 if (!bus->tx_enabled)
520 return -1;
521
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800522 return bus->binding->tx(bus->binding, pkt);
523}
524
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800525static void mctp_send_tx_queue(struct mctp_bus *bus)
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800526{
527 struct mctp_pktbuf *pkt;
528
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800529 while ((pkt = bus->tx_queue_head)) {
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800530 int rc;
531
532 rc = mctp_packet_tx(bus, pkt);
533 if (rc)
534 break;
535
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800536 bus->tx_queue_head = pkt->next;
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800537 mctp_pktbuf_free(pkt);
538 }
539
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800540 if (!bus->tx_queue_head)
541 bus->tx_queue_tail = NULL;
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800542
543}
544
545void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable)
546{
547 struct mctp_bus *bus = binding->bus;
548 bus->tx_enabled = enable;
549 if (enable)
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800550 mctp_send_tx_queue(bus);
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800551}
552
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930553static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src,
554 mctp_eid_t dest, void *msg, size_t msg_len)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800555{
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800556 size_t max_payload_len, payload_len, p;
Jeremy Kerr1cd31182019-02-27 18:01:00 +0800557 struct mctp_pktbuf *pkt;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800558 struct mctp_hdr *hdr;
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800559 int i;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800560
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800561 max_payload_len = bus->binding->pkt_size - sizeof(*hdr);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800562
Andrew Jeffery298865f2020-02-06 11:51:29 +1030563 mctp_prdebug("%s: Generating packets for transmission of %zu byte message from %hhu to %hhu",
564 __func__, msg_len, src, dest);
565
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800566 /* queue up packets, each of max MCTP_MTU size */
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800567 for (p = 0, i = 0; p < msg_len; i++) {
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800568 payload_len = msg_len - p;
569 if (payload_len > max_payload_len)
570 payload_len = max_payload_len;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800571
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800572 pkt = mctp_pktbuf_alloc(bus->binding,
573 payload_len + sizeof(*hdr));
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800574 hdr = mctp_pktbuf_hdr(pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800575
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800576 /* todo: tags */
577 hdr->ver = bus->binding->version & 0xf;
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800578 hdr->dest = dest;
579 hdr->src = src;
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800580 hdr->flags_seq_tag = MCTP_HDR_FLAG_TO |
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800581 (0 << MCTP_HDR_TAG_SHIFT);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800582
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800583 if (i == 0)
584 hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM;
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800585 if (p + payload_len >= msg_len)
Jeremy Kerrc855d7b2019-08-01 21:18:09 +0800586 hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM;
587 hdr->flags_seq_tag |=
588 (i & MCTP_HDR_SEQ_MASK) << MCTP_HDR_SEQ_SHIFT;
589
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800590 memcpy(mctp_pktbuf_data(pkt), msg + p, payload_len);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800591
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800592 /* add to tx queue */
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800593 if (bus->tx_queue_tail)
594 bus->tx_queue_tail->next = pkt;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800595 else
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800596 bus->tx_queue_head = pkt;
597 bus->tx_queue_tail = pkt;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800598
Jeremy Kerrdf15f7e2019-08-05 15:41:19 +0800599 p += payload_len;
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800600 }
601
Andrew Jeffery298865f2020-02-06 11:51:29 +1030602 mctp_prdebug("%s: Enqueued %d packets", __func__, i);
603
Jeremy Kerrcc2458d2019-03-01 08:23:33 +0800604 mctp_send_tx_queue(bus);
Jeremy Kerr24db71f2019-02-07 21:37:35 +0800605
606 return 0;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800607}
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800608
609int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
610 void *msg, size_t msg_len)
611{
612 struct mctp_bus *bus;
613
614 bus = find_bus_for_eid(mctp, eid);
Andrew Jefferyb93b6112020-06-05 14:13:44 +0930615 return mctp_message_tx_on_bus(bus, bus->eid, eid, msg, msg_len);
Jeremy Kerr1a4ec3c2019-09-03 11:01:50 +0800616}