@@ -192,6 +192,12 @@ struct peer {
192
192
} recovery ;
193
193
};
194
194
195
+ struct msg_type_support {
196
+ uint8_t msg_type ;
197
+ uint32_t * versions ;
198
+ size_t num_versions ;
199
+ };
200
+
195
201
struct ctx {
196
202
sd_event * event ;
197
203
sd_bus * bus ;
@@ -219,6 +225,10 @@ struct ctx {
219
225
220
226
uint8_t uuid [16 ];
221
227
228
+ // Supported message types and their versions
229
+ struct msg_type_support * supported_msg_types ;
230
+ size_t num_supported_msg_types ;
231
+
222
232
// Verbose logging
223
233
bool verbose ;
224
234
};
@@ -667,42 +677,64 @@ handle_control_get_version_support(struct ctx *ctx, int sd,
667
677
struct mctp_ctrl_cmd_get_mctp_ver_support * req = NULL ;
668
678
struct mctp_ctrl_resp_get_mctp_ver_support * resp = NULL ;
669
679
uint32_t * versions = NULL ;
670
- // space for 4 versions
671
- uint8_t respbuf [sizeof (* resp ) + 4 * sizeof (* versions )];
680
+ uint8_t * respbuf = NULL ;
672
681
size_t resp_len ;
682
+ ssize_t i , ver_idx = -1 , ver_count = 0 ;
683
+ int status ;
673
684
674
685
if (buf_size < sizeof (struct mctp_ctrl_cmd_get_mctp_ver_support )) {
675
686
warnx ("short Get Version Support message" );
676
687
return - ENOMSG ;
677
688
}
678
689
679
690
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
697
711
resp -> completion_code =
698
712
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 );
700
729
}
701
730
702
731
resp -> ctrl_hdr .command_code = req -> ctrl_hdr .command_code ;
703
732
resp -> ctrl_hdr .rq_dgram_inst =
704
733
(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 ;
706
738
}
707
739
708
740
static int handle_control_get_endpoint_id (struct ctx * ctx , int sd ,
@@ -761,28 +793,42 @@ static int handle_control_get_message_type_support(
761
793
const uint8_t * buf , const size_t buf_size )
762
794
{
763
795
struct mctp_ctrl_cmd_get_msg_type_support * req = NULL ;
764
- ;
765
796
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 ;
768
800
769
801
if (buf_size < sizeof (* req )) {
770
802
warnx ("short Get Message Type Support message" );
771
803
return - ENOMSG ;
772
804
}
773
805
774
806
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
+
775
816
resp = (void * )resp_buf ;
776
- resp -> ctrl_hdr .command_code = req -> ctrl_hdr .command_code ;
777
817
resp -> ctrl_hdr .rq_dgram_inst =
778
818
(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 ;
779
821
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
+ }
784
828
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 ;
786
832
}
787
833
788
834
static int
@@ -2829,6 +2875,71 @@ static int method_net_learn_endpoint(sd_bus_message *call, void *data,
2829
2875
return rc ;
2830
2876
}
2831
2877
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
+
2832
2943
// clang-format off
2833
2944
static const sd_bus_vtable bus_link_owner_vtable [] = {
2834
2945
SD_BUS_VTABLE_START (0 ),
@@ -3145,6 +3256,17 @@ static const sd_bus_vtable bus_network_vtable[] = {
3145
3256
SD_BUS_VTABLE_PROPERTY_CONST ),
3146
3257
SD_BUS_VTABLE_END
3147
3258
};
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
+ };
3148
3270
// clang-format on
3149
3271
3150
3272
static int emit_endpoint_added (const struct peer * peer )
@@ -3295,6 +3417,14 @@ static int setup_bus(struct ctx *ctx)
3295
3417
goto out ;
3296
3418
}
3297
3419
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
+
3298
3428
rc = 0 ;
3299
3429
out :
3300
3430
return rc ;
@@ -3994,6 +4124,33 @@ static int parse_config(struct ctx *ctx)
3994
4124
return rc ;
3995
4125
}
3996
4126
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
+
3997
4154
static void setup_config_defaults (struct ctx * ctx )
3998
4155
{
3999
4156
ctx -> mctp_timeout = 250000 ; // 250ms
@@ -4002,7 +4159,13 @@ static void setup_config_defaults(struct ctx *ctx)
4002
4159
4003
4160
static void free_config (struct ctx * ctx )
4004
4161
{
4162
+ int i ;
4163
+
4005
4164
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 );
4006
4169
}
4007
4170
4008
4171
int main (int argc , char * * argv )
@@ -4013,6 +4176,8 @@ int main(int argc, char **argv)
4013
4176
setlinebuf (stdout );
4014
4177
4015
4178
setup_config_defaults (ctx );
4179
+ setup_ctrl_cmd_defaults (ctx );
4180
+
4016
4181
mctp_ops_init ();
4017
4182
4018
4183
rc = parse_args (ctx , argc , argv );
0 commit comments