Skip to content

Commit c32e360

Browse files
committed
GetMsgType : Take from config
GetMsgType response is hardcoded and always return only control message support. Read supported message types from config file and reply in control message Tested by sending GetMsgType and GetVersion from another EP Default responses for GetMsgType and GetVersion for type 0 5, 0, 1, 0 and 4, 0, 4, 241, 240, 255, 0, 241, 241, 255, 0, 241, 242, 255, 0, 241, 243, 241, 0 After calling busctl call au.com.codeconstruct.MCTP1 /au/com/codeconstruct/mctp1 au.com.codeconstruct.MCTP1 RegisterResponder yau 5 1 0xF1F2F3F4 Response for GetMsgType and GetVersion for type 5 5, 0, 2, 0, 5 and 4, 0, 1, 244, 243, 242, 241 Signed-off-by: Nidhin MS <[email protected]>
1 parent 3e0e9c2 commit c32e360

File tree

4 files changed

+255
-30
lines changed

4 files changed

+255
-30
lines changed

docs/mctpd.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,39 @@ Service au.com.codeconstruct.MCTP1:
2525

2626
## Top-level object: `/au/com/codeconstruct/mctp1`
2727

28-
This object serves as the global MCTP daemon namespace; it doesn't contain
29-
much at present, but hosts two trees of MCTP objects:
28+
This object serves as the global MCTP daemon namespace.
29+
It hosts `au.com.codeconstruct.MCTP1` dbus interface to modify mctp properties like
30+
supported message types.
31+
```
32+
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
33+
au.com.codeconstruct.MCTP1 interface - - -
34+
.RegisterResponder method yau - -
35+
```
36+
37+
#### `.RegisterResponder`: `yau`
38+
39+
This method is used to add support for mctp message types other than control
40+
messages. Once called successfully subsequent response for get message type
41+
control command will include this new message type also. Also the versions
42+
passed to this method will be used to respond to get version control command.
43+
44+
`RegisterResponder <msg type> <versions>`
45+
46+
If message type is already registered then dbus call will fail
47+
48+
`<msg type>` Message type defined in DSP0239
49+
50+
`<versions>` Versions supported for this message type formatted as uint32 integers as
51+
specified in DSP0236
52+
53+
Example for PLDM type with two versions:
54+
55+
```shell
56+
busctl call au.com.codeconstruct.MCTP1 /au/com/codeconstruct/mctp1 \
57+
au.com.codeconstruct.MCTP1 RegisterResponder yau 1 2 0xF1F2F3F4 0xF0F0F0F1
58+
```
59+
60+
Also it hosts two trees of MCTP objects:
3061

3162
* Interfaces: Local hardware transport bindings that connect us to a MCTP bus
3263
* Endpoints: MCTP endpoints that `mctpd` knows about, both remote and local

src/mctpd.c

Lines changed: 196 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ struct peer {
201201
uint8_t pool_start;
202202
};
203203

204+
struct msg_type_support {
205+
uint8_t msg_type;
206+
uint32_t *versions;
207+
size_t num_versions;
208+
};
209+
204210
struct ctx {
205211
sd_event *event;
206212
sd_bus *bus;
@@ -232,6 +238,10 @@ struct ctx {
232238

233239
uint8_t uuid[16];
234240

241+
// Supported message types and their versions
242+
struct msg_type_support* supported_msg_types;
243+
size_t num_supported_msg_types;
244+
235245
// Verbose logging
236246
bool verbose;
237247

@@ -838,39 +848,62 @@ handle_control_get_version_support(struct ctx *ctx, int sd,
838848
struct mctp_ctrl_cmd_get_mctp_ver_support *req = NULL;
839849
struct mctp_ctrl_resp_get_mctp_ver_support *resp = NULL;
840850
uint32_t *versions = NULL;
841-
// space for 4 versions
842-
uint8_t respbuf[sizeof(*resp) + 4 * sizeof(*versions)] = { 0 };
851+
uint8_t *respbuf = NULL;
843852
size_t resp_len;
853+
ssize_t i, ver_idx = -1, ver_count = 0;
854+
int status;
844855

845856
if (buf_size < sizeof(struct mctp_ctrl_cmd_get_mctp_ver_support)) {
846857
warnx("short Get Version Support message");
847858
return -ENOMSG;
848859
}
849860

850861
req = (void *)buf;
851-
resp = (void *)respbuf;
852-
mctp_ctrl_msg_hdr_init_resp(&resp->ctrl_hdr, req->ctrl_hdr);
853-
versions = (void *)(resp + 1);
854-
switch (req->msg_type_number) {
855-
case 0xff: // Base Protocol
856-
case 0x00: // Control protocol
857-
// from DSP0236 1.3.1 section 12.6.2. Big endian.
858-
versions[0] = htonl(0xF1F0FF00);
859-
versions[1] = htonl(0xF1F1FF00);
860-
versions[2] = htonl(0xF1F2FF00);
861-
versions[3] = htonl(0xF1F3F100);
862-
resp->number_of_entries = 4;
863-
resp->completion_code = MCTP_CTRL_CC_SUCCESS;
864-
resp_len = sizeof(*resp) + 4 * sizeof(*versions);
865-
break;
866-
default:
867-
// Unsupported message type
862+
if (req->msg_type_number == 0xFF) {
863+
// use same version for base spec and control protocol
864+
req->msg_type_number = 0;
865+
}
866+
for (i = 0; i < ctx->num_supported_msg_types; i++) {
867+
if (ctx->supported_msg_types[i].msg_type ==
868+
req->msg_type_number) {
869+
ver_idx = i;
870+
break;
871+
}
872+
}
873+
874+
if (ver_idx < 0) {
875+
respbuf = malloc(sizeof(struct mctp_ctrl_resp));
876+
if (!respbuf) {
877+
warnx("Failed to allocate response buffer");
878+
return -ENOMEM;
879+
}
880+
resp = (void *)respbuf;
881+
// Nobody registered yet as responder for this type
868882
resp->completion_code =
869883
MCTP_CTRL_CC_GET_MCTP_VER_SUPPORT_UNSUPPORTED_TYPE;
870-
resp_len = sizeof(*resp);
884+
resp_len = sizeof(struct mctp_ctrl_resp);
885+
} else {
886+
ver_count = ctx->supported_msg_types[ver_idx].num_versions;
887+
respbuf =
888+
malloc(sizeof(*resp) + (ver_count * sizeof(uint32_t)));
889+
if (!respbuf) {
890+
warnx("Failed to allocate response buffer for versions");
891+
return -ENOMEM;
892+
}
893+
resp = (void *)respbuf;
894+
resp->number_of_entries = ver_count;
895+
versions = (void *)(resp + 1);
896+
memcpy(versions, ctx->supported_msg_types[ver_idx].versions,
897+
ver_count * sizeof(uint32_t));
898+
resp->completion_code = MCTP_CTRL_CC_SUCCESS;
899+
resp_len = sizeof(*resp) + ver_count * sizeof(uint32_t);
871900
}
872901

873-
return reply_message(ctx, sd, resp, resp_len, addr);
902+
mctp_ctrl_msg_hdr_init_resp(&resp->ctrl_hdr, req->ctrl_hdr);
903+
904+
status = reply_message(ctx, sd, resp, resp_len, addr);
905+
free(respbuf);
906+
return status;
874907
}
875908

876909
static int handle_control_get_endpoint_id(struct ctx *ctx, int sd,
@@ -927,24 +960,39 @@ static int handle_control_get_message_type_support(
927960
{
928961
struct mctp_ctrl_cmd_get_msg_type_support *req = NULL;
929962
struct mctp_ctrl_resp_get_msg_type_support *resp = NULL;
930-
uint8_t resp_buf[sizeof(*resp) + 1] = { 0 };
931-
size_t resp_len;
963+
uint8_t *resp_buf, *msg_types;
964+
size_t resp_len, type_count;
965+
size_t i;
932966

933967
if (buf_size < sizeof(*req)) {
934968
warnx("short Get Message Type Support message");
935969
return -ENOMSG;
936970
}
937971

938972
req = (void *)buf;
973+
type_count = ctx->num_supported_msg_types;
974+
// Allocate extra space for the message types
975+
resp_len = sizeof(*resp) + type_count;
976+
resp_buf = malloc(resp_len);
977+
if (!resp_buf) {
978+
warnx("Failed to allocate response buffer");
979+
return -ENOMEM;
980+
}
981+
939982
resp = (void *)resp_buf;
940983
mctp_ctrl_msg_hdr_init_resp(&resp->ctrl_hdr, req->ctrl_hdr);
984+
resp->completion_code = MCTP_CTRL_CC_SUCCESS;
941985

942-
// Only control messages supported
943-
resp->msg_type_count = 1;
944-
*((uint8_t *)(resp + 1)) = MCTP_CTRL_HDR_MSG_TYPE;
945-
resp_len = sizeof(*resp) + resp->msg_type_count;
986+
resp->msg_type_count = type_count;
987+
// Append message types after msg_type_count
988+
msg_types = (uint8_t *)(resp + 1);
989+
for (i = 0; i < type_count; i++) {
990+
msg_types[i] = ctx->supported_msg_types[i].msg_type;
991+
}
946992

947-
return reply_message(ctx, sd, resp, resp_len, addr);
993+
int result = reply_message(ctx, sd, resp, resp_len, addr);
994+
free(resp_buf);
995+
return result;
948996
}
949997

950998
static int
@@ -3319,6 +3367,71 @@ static int method_net_learn_endpoint(sd_bus_message *call, void *data,
33193367
return rc;
33203368
}
33213369

3370+
static int method_register_responder(sd_bus_message *call, void *data,
3371+
sd_bus_error *berr)
3372+
{
3373+
struct ctx *ctx = data;
3374+
uint8_t msg_type;
3375+
const uint32_t *versions = NULL;
3376+
size_t versions_len;
3377+
int rc, i;
3378+
3379+
rc = sd_bus_message_read(call, "y", &msg_type);
3380+
if (rc < 0)
3381+
goto err;
3382+
rc = sd_bus_message_read_array(call, 'u', (const void **)&versions,
3383+
&versions_len);
3384+
if (rc < 0)
3385+
goto err;
3386+
3387+
if (versions_len == 0) {
3388+
warnx("No versions provided for message type %d", msg_type);
3389+
return sd_bus_error_setf(
3390+
berr, SD_BUS_ERROR_INVALID_ARGS,
3391+
"No versions provided for message type %d", msg_type);
3392+
}
3393+
3394+
for (i = 0; i < ctx->num_supported_msg_types; i++) {
3395+
if (ctx->supported_msg_types[i].msg_type == msg_type) {
3396+
warnx("Message type %d already registered", msg_type);
3397+
return sd_bus_error_setf(
3398+
berr, SD_BUS_ERROR_INVALID_ARGS,
3399+
"Message type %d already registered", msg_type);
3400+
}
3401+
}
3402+
3403+
struct msg_type_support *msg_types =
3404+
realloc(ctx->supported_msg_types,
3405+
(ctx->num_supported_msg_types + 1) *
3406+
sizeof(struct msg_type_support));
3407+
if (!msg_types) {
3408+
goto oom_err;
3409+
}
3410+
ctx->supported_msg_types = msg_types;
3411+
ctx->supported_msg_types[ctx->num_supported_msg_types].msg_type =
3412+
msg_type;
3413+
ctx->supported_msg_types[ctx->num_supported_msg_types].num_versions =
3414+
versions_len / sizeof(uint32_t);
3415+
ctx->supported_msg_types[ctx->num_supported_msg_types].versions =
3416+
malloc(versions_len);
3417+
if (!ctx->supported_msg_types[ctx->num_supported_msg_types].versions) {
3418+
goto oom_err;
3419+
}
3420+
// Assume callers's responsibility to provide version in uint32 format from spec
3421+
memcpy(ctx->supported_msg_types[ctx->num_supported_msg_types].versions,
3422+
versions, versions_len);
3423+
3424+
ctx->num_supported_msg_types++;
3425+
3426+
return sd_bus_reply_method_return(call, "");
3427+
oom_err:
3428+
return sd_bus_error_setf(berr, SD_BUS_ERROR_NO_MEMORY,
3429+
"Failed to allocate memory");
3430+
err:
3431+
set_berr(ctx, rc, berr);
3432+
return rc;
3433+
}
3434+
33223435
// clang-format off
33233436
static const sd_bus_vtable bus_link_owner_vtable[] = {
33243437
SD_BUS_VTABLE_START(0),
@@ -3672,6 +3785,17 @@ static const sd_bus_vtable bus_network_vtable[] = {
36723785
SD_BUS_VTABLE_PROPERTY_CONST),
36733786
SD_BUS_VTABLE_END
36743787
};
3788+
3789+
static const sd_bus_vtable mctp_base_vtable[] = {
3790+
SD_BUS_VTABLE_START(0),
3791+
SD_BUS_METHOD_WITH_ARGS("RegisterResponder",
3792+
SD_BUS_ARGS("y", msg_type,
3793+
"au", versions),
3794+
SD_BUS_NO_RESULT,
3795+
method_register_responder,
3796+
0),
3797+
SD_BUS_VTABLE_END,
3798+
};
36753799
// clang-format on
36763800

36773801
static int emit_endpoint_added(const struct peer *peer)
@@ -3822,6 +3946,14 @@ static int setup_bus(struct ctx *ctx)
38223946
goto out;
38233947
}
38243948

3949+
rc = sd_bus_add_object_vtable(ctx->bus, NULL, MCTP_DBUS_PATH,
3950+
MCTP_DBUS_NAME,
3951+
mctp_base_vtable, ctx);
3952+
if (rc < 0) {
3953+
warnx("Adding MCTP base vtable failed: %s", strerror(-rc));
3954+
goto out;
3955+
}
3956+
38253957
rc = 0;
38263958
out:
38273959
return rc;
@@ -4613,6 +4745,34 @@ static int parse_config(struct ctx *ctx)
46134745
return rc;
46144746
}
46154747

4748+
static void setup_ctrl_cmd_defaults(struct ctx *ctx)
4749+
{
4750+
ctx->supported_msg_types = NULL;
4751+
ctx->num_supported_msg_types = 0;
4752+
4753+
// Default to supporting only control messages
4754+
ctx->supported_msg_types = malloc(sizeof(struct msg_type_support));
4755+
if (!ctx->supported_msg_types) {
4756+
warnx("Out of memory for supported message types");
4757+
return;
4758+
}
4759+
ctx->num_supported_msg_types = 1;
4760+
ctx->supported_msg_types[0].msg_type = MCTP_CTRL_HDR_MSG_TYPE;
4761+
4762+
ctx->supported_msg_types[0].versions = malloc(sizeof(uint32_t) * 4);
4763+
if (!ctx->supported_msg_types[0].versions) {
4764+
warnx("Out of memory for versions");
4765+
free(ctx->supported_msg_types);
4766+
ctx->num_supported_msg_types = 0;
4767+
return;
4768+
}
4769+
ctx->supported_msg_types[0].num_versions = 4;
4770+
ctx->supported_msg_types[0].versions[0] = htonl(0xF1F0FF00);
4771+
ctx->supported_msg_types[0].versions[1] = htonl(0xF1F1FF00);
4772+
ctx->supported_msg_types[0].versions[2] = htonl(0xF1F2FF00);
4773+
ctx->supported_msg_types[0].versions[3] = htonl(0xF1F3F100);
4774+
}
4775+
46164776
static void setup_config_defaults(struct ctx *ctx)
46174777
{
46184778
ctx->mctp_timeout = 250000; // 250ms
@@ -4624,7 +4784,13 @@ static void setup_config_defaults(struct ctx *ctx)
46244784

46254785
static void free_config(struct ctx *ctx)
46264786
{
4787+
int i;
4788+
46274789
free(ctx->config_filename);
4790+
for (i = 0; i < ctx->num_supported_msg_types; i++) {
4791+
free(ctx->supported_msg_types[i].versions);
4792+
}
4793+
free(ctx->supported_msg_types);
46284794
}
46294795

46304796
static int endpoint_send_allocate_endpoint_ids(
@@ -4778,6 +4944,8 @@ int main(int argc, char **argv)
47784944
setlinebuf(stdout);
47794945

47804946
setup_config_defaults(ctx);
4947+
setup_ctrl_cmd_defaults(ctx);
4948+
47814949
mctp_ops_init();
47824950

47834951
rc = parse_args(ctx, argc, argv);

tests/mctp_test_utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
async def mctpd_mctp_base_iface_obj(dbus):
2+
obj = await dbus.get_proxy_object(
3+
'au.com.codeconstruct.MCTP1',
4+
'/au/com/codeconstruct/mctp1'
5+
)
6+
return await obj.get_interface('au.com.codeconstruct.MCTP1')
17

28
async def mctpd_mctp_iface_obj(dbus, iface):
39
obj = await dbus.get_proxy_object(

tests/test_mctpd_endpoint.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ async def test_accept_multiple_set_eids_for_single_interface(dbus, mctpd):
107107
# expect new EID on D-Bus
108108
assert await mctpd_mctp_endpoint_control_obj(dbus, f"/au/com/codeconstruct/mctp1/networks/1/endpoints/{second_eid}")
109109

110+
async def test_get_message_types(dbus, mctpd):
111+
bo = mctpd.network.endpoints[0]
112+
iface = mctpd.system.interfaces[0]
113+
await mctpd.system.add_route(mctpd.system.Route(bo.eid, 1, iface = iface))
114+
await mctpd.system.add_neighbour(mctpd.system.Neighbour(iface, bo.lladdr, bo.eid))
115+
116+
# Check default response when no responder registered
117+
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x05, bytes([0x00])))
118+
assert rsp.hex(' ') == '00 05 00 01 00'
119+
120+
# Register spdm responder with a random version
121+
mctp = await mctpd_mctp_base_iface_obj(dbus)
122+
await mctp.call_register_responder(5, [0xF1F2F3F4])
123+
124+
# Verify get message type response includes spdm
125+
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x05, bytes([0x00])))
126+
assert rsp.hex(' ') == '00 05 00 02 00 05'
127+
# Verify version passed in dbus call is responded back
128+
rsp = await bo.send_control(mctpd.network.mctp_socket, MCTPControlCommand(True, 0, 0x04, bytes([0x05])))
129+
assert rsp.hex(' ') == '00 04 00 01 f4 f3 f2 f1'
110130

111131
class TestDiscovery:
112132
@pytest.fixture

0 commit comments

Comments
 (0)