Skip to content

Commit a964b55

Browse files
committed
mctpd: Add VendorDefinedMessageTypes property
Implement Get VDM Support (0x06) control command to query vendor defined message capabilities from peers. Expose via D-Bus property a(yvu) containing format, vendor_id (PCIe 16-bit or IANA 32-bit), and command set. Includes positive test for both formats and negative tests for invalid responses (wrong lengths, invalid format, unsupported command). Signed-off-by: Nidhin MS <nidhin.ms@intel.com>
1 parent 07c7a5d commit a964b55

4 files changed

Lines changed: 382 additions & 16 deletions

File tree

src/mctp-control-spec.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,20 @@ struct mctp_ctrl_resp_get_vdm_support {
114114
uint8_t completion_code;
115115
uint8_t vendor_id_set_selector;
116116
uint8_t vendor_id_format;
117-
union {
118-
uint16_t vendor_id_data_pcie;
119-
uint32_t vendor_id_data_iana;
120-
};
121117
/* following bytes are dependent on vendor id format
122118
* and shall be interpreted by appropriate binding handler */
123119
} __attribute__((__packed__));
124120

121+
struct mctp_vdm_pcie_data {
122+
uint16_t vendor_id;
123+
uint16_t cmd_set;
124+
} __attribute__((__packed__));
125+
126+
struct mctp_vdm_iana_data {
127+
uint32_t enterprise_number;
128+
uint16_t cmd_set;
129+
} __attribute__((__packed__));
130+
125131
struct mctp_pci_ctrl_resp_get_vdm_support {
126132
struct mctp_ctrl_msg_hdr ctrl_hdr;
127133
uint8_t completion_code;

src/mctpd.c

Lines changed: 201 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ struct link {
148148
struct ctx *ctx;
149149
};
150150

151+
struct vdm_type_support;
152+
151153
struct peer {
152154
uint32_t net;
153155
mctp_eid_t eid;
@@ -185,6 +187,9 @@ struct peer {
185187
uint8_t *message_types;
186188
size_t num_message_types;
187189

190+
struct vdm_type_support *vdm_types;
191+
size_t num_vdm_types;
192+
188193
// From Get Endpoint ID
189194
uint8_t endpoint_type;
190195
uint8_t medium_spec;
@@ -1060,8 +1065,9 @@ handle_control_get_vdm_type_support(struct ctx *ctx, int sd,
10601065
struct mctp_ctrl_resp_get_vdm_support *resp = NULL;
10611066
struct mctp_ctrl_cmd_get_vdm_support *req = NULL;
10621067
size_t resp_len, max_rsp_len, vdm_count;
1068+
struct mctp_vdm_pcie_data *vdm_pcie;
1069+
struct mctp_vdm_iana_data *vdm_iana;
10631070
struct vdm_type_support *cur_vdm;
1064-
uint16_t *cmd_type_ptr;
10651071
uint8_t *resp_buf;
10661072
int rc;
10671073

@@ -1073,15 +1079,14 @@ handle_control_get_vdm_type_support(struct ctx *ctx, int sd,
10731079
req = (void *)buf;
10741080
vdm_count = ctx->num_supported_vdm_types;
10751081
// Allocate space for 32 bit VID + 16 bit cmd set
1076-
max_rsp_len = sizeof(*resp) + sizeof(uint16_t);
1082+
max_rsp_len = sizeof(*resp) + sizeof(struct mctp_vdm_iana_data);
10771083
resp_len = max_rsp_len;
10781084
resp_buf = malloc(max_rsp_len);
10791085
if (!resp_buf) {
10801086
warnx("Failed to allocate response buffer");
10811087
return -ENOMEM;
10821088
}
10831089
resp = (void *)resp_buf;
1084-
cmd_type_ptr = (uint16_t *)(resp + 1);
10851090
mctp_ctrl_msg_hdr_init_resp(&resp->ctrl_hdr, req->ctrl_hdr);
10861091

10871092
if (req->vendor_id_set_selector >= vdm_count) {
@@ -1103,17 +1108,17 @@ handle_control_get_vdm_type_support(struct ctx *ctx, int sd,
11031108
resp->vendor_id_format = cur_vdm->format;
11041109

11051110
if (cur_vdm->format == VID_FORMAT_PCIE) {
1106-
// 4 bytes was reserved for VID, but PCIe VID uses only 2 bytes.
1107-
cmd_type_ptr--;
1108-
resp_len = max_rsp_len - sizeof(uint16_t);
1109-
resp->vendor_id_data_pcie =
1110-
htobe16(cur_vdm->vendor_id.pcie);
1111+
vdm_pcie = (void *)(resp + 1);
1112+
resp_len = sizeof(*resp) +
1113+
sizeof(struct mctp_vdm_pcie_data);
1114+
vdm_pcie->vendor_id = htobe16(cur_vdm->vendor_id.pcie);
1115+
vdm_pcie->cmd_set = htobe16(cur_vdm->cmd_set);
11111116
} else {
1112-
resp->vendor_id_data_iana =
1117+
vdm_iana = (void *)(resp + 1);
1118+
vdm_iana->enterprise_number =
11131119
htobe32(cur_vdm->vendor_id.iana);
1120+
vdm_iana->cmd_set = htobe16(cur_vdm->cmd_set);
11141121
}
1115-
1116-
*cmd_type_ptr = htobe16(cur_vdm->cmd_set);
11171122
}
11181123

11191124
rc = reply_message(ctx, sd, resp, resp_len, addr);
@@ -2085,6 +2090,7 @@ static int remove_peer(struct peer *peer)
20852090

20862091
n->peers[peer->eid] = NULL;
20872092
free(peer->message_types);
2093+
free(peer->vdm_types);
20882094
free(peer->uuid);
20892095

20902096
for (idx = 0; idx < ctx->num_peers; idx++) {
@@ -2127,6 +2133,7 @@ static void free_peers(struct ctx *ctx)
21272133
for (size_t i = 0; i < ctx->num_peers; i++) {
21282134
struct peer *peer = ctx->peers[i];
21292135
free(peer->message_types);
2136+
free(peer->vdm_types);
21302137
free(peer->uuid);
21312138
free(peer->path);
21322139
free(peer->bridge_ep_poll.sources);
@@ -2585,6 +2592,112 @@ static int query_get_peer_msgtypes(struct peer *peer)
25852592
return rc;
25862593
}
25872594

2595+
static int query_get_peer_vdm_types(struct peer *peer)
2596+
{
2597+
struct mctp_ctrl_resp_get_vdm_support *resp = NULL;
2598+
struct vdm_type_support *cur_vdm_type, *new_vdm;
2599+
struct vdm_type_support *vdm_types = NULL;
2600+
struct mctp_ctrl_cmd_get_vdm_support req;
2601+
size_t buf_size, expect_size, new_size;
2602+
struct mctp_vdm_pcie_data *vdm_pcie;
2603+
struct mctp_vdm_iana_data *vdm_iana;
2604+
struct sockaddr_mctp_ext addr;
2605+
size_t num_vdm_types = 0;
2606+
uint8_t *buf = NULL;
2607+
uint8_t iid, fmt;
2608+
int rc;
2609+
2610+
req.ctrl_hdr.command_code = MCTP_CTRL_CMD_GET_VENDOR_MESSAGE_SUPPORT;
2611+
req.vendor_id_set_selector = 0;
2612+
2613+
while (true) {
2614+
iid = mctp_next_iid(peer->ctx);
2615+
2616+
mctp_ctrl_msg_hdr_init_req(
2617+
&req.ctrl_hdr, iid,
2618+
MCTP_CTRL_CMD_GET_VENDOR_MESSAGE_SUPPORT);
2619+
if (buf) {
2620+
free(buf);
2621+
buf = NULL;
2622+
}
2623+
rc = endpoint_query_peer(peer, MCTP_CTRL_HDR_MSG_TYPE, &req,
2624+
sizeof(req), &buf, &buf_size, &addr);
2625+
if (rc < 0)
2626+
break;
2627+
2628+
/* Check for minimum length of PCIe VDM*/
2629+
expect_size = sizeof(*resp) + sizeof(struct mctp_vdm_pcie_data);
2630+
rc = mctp_ctrl_validate_response(
2631+
buf, buf_size, expect_size, peer_tostr_short(peer), iid,
2632+
MCTP_CTRL_CMD_GET_VENDOR_MESSAGE_SUPPORT);
2633+
if (rc)
2634+
break;
2635+
2636+
resp = (void *)buf;
2637+
fmt = resp->vendor_id_format;
2638+
if (fmt != MCTP_GET_VDM_SUPPORT_PCIE_FORMAT_ID &&
2639+
fmt != MCTP_GET_VDM_SUPPORT_IANA_FORMAT_ID) {
2640+
warnx("%s: bad vendor_id_format 0x%02x dest %s",
2641+
__func__, fmt, peer_tostr(peer));
2642+
rc = -ENOMSG;
2643+
break;
2644+
}
2645+
2646+
if (fmt == MCTP_GET_VDM_SUPPORT_IANA_FORMAT_ID) {
2647+
/* Accomodate 2 bytes for IANA VID */
2648+
expect_size = sizeof(*resp) +
2649+
sizeof(struct mctp_vdm_iana_data);
2650+
}
2651+
2652+
if (buf_size != expect_size) {
2653+
warnx("%s: bad reply length. got %zu, expected %zu dest %s",
2654+
__func__, buf_size, expect_size,
2655+
peer_tostr(peer));
2656+
rc = -ENOMSG;
2657+
break;
2658+
}
2659+
2660+
new_size =
2661+
(num_vdm_types + 1) * sizeof(struct vdm_type_support);
2662+
new_vdm = realloc(vdm_types, new_size);
2663+
if (!new_vdm) {
2664+
rc = -ENOMEM;
2665+
break;
2666+
}
2667+
vdm_types = new_vdm;
2668+
cur_vdm_type = vdm_types + num_vdm_types;
2669+
cur_vdm_type->format = fmt;
2670+
2671+
if (fmt == MCTP_GET_VDM_SUPPORT_IANA_FORMAT_ID) {
2672+
vdm_iana = (struct mctp_vdm_iana_data *)(resp + 1);
2673+
cur_vdm_type->vendor_id.iana =
2674+
be32toh(vdm_iana->enterprise_number);
2675+
cur_vdm_type->cmd_set = be16toh(vdm_iana->cmd_set);
2676+
} else {
2677+
vdm_pcie = (struct mctp_vdm_pcie_data *)(resp + 1);
2678+
cur_vdm_type->vendor_id.pcie =
2679+
be16toh(vdm_pcie->vendor_id);
2680+
cur_vdm_type->cmd_set = be16toh(vdm_pcie->cmd_set);
2681+
}
2682+
num_vdm_types++;
2683+
if (resp->vendor_id_set_selector ==
2684+
MCTP_GET_VDM_SUPPORT_NO_MORE_CAP_SET) {
2685+
peer->vdm_types = vdm_types;
2686+
vdm_types = NULL;
2687+
peer->num_vdm_types = num_vdm_types;
2688+
rc = 0;
2689+
break;
2690+
}
2691+
2692+
/* Use the next selector from the response. 0xFF indicates no more entries */
2693+
req.vendor_id_set_selector = resp->vendor_id_set_selector;
2694+
}
2695+
2696+
free(buf);
2697+
free(vdm_types);
2698+
return rc;
2699+
}
2700+
25882701
static int peer_set_uuid(struct peer *peer, const uint8_t uuid[16])
25892702
{
25902703
if (!peer->uuid) {
@@ -3019,6 +3132,7 @@ static int method_learn_endpoint(sd_bus_message *call, void *data,
30193132
static int query_peer_properties(struct peer *peer)
30203133
{
30213134
const unsigned int max_retries = 4;
3135+
bool supports_vdm = false;
30223136
int rc;
30233137

30243138
for (unsigned int i = 0; i < max_retries; i++) {
@@ -3047,6 +3161,41 @@ static int query_peer_properties(struct peer *peer)
30473161
}
30483162
}
30493163

3164+
for (unsigned int i = 0; i < peer->num_message_types; i++) {
3165+
if (peer->message_types[i] ==
3166+
MCTP_GET_VDM_SUPPORT_IANA_FORMAT_ID ||
3167+
peer->message_types[i] ==
3168+
MCTP_GET_VDM_SUPPORT_PCIE_FORMAT_ID) {
3169+
supports_vdm = true;
3170+
break;
3171+
}
3172+
}
3173+
3174+
if (supports_vdm) {
3175+
for (unsigned int i = 0; i < max_retries; i++) {
3176+
rc = query_get_peer_vdm_types(peer);
3177+
// Success
3178+
if (rc == 0)
3179+
break;
3180+
3181+
// On timeout, retry
3182+
if (rc == -ETIMEDOUT) {
3183+
if (peer->ctx->verbose)
3184+
warnx("Retrying to get vendor message types for %s. Attempt %u",
3185+
peer_tostr(peer), i + 1);
3186+
rc = 0;
3187+
continue;
3188+
}
3189+
3190+
if (rc < 0) {
3191+
warnx("Error getting vendor message types for %s. Ignoring error %d %s",
3192+
peer_tostr(peer), rc, strerror(-rc));
3193+
rc = 0;
3194+
break;
3195+
}
3196+
}
3197+
}
3198+
30503199
for (unsigned int i = 0; i < max_retries; i++) {
30513200
rc = query_get_peer_uuid(peer);
30523201

@@ -3939,6 +4088,42 @@ static int bus_endpoint_get_prop(sd_bus *bus, const char *path,
39394088
rc = sd_bus_message_append_array(reply, 'y',
39404089
peer->message_types,
39414090
peer->num_message_types);
4091+
} else if (strcmp(property, "VendorDefinedMessageTypes") == 0) {
4092+
rc = sd_bus_message_open_container(reply, 'a', "(yvu)");
4093+
if (rc < 0)
4094+
return rc;
4095+
4096+
for (size_t i = 0; i < peer->num_vdm_types; i++) {
4097+
struct vdm_type_support *vdm = &peer->vdm_types[i];
4098+
rc = sd_bus_message_open_container(reply, 'r', "yvu");
4099+
if (rc < 0)
4100+
return rc;
4101+
4102+
rc = sd_bus_message_append(reply, "y", vdm->format);
4103+
if (rc < 0)
4104+
return rc;
4105+
4106+
if (vdm->format == VID_FORMAT_PCIE) {
4107+
rc = sd_bus_message_append(reply, "v", "q",
4108+
vdm->vendor_id.pcie);
4109+
} else {
4110+
rc = sd_bus_message_append(reply, "v", "u",
4111+
vdm->vendor_id.iana);
4112+
}
4113+
if (rc < 0)
4114+
return rc;
4115+
4116+
rc = sd_bus_message_append(reply, "u",
4117+
(uint32_t)vdm->cmd_set);
4118+
if (rc < 0)
4119+
return rc;
4120+
4121+
rc = sd_bus_message_close_container(reply);
4122+
if (rc < 0)
4123+
return rc;
4124+
}
4125+
4126+
rc = sd_bus_message_close_container(reply);
39424127
} else if (strcmp(property, "UUID") == 0 && peer->uuid) {
39434128
const char *s = dfree(bytes_to_uuid(peer->uuid));
39444129
rc = sd_bus_message_append(reply, "s", s);
@@ -4128,6 +4313,11 @@ static const sd_bus_vtable bus_endpoint_obmc_vtable[] = {
41284313
bus_endpoint_get_prop,
41294314
0,
41304315
SD_BUS_VTABLE_PROPERTY_CONST),
4316+
SD_BUS_PROPERTY("VendorDefinedMessageTypes",
4317+
"a(yvu)",
4318+
bus_endpoint_get_prop,
4319+
0,
4320+
SD_BUS_VTABLE_PROPERTY_CONST),
41314321
SD_BUS_VTABLE_END
41324322
};
41334323

tests/mctpenv/__init__.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,15 @@ def to_buf(self):
348348

349349

350350
class Endpoint:
351-
def __init__(self, iface, lladdr, ep_uuid=None, eid=0, types=None):
351+
def __init__(
352+
self, iface, lladdr, ep_uuid=None, eid=0, types=None, vdm_msg_types=None
353+
):
352354
self.iface = iface
353355
self.lladdr = lladdr
354356
self.uuid = ep_uuid or uuid.uuid1()
355357
self.eid = eid
356358
self.types = types or [0]
359+
self.vdm_msg_types = vdm_msg_types or []
357360
self.bridged_eps = []
358361
self.allocated_pool = None # or (start, size)
359362

@@ -428,6 +431,28 @@ async def handle_mctp_control(self, sock, addr, data):
428431
data = bytes(hdr + [0x00, len(types)] + types)
429432
await sock.send(raddr, data)
430433

434+
elif opcode == 6:
435+
# Get Vendor Defined Message Support
436+
vdm_support = self.vdm_msg_types
437+
selector = data[2]
438+
if selector >= len(vdm_support):
439+
await sock.send(raddr, bytes(hdr + [0x02]))
440+
return
441+
cur_vdm = vdm_support[selector]
442+
selector = (
443+
0xFF if selector == (len(vdm_support) - 1) else selector + 1
444+
)
445+
resp = hdr + [0x00, selector, cur_vdm[0]]
446+
if cur_vdm[0] == 0:
447+
resp = resp + list(cur_vdm[1].to_bytes(2, 'big'))
448+
elif cur_vdm[0] == 1:
449+
resp = resp + list(cur_vdm[1].to_bytes(4, 'big'))
450+
else:
451+
await sock.send(raddr, bytes(hdr + [0x02]))
452+
return
453+
resp = resp + list(cur_vdm[2].to_bytes(2, 'big'))
454+
await sock.send(raddr, bytes(resp))
455+
431456
elif opcode == 8:
432457
# Allocate Endpoint IDs
433458
(_, _, _, pool_size, pool_start) = data

0 commit comments

Comments
 (0)