@@ -192,6 +192,12 @@ struct peer {
192192 } recovery ;
193193};
194194
195+ struct msg_type_support {
196+ uint8_t msg_type ;
197+ uint32_t * versions ;
198+ size_t num_versions ;
199+ };
200+
195201struct ctx {
196202 sd_event * event ;
197203 sd_bus * bus ;
@@ -219,6 +225,10 @@ struct ctx {
219225
220226 uint8_t uuid [16 ];
221227
228+ // Supported message types and their versions
229+ struct msg_type_support * supported_msg_types ;
230+ size_t num_supported_msg_types ;
231+
222232 // Verbose logging
223233 bool verbose ;
224234};
@@ -667,42 +677,64 @@ handle_control_get_version_support(struct ctx *ctx, int sd,
667677 struct mctp_ctrl_cmd_get_mctp_ver_support * req = NULL ;
668678 struct mctp_ctrl_resp_get_mctp_ver_support * resp = NULL ;
669679 uint32_t * versions = NULL ;
670- // space for 4 versions
671- uint8_t respbuf [sizeof (* resp ) + 4 * sizeof (* versions )];
680+ uint8_t * respbuf = NULL ;
672681 size_t resp_len ;
682+ ssize_t i , ver_idx = -1 , ver_count = 0 ;
683+ int status ;
673684
674685 if (buf_size < sizeof (struct mctp_ctrl_cmd_get_mctp_ver_support )) {
675686 warnx ("short Get Version Support message" );
676687 return - ENOMSG ;
677688 }
678689
679690 req = (void * )buf ;
680- resp = (void * )respbuf ;
681- memset (resp , 0x0 , sizeof (* resp ));
682- versions = (void * )(resp + 1 );
683- switch (req -> msg_type_number ) {
684- case 0xff : // Base Protocol
685- case 0x00 : // Control protocol
686- // from DSP0236 1.3.1 section 12.6.2. Big endian.
687- versions [0 ] = htonl (0xF1F0FF00 );
688- versions [1 ] = htonl (0xF1F1FF00 );
689- versions [2 ] = htonl (0xF1F2FF00 );
690- versions [3 ] = htonl (0xF1F3F100 );
691- resp -> number_of_entries = 4 ;
692- resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
693- resp_len = sizeof (* resp ) + 4 * sizeof (* versions );
694- break ;
695- default :
696- // Unsupported message type
691+ if (req -> msg_type_number == 0xFF ) {
692+ // use same version for base spec and control protocol
693+ req -> msg_type_number = 0 ;
694+ }
695+ for (i = 0 ; i < ctx -> num_supported_msg_types ; i ++ ) {
696+ if (ctx -> supported_msg_types [i ].msg_type ==
697+ req -> msg_type_number ) {
698+ ver_idx = i ;
699+ break ;
700+ }
701+ }
702+
703+ if (ver_idx < 0 ) {
704+ respbuf = malloc (sizeof (struct mctp_ctrl_resp ));
705+ if (!respbuf ) {
706+ warnx ("Failed to allocate response buffer" );
707+ return - ENOMEM ;
708+ }
709+ resp = (void * )respbuf ;
710+ // Nobody registered yet as responder for this type
697711 resp -> completion_code =
698712 MCTP_CTRL_CC_GET_MCTP_VER_SUPPORT_UNSUPPORTED_TYPE ;
699- resp_len = sizeof (* resp );
713+ resp_len = sizeof (struct mctp_ctrl_resp );
714+ } else {
715+ ver_count = ctx -> supported_msg_types [ver_idx ].num_versions ;
716+ respbuf =
717+ malloc (sizeof (* resp ) + (ver_count * sizeof (uint32_t )));
718+ if (!respbuf ) {
719+ warnx ("Failed to allocate response buffer for versions" );
720+ return - ENOMEM ;
721+ }
722+ resp = (void * )respbuf ;
723+ resp -> number_of_entries = ver_count ;
724+ versions = (void * )(resp + 1 );
725+ memcpy (versions , ctx -> supported_msg_types [ver_idx ].versions ,
726+ ver_count * sizeof (uint32_t ));
727+ resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
728+ resp_len = sizeof (* resp ) + ver_count * sizeof (uint32_t );
700729 }
701730
702731 resp -> ctrl_hdr .command_code = req -> ctrl_hdr .command_code ;
703732 resp -> ctrl_hdr .rq_dgram_inst =
704733 (req -> ctrl_hdr .rq_dgram_inst & IID_MASK ) | RQDI_RESP ;
705- return reply_message (ctx , sd , resp , resp_len , addr );
734+
735+ status = reply_message (ctx , sd , resp , resp_len , addr );
736+ free (respbuf );
737+ return status ;
706738}
707739
708740static int handle_control_get_endpoint_id (struct ctx * ctx , int sd ,
@@ -761,28 +793,42 @@ static int handle_control_get_message_type_support(
761793 const uint8_t * buf , const size_t buf_size )
762794{
763795 struct mctp_ctrl_cmd_get_msg_type_support * req = NULL ;
764- ;
765796 struct mctp_ctrl_resp_get_msg_type_support * resp = NULL ;
766- uint8_t resp_buf [sizeof (* resp ) + 1 ];
767- size_t resp_len ;
797+ uint8_t * resp_buf , * msg_types ;
798+ size_t resp_len , type_count ;
799+ size_t i ;
768800
769801 if (buf_size < sizeof (* req )) {
770802 warnx ("short Get Message Type Support message" );
771803 return - ENOMSG ;
772804 }
773805
774806 req = (void * )buf ;
807+ type_count = ctx -> num_supported_msg_types ;
808+ // Allocate extra space for the message types
809+ resp_len = sizeof (* resp ) + type_count ;
810+ resp_buf = malloc (resp_len );
811+ if (!resp_buf ) {
812+ warnx ("Failed to allocate response buffer" );
813+ return - ENOMEM ;
814+ }
815+
775816 resp = (void * )resp_buf ;
776- resp -> ctrl_hdr .command_code = req -> ctrl_hdr .command_code ;
777817 resp -> ctrl_hdr .rq_dgram_inst =
778818 (req -> ctrl_hdr .rq_dgram_inst & IID_MASK ) | RQDI_RESP ;
819+ resp -> ctrl_hdr .command_code = req -> ctrl_hdr .command_code ;
820+ resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
779821
780- // Only control messages supported
781- resp -> msg_type_count = 1 ;
782- * ((uint8_t * )(resp + 1 )) = MCTP_CTRL_HDR_MSG_TYPE ;
783- resp_len = sizeof (* resp ) + resp -> msg_type_count ;
822+ resp -> msg_type_count = type_count ;
823+ // Append message types after msg_type_count
824+ msg_types = (uint8_t * )(resp + 1 );
825+ for (i = 0 ; i < type_count ; i ++ ) {
826+ msg_types [i ] = ctx -> supported_msg_types [i ].msg_type ;
827+ }
784828
785- return reply_message (ctx , sd , resp , resp_len , addr );
829+ int result = reply_message (ctx , sd , resp , resp_len , addr );
830+ free (resp_buf );
831+ return result ;
786832}
787833
788834static int
@@ -2829,6 +2875,71 @@ static int method_net_learn_endpoint(sd_bus_message *call, void *data,
28292875 return rc ;
28302876}
28312877
2878+ static int method_register_responder (sd_bus_message * call , void * data ,
2879+ sd_bus_error * berr )
2880+ {
2881+ struct ctx * ctx = data ;
2882+ uint8_t msg_type ;
2883+ const uint32_t * versions = NULL ;
2884+ size_t versions_len ;
2885+ int rc , i ;
2886+
2887+ rc = sd_bus_message_read (call , "y" , & msg_type );
2888+ if (rc < 0 )
2889+ goto err ;
2890+ rc = sd_bus_message_read_array (call , 'u' , (const void * * )& versions ,
2891+ & versions_len );
2892+ if (rc < 0 )
2893+ goto err ;
2894+
2895+ if (versions_len == 0 ) {
2896+ warnx ("No versions provided for message type %d" , msg_type );
2897+ return sd_bus_error_setf (
2898+ berr , SD_BUS_ERROR_INVALID_ARGS ,
2899+ "No versions provided for message type %d" , msg_type );
2900+ }
2901+
2902+ for (i = 0 ; i < ctx -> num_supported_msg_types ; i ++ ) {
2903+ if (ctx -> supported_msg_types [i ].msg_type == msg_type ) {
2904+ warnx ("Message type %d already registered" , msg_type );
2905+ return sd_bus_error_setf (
2906+ berr , SD_BUS_ERROR_INVALID_ARGS ,
2907+ "Message type %d already registered" , msg_type );
2908+ }
2909+ }
2910+
2911+ struct msg_type_support * msg_types =
2912+ realloc (ctx -> supported_msg_types ,
2913+ (ctx -> num_supported_msg_types + 1 ) *
2914+ sizeof (struct msg_type_support ));
2915+ if (!msg_types ) {
2916+ goto oom_err ;
2917+ }
2918+ ctx -> supported_msg_types = msg_types ;
2919+ ctx -> supported_msg_types [ctx -> num_supported_msg_types ].msg_type =
2920+ msg_type ;
2921+ ctx -> supported_msg_types [ctx -> num_supported_msg_types ].num_versions =
2922+ versions_len / sizeof (uint32_t );
2923+ ctx -> supported_msg_types [ctx -> num_supported_msg_types ].versions =
2924+ malloc (versions_len );
2925+ if (!ctx -> supported_msg_types [ctx -> num_supported_msg_types ].versions ) {
2926+ goto oom_err ;
2927+ }
2928+ // Assume callers's responsibility to provide version in uint32 format from spec
2929+ memcpy (ctx -> supported_msg_types [ctx -> num_supported_msg_types ].versions ,
2930+ versions , versions_len );
2931+
2932+ ctx -> num_supported_msg_types ++ ;
2933+
2934+ return sd_bus_reply_method_return (call , "" );
2935+ oom_err :
2936+ return sd_bus_error_setf (berr , SD_BUS_ERROR_NO_MEMORY ,
2937+ "Failed to allocate memory" );
2938+ err :
2939+ set_berr (ctx , rc , berr );
2940+ return rc ;
2941+ }
2942+
28322943// clang-format off
28332944static const sd_bus_vtable bus_link_owner_vtable [] = {
28342945 SD_BUS_VTABLE_START (0 ),
@@ -3145,6 +3256,17 @@ static const sd_bus_vtable bus_network_vtable[] = {
31453256 SD_BUS_VTABLE_PROPERTY_CONST ),
31463257 SD_BUS_VTABLE_END
31473258};
3259+
3260+ static const sd_bus_vtable mctp_base_vtable [] = {
3261+ SD_BUS_VTABLE_START (0 ),
3262+ SD_BUS_METHOD_WITH_ARGS ("RegisterResponder" ,
3263+ SD_BUS_ARGS ("y" , msg_type ,
3264+ "au" , versions ),
3265+ SD_BUS_NO_RESULT ,
3266+ method_register_responder ,
3267+ 0 ),
3268+ SD_BUS_VTABLE_END ,
3269+ };
31483270// clang-format on
31493271
31503272static int emit_endpoint_added (const struct peer * peer )
@@ -3295,6 +3417,14 @@ static int setup_bus(struct ctx *ctx)
32953417 goto out ;
32963418 }
32973419
3420+ rc = sd_bus_add_object_vtable (ctx -> bus , NULL , MCTP_DBUS_PATH ,
3421+ MCTP_DBUS_NAME ,
3422+ mctp_base_vtable , ctx );
3423+ if (rc < 0 ) {
3424+ warnx ("Adding MCTP base vtable failed: %s" , strerror (- rc ));
3425+ goto out ;
3426+ }
3427+
32983428 rc = 0 ;
32993429out :
33003430 return rc ;
@@ -3994,6 +4124,33 @@ static int parse_config(struct ctx *ctx)
39944124 return rc ;
39954125}
39964126
4127+ static void setup_ctrl_cmd_defaults (struct ctx * ctx )
4128+ {
4129+ ctx -> supported_msg_types = NULL ;
4130+ ctx -> num_supported_msg_types = 0 ;
4131+
4132+ // Default to supporting only control messages
4133+ ctx -> supported_msg_types = malloc (sizeof (struct msg_type_support ));
4134+ if (!ctx -> supported_msg_types ) {
4135+ warnx ("Out of memory for supported message types" );
4136+ return ;
4137+ }
4138+ ctx -> num_supported_msg_types = 1 ;
4139+ ctx -> supported_msg_types [0 ].msg_type = MCTP_CTRL_HDR_MSG_TYPE ;
4140+
4141+ ctx -> supported_msg_types [0 ].versions = malloc (sizeof (uint32_t ) * 4 );
4142+ if (!ctx -> supported_msg_types [0 ].versions ) {
4143+ warnx ("Out of memory for versions" );
4144+ free (ctx -> supported_msg_types );
4145+ return ;
4146+ }
4147+ ctx -> supported_msg_types [0 ].num_versions = 4 ;
4148+ ctx -> supported_msg_types [0 ].versions [0 ] = htonl (0xF1F0FF00 );
4149+ ctx -> supported_msg_types [0 ].versions [1 ] = htonl (0xF1F1FF00 );
4150+ ctx -> supported_msg_types [0 ].versions [2 ] = htonl (0xF1F2FF00 );
4151+ ctx -> supported_msg_types [0 ].versions [3 ] = htonl (0xF1F3F100 );
4152+ }
4153+
39974154static void setup_config_defaults (struct ctx * ctx )
39984155{
39994156 ctx -> mctp_timeout = 250000 ; // 250ms
@@ -4002,7 +4159,13 @@ static void setup_config_defaults(struct ctx *ctx)
40024159
40034160static void free_config (struct ctx * ctx )
40044161{
4162+ int i ;
4163+
40054164 free (ctx -> config_filename );
4165+ for (i = 0 ; i < ctx -> num_supported_msg_types ; i ++ ) {
4166+ free (ctx -> supported_msg_types [i ].versions );
4167+ }
4168+ free (ctx -> supported_msg_types );
40064169}
40074170
40084171int main (int argc , char * * argv )
@@ -4013,6 +4176,8 @@ int main(int argc, char **argv)
40134176 setlinebuf (stdout );
40144177
40154178 setup_config_defaults (ctx );
4179+ setup_ctrl_cmd_defaults (ctx );
4180+
40164181 mctp_ops_init ();
40174182
40184183 rc = parse_args (ctx , argc , argv );
0 commit comments