Skip to content

Commit ba6727e

Browse files
wigolamboar
authored andcommitted
core: Support transport control commands
This change introduces a control message request handler for MCTP bindings. If a handler is provided, transport control messages will be forwarded to the handler, otherwise they will be forwarded to the default handler. Change-Id: I62266d6bf2d512ec97759c0b8a3477c5e433d609 Signed-off-by: Wiktor Gołgowski <[email protected]> [AJ: Split out general control message handler, formatting] Signed-off-by: Andrew Jeffery <[email protected]>
1 parent 1dbf021 commit ba6727e

File tree

6 files changed

+279
-15
lines changed

6 files changed

+279
-15
lines changed

CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ add_executable (test_serial tests/test_serial.c tests/test-utils.c)
3333
target_link_libraries (test_serial mctp)
3434
add_test (NAME serial COMMAND test_serial)
3535

36+
add_executable (test_cmds tests/test_cmds.c tests/test-utils.c)
37+
target_link_libraries (test_cmds mctp)
38+
add_test (NAME control_commands COMMAND test_cmds)
39+
3640
install (TARGETS mctp DESTINATION lib)
3741
install (FILES libmctp.h DESTINATION include)
3842

Makefile.am

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ ACLOCAL_AMFLAGS = -I m4
22

33
lib_LTLIBRARIES = libmctp.la
44
libmctp_la_SOURCES = core.c alloc.c log.c \
5-
libmctp-alloc.h libmctp-log.h
5+
libmctp-alloc.h libmctp-log.h \
6+
libmctp-cmds.h
67
include_HEADERS = libmctp.h
78

89
if LIBMCTP_BINDING_serial
@@ -40,7 +41,7 @@ AM_LDFLAGS = $(CODE_COVERAGE_LDFLAGS)
4041
TESTS = $(check_PROGRAMS)
4142

4243
check_PROGRAMS = tests/test_eid tests/test_seq tests/test_bridge \
43-
tests/test_astlpc tests/test_serial
44+
tests/test_astlpc tests/test_serial tests/test_cmds
4445
# We set a global LDADD here, as there's no way to specify it for all
4546
# tests. This means other targets' LDADDs need to be overridden.
4647
LDADD = tests/libtest-utils.a libmctp.la

core.c

+78-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "libmctp.h"
1515
#include "libmctp-alloc.h"
1616
#include "libmctp-log.h"
17+
#include "libmctp-cmds.h"
1718

1819
/* Internal data structures */
1920

@@ -313,12 +314,85 @@ int mctp_bridge_busses(struct mctp *mctp,
313314
return 0;
314315
}
315316

316-
static void mctp_rx(struct mctp *mctp, struct mctp_bus *bus,
317-
mctp_eid_t src, mctp_eid_t dest, void *buf, size_t len)
317+
static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr)
318318
{
319+
return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) &&
320+
(hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT));
321+
}
322+
323+
static 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+
353+
static 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+
359+
static 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+
*/
370+
static 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+
319375
if (mctp->route_policy == ROUTE_ENDPOINT &&
320-
dest == bus->eid && mctp->message_rx)
321-
mctp->message_rx(src, mctp->message_rx_data, buf, len);
376+
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+
}
322396

