@@ -208,6 +208,21 @@ struct msg_type_support {
208208 sd_bus_track * source_peer ;
209209};
210210
211+ enum vid_format {
212+ VID_FORMAT_PCIE = MCTP_GET_VDM_SUPPORT_PCIE_FORMAT_ID ,
213+ VID_FORMAT_IANA = MCTP_GET_VDM_SUPPORT_IANA_FORMAT_ID ,
214+ };
215+
216+ struct vdm_type_support {
217+ enum vid_format format ;
218+ union {
219+ uint16_t pcie ;
220+ uint32_t iana ;
221+ } vendor_id ;
222+ uint16_t cmd_set ;
223+ sd_bus_track * source_peer ;
224+ };
225+
211226struct ctx {
212227 sd_event * event ;
213228 sd_bus * bus ;
@@ -243,6 +258,9 @@ struct ctx {
243258 struct msg_type_support * supported_msg_types ;
244259 size_t num_supported_msg_types ;
245260
261+ struct vdm_type_support * supported_vdm_types ;
262+ size_t num_supported_vdm_types ;
263+
246264 // Verbose logging
247265 bool verbose ;
248266
@@ -999,6 +1017,75 @@ static int handle_control_get_message_type_support(
9991017 return rc ;
10001018}
10011019
1020+ static int
1021+ handle_control_get_vdm_type_support (struct ctx * ctx , int sd ,
1022+ const struct sockaddr_mctp_ext * addr ,
1023+ const uint8_t * buf , const size_t buf_size )
1024+ {
1025+ struct mctp_ctrl_resp_get_vdm_support * resp = NULL ;
1026+ struct mctp_ctrl_cmd_get_vdm_support * req = NULL ;
1027+ size_t resp_len , max_rsp_len , vdm_count ;
1028+ struct vdm_type_support * cur_vdm ;
1029+ uint16_t * cmd_type_ptr ;
1030+ uint8_t * resp_buf ;
1031+ int rc ;
1032+
1033+ if (buf_size < sizeof (* req )) {
1034+ warnx ("short Get VDM Type Support message" );
1035+ return - ENOMSG ;
1036+ }
1037+
1038+ req = (void * )buf ;
1039+ vdm_count = ctx -> num_supported_vdm_types ;
1040+ // Allocate space for 32 bit VID + 16 bit cmd set
1041+ max_rsp_len = sizeof (* resp ) + sizeof (uint16_t );
1042+ resp_len = max_rsp_len ;
1043+ resp_buf = malloc (max_rsp_len );
1044+ if (!resp_buf ) {
1045+ warnx ("Failed to allocate response buffer" );
1046+ return - ENOMEM ;
1047+ }
1048+ resp = (void * )resp_buf ;
1049+ cmd_type_ptr = (uint16_t * )(resp + 1 );
1050+ mctp_ctrl_msg_hdr_init_resp (& resp -> ctrl_hdr , req -> ctrl_hdr );
1051+
1052+ if (req -> vendor_id_set_selector >= vdm_count ) {
1053+ if (ctx -> verbose ) {
1054+ warnx ("Get VDM Type Support selector %u out of range (max %zu)" ,
1055+ req -> vendor_id_set_selector , vdm_count );
1056+ }
1057+ resp_len = sizeof (struct mctp_ctrl_resp );
1058+ resp -> completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA ;
1059+ } else {
1060+ cur_vdm =
1061+ & ctx -> supported_vdm_types [req -> vendor_id_set_selector ];
1062+ resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
1063+ resp -> vendor_id_set_selector = req -> vendor_id_set_selector + 1 ;
1064+ if (req -> vendor_id_set_selector == (vdm_count - 1 )) {
1065+ resp -> vendor_id_set_selector =
1066+ MCTP_GET_VDM_SUPPORT_NO_MORE_CAP_SET ;
1067+ }
1068+ resp -> vendor_id_format = cur_vdm -> format ;
1069+
1070+ if (cur_vdm -> format == VID_FORMAT_PCIE ) {
1071+ // 4 bytes was reserved for VID, but PCIe VID uses only 2 bytes.
1072+ cmd_type_ptr -- ;
1073+ resp_len = max_rsp_len - sizeof (uint16_t );
1074+ resp -> vendor_id_data_pcie =
1075+ htobe16 (cur_vdm -> vendor_id .pcie );
1076+ } else {
1077+ resp -> vendor_id_data_iana =
1078+ htobe32 (cur_vdm -> vendor_id .iana );
1079+ }
1080+
1081+ * cmd_type_ptr = htobe16 (cur_vdm -> cmd_set );
1082+ }
1083+
1084+ rc = reply_message (ctx , sd , resp , resp_len , addr );
1085+ free (resp_buf );
1086+ return rc ;
1087+ }
1088+
10021089static int
10031090handle_control_resolve_endpoint_id (struct ctx * ctx , int sd ,
10041091 const struct sockaddr_mctp_ext * addr ,
@@ -1202,6 +1289,10 @@ static int cb_listen_control_msg(sd_event_source *s, int sd, uint32_t revents,
12021289 rc = handle_control_get_message_type_support (ctx , sd , & addr ,
12031290 buf , buf_size );
12041291 break ;
1292+ case MCTP_CTRL_CMD_GET_VENDOR_MESSAGE_SUPPORT :
1293+ rc = handle_control_get_vdm_type_support (ctx , sd , & addr , buf ,
1294+ buf_size );
1295+ break ;
12051296 case MCTP_CTRL_CMD_RESOLVE_ENDPOINT_ID :
12061297 rc = handle_control_resolve_endpoint_id (ctx , sd , & addr , buf ,
12071298 buf_size );
@@ -3456,6 +3547,33 @@ static int on_dbus_peer_removed(sd_bus_track *track, void *userdata)
34563547 return 0 ;
34573548}
34583549
3550+ static int on_dbus_peer_removed_vdm_type (sd_bus_track * track , void * userdata )
3551+ {
3552+ struct ctx * ctx = userdata ;
3553+ size_t i ;
3554+
3555+ for (i = 0 ; i < ctx -> num_supported_vdm_types ; i ++ ) {
3556+ struct vdm_type_support * vdm_type =
3557+ & ctx -> supported_vdm_types [i ];
3558+
3559+ if (vdm_type -> source_peer != track )
3560+ continue ;
3561+ if (ctx -> verbose ) {
3562+ warnx ("Removing VDM type support entry format %d cmd_set 0x%04x" ,
3563+ vdm_type -> format , vdm_type -> cmd_set );
3564+ }
3565+ if (i != ctx -> num_supported_vdm_types - 1 ) {
3566+ * vdm_type = ctx -> supported_vdm_types
3567+ [ctx -> num_supported_vdm_types - 1 ];
3568+ }
3569+ ctx -> num_supported_vdm_types -- ;
3570+ break ;
3571+ }
3572+
3573+ sd_bus_track_unref (track );
3574+ return 0 ;
3575+ }
3576+
34593577static int method_register_type_support (sd_bus_message * call , void * data ,
34603578 sd_bus_error * berr )
34613579{
@@ -3542,6 +3660,121 @@ static int method_register_type_support(sd_bus_message *call, void *data,
35423660 return rc ;
35433661}
35443662
3663+ static int method_register_vdm_type_support (sd_bus_message * call , void * data ,
3664+ sd_bus_error * berr )
3665+ {
3666+ struct vdm_type_support new_vdm , * cur_vdm_type , * new_vdm_types_arr ;
3667+ const char * vid_type_str ;
3668+ struct ctx * ctx = data ;
3669+ uint8_t vid_format ;
3670+ uint16_t vid_pcie ;
3671+ uint32_t vid_iana ;
3672+ int rc ;
3673+
3674+ rc = sd_bus_message_read (call , "y" , & vid_format );
3675+ if (rc < 0 )
3676+ goto err ;
3677+ new_vdm .format = vid_format ;
3678+
3679+ rc = sd_bus_message_peek_type (call , NULL , & vid_type_str );
3680+ if (rc < 0 ) {
3681+ return sd_bus_error_setf (berr , SD_BUS_ERROR_INVALID_ARGS ,
3682+ "Failed to read variant type" );
3683+ }
3684+
3685+ if (new_vdm .format == VID_FORMAT_PCIE ) {
3686+ if (strcmp (vid_type_str , "q" ) != 0 ) {
3687+ return sd_bus_error_setf (
3688+ berr , SD_BUS_ERROR_INVALID_ARGS ,
3689+ "Expected format is PCIe but variant contains '%s'" ,
3690+ vid_type_str );
3691+ }
3692+ rc = sd_bus_message_read (call , "v" , "q" , & vid_pcie );
3693+ if (rc < 0 )
3694+ goto err ;
3695+ new_vdm .vendor_id .pcie = vid_pcie ;
3696+ } else if (new_vdm .format == VID_FORMAT_IANA ) {
3697+ if (strcmp (vid_type_str , "u" ) != 0 ) {
3698+ return sd_bus_error_setf (
3699+ berr , SD_BUS_ERROR_INVALID_ARGS ,
3700+ "Expected format is IANA but variant contains '%s'" ,
3701+ vid_type_str );
3702+ }
3703+ rc = sd_bus_message_read (call , "v" , "u" , & vid_iana );
3704+ if (rc < 0 )
3705+ goto err ;
3706+ new_vdm .vendor_id .iana = vid_iana ;
3707+ } else {
3708+ return sd_bus_error_setf (berr , SD_BUS_ERROR_INVALID_ARGS ,
3709+ "Unsupported VID format: %d" ,
3710+ new_vdm .format );
3711+ }
3712+
3713+ rc = sd_bus_message_read (call , "q" , & new_vdm .cmd_set );
3714+ if (rc < 0 )
3715+ goto err ;
3716+
3717+ // Check for duplicates
3718+ for (size_t i = 0 ; i < ctx -> num_supported_vdm_types ; i ++ ) {
3719+ if (ctx -> supported_vdm_types [i ].format != new_vdm .format )
3720+ continue ;
3721+
3722+ if (ctx -> supported_vdm_types [i ].cmd_set != new_vdm .cmd_set )
3723+ continue ;
3724+
3725+ bool vid_matches = false;
3726+ if (new_vdm .format == VID_FORMAT_PCIE ) {
3727+ vid_matches =
3728+ (ctx -> supported_vdm_types [i ].vendor_id .pcie ==
3729+ new_vdm .vendor_id .pcie );
3730+ } else {
3731+ vid_matches =
3732+ (ctx -> supported_vdm_types [i ].vendor_id .iana ==
3733+ new_vdm .vendor_id .iana );
3734+ }
3735+
3736+ if (vid_matches ) {
3737+ return sd_bus_error_setf (berr ,
3738+ SD_BUS_ERROR_INVALID_ARGS ,
3739+ "VDM type already registered" );
3740+ }
3741+ }
3742+
3743+ new_vdm_types_arr = realloc (ctx -> supported_vdm_types ,
3744+ (ctx -> num_supported_vdm_types + 1 ) *
3745+ sizeof (struct vdm_type_support ));
3746+ if (!new_vdm_types_arr )
3747+ return sd_bus_error_setf (
3748+ berr , SD_BUS_ERROR_NO_MEMORY ,
3749+ "Failed to allocate memory for VDM types" );
3750+ ctx -> supported_vdm_types = new_vdm_types_arr ;
3751+
3752+ cur_vdm_type = & ctx -> supported_vdm_types [ctx -> num_supported_vdm_types ];
3753+ memcpy (cur_vdm_type , & new_vdm , sizeof (struct vdm_type_support ));
3754+
3755+ // Track peer
3756+ rc = sd_bus_track_new (ctx -> bus , & cur_vdm_type -> source_peer ,
3757+ on_dbus_peer_removed_vdm_type , ctx );
3758+ if (rc < 0 )
3759+ goto track_err ;
3760+
3761+ rc = sd_bus_track_add_sender (cur_vdm_type -> source_peer , call );
3762+ if (rc < 0 )
3763+ goto track_err ;
3764+
3765+ ctx -> num_supported_vdm_types ++ ;
3766+ return sd_bus_reply_method_return (call , "" );
3767+
3768+ track_err :
3769+ sd_bus_track_unref (cur_vdm_type -> source_peer );
3770+ set_berr (ctx , rc , berr );
3771+ return rc ;
3772+
3773+ err :
3774+ set_berr (ctx , rc , berr );
3775+ return rc ;
3776+ }
3777+
35453778// clang-format off
35463779static const sd_bus_vtable bus_link_owner_vtable [] = {
35473780 SD_BUS_VTABLE_START (0 ),
@@ -3904,6 +4137,13 @@ static const sd_bus_vtable mctp_base_vtable[] = {
39044137 SD_BUS_NO_RESULT ,
39054138 method_register_type_support ,
39064139 0 ),
4140+ SD_BUS_METHOD_WITH_ARGS ("RegisterVDMTypeSupport" ,
4141+ SD_BUS_ARGS ("y" , format ,
4142+ "v" , format_data ,
4143+ "q" , vendor_subtype ),
4144+ SD_BUS_NO_RESULT ,
4145+ method_register_vdm_type_support ,
4146+ 0 ),
39074147 SD_BUS_VTABLE_END ,
39084148};
39094149// clang-format on
@@ -4859,6 +5099,9 @@ static void setup_ctrl_cmd_defaults(struct ctx *ctx)
48595099 ctx -> supported_msg_types = NULL ;
48605100 ctx -> num_supported_msg_types = 0 ;
48615101
5102+ ctx -> supported_vdm_types = NULL ;
5103+ ctx -> num_supported_vdm_types = 0 ;
5104+
48625105 // Default to supporting only control messages
48635106 ctx -> supported_msg_types = malloc (sizeof (struct msg_type_support ));
48645107 if (!ctx -> supported_msg_types ) {
@@ -4904,6 +5147,9 @@ static void free_ctrl_cmd_defaults(struct ctx *ctx)
49045147 free (ctx -> supported_msg_types [i ].versions );
49055148 }
49065149 free (ctx -> supported_msg_types );
5150+ free (ctx -> supported_vdm_types );
5151+ ctx -> supported_vdm_types = NULL ;
5152+ ctx -> num_supported_vdm_types = 0 ;
49075153}
49085154
49095155static int endpoint_send_allocate_endpoint_ids (
0 commit comments