@@ -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 );
@@ -3420,6 +3511,33 @@ static int on_dbus_peer_removed(sd_bus_track *track, void *userdata)
34203511 return 0 ;
34213512}
34223513
3514+ static int on_dbus_peer_removed_vdm_type (sd_bus_track * track , void * userdata )
3515+ {
3516+ struct ctx * ctx = userdata ;
3517+ size_t i ;
3518+
3519+ for (i = 0 ; i < ctx -> num_supported_vdm_types ; i ++ ) {
3520+ struct vdm_type_support * vdm_type =
3521+ & ctx -> supported_vdm_types [i ];
3522+
3523+ if (vdm_type -> source_peer != track )
3524+ continue ;
3525+ if (ctx -> verbose ) {
3526+ warnx ("Removing VDM type support entry format %d cmd_set 0x%04x" ,
3527+ vdm_type -> format , vdm_type -> cmd_set );
3528+ }
3529+ if (i != ctx -> num_supported_vdm_types - 1 ) {
3530+ * vdm_type = ctx -> supported_vdm_types
3531+ [ctx -> num_supported_vdm_types - 1 ];
3532+ }
3533+ ctx -> num_supported_vdm_types -- ;
3534+ break ;
3535+ }
3536+
3537+ sd_bus_track_unref (track );
3538+ return 0 ;
3539+ }
3540+
34233541static int method_register_type_support (sd_bus_message * call , void * data ,
34243542 sd_bus_error * berr )
34253543{
@@ -3506,6 +3624,121 @@ static int method_register_type_support(sd_bus_message *call, void *data,
35063624 return rc ;
35073625}
35083626
3627+ static int method_register_vdm_type_support (sd_bus_message * call , void * data ,
3628+ sd_bus_error * berr )
3629+ {
3630+ struct vdm_type_support new_vdm , * cur_vdm_type , * new_vdm_types_arr ;
3631+ const char * vid_type_str ;
3632+ struct ctx * ctx = data ;
3633+ uint8_t vid_format ;
3634+ uint16_t vid_pcie ;
3635+ uint32_t vid_iana ;
3636+ int rc ;
3637+
3638+ rc = sd_bus_message_read (call , "y" , & vid_format );
3639+ if (rc < 0 )
3640+ goto err ;
3641+ new_vdm .format = vid_format ;
3642+
3643+ rc = sd_bus_message_peek_type (call , NULL , & vid_type_str );
3644+ if (rc < 0 ) {
3645+ return sd_bus_error_setf (berr , SD_BUS_ERROR_INVALID_ARGS ,
3646+ "Failed to read variant type" );
3647+ }
3648+
3649+ if (new_vdm .format == VID_FORMAT_PCIE ) {
3650+ if (strcmp (vid_type_str , "q" ) != 0 ) {
3651+ return sd_bus_error_setf (
3652+ berr , SD_BUS_ERROR_INVALID_ARGS ,
3653+ "Expected format is PCIe but variant contains '%s'" ,
3654+ vid_type_str );
3655+ }
3656+ rc = sd_bus_message_read (call , "v" , "q" , & vid_pcie );
3657+ if (rc < 0 )
3658+ goto err ;
3659+ new_vdm .vendor_id .pcie = vid_pcie ;
3660+ } else if (new_vdm .format == VID_FORMAT_IANA ) {
3661+ if (strcmp (vid_type_str , "u" ) != 0 ) {
3662+ return sd_bus_error_setf (
3663+ berr , SD_BUS_ERROR_INVALID_ARGS ,
3664+ "Expected format is IANA but variant contains '%s'" ,
3665+ vid_type_str );
3666+ }
3667+ rc = sd_bus_message_read (call , "v" , "u" , & vid_iana );
3668+ if (rc < 0 )
3669+ goto err ;
3670+ new_vdm .vendor_id .iana = vid_iana ;
3671+ } else {
3672+ return sd_bus_error_setf (berr , SD_BUS_ERROR_INVALID_ARGS ,
3673+ "Unsupported VID format: %d" ,
3674+ new_vdm .format );
3675+ }
3676+
3677+ rc = sd_bus_message_read (call , "q" , & new_vdm .cmd_set );
3678+ if (rc < 0 )
3679+ goto err ;
3680+
3681+ // Check for duplicates
3682+ for (size_t i = 0 ; i < ctx -> num_supported_vdm_types ; i ++ ) {
3683+ if (ctx -> supported_vdm_types [i ].format != new_vdm .format )
3684+ continue ;
3685+
3686+ if (ctx -> supported_vdm_types [i ].cmd_set != new_vdm .cmd_set )
3687+ continue ;
3688+
3689+ bool vid_matches = false;
3690+ if (new_vdm .format == VID_FORMAT_PCIE ) {
3691+ vid_matches =
3692+ (ctx -> supported_vdm_types [i ].vendor_id .pcie ==
3693+ new_vdm .vendor_id .pcie );
3694+ } else {
3695+ vid_matches =
3696+ (ctx -> supported_vdm_types [i ].vendor_id .iana ==
3697+ new_vdm .vendor_id .iana );
3698+ }
3699+
3700+ if (vid_matches ) {
3701+ return sd_bus_error_setf (berr ,
3702+ SD_BUS_ERROR_INVALID_ARGS ,
3703+ "VDM type already registered" );
3704+ }
3705+ }
3706+
3707+ new_vdm_types_arr = realloc (ctx -> supported_vdm_types ,
3708+ (ctx -> num_supported_vdm_types + 1 ) *
3709+ sizeof (struct vdm_type_support ));
3710+ if (!new_vdm_types_arr )
3711+ return sd_bus_error_setf (
3712+ berr , SD_BUS_ERROR_NO_MEMORY ,
3713+ "Failed to allocate memory for VDM types" );
3714+ ctx -> supported_vdm_types = new_vdm_types_arr ;
3715+
3716+ cur_vdm_type = & ctx -> supported_vdm_types [ctx -> num_supported_vdm_types ];
3717+ memcpy (cur_vdm_type , & new_vdm , sizeof (struct vdm_type_support ));
3718+
3719+ // Track peer
3720+ rc = sd_bus_track_new (ctx -> bus , & cur_vdm_type -> source_peer ,
3721+ on_dbus_peer_removed_vdm_type , ctx );
3722+ if (rc < 0 )
3723+ goto track_err ;
3724+
3725+ rc = sd_bus_track_add_sender (cur_vdm_type -> source_peer , call );
3726+ if (rc < 0 )
3727+ goto track_err ;
3728+
3729+ ctx -> num_supported_vdm_types ++ ;
3730+ return sd_bus_reply_method_return (call , "" );
3731+
3732+ track_err :
3733+ sd_bus_track_unref (cur_vdm_type -> source_peer );
3734+ set_berr (ctx , rc , berr );
3735+ return rc ;
3736+
3737+ err :
3738+ set_berr (ctx , rc , berr );
3739+ return rc ;
3740+ }
3741+
35093742// clang-format off
35103743static const sd_bus_vtable bus_link_owner_vtable [] = {
35113744 SD_BUS_VTABLE_START (0 ),
@@ -3868,6 +4101,13 @@ static const sd_bus_vtable mctp_base_vtable[] = {
38684101 SD_BUS_NO_RESULT ,
38694102 method_register_type_support ,
38704103 0 ),
4104+ SD_BUS_METHOD_WITH_ARGS ("RegisterVDMTypeSupport" ,
4105+ SD_BUS_ARGS ("y" , format ,
4106+ "v" , format_data ,
4107+ "q" , vendor_subtype ),
4108+ SD_BUS_NO_RESULT ,
4109+ method_register_vdm_type_support ,
4110+ 0 ),
38714111 SD_BUS_VTABLE_END ,
38724112};
38734113// clang-format on
@@ -4823,6 +5063,9 @@ static void setup_ctrl_cmd_defaults(struct ctx *ctx)
48235063 ctx -> supported_msg_types = NULL ;
48245064 ctx -> num_supported_msg_types = 0 ;
48255065
5066+ ctx -> supported_vdm_types = NULL ;
5067+ ctx -> num_supported_vdm_types = 0 ;
5068+
48265069 // Default to supporting only control messages
48275070 ctx -> supported_msg_types = malloc (sizeof (struct msg_type_support ));
48285071 if (!ctx -> supported_msg_types ) {
@@ -4868,6 +5111,9 @@ static void free_ctrl_cmd_defaults(struct ctx *ctx)
48685111 free (ctx -> supported_msg_types [i ].versions );
48695112 }
48705113 free (ctx -> supported_msg_types );
5114+ free (ctx -> supported_vdm_types );
5115+ ctx -> supported_vdm_types = NULL ;
5116+ ctx -> num_supported_vdm_types = 0 ;
48715117}
48725118
48735119static int endpoint_send_allocate_endpoint_ids (
0 commit comments