323397
if (mctp->route_policy == ROUTE_BRIDGE) {
324398
int i;

libmctp-cmds.h

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2+
#ifndef _LIBMCTP_CMDS_H
3+
#define _LIBMCTP_CMDS_H
4+
5+
#ifdef __cplusplus
6+
extern "C" {
7+
#endif
8+
9+
#include "libmctp.h"
10+
11+
/*
12+
* Helper structs and functions for MCTP control messages.
13+
* See DSP0236 v1.3.0 sec. 11 for reference.
14+
*/
15+
16+
struct mctp_ctrl_msg_hdr {
17+
uint8_t ic_msg_type;
18+
uint8_t rq_dgram_inst;
19+
uint8_t command_code;
20+
uint8_t completion_code;
21+
};
22+
23+
#define MCTP_CTRL_HDR_MSG_TYPE 0
24+
#define MCTP_CTRL_HDR_FLAG_REQUEST (1 << 7)
25+
#define MCTP_CTRL_HDR_FLAG_DGRAM (1 << 6)
26+
#define MCTP_CTRL_HDR_INSTANCE_ID_MASK 0x1F
27+
28+
/*
29+
* MCTP Control Command IDs
30+
* See DSP0236 v1.3.0 Table 12.
31+
*/
32+
#define MCTP_CTRL_CMD_RESERVED 0x00
33+
#define MCTP_CTRL_CMD_SET_ENDPOINT_ID 0x01
34+
#define MCTP_CTRL_CMD_GET_ENDPOINT_ID 0x02
35+
#define MCTP_CTRL_CMD_GET_ENDPOINT_UUID 0x03
36+
#define MCTP_CTRL_CMD_GET_VERSION_SUPPORT 0x04
37+
#define MCTP_CTRL_CMD_GET_MESSAGE_TYPE_SUPPORT 0x05
38+
#define MCTP_CTRL_CMD_GET_VENDOR_MESSAGE_SUPPORT 0x06
39+
#define MCTP_CTRL_CMD_RESOLVE_ENDPOINT_ID 0x07
40+
#define MCTP_CTRL_CMD_ALLOCATE_ENDPOINT_IDS 0x08
41+
#define MCTP_CTRL_CMD_ROUTING_INFO_UPDATE 0x09
42+
#define MCTP_CTRL_CMD_GET_ROUTING_TABLE_ENTRIES 0x0A
43+
#define MCTP_CTRL_CMD_PREPARE_ENDPOINT_DISCOVERY 0x0B
44+
#define MCTP_CTRL_CMD_ENDPOINT_DISCOVERY 0x0C
45+
#define MCTP_CTRL_CMD_DISCOVERY_NOTIFY 0x0D
46+
#define MCTP_CTRL_CMD_GET_NETWORK_ID 0x0E
47+
#define MCTP_CTRL_CMD_QUERY_HOP 0x0F
48+
#define MCTP_CTRL_CMD_RESOLVE_UUID 0x10
49+
#define MCTP_CTRL_CMD_QUERY_RATE_LIMIT 0x11
50+
#define MCTP_CTRL_CMD_REQUEST_TX_RATE_LIMIT 0x12
51+
#define MCTP_CTRL_CMD_UPDATE_RATE_LIMIT 0x13
52+
#define MCTP_CTRL_CMD_QUERY_SUPPORTED_INTERFACES 0x14
53+
#define MCTP_CTRL_CMD_MAX 0x15
54+
/* 0xF0 - 0xFF are transport specific */
55+
#define MCTP_CTRL_CMD_FIRST_TRANSPORT 0xF0
56+
#define MCTP_CTRL_CMD_LAST_TRANSPORT 0xFF
57+
58+
/*
59+
* MCTP Control Completion Codes
60+
* See DSP0236 v1.3.0 Table 13.
61+
*/
62+
#define MCTP_CTRL_CC_SUCCESS 0x00
63+
#define MCTP_CTRL_CC_ERROR 0x01
64+
#define MCTP_CTRL_CC_ERROR_INVALID_DATA 0x02
65+
#define MCTP_CTRL_CC_ERROR_INVALID_LENGTH 0x03
66+
#define MCTP_CTRL_CC_ERROR_NOT_READY 0x04
67+
#define MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD 0x05
68+
/* 0x80 - 0xFF are command specific */
69+
70+
#ifdef __cplusplus
71+
}
72+
#endif
73+
74+
#endif /* _LIBMCTP_CMDS_H */

libmctp.h

+14-9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ extern "C" {
1414

1515
typedef uint8_t mctp_eid_t;
1616

17+
/* Special Endpoint ID values */
18+
#define MCTP_EID_NULL 0
19+
#define MCTP_EID_BROADCAST 0xff
20+
1721
/* MCTP packet definitions */
1822
struct mctp_hdr {
1923
uint8_t ver;
@@ -92,15 +96,16 @@ int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
9296

9397
/* hardware bindings */
9498
struct mctp_binding {
95-
const char *name;
96-
uint8_t version;
97-
struct mctp_bus *bus;
98-
struct mctp *mctp;
99-
int pkt_size;
100-
int pkt_pad;
101-
int (*start)(struct mctp_binding *binding);
102-
int (*tx)(struct mctp_binding *binding,
103-
struct mctp_pktbuf *pkt);
99+
const char *name;
100+
uint8_t version;
101+
struct mctp_bus *bus;
102+
struct mctp *mctp;
103+
int pkt_size;
104+
int pkt_pad;
105+
int (*start)(struct mctp_binding *binding);
106+
int (*tx)(struct mctp_binding *binding, struct mctp_pktbuf *pkt);
107+
mctp_rx_fn control_rx;
108+
void *control_rx_data;
104109
};
105110

106111
void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable);

tests/test_cmds.c

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2+
3+
#include "test-utils.h"
4+
5+
#include <stdio.h>
6+
#include <string.h>
7+
#include <assert.h>
8+
9+
#include <libmctp.h>
10+
#include <libmctp-alloc.h>
11+
#include <libmctp-cmds.h>
12+
13+
#ifdef NDEBUG
14+
#undef NDEBUG
15+
#endif
16+
17+
static const mctp_eid_t eid_1 = 9;
18+
static const mctp_eid_t eid_2 = 10;
19+
20+
struct msg_payload {
21+
struct mctp_hdr hdr;
22+
struct mctp_ctrl_msg_hdr ctrl_hdr;
23+
};
24+
25+
struct callback_data {
26+
uint8_t invoked;
27+
union {
28+
uint8_t command_code;
29+
uint8_t completion_code;
30+
};
31+
};
32+
33+
static void control_message_transport_callback(mctp_eid_t src, void *data,
34+
void *buf, size_t len)
35+
{
36+
struct callback_data *ctx = data;
37+
struct mctp_ctrl_msg_hdr *msg_hdr = buf;
38+
printf("Transport control message received - command code: 0x%X\n",
39+
msg_hdr->command_code);
40+
ctx->invoked++;
41+
assert(msg_hdr->command_code == ctx->command_code);
42+
}
43+
44+
static void rcv_ctrl_msg(struct mctp_binding *b, const void *buf, size_t len)
45+
{
46+
struct mctp_pktbuf *pkt = mctp_pktbuf_alloc(b, len);
47+
memcpy(mctp_pktbuf_hdr(pkt), buf, len);
48+
mctp_bus_rx(b, pkt);
49+
}
50+
51+
static void setup_test_binding(struct mctp_binding *test_binding,
52+
struct mctp *test_endpoint, void *callback_ctx)
53+
{
54+
assert(test_binding != NULL);
55+
assert(test_endpoint != NULL);
56+
assert(callback_ctx != NULL);
57+
58+
memset(test_binding, 0, sizeof(*test_binding));
59+
test_binding->name = "test";
60+
test_binding->version = 1;
61+
test_binding->tx = NULL;
62+
test_binding->pkt_size = MCTP_PACKET_SIZE(MCTP_BTU);
63+
test_binding->pkt_pad = 0;
64+
test_binding->control_rx = control_message_transport_callback;
65+
test_binding->control_rx_data = callback_ctx;
66+
67+
mctp_register_bus(test_endpoint, test_binding, eid_1);
68+
mctp_binding_set_tx_enabled(test_binding, true);
69+
}
70+
71+
static void send_transport_control_message(void)
72+
{
73+
struct mctp *endpoint = mctp_init();
74+
struct mctp_binding binding;
75+
struct callback_data ctx;
76+
static const struct msg_payload send_control_message_payload = {
77+
.hdr = {
78+
.dest = eid_1,
79+
.src = eid_2,
80+
.flags_seq_tag = MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM,
81+
},
82+
.ctrl_hdr = {
83+
.ic_msg_type = MCTP_CTRL_HDR_MSG_TYPE,
84+
.rq_dgram_inst = MCTP_CTRL_HDR_FLAG_REQUEST,
85+
.command_code = 0xF2,
86+
},
87+
};
88+
89+
memset(&ctx, 0, sizeof(ctx));
90+
setup_test_binding(&binding, endpoint, &ctx);
91+
ctx.command_code = send_control_message_payload.ctrl_hdr.command_code;
92+
printf("Sending transport control message: 0x%X\n",
93+
send_control_message_payload.ctrl_hdr.command_code);
94+
rcv_ctrl_msg(&binding, (void *)&send_control_message_payload,
95+
sizeof(send_control_message_payload));
96+
assert(ctx.invoked == 1);
97+
98+
mctp_destroy(endpoint);
99+
}
100+
101+
int main(int argc, char *argv[])
102+
{
103+
send_transport_control_message();
104+
105+
return EXIT_SUCCESS;
106+
}

0 commit comments

Comments
 (0)