Skip to content

Commit f65eed4

Browse files
PavanMarthaIntelmsnidhin
authored andcommitted
mctpd: add dbus method RegisterVDMTypeSupport
Add a new DBus method RegisterVDMTypeSupport to support vendor defined message support as responder Add a new control command handler for get vdm message Tested: Unit tests passed Tested by sending GetVDM command from another endpoint Signed-off-by: Nidhin MS <nidhin.ms@intel.com> Signed-off-by: PavanKumarIntel <pavanx.kumar.martha@intel.com>
1 parent 236330c commit f65eed4

File tree

3 files changed

+316
-0
lines changed

3 files changed

+316
-0
lines changed

docs/mctpd.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ the MCTP stack, such as supported message types.
3232
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
3333
au.com.codeconstruct.MCTP1 interface - - -
3434
.RegisterTypeSupport method yau - -
35+
.RegisterVDMTypeSupport method yvq - -
3536
```
3637

3738
#### `.RegisterTypeSupport`: `yau`
@@ -53,6 +54,28 @@ De-registration is automatic - the specified types (and versions) are registered
5354
for as long as the dbus sender remains attached to the message bus, and are
5455
unregistered on disconnect.
5556

57+
#### `.RegisterVDMTypeSupport`: `yvq`
58+
59+
This method is used to add support for MCTP Vendor Defined Message (VDM) types.
60+
Once called successfully, subsequent responses for Get Vendor Defined Message
61+
Support control commands will include this new VDM type.
62+
63+
`RegisterVDMTypeSupport <vid format> <vendor id> <command set type>`
64+
65+
If the VDM type is already registered, then dbus call will fail.
66+
67+
- `<vid format>` Vendor ID format:
68+
- `0x00` - PCI/PCIe Vendor ID (16-bit)
69+
- `0x01` - IANA Enterprise Number (32-bit)
70+
- `<vendor id>` Vendor identifier as a variant type:
71+
- For PCIe format: 16-bit unsigned integer (`q`)
72+
- For IANA format: 32-bit unsigned integer (`u`)
73+
- `<command set type>` Command set type (16-bit unsigned integer) as defined by the vendor
74+
75+
De-registration is automatic - the specified VDM types are registered for as
76+
long as the dbus sender remains attached to the message bus, and are
77+
removed when the sender disconnects.
78+
5679
Also it hosts two trees of MCTP objects:
5780

5881
* Interfaces: Local hardware transport bindings that connect us to a MCTP bus

src/mctpd.c

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,16 @@ struct msg_type_support {
208208
sd_bus_track *source_peer;
209209
};
210210

211+
struct vdm_type_support {
212+
uint8_t vid_format;
213+
union {
214+
uint16_t pcie;
215+
uint32_t iana;
216+
} vendor_id;
217+
uint16_t cmd_set;
218+
sd_bus_track *source_peer;
219+
};
220+
211221
struct ctx {
212222
sd_event *event;
213223
sd_bus *bus;
@@ -243,6 +253,9 @@ struct ctx {
243253
struct msg_type_support *supported_msg_types;
244254
size_t num_supported_msg_types;
245255

256+
struct vdm_type_support *supported_vdm_types;
257+
size_t num_supported_vdm_types;
258+
246259
// Verbose logging
247260
bool verbose;
248261

@@ -999,6 +1012,83 @@ static int handle_control_get_message_type_support(
9991012
return rc;
10001013
}
10011014

1015+
static int
1016+
handle_control_get_vdm_type_support(struct ctx *ctx, int sd,
1017+
const struct sockaddr_mctp_ext *addr,
1018+
const uint8_t *buf, const size_t buf_size)
1019+
{
1020+
size_t resp_len, max_rsp_len, vdm_count, vid_size_left;
1021+
struct mctp_ctrl_resp_get_vdm_support *resp = NULL;
1022+
struct mctp_ctrl_cmd_get_vdm_support *req = NULL;
1023+
struct vdm_type_support *cur_vdm;
1024+
uint8_t *resp_buf;
1025+
int rc;
1026+
1027+
if (buf_size < sizeof(*req)) {
1028+
warnx("short Get Message Type Support message");
1029+
return -ENOMSG;
1030+
}
1031+
1032+
req = (void *)buf;
1033+
vdm_count = ctx->num_supported_vdm_types;
1034+
// Allocate space for 32 bit VID + 16 bit cmd set
1035+
max_rsp_len = sizeof(*resp) + sizeof(uint16_t);
1036+
resp_buf = malloc(max_rsp_len);
1037+
if (!resp_buf) {
1038+
warnx("Failed to allocate response buffer");
1039+
return -ENOMEM;
1040+
}
1041+
resp = (void *)resp_buf;
1042+
mctp_ctrl_msg_hdr_init_resp(&resp->ctrl_hdr, req->ctrl_hdr);
1043+
1044+
if (vdm_count == 0) {
1045+
if (ctx->verbose) {
1046+
warnx("Get VDM Type Support but no VDMs registered");
1047+
}
1048+
resp_len = sizeof(struct mctp_ctrl_resp);
1049+
resp->completion_code = MCTP_CTRL_CC_ERROR;
1050+
} else if (req->vendor_id_set_selector >= vdm_count) {
1051+
if (ctx->verbose) {
1052+
warnx("Get VDM Type Support selector %u out of range (max %zu)",
1053+
req->vendor_id_set_selector, vdm_count);
1054+
}
1055+
resp_len = sizeof(struct mctp_ctrl_resp);
1056+
resp->completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA;
1057+
} else {
1058+
cur_vdm =
1059+
&ctx->supported_vdm_types[req->vendor_id_set_selector];
1060+
vid_size_left = (cur_vdm->vid_format ==
1061+
MCTP_GET_VDM_SUPPORT_PCIE_FORMAT_ID) ?
1062+
sizeof(uint16_t) :
1063+
0;
1064+
resp_len = max_rsp_len - vid_size_left;
1065+
1066+
resp->completion_code = MCTP_CTRL_CC_SUCCESS;
1067+
resp->vendor_id_set_selector =
1068+
req->vendor_id_set_selector == (vdm_count - 1) ?
1069+
MCTP_GET_VDM_SUPPORT_NO_MORE_CAP_SET :
1070+
req->vendor_id_set_selector + 1;
1071+
resp->vendor_id_format = cur_vdm->vid_format;
1072+
uint8_t *out_ptr = (uint8_t *)(resp + 1);
1073+
out_ptr -= vid_size_left;
1074+
1075+
if (cur_vdm->vid_format ==
1076+
MCTP_GET_VDM_SUPPORT_PCIE_FORMAT_ID) {
1077+
resp->vendor_id_data_pcie =
1078+
htobe16(cur_vdm->vendor_id.pcie);
1079+
} else {
1080+
resp->vendor_id_data_iana =
1081+
htobe32(cur_vdm->vendor_id.iana);
1082+
}
1083+
uint16_t *cmd_type_ptr = (uint16_t *)out_ptr;
1084+
*cmd_type_ptr = htobe16(cur_vdm->cmd_set);
1085+
}
1086+
1087+
rc = reply_message(ctx, sd, resp, resp_len, addr);
1088+
free(resp_buf);
1089+
return rc;
1090+
}
1091+
10021092
static int
10031093
handle_control_resolve_endpoint_id(struct ctx *ctx, int sd,
10041094
const struct sockaddr_mctp_ext *addr,
@@ -1202,6 +1292,10 @@ static int cb_listen_control_msg(sd_event_source *s, int sd, uint32_t revents,
12021292
rc = handle_control_get_message_type_support(ctx, sd, &addr,
12031293
buf, buf_size);
12041294
break;
1295+
case MCTP_CTRL_CMD_GET_VENDOR_MESSAGE_SUPPORT:
1296+
rc = handle_control_get_vdm_type_support(ctx, sd, &addr, buf,
1297+
buf_size);
1298+
break;
12051299
case MCTP_CTRL_CMD_RESOLVE_ENDPOINT_ID:
12061300
rc = handle_control_resolve_endpoint_id(ctx, sd, &addr, buf,
12071301
buf_size);
@@ -3420,6 +3514,33 @@ static int on_dbus_peer_removed(sd_bus_track *track, void *userdata)
34203514
return 0;
34213515
}
34223516

3517+
static int on_dbus_peer_removed_vdm_type(sd_bus_track *track, void *userdata)
3518+
{
3519+
struct ctx *ctx = userdata;
3520+
size_t i;
3521+
3522+
for (i = 0; i < ctx->num_supported_vdm_types; i++) {
3523+
struct vdm_type_support *vdm_type =
3524+
&ctx->supported_vdm_types[i];
3525+
3526+
if (vdm_type->source_peer != track)
3527+
continue;
3528+
if (ctx->verbose) {
3529+
warnx("Removing VDM type support entry vid_format %d cmd_set 0x%04x",
3530+
vdm_type->vid_format, vdm_type->cmd_set);
3531+
}
3532+
if (i != ctx->num_supported_vdm_types - 1) {
3533+
*vdm_type = ctx->supported_vdm_types
3534+
[ctx->num_supported_vdm_types - 1];
3535+
}
3536+
ctx->num_supported_vdm_types--;
3537+
break;
3538+
}
3539+
3540+
sd_bus_track_unref(track);
3541+
return 0;
3542+
}
3543+
34233544
static int method_register_type_support(sd_bus_message *call, void *data,
34243545
sd_bus_error *berr)
34253546
{
@@ -3506,6 +3627,104 @@ static int method_register_type_support(sd_bus_message *call, void *data,
35063627
return rc;
35073628
}
35083629

3630+
static int method_register_vdm_type_support(sd_bus_message *call, void *data,
3631+
sd_bus_error *berr)
3632+
{
3633+
struct vdm_type_support new_vdm, *cur_vdm_type, *new_vdm_types_arr;
3634+
struct ctx *ctx = data;
3635+
uint16_t vid_pcie;
3636+
uint32_t vid_iana;
3637+
int rc;
3638+
3639+
rc = sd_bus_message_read(call, "y", &new_vdm.vid_format);
3640+
if (rc < 0)
3641+
goto err;
3642+
3643+
if (new_vdm.vid_format != MCTP_GET_VDM_SUPPORT_PCIE_FORMAT_ID &&
3644+
new_vdm.vid_format != MCTP_GET_VDM_SUPPORT_IANA_FORMAT_ID) {
3645+
return sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS,
3646+
"Unsupported VID format: %d",
3647+
new_vdm.vid_format);
3648+
}
3649+
3650+
if (new_vdm.vid_format == MCTP_GET_VDM_SUPPORT_PCIE_FORMAT_ID) {
3651+
rc = sd_bus_message_read(call, "v", "q", &vid_pcie);
3652+
if (rc < 0)
3653+
goto err;
3654+
new_vdm.vendor_id.pcie = vid_pcie;
3655+
} else if (new_vdm.vid_format == MCTP_GET_VDM_SUPPORT_IANA_FORMAT_ID) {
3656+
rc = sd_bus_message_read(call, "v", "u", &vid_iana);
3657+
if (rc < 0)
3658+
goto err;
3659+
new_vdm.vendor_id.iana = vid_iana;
3660+
}
3661+
3662+
rc = sd_bus_message_read(call, "q", &new_vdm.cmd_set);
3663+
if (rc < 0)
3664+
goto err;
3665+
3666+
// Check for duplicates
3667+
for (size_t i = 0; i < ctx->num_supported_vdm_types; i++) {
3668+
if (ctx->supported_vdm_types[i].vid_format !=
3669+
new_vdm.vid_format)
3670+
continue;
3671+
3672+
if (ctx->supported_vdm_types[i].cmd_set != new_vdm.cmd_set)
3673+
continue;
3674+
3675+
bool vid_matches = false;
3676+
if (new_vdm.vid_format == MCTP_GET_VDM_SUPPORT_PCIE_FORMAT_ID) {
3677+
vid_matches =
3678+
(ctx->supported_vdm_types[i].vendor_id.pcie ==
3679+
new_vdm.vendor_id.pcie);
3680+
} else {
3681+
vid_matches =
3682+
(ctx->supported_vdm_types[i].vendor_id.iana ==
3683+
new_vdm.vendor_id.iana);
3684+
}
3685+
3686+
if (vid_matches) {
3687+
return sd_bus_error_setf(berr,
3688+
SD_BUS_ERROR_INVALID_ARGS,
3689+
"VDM type already registered");
3690+
}
3691+
}
3692+
3693+
new_vdm_types_arr = realloc(ctx->supported_vdm_types,
3694+
(ctx->num_supported_vdm_types + 1) *
3695+
sizeof(struct vdm_type_support));
3696+
if (!new_vdm_types_arr)
3697+
return sd_bus_error_setf(
3698+
berr, SD_BUS_ERROR_NO_MEMORY,
3699+
"Failed to allocate memory for VDM types");
3700+
ctx->supported_vdm_types = new_vdm_types_arr;
3701+
3702+
cur_vdm_type = &ctx->supported_vdm_types[ctx->num_supported_vdm_types];
3703+
memcpy(cur_vdm_type, &new_vdm, sizeof(struct vdm_type_support));
3704+
3705+
// Track peer
3706+
rc = sd_bus_track_new(ctx->bus, &cur_vdm_type->source_peer,
3707+
on_dbus_peer_removed_vdm_type, ctx);
3708+
if (rc < 0)
3709+
goto track_err;
3710+
3711+
rc = sd_bus_track_add_sender(cur_vdm_type->source_peer, call);
3712+
if (rc < 0)
3713+
goto track_err;
3714+
3715+
ctx->num_supported_vdm_types++;
3716+
return sd_bus_reply_method_return(call, "");
3717+
3718+
track_err:
3719+
sd_bus_track_unref(cur_vdm_type->source_peer);
3720+
set_berr(ctx, rc, berr);
3721+
return rc;
3722+
3723+
err:
3724+
set_berr(ctx, rc, berr);
3725+
return rc;
3726+
}
3727+
35093728
// clang-format off
35103729
static const sd_bus_vtable bus_link_owner_vtable[] = {
35113730
SD_BUS_VTABLE_START(0),
@@ -3868,6 +4087,13 @@ static const sd_bus_vtable mctp_base_vtable[] = {
38684087
SD_BUS_NO_RESULT,
38694088
method_register_type_support,
38704089
0),
4090+
SD_BUS_METHOD_WITH_ARGS("RegisterVDMTypeSupport",
4091+
SD_BUS_ARGS("y", format,
4092+
"v", format_data,
4093+
"q", vendor_subtype),
4094+
SD_BUS_NO_RESULT,
4095+
method_register_vdm_type_support,
4096+
0),
38714097
SD_BUS_VTABLE_END,
38724098
};
38734099
// clang-format on
@@ -4823,6 +5049,9 @@ static void setup_ctrl_cmd_defaults(struct ctx *ctx)
48235049
ctx->supported_msg_types = NULL;
48245050
ctx->num_supported_msg_types = 0;
48255051

5052+
ctx->supported_vdm_types = NULL;
5053+
ctx->num_supported_vdm_types = 0;
5054+
48265055
// Default to supporting only control messages
48275056
ctx->supported_msg_types = malloc(sizeof(struct msg_type_support));
48285057
if (!ctx->supported_msg_types) {
@@ -4868,6 +5097,9 @@ static void free_ctrl_cmd_defaults(struct ctx *ctx)
48685097
free(ctx->supported_msg_types[i].versions);
48695098
}
48705099
free(ctx->supported_msg_types);
5100+
free(ctx->supported_vdm_types);
5101+
ctx->supported_vdm_types = NULL;
5102+
ctx->num_supported_vdm_types = 0;
48715103
}
48725104

48735105
static int endpoint_send_allocate_endpoint_ids(

tests/test_mctpd.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,3 +1290,64 @@ async def test_get_message_types(dbus, mctpd):
12901290
cmd = MCTPControlCommand(True, 0, 0x04, bytes([0x05]))
12911291
rsp = await ep.send_control(mctpd.network.mctp_socket, cmd)
12921292
assert rsp.hex(' ') == '00 04 00 01 f4 f3 f2 f1'
1293+
1294+
""" Test RegisterVDMTypeSupport with PCIe and IANA VDMs """
1295+
async def test_register_vdm_type_support(mctpd):
1296+
ep = mctpd.network.endpoints[0]
1297+
ep.eid = 12
1298+
iface = mctpd.system.interfaces[0]
1299+
await mctpd.system.add_route(mctpd.system.Route(ep.eid, 1, iface = iface))
1300+
await mctpd.system.add_neighbour(
1301+
mctpd.system.Neighbour(iface, ep.lladdr, ep.eid)
1302+
)
1303+
1304+
# Verify error response when no VDM is registered
1305+
cmd = MCTPControlCommand(True, 0, 0x06, bytes([0x00]))
1306+
rsp = await ep.send_control(mctpd.network.mctp_socket, cmd)
1307+
assert rsp.hex(' ') == '00 06 01'
1308+
1309+
async with asyncdbus.MessageBus().connect() as temp_bus:
1310+
mctp = await mctpd_mctp_base_iface_obj(temp_bus)
1311+
1312+
# Register PCIe VDM: format=0x00, VID=0xABCD, command_set=0x0001
1313+
await mctp.call_register_vdm_type_support(0x00,
1314+
asyncdbus.Variant('q', 0xABCD), 0x0001)
1315+
1316+
# Register IANA VDM: format=0x01, VID=0x1234ABCD, command_set=0x5678
1317+
await mctp.call_register_vdm_type_support(0x01,
1318+
asyncdbus.Variant('u', 0x1234ABCD), 0x5678)
1319+
1320+
# Verify DBus call fails with invalid format 0x02
1321+
with pytest.raises(asyncdbus.errors.DBusError) as ex:
1322+
await mctp.call_register_vdm_type_support(0x02,
1323+
asyncdbus.Variant('q', 0xABCD), 0x0001)
1324+
assert "Unsupported VID format" in str(ex.value)
1325+
1326+
# Verify DBus call fails with duplicate PCIe VDM
1327+
with pytest.raises(asyncdbus.errors.DBusError) as ex:
1328+
await mctp.call_register_vdm_type_support(0x00,
1329+
asyncdbus.Variant('q', 0xABCD), 0x0001)
1330+
assert str(ex.value) == "VDM type already registered"
1331+
1332+
# Verify PCIe VDM (selector 0)
1333+
cmd = MCTPControlCommand(True, 0, 0x06, bytes([0x00]))
1334+
rsp = await ep.send_control(mctpd.network.mctp_socket, cmd)
1335+
assert rsp.hex(' ') == '00 06 00 01 00 ab cd 00 01'
1336+
1337+
# Verify IANA VDM (selector 1)
1338+
cmd = MCTPControlCommand(True, 0, 0x06, bytes([0x01]))
1339+
rsp = await ep.send_control(mctpd.network.mctp_socket, cmd)
1340+
assert rsp.hex(' ') == '00 06 00 ff 01 12 34 ab cd 56 78'
1341+
1342+
# Verify error with incorrect selector
1343+
cmd = MCTPControlCommand(True, 0, 0x06, bytes([0x05]))
1344+
rsp = await ep.send_control(mctpd.network.mctp_socket, cmd)
1345+
assert rsp.hex(' ') == '00 06 02'
1346+
1347+
# Give mctpd a moment to process the disconnection
1348+
await trio.sleep(0.1)
1349+
1350+
# Verify VDM types are removed after disconnect
1351+
cmd = MCTPControlCommand(True, 0, 0x06, bytes([0x00]))
1352+
rsp = await ep.send_control(mctpd.network.mctp_socket, cmd)
1353+
assert rsp.hex(' ') == '00 06 01' # Should be error again

0 commit comments

Comments
 (0)