While the existing documentation is good, there are a couple things that have changed since it was originally written, and I had to make a couple minor adjustments to get it to work. Here’s the code to send a message. The receive part should work as originally published; what is important is the set of headers. I built and ran this on an AARCH64 platform running Fedora 38.
I split the code into a header and a .c file for reasons I will address in another article.
spdmcli.h
#include <stdint.h>
#define MCTP_TAG_OWNER 0x08
struct mctp_addr {
uint8_t s_addr;
};
struct sockaddr_mctp {
uint16_t smctp_family;
uint32_t smctp_network;
struct mctp_addr smctp_addr;
uint8_t smctp_type;
uint8_t smctp_tag;
}
I also coded this for spdm, not MCTP control messages. The difference is the value for addr.smctp_type
EDIT: I also added the recvfrom call to make this complete.
spdmcli.c
#include <linux/mctp.h>
#endif
#include <linux/if_link.h>
#include <linux/rtnetlink.h>
#include "stdio.h"
#include "spdmcli.h"
int main(void)
{
struct sockaddr_mctp addr = { 0 };
char buf[] = "hello, world!";
int sd, rc;
/* create the MCTP socket */
sd = socket(AF_MCTP, SOCK_DGRAM, 0);
if (sd < 0)
err(EXIT_FAILURE, "socket() failed");
/* populate the remote address information */
addr.smctp_family = AF_MCTP; /* we're using the MCTP family */
addr.smctp_addr.s_addr = 0x32; /* send to remote endpoint ID 32 */
addr.smctp_type = 5; /* encapsulated protocol type iSPDM = 5 */
addr.smctp_tag = MCTP_TAG_OWNER; /* we own the tag, and so the kernel
will allocate one for us */
addr.smctp_network = 1 ;
/* send the MCTP message */
rc = sendto(sd, buf, sizeof(buf), 0,
(struct sockaddr *)&addr, sizeof(addr));
if (rc != sizeof(buf))
err(EXIT_FAILURE, "sendto() failed");
//EDIT: The following code recieves a message from the network and prints it to the console.
if (rc < 0){
err(EXIT_FAILURE, "recvfrom() failed");
}
printf("recv rc = %d\n",rc);
for (int i =0; i< rc; i++){
printf("%x", rxbuf[i]);
}
return EXIT_SUCCESS;
}