@@ -192,6 +192,16 @@ struct peer {
192192 } recovery ;
193193};
194194
195+ struct msg_type_support {
196+ size_t count ;
197+
198+ // Assume array index follows same order. Msg type at msg_types[0]
199+ // will have version_counts[0] versions stored at versions[0]
200+ uint8_t * msg_types ;
201+ size_t * version_counts ;
202+ uint32_t * * versions ;
203+ };
204+
195205struct ctx {
196206 sd_event * event ;
197207 sd_bus * bus ;
@@ -219,6 +229,9 @@ struct ctx {
219229
220230 uint8_t uuid [16 ];
221231
232+ // Supported message types and their versions
233+ struct msg_type_support supported_msg_types ;
234+
222235 // Verbose logging
223236 bool verbose ;
224237};
@@ -670,6 +683,7 @@ handle_control_get_version_support(struct ctx *ctx, int sd,
670683 // space for 4 versions
671684 uint8_t respbuf [sizeof (* resp ) + 4 * sizeof (* versions )];
672685 size_t resp_len ;
686+ ssize_t i , ver_idx = -1 , ver_count = 0 ;
673687
674688 if (buf_size < sizeof (struct mctp_ctrl_cmd_get_mctp_ver_support )) {
675689 warnx ("short Get Version Support message" );
@@ -679,24 +693,32 @@ handle_control_get_version_support(struct ctx *ctx, int sd,
679693 req = (void * )buf ;
680694 resp = (void * )respbuf ;
681695 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+ if (req -> msg_type_number == 0xFF ) {
697+ // use same version for base spec and control protocol
698+ req -> msg_type_number = 0 ;
699+ }
700+ for (i = 0 ; i < ctx -> supported_msg_types .count ; i ++ ) {
701+ if (ctx -> supported_msg_types .msg_types [i ] ==
702+ req -> msg_type_number ) {
703+ ver_idx = i ;
704+ break ;
705+ }
706+ }
707+ if (ver_idx < 0 ) {
696708 // Unsupported message type
697709 resp -> completion_code =
698710 MCTP_CTRL_CC_GET_MCTP_VER_SUPPORT_UNSUPPORTED_TYPE ;
699- resp_len = sizeof (* resp );
711+ // Number of enrties not needed in unsupprted cmd
712+ resp_len = sizeof (* resp ) - sizeof (uint8_t );
713+ } else {
714+ versions = (void * )(resp + 1 );
715+ ver_count = ctx -> supported_msg_types .version_counts [ver_idx ];
716+ memcpy (versions , ctx -> supported_msg_types .versions [ver_idx ],
717+ ver_count * sizeof (uint32_t ));
718+ resp -> number_of_entries = ver_count ;
719+
720+ resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
721+ resp_len = sizeof (* resp ) + ver_count * sizeof (uint32_t );
700722 }
701723
702724 resp -> ctrl_hdr .command_code = req -> ctrl_hdr .command_code ;
@@ -761,28 +783,39 @@ static int handle_control_get_message_type_support(
761783 const uint8_t * buf , const size_t buf_size )
762784{
763785 struct mctp_ctrl_cmd_get_msg_type_support * req = NULL ;
764- ;
765786 struct mctp_ctrl_resp_get_msg_type_support * resp = NULL ;
766- uint8_t resp_buf [ sizeof ( * resp ) + 1 ] ;
767- size_t resp_len ;
787+ uint8_t * resp_buf ;
788+ size_t resp_len , type_count ;
768789
769790 if (buf_size < sizeof (* req )) {
770791 warnx ("short Get Message Type Support message" );
771792 return - ENOMSG ;
772793 }
773794
774795 req = (void * )buf ;
796+ type_count = ctx -> supported_msg_types .count ;
797+ // Allocate extra space for the message types
798+ resp_len = sizeof (* resp ) + type_count ;
799+ resp_buf = malloc (resp_len );
800+ if (!resp_buf ) {
801+ warnx ("Failed to allocate response buffer" );
802+ return - ENOMEM ;
803+ }
804+
775805 resp = (void * )resp_buf ;
776- resp -> ctrl_hdr .command_code = req -> ctrl_hdr .command_code ;
777806 resp -> ctrl_hdr .rq_dgram_inst =
778807 (req -> ctrl_hdr .rq_dgram_inst & IID_MASK ) | RQDI_RESP ;
808+ resp -> ctrl_hdr .command_code = req -> ctrl_hdr .command_code ;
809+ resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
779810
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 ;
811+ resp -> msg_type_count = type_count ;
812+ // Append message types after msg_type_count
813+ memcpy ((uint8_t * )(resp + 1 ), ctx -> supported_msg_types . msg_types ,
814+ type_count ) ;
784815
785- return reply_message (ctx , sd , resp , resp_len , addr );
816+ int result = reply_message (ctx , sd , resp , resp_len , addr );
817+ free (resp_buf );
818+ return result ;
786819}
787820
788821static int
@@ -2829,6 +2862,91 @@ static int method_net_learn_endpoint(sd_bus_message *call, void *data,
28292862 return rc ;
28302863}
28312864
2865+ static int method_register_responder (sd_bus_message * call , void * data ,
2866+ sd_bus_error * berr )
2867+ {
2868+ struct ctx * ctx = data ;
2869+ uint8_t msg_type ;
2870+ const uint32_t * versions = NULL ;
2871+ size_t versions_len ;
2872+ int rc ;
2873+ int i ;
2874+
2875+ rc = sd_bus_message_read (call , "y" , & msg_type );
2876+ if (rc < 0 )
2877+ goto err ;
2878+ rc = sd_bus_message_read_array (call , 'u' , (const void * * )& versions ,
2879+ & versions_len );
2880+ if (rc < 0 )
2881+ goto err ;
2882+
2883+ if (versions_len == 0 ) {
2884+ warnx ("No versions provided for message type %d" , msg_type );
2885+ return sd_bus_error_setf (
2886+ berr , SD_BUS_ERROR_INVALID_ARGS ,
2887+ "No versions provided for message type %d" , msg_type );
2888+ }
2889+
2890+ for (i = 0 ; i < ctx -> supported_msg_types .count ; i ++ ) {
2891+ if (ctx -> supported_msg_types .msg_types [i ] == msg_type ) {
2892+ warnx ("Message type %d already registered" , msg_type );
2893+ return sd_bus_error_setf (
2894+ berr , SD_BUS_ERROR_INVALID_ARGS ,
2895+ "Message type %d already registered" , msg_type );
2896+ }
2897+ }
2898+
2899+ uint8_t * msg_types =
2900+ realloc (ctx -> supported_msg_types .msg_types ,
2901+ (ctx -> supported_msg_types .count + 1 ) * sizeof (uint8_t ));
2902+ if (!msg_types ) {
2903+ goto oom_err ;
2904+ }
2905+ ctx -> supported_msg_types .msg_types = msg_types ;
2906+
2907+ uint32_t * * versions_ptr = realloc (ctx -> supported_msg_types .versions ,
2908+ (ctx -> supported_msg_types .count + 1 ) *
2909+ sizeof (uint32_t * ));
2910+ if (!versions_ptr ) {
2911+ // realloc ptrs are not cleared. msg_types will have one byte extra capacity.
2912+ // same for next alloc also.
2913+ goto oom_err ;
2914+ }
2915+ ctx -> supported_msg_types .versions = versions_ptr ;
2916+
2917+ size_t * version_counts =
2918+ realloc (ctx -> supported_msg_types .version_counts ,
2919+ (ctx -> supported_msg_types .count + 1 ) * sizeof (size_t ));
2920+ if (!version_counts ) {
2921+ goto oom_err ;
2922+ }
2923+ ctx -> supported_msg_types .version_counts = version_counts ;
2924+
2925+ uint32_t * msg_versions = malloc (versions_len );
2926+ if (!msg_versions ) {
2927+ goto oom_err ;
2928+ }
2929+ // Assume callers's responsibility to provide version in uint32 format from spec
2930+ memcpy (msg_versions , versions , versions_len );
2931+
2932+ ctx -> supported_msg_types .msg_types [ctx -> supported_msg_types .count ] =
2933+ msg_type ;
2934+ ctx -> supported_msg_types .versions [ctx -> supported_msg_types .count ] =
2935+ msg_versions ;
2936+ ctx -> supported_msg_types .version_counts [ctx -> supported_msg_types .count ] =
2937+ versions_len / sizeof (uint32_t );
2938+ ctx -> supported_msg_types .count ++ ;
2939+
2940+ return sd_bus_reply_method_return (call , "" );
2941+
2942+ oom_err :
2943+ return sd_bus_error_setf (berr , SD_BUS_ERROR_NO_MEMORY ,
2944+ "Failed to allocate memory" );
2945+ err :
2946+ set_berr (ctx , rc , berr );
2947+ return rc ;
2948+ }
2949+
28322950// clang-format off
28332951static const sd_bus_vtable bus_link_owner_vtable [] = {
28342952 SD_BUS_VTABLE_START (0 ),
@@ -3145,6 +3263,17 @@ static const sd_bus_vtable bus_network_vtable[] = {
31453263 SD_BUS_VTABLE_PROPERTY_CONST ),
31463264 SD_BUS_VTABLE_END
31473265};
3266+
3267+ static const sd_bus_vtable mctp_base_vtable [] = {
3268+ SD_BUS_VTABLE_START (0 ),
3269+ SD_BUS_METHOD_WITH_ARGS ("RegisterResponder" ,
3270+ SD_BUS_ARGS ("y" , msg_type ,
3271+ "au" , versions ),
3272+ SD_BUS_NO_RESULT ,
3273+ method_register_responder ,
3274+ 0 ),
3275+ SD_BUS_VTABLE_END ,
3276+ };
31483277// clang-format on
31493278
31503279static int emit_endpoint_added (const struct peer * peer )
@@ -3295,6 +3424,14 @@ static int setup_bus(struct ctx *ctx)
32953424 goto out ;
32963425 }
32973426
3427+ rc = sd_bus_add_object_vtable (ctx -> bus , NULL , MCTP_DBUS_PATH ,
3428+ MCTP_DBUS_NAME ,
3429+ mctp_base_vtable , ctx );
3430+ if (rc < 0 ) {
3431+ warnx ("Adding MCTP base vtable failed: %s" , strerror (- rc ));
3432+ goto out ;
3433+ }
3434+
32983435 rc = 0 ;
32993436out :
33003437 return rc ;
@@ -3996,13 +4133,68 @@ static int parse_config(struct ctx *ctx)
39964133
39974134static void setup_config_defaults (struct ctx * ctx )
39984135{
4136+ uint32_t * ctrl_cmd_versions = NULL ;
4137+ ctx -> supported_msg_types .msg_types = NULL ;
4138+ ctx -> supported_msg_types .versions = NULL ;
4139+ ctx -> supported_msg_types .version_counts = NULL ;
4140+
39994141 ctx -> mctp_timeout = 250000 ; // 250ms
40004142 ctx -> default_role = ENDPOINT_ROLE_BUS_OWNER ;
4143+ ctx -> supported_msg_types .count = 0 ;
4144+
4145+ // Default to supporting only control messages
4146+ ctx -> supported_msg_types .msg_types = malloc (1 );
4147+ if (!ctx -> supported_msg_types .msg_types ) {
4148+ warnx ("Out of memory for supported message types" );
4149+ goto oom_err ;
4150+ }
4151+ ctrl_cmd_versions = malloc (sizeof (uint32_t ) * 4 );
4152+ if (!ctrl_cmd_versions ) {
4153+ warnx ("Out of memory for versions" );
4154+ goto oom_err ;
4155+ }
4156+ ctx -> supported_msg_types .versions = malloc (sizeof (uint32_t * ));
4157+ if (!ctx -> supported_msg_types .versions ) {
4158+ warnx ("Out of memory for versions" );
4159+ goto oom_err ;
4160+ }
4161+ ctx -> supported_msg_types .version_counts = malloc (sizeof (size_t ));
4162+ if (!ctx -> supported_msg_types .version_counts ) {
4163+ warnx ("Out of memory for version counts" );
4164+ goto oom_err ;
4165+ }
4166+
4167+ ctx -> supported_msg_types .count = 1 ;
4168+ ctx -> supported_msg_types .msg_types [0 ] = MCTP_CTRL_HDR_MSG_TYPE ;
4169+ ctrl_cmd_versions [0 ] = htonl (0xF1F0FF00 );
4170+ ctrl_cmd_versions [1 ] = htonl (0xF1F1FF00 );
4171+ ctrl_cmd_versions [2 ] = htonl (0xF1F2FF00 );
4172+ ctrl_cmd_versions [3 ] = htonl (0xF1F3F100 );
4173+ ctx -> supported_msg_types .versions [0 ] = ctrl_cmd_versions ;
4174+ ctx -> supported_msg_types .version_counts [0 ] = 4 ;
4175+
4176+ return ;
4177+ oom_err :
4178+ free (ctrl_cmd_versions );
4179+ free (ctx -> supported_msg_types .msg_types );
4180+ free (ctx -> supported_msg_types .versions );
4181+ free (ctx -> supported_msg_types .version_counts );
4182+ ctx -> supported_msg_types .msg_types = NULL ;
4183+ ctx -> supported_msg_types .versions = NULL ;
4184+ ctx -> supported_msg_types .version_counts = NULL ;
40014185}
40024186
40034187static void free_config (struct ctx * ctx )
40044188{
4189+ int i ;
4190+
40054191 free (ctx -> config_filename );
4192+ for (i = 0 ; i < ctx -> supported_msg_types .count ; i ++ ) {
4193+ free (ctx -> supported_msg_types .versions [i ]);
4194+ }
4195+ free (ctx -> supported_msg_types .versions );
4196+ free (ctx -> supported_msg_types .version_counts );
4197+ free (ctx -> supported_msg_types .msg_types );
40064198}
40074199
40084200int main (int argc , char * * argv )
0 commit comments