### Create and Install libmctp Static Library Source: https://github.com/openbmc/libmctp/blob/master/CMakeLists.txt Builds a static library named 'mctp' from the specified C source files. It also configures include directories, making them public for consumers of the library and ensuring they are placed in the correct location upon installation. The library is installed into the 'lib' directory. ```cmake add_library (mctp STATIC alloc.c astlpc.c crc32.c core.c log.c libmctp.h serial.c crc-16-ccitt.c control.c) target_include_directories (mctp PUBLIC $ $ #include #include #include /* Custom logging function */ static void custom_log_handler(int level, const char *fmt, va_list args) { const char *level_str; switch (level) { case MCTP_LOG_ERR: level_str = "ERROR"; break; case MCTP_LOG_WARNING: level_str = "WARNING"; break; case MCTP_LOG_NOTICE: level_str = "NOTICE"; break; case MCTP_LOG_INFO: level_str = "INFO"; break; case MCTP_LOG_DEBUG: level_str = "DEBUG"; break; default: level_str = "UNKNOWN"; } printf("[MCTP %s] ", level_str); vprintf(fmt, args); printf("\n"); } int main(void) { /* Option 1: Log to stderr with specified level */ mctp_set_log_stdio(MCTP_LOG_DEBUG); /* Option 2: Log to syslog */ openlog("mctp-daemon", LOG_PID, LOG_DAEMON); mctp_set_log_syslog(); /* Option 3: Custom log handler */ mctp_set_log_custom(custom_log_handler); /* Initialize MCTP - will now produce log output */ struct mctp *mctp = mctp_init(); /* ... rest of application ... */ mctp_destroy(mctp); closelog(); return 0; } ``` -------------------------------- ### Configure MCTP over I2C with Neighbor Mapping in C Source: https://context7.com/openbmc/libmctp/llms.txt Demonstrates how to initialize MCTP, set up an I2C binding with a custom transmit function, register the binding with the MCTP core, and establish an EID-to-I2C address mapping for a remote endpoint. It includes example message transmission and reception simulation. Dependencies include libmctp and libmctp-i2c. ```c #include #include #include #include #define OWN_I2C_ADDR 0x20 /* Our I2C address (7-bit) */ #define REMOTE_I2C_ADDR 0x30 /* Remote device I2C address */ #define REMOTE_EID 15 /* Remote MCTP endpoint ID */ /* I2C hardware context */ struct i2c_hw_ctx { int i2c_bus_fd; uint8_t last_dest_addr; }; /* I2C TX function - called by stack to transmit I2C frame */ static int i2c_tx_func(const void *buf, size_t len, void *ctx) { struct i2c_hw_ctx *hw = (struct i2c_hw_ctx *)ctx; const uint8_t *frame = (const uint8_t *)buf; uint8_t dest_addr, cmd, bytecount, src_addr; /* Parse I2C MCTP frame header (4 bytes) */ dest_addr = frame[0]; /* Destination I2C address */ cmd = frame[1]; /* Command code (0x0F for MCTP) */ bytecount = frame[2]; /* Payload length */ src_addr = frame[3]; /* Source I2C address */ printf("I2C TX: dest=0x%02x cmd=0x%02x len=%d\n", dest_addr >> 1, cmd, bytecount); /* Send I2C frame to hardware */ /* ... platform-specific I2C write ... */ return len; } int setup_i2c_binding(void) { struct mctp *mctp; struct mctp_binding_i2c i2c; struct i2c_hw_ctx hw_ctx = {0}; int rc; /* Initialize MCTP */ mctp = mctp_init(); if (!mctp) return -1; /* Configure I2C binding */ rc = mctp_i2c_setup(&i2c, OWN_I2C_ADDR, i2c_tx_func, &hw_ctx); if (rc < 0) { fprintf(stderr, "Failed to setup I2C binding\n"); mctp_destroy(mctp); return -1; } /* Register with MCTP core */ rc = mctp_register_bus(mctp, mctp_binding_i2c_core(&i2c), 12); if (rc < 0) { fprintf(stderr, "Failed to register I2C bus\n"); mctp_i2c_cleanup(&i2c); mctp_destroy(mctp); return -1; } /* Map remote EID to I2C address (LRU cache maintained by binding) */ rc = mctp_i2c_set_neighbour(&i2c, REMOTE_EID, REMOTE_I2C_ADDR); if (rc < 0) { fprintf(stderr, "Failed to set neighbor mapping\n"); return -1; } printf("I2C binding configured: local_addr=0x%02x local_eid=%d\n", OWN_I2C_ADDR, 12); printf("Neighbor mapping: EID %d -> I2C 0x%02x\n", REMOTE_EID, REMOTE_I2C_ADDR); /* Transmit message to remote endpoint */ uint8_t message[64] = {0x01, 0x02, 0x03}; rc = mctp_message_tx(mctp, REMOTE_EID, false, 1, message, sizeof(message)); if (rc < 0) { fprintf(stderr, "Failed to send message\n"); } /* Simulate receiving I2C frame from hardware */ uint8_t rx_frame[] = { 0x20 << 1, /* Dest: our address */ 0x0F, /* MCTP command code */ 68, /* Bytecount (64 + 4 MCTP header) */ 0x30 << 1 | 1, /* Source: remote address with read bit */ /* MCTP header (4 bytes) */ 0x01, /* Version */ 12, /* Dest EID */ REMOTE_EID, /* Source EID */ 0xC0, /* SOM | EOM | tag 0 */ /* MCTP payload (64 bytes) */ 0xAA, 0xBB, /* ... */ }; mctp_i2c_rx(&i2c, rx_frame, sizeof(rx_frame)); /* Cleanup */ mctp_i2c_cleanup(&i2c); mctp_destroy(mctp); return 0; } ``` -------------------------------- ### Get Generic Binding from Specific Structure Source: https://github.com/openbmc/libmctp/blob/master/README.md Provides a function to retrieve the generic `struct mctp_binding` from a hardware-specific binding structure. This generic pointer is then used for registering the binding with the MCTP core. ```c struct mctp_binding *mctp_binding_foo_core(struct mctp_binding_foo *b) { return &b->binding; } ``` -------------------------------- ### Run AFL++ for libmctp Fuzzing (Single Instance) Source: https://github.com/openbmc/libmctp/blob/master/docs/fuzzing.md Initiates a single instance of AFL++ for testing libmctp fuzz targets. This is useful for initial testing and debugging. ```shell afl-fuzz -i fuzzrun/hf11/ -o fuzzrun/out12single ./bfuzz/tests/fuzz/i2c-fuzz ``` -------------------------------- ### Configure ASTLPC Binding with File-Based IO (C) Source: https://context7.com/openbmc/libmctp/llms.txt Initializes the MCTP over LPC binding using a file-based interface, simplifying development and testing. This method uses a device file (e.g., /dev/mctp-lpc) for KCS operations. It requires the libmctp and libmctp-astlpc libraries. This is a simpler alternative to MMIO access. ```c /* File-based interface (simpler, for development) */ int setup_astlpc_fileio(void) { struct mctp *mctp; struct mctp_binding_astlpc *astlpc; /* Initialize using file-based KCS device */ astlpc = mctp_astlpc_init_fileio("/dev/mctp-lpc"); if (!astlpc) { perror("mctp_astlpc_init_fileio"); return -1; } mctp = mctp_init(); mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), 8); /* Use as normal... */ mctp_astlpc_destroy(astlpc); mctp_destroy(mctp); return 0; } ``` -------------------------------- ### Build Fuzz Targets for libmctp Source: https://github.com/openbmc/libmctp/blob/master/docs/fuzzing.md This script builds various fuzzing target variants required for different fuzz engines and stages. It's executed from the top-level libmctp directory. ```shell ./tests/fuzz/fuzz-build.py ``` -------------------------------- ### Reproduce libmctp Fuzzing Crashes Source: https://github.com/openbmc/libmctp/blob/master/docs/fuzzing.md Manually runs a specific fuzz target binary with a crashing testcase file to reproduce a crash. This allows for debugging with tools like GDB. ```shell ./bnoopt/tests/fuzz/i2c-fuzz < crashing.bin ``` -------------------------------- ### Run Honggfuzz for libmctp Fuzzing Source: https://github.com/openbmc/libmctp/blob/master/docs/fuzzing.md Executes Honggfuzz for fuzzing libmctp targets. It utilizes a corpus directory for input and supports performance counter usage with optional thread count settings. ```shell nice honggfuzz -T -i corpusdir --linux_perf_branch -- ./bhf/tests/fuzz/i2c-fuzz ``` ```shell echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid ``` ```shell nice honggfuzz -T -i corpusdir --threads 24 -- ./bhf/tests/fuzz/i2c-fuzz ``` -------------------------------- ### Generate Code Coverage Report for libmctp Fuzzing Source: https://github.com/openbmc/libmctp/blob/master/docs/fuzzing.md Generates a code coverage report for libmctp fuzz tests. This script compiles the binary with coverage flags, uses grcov for aggregation, and genhtml for report creation. ```shell ./tests/fuzz/fuzz-coverage.py fuzzrun/corpus bnoopt/tests/fuzz/i2c-fuzz . bnoopt/ coverage-output ``` -------------------------------- ### Configure BMC ASTLPC Binding with MMIO Access (C) Source: https://context7.com/openbmc/libmctp/llms.txt Sets up the MCTP over LPC KCS interface for BMC-to-host communication using memory-mapped I/O. This involves mapping LPC memory, defining KCS and LPC read/write operations, initializing the ASTLPC binding in BMC mode, registering it with MCTP, and performing a sample transmission. Dependencies include libmctp, libmctp-astlpc, standard C libraries, and system calls for memory mapping. ```c #include #include #include #include #include #define LPC_MEMORY_SIZE 0x10000 /* 64KB shared memory window */ /* Custom LPC/KCS operations for MMIO access */ struct lpc_mmio_ctx { void *kcs_base; /* KCS register base address */ void *lpc_mem_base; /* LPC memory window base */ }; static int mmio_kcs_read(void *data, enum mctp_binding_astlpc_kcs_reg reg, uint8_t *val) { struct lpc_mmio_ctx *ctx = (struct lpc_mmio_ctx *)data; volatile uint8_t *kcs = (volatile uint8_t *)ctx->kcs_base; *val = kcs[reg]; return 0; } static int mmio_kcs_write(void *data, enum mctp_binding_astlpc_kcs_reg reg, uint8_t val) { struct lpc_mmio_ctx *ctx = (struct lpc_mmio_ctx *)data; volatile uint8_t *kcs = (volatile uint8_t *)ctx->kcs_base; kcs[reg] = val; return 0; } static int mmio_lpc_read(void *data, void *buf, long offset, size_t len) { struct lpc_mmio_ctx *ctx = (struct lpc_mmio_ctx *)data; memcpy(buf, ctx->lpc_mem_base + offset, len); return 0; } static int mmio_lpc_write(void *data, const void *buf, long offset, size_t len) { struct lpc_mmio_ctx *ctx = (struct lpc_mmio_ctx *)data; memcpy(ctx->lpc_mem_base + offset, buf, len); return 0; } int setup_astlpc_bmc_binding(void) { struct mctp *mctp; struct mctp_binding_astlpc *astlpc; struct lpc_mmio_ctx mmio_ctx; int mem_fd; void *lpc_map; /* Map LPC memory window */ mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (mem_fd < 0) { perror("open /dev/mem"); return -1; } lpc_map = mmap(NULL, LPC_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0x1E789000); /* Aspeed LPC base */ if (lpc_map == MAP_FAILED) { perror("mmap"); close(mem_fd); return -1; } /* Setup MMIO context */ mmio_ctx.kcs_base = (void *)0x1E78A000; /* KCS registers */ mmio_ctx.lpc_mem_base = lpc_map; /* Define hardware operations */ struct mctp_binding_astlpc_ops ops = { .kcs_read = mmio_kcs_read, .kcs_write = mmio_kcs_write, .lpc_read = mmio_lpc_read, .lpc_write = mmio_lpc_write, }; /* Initialize ASTLPC binding in BMC mode */ astlpc = mctp_astlpc_init( MCTP_BINDING_ASTLPC_MODE_BMC, /* BMC mode */ MCTP_BTU, /* MTU */ lpc_map, /* Shared memory */ &ops, /* Hardware operations */ &mmio_ctx /* Operations context */ ); if (!astlpc) { fprintf(stderr, "Failed to initialize ASTLPC binding\n"); munmap(lpc_map, LPC_MEMORY_SIZE); close(mem_fd); return -1; } /* Initialize MCTP and register binding */ mctp = mctp_init(); mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), 8); /* Setup polling for completion */ struct pollfd pollfd; mctp_astlpc_init_pollfd(astlpc, &pollfd); /* Send message to host */ uint8_t message[128]; memset(message, 0xCC, sizeof(message)); mctp_message_tx(mctp, 9, false, 3, message, sizeof(message)); /* Poll until transmission done */ while (!mctp_astlpc_tx_done(astlpc)) { poll(&pollfd, 1, 100); mctp_astlpc_poll(astlpc); } printf("ASTLPC transmission complete\n"); /* Cleanup */ mctp_astlpc_destroy(astlpc); mctp_destroy(mctp); munmap(lpc_map, LPC_MEMORY_SIZE); close(mem_fd); return 0; } ``` -------------------------------- ### Configure Serial MCTP with Custom TX Function (C) Source: https://context7.com/openbmc/libmctp/llms.txt This C code demonstrates setting up MCTP communication over a serial port with a user-defined transmission function. It includes opening the serial device, configuring serial port settings, initializing the MCTP and serial bindings, registering a custom TX function, and setting up an event loop to handle incoming data. Dependencies include libmctp, libmctp-serial, stdio, unistd, and fcntl. ```c #include #include #include #include #include /* Custom transmission context */ struct serial_tx_ctx { int fd; size_t bytes_sent; }; /* Custom TX function called by stack to send serial data */ static int serial_tx_func(void *data, void *buf, size_t len) { struct serial_tx_ctx *ctx = (struct serial_tx_ctx *)data; ssize_t rc; printf("Transmitting %zu bytes to serial device\n", len); rc = write(ctx->fd, buf, len); if (rc < 0) { perror("write"); return -1; } ctx->bytes_sent += rc; return rc; } int setup_serial_binding(void) { struct mctp *mctp; struct mctp_binding_serial *serial; struct serial_tx_ctx tx_ctx; int fd; /* Open serial device */ fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd < 0) { perror("open serial device"); return -1; } /* Configure serial port settings (baud rate, etc.) */ /* ... termios configuration ... */ /* Initialize MCTP and serial binding */ mctp = mctp_init(); serial = mctp_serial_init(); /* Setup TX context */ tx_ctx.fd = fd; tx_ctx.bytes_sent = 0; /* Register custom TX function */ mctp_serial_set_tx_fn(serial, serial_tx_func, &tx_ctx); /* Configure serial binding for RX (uses same fd) */ mctp_serial_open_fd(serial, fd); /* Register with MCTP core */ mctp_register_bus(mctp, mctp_binding_serial_core(serial), 10); /* Event loop */ struct pollfd pfd; mctp_serial_init_pollfd(serial, &pfd); while (1) { int rc = poll(&pfd, 1, 5000); if (rc > 0 && (pfd.revents & POLLIN)) { /* Read and process incoming serial data */ mctp_serial_read(serial); } } return 0; } /* * Serial framing format (DSP0253): * - Frame start/end: 0x7E * - Escape character: 0x7D (escapes 0x7E and 0x7D in data) * - CRC-16-CCITT for integrity * - Automatic framing/deframing by binding */ ``` -------------------------------- ### Initialize MCTP Stack in Endpoint Mode (C) Source: https://context7.com/openbmc/libmctp/llms.txt Initializes the MCTP stack, registers a serial hardware binding, and sets up a message reception callback for endpoint operation. It handles MCTP message fragmentation, reassembly, and routing via the serial interface. Dependencies include libmctp and libmctp-serial. Input is typically via serial port '/dev/ttyS0', and output is received messages printed to stdout. ```c #include #include #include #include /* Callback invoked when complete MCTP message is received */ static void rx_message_callback(uint8_t src_eid, bool tag_owner, uint8_t msg_tag, void *data, void *msg, size_t len) { printf("Received message from EID %d, length %zu bytes\n", src_eid, len); printf("Tag: %d, Tag Owner: %s\n", msg_tag, tag_owner ? "true" : "false"); /* Process message data */ uint8_t *payload = (uint8_t *)msg; printf("First byte: 0x%02x\n", payload[0]); /* User data passed to mctp_set_rx_all() */ int *counter = (int *)data; (*counter)++; } int main(void) { struct mctp *mctp; struct mctp_binding_serial *serial; int message_count = 0; int rc; /* Step 1: Initialize MCTP core */ mctp = mctp_init(); if (!mctp) { fprintf(stderr, "Failed to initialize MCTP\n"); return 1; } /* Step 2: Initialize serial binding */ serial = mctp_serial_init(); if (!serial) { fprintf(stderr, "Failed to initialize serial binding\n"); mctp_destroy(mctp); return 1; } /* Step 3: Configure serial binding for file-based I/O */ rc = mctp_serial_open_path(serial, "/dev/ttyS0"); if (rc < 0) { fprintf(stderr, "Failed to open serial device\n"); mctp_serial_destroy(serial); mctp_destroy(mctp); return 1; } /* Step 4: Register binding with EID 8 */ rc = mctp_register_bus(mctp, mctp_binding_serial_core(serial), 8); if (rc < 0) { fprintf(stderr, "Failed to register bus\n"); mctp_serial_destroy(serial); mctp_destroy(mctp); return 1; } /* Step 5: Set receive callback */ rc = mctp_set_rx_all(mctp, rx_message_callback, &message_count); if (rc < 0) { fprintf(stderr, "Failed to set RX callback\n"); mctp_serial_destroy(serial); mctp_destroy(mctp); return 1; } /* Step 6: Poll for incoming messages */ struct pollfd fds[1]; mctp_serial_init_pollfd(serial, &fds[0]); while (message_count < 10) { rc = poll(fds, 1, 1000); /* 1 second timeout */ if (rc > 0 && (fds[0].revents & POLLIN)) { mctp_serial_read(serial); } } printf("Received %d messages\n", message_count); /* Cleanup */ mctp_serial_destroy(serial); mctp_destroy(mctp); return 0; } ``` -------------------------------- ### CMake Build Configuration for libmctp Source: https://github.com/openbmc/libmctp/blob/master/CMakeLists.txt Configures the CMake build system for the libmctp project. This includes setting the minimum required CMake version, defining build options like developer testing flags, and setting compiler flags for debugging and sanitization when the DEV option is enabled. It also defines preprocessor macros for logging and file I/O. ```cmake cmake_minimum_required (VERSION 3.5 FATAL_ERROR) option(DEV "Option for developer testing" OFF) if(DEV) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \ -Werror \ -Wall \ -Wextra \ -Wnull-dereference \ -Wformat-security \ -Wno-type-limits \ -fsanitize=address,leak,undefined \ -ggdb \ ") endif() add_definitions (-DMCTP_LOG_STDERR) add_definitions (-DMCTP_HAVE_FILEIO) add_definitions (-DMCTP_HAVE_STDIO) add_definitions (-DMCTP_DEFAULT_ALLOC) ``` -------------------------------- ### Build and Test Executables for libmctp Source: https://github.com/openbmc/libmctp/blob/master/CMakeLists.txt Compiles several C executable targets, each designed to test a specific component of the libmctp library (e.g., 'test_eid', 'test_seq'). These executables are linked against the 'mctp' static library and defined as tests within the CMake build system to facilitate automated testing. ```cmake enable_testing () add_executable (test_eid tests/test_eid.c tests/test-utils.c) target_link_libraries (test_eid mctp) add_test (NAME eid COMMAND test_eid) add_executable (test_seq tests/test_seq.c tests/test-utils.c) target_link_libraries (test_seq mctp) add_test (NAME seq COMMAND test_seq) add_executable (test_bridge tests/test_bridge.c tests/test-utils.c) target_link_libraries (test_bridge mctp) add_test (NAME bridge COMMAND test_bridge) add_executable (test_astlpc tests/test_astlpc.c tests/test-utils.c) target_link_libraries (test_astlpc mctp) add_test (NAME astlpc COMMAND test_astlpc) add_executable (test_serial tests/test_serial.c tests/test-utils.c) target_link_libraries (test_serial mctp) add_test (NAME serial COMMAND test_serial) add_executable (test_cmds tests/test_cmds.c tests/test-utils.c) target_link_libraries (test_cmds mctp) add_test (NAME control_commands COMMAND test_cmds) add_executable (test_core tests/test_core.c tests/test-utils.c) target_link_libraries (test_core mctp) add_test (NAME core COMMAND test_core) ``` -------------------------------- ### Bridge Serial and I2C Interfaces with libmctp Source: https://context7.com/openbmc/libmctp/llms.txt This C code demonstrates how to set up a transparent bridge to forward messages between serial and I2C interfaces using libmctp. It initializes the MCTP core, serial binding, and I2C binding, then connects them using mctp_bridge_busses. The code includes polling for serial input and a placeholder for I2C data handling. It automatically handles different MTUs by reassembling and re-fragmenting messages. ```c #include #include #include int setup_bridge(void) { struct mctp *mctp; struct mctp_binding_serial *serial; struct mctp_binding_i2c i2c; /* Initialize MCTP core */ mctp = mctp_init(); /* Initialize serial binding */ serial = mctp_serial_init(); mctp_serial_open_path(serial, "/dev/ttyS0"); /* Initialize I2C binding */ mctp_i2c_setup(&i2c, 0x20, i2c_tx_callback, NULL); /* * Bridge mode: no EID defined, messages forwarded bidirectionally * Handles different MTUs automatically (reassemble + re-fragment) */ mctp_bridge_busses(mctp, mctp_binding_serial_core(serial), mctp_binding_i2c_core(&i2c)); printf("Bridge established between serial and I2C\n"); printf("Messages will be transparently forwarded\n"); /* Poll both interfaces */ struct pollfd fds[1]; mctp_serial_init_pollfd(serial, &fds[0]); while (1) { poll(fds, 1, 1000); if (fds[0].revents & POLLIN) { mctp_serial_read(serial); } /* Handle I2C RX via hardware interrupt or polling */ /* mctp_i2c_rx() when I2C data available */ } return 0; } ``` -------------------------------- ### Define Generic MCTP Binding Structure Source: https://github.com/openbmc/libmctp/blob/master/README.md Defines the structure for a hardware-specific MCTP binding, which wraps the generic `struct mctp_binding`. This structure includes hardware-specific members and is initialized using a dedicated `_init` function. ```c struct mctp_binding_foo { struct mctp_binding binding; /* hardware-specific members here... */ }; struct mctp_binding_foo *mctp_binding_foo_init(const char *path); ``` -------------------------------- ### Run AFL++ Runner for libmctp Fuzzing (Multi-threaded) Source: https://github.com/openbmc/libmctp/blob/master/docs/fuzzing.md Utilizes the afl_runner script to run AFL++ with multiple threads for libmctp fuzzing. This command specifies input, output, compiler log, and binary paths, along with the number of threads. ```shell nice aflr run -t bfuzz/tests/fuzz/i2c-fuzz -i workdir/out5/m_i2c-fuzz/queue -o workdir/out6 -c bcmplog/tests/fuzz/i2c-fuzz -s bfuzzasan/tests/fuzz/i2c-fuzz -n 20 --session-name fuzz ``` ```shell aflr kill fuzz ``` ```shell aflr tui workdir/out6 ``` ```shell afl-whatsup workdir/out6 ``` -------------------------------- ### Transmit MCTP Message with Tag Management Source: https://context7.com/openbmc/libmctp/llms.txt Demonstrates sending a simple MCTP message and a request with automatic tag allocation. Includes a handler for matching responses by tag. Uses libmctp and libmctp-serial. ```c #include #include #include #include int transmit_simple_message(struct mctp *mctp) { uint8_t message[100]; uint8_t remote_eid = 9; uint8_t msg_tag = 2; bool tag_owner = false; /* Sender does not own tag */ int rc; /* Prepare message payload */ message[0] = 0x01; /* Message type */ memset(&message[1], 0xAB, sizeof(message) - 1); /* Check if bus is ready (no pending transmission) */ if (!mctp_is_tx_ready(mctp, remote_eid)) { fprintf(stderr, "Bus busy, cannot transmit\n"); return -EBUSY; } /* Transmit message (stack makes internal copy) */ rc = mctp_message_tx(mctp, remote_eid, tag_owner, msg_tag, message, sizeof(message)); if (rc < 0) { fprintf(stderr, "Transmission failed: %d\n", rc); return rc; } printf("Message sent successfully to EID %d\n", remote_eid); return 0; } int transmit_request_with_tag_allocation(struct mctp *mctp) { uint8_t *request_msg; uint8_t remote_eid = 10; uint8_t allocated_tag; size_t request_len = 256; int rc; /* Allocate message buffer (stack takes ownership) */ request_msg = malloc(request_len); if (!request_msg) return -ENOMEM; /* Build request message */ request_msg[0] = 0x05; /* Request message type */ memset(&request_msg[1], 0x12, request_len - 1); /* * Send request with automatic tag allocation * Stack sets Tag Owner (TO) bit and returns tag value */ rc = mctp_message_tx_request(mctp, remote_eid, request_msg, request_len, &allocated_tag); if (rc == -EBUSY) { fprintf(stderr, "No available tags for request\n"); free(request_msg); return rc; } else if (rc < 0) { fprintf(stderr, "Request transmission failed: %d\n", rc); free(request_msg); return rc; } printf("Request sent with allocated tag: %d\n", allocated_tag); printf("Watch for response with same tag in RX callback\n"); /* request_msg freed by stack after transmission */ return 0; } /* RX callback matching responses by tag */ static void rx_response_handler(uint8_t src_eid, bool tag_owner, uint8_t msg_tag, void *data, void *msg, size_t len) { uint8_t *expected_tag = (uint8_t *)data; /* Response has TO bit clear (tag_owner = false) */ if (!tag_owner && msg_tag == *expected_tag) { printf("Received matching response to our request\n"); printf("Response length: %zu bytes\n", len); /* Process response */ } } ``` -------------------------------- ### Custom Time Source for libmctp in Embedded Systems Source: https://context7.com/openbmc/libmctp/llms.txt Provides alternative time source functions for libmctp, suitable for embedded systems lacking a standard time library. It supports using a system tick counter or a hardware Real-Time Clock (RTC). The custom time function must return milliseconds. Dependencies include ``. ```c #include /* Embedded system tick counter (example) */ static volatile uint64_t system_ticks = 0; /* Incremented by timer ISR */ static const uint64_t TICKS_PER_MS = 1000; /* Custom time function - must return milliseconds */ static uint64_t embedded_time_ms(void *ctx) { (void)ctx; return system_ticks / TICKS_PER_MS; } /* Alternative: Use hardware RTC */ struct rtc_ctx { volatile uint32_t *rtc_counter_reg; uint32_t rtc_frequency_hz; }; static uint64_t rtc_time_ms(void *ctx) { struct rtc_ctx *rtc = (struct rtc_ctx *)ctx; uint32_t counter = *rtc->rtc_counter_reg; /* Convert counter to milliseconds */ return ((uint64_t)counter * 1000) / rtc->rtc_frequency_hz; } int setup_custom_time(struct mctp *mctp) { struct rtc_ctx rtc; /* Option 1: Simple tick counter */ mctp_set_now_op(mctp, embedded_time_ms, NULL); /* Option 2: Hardware RTC */ rtc.rtc_counter_reg = (volatile uint32_t *)0x40000000; rtc.rtc_frequency_hz = 32768; mctp_set_now_op(mctp, rtc_time_ms, &rtc); /* Query current time */ uint64_t now = mctp_now(mctp); printf("Current time: %lu ms\n", (unsigned long)now); /* * Time used for: * - Request tag expiration (6 second timeout) * - Reassembly context timeouts * - Custom protocol timeouts */ return 0; } ``` -------------------------------- ### Define KCS Header Structure Source: https://github.com/openbmc/libmctp/blob/master/docs/bindings/vendor-ibm-astlpc.md Defines the structure for the KCS header used in the LPC FW mapping. This structure includes fields for magic number, version information, and offsets/sizes for transmit and receive areas. It is packed to ensure no padding. ```c struct mctp_lpcmap_hdr { uint32_t magic; uint16_t bmc_ver_min; uint16_t bmc_ver_cur; uint16_t host_ver_min; uint16_t host_ver_cur; uint16_t negotiated_ver; uint16_t pad0; uint32_t rx_offset; uint32_t rx_size; uint32_t tx_offset; uint32_t tx_size; } __attribute__((packed)); ``` -------------------------------- ### Configure Custom Memory Allocators for libmctp Source: https://context7.com/openbmc/libmctp/llms.txt Provides custom allocation functions for embedded environments lacking malloc. It includes a simple pool allocator and a context-aware message allocator, demonstrating how to integrate them with libmctp using `mctp_set_alloc_ops` and `mctp_set_alloc_ctx`. ```c #include #include /* Custom memory pool for embedded system */ static uint8_t memory_pool[65536]; static size_t pool_offset = 0; static void *custom_alloc(size_t size) { void *ptr = NULL; if (pool_offset + size <= sizeof(memory_pool)) { ptr = &memory_pool[pool_offset]; pool_offset += size; /* Align to 8-byte boundary */ pool_offset = (pool_offset + 7) & ~7; } return ptr; } static void custom_free(void *ptr) { /* Simple pool allocator doesn't support free */ (void)ptr; } /* Context-aware message allocator */ struct msg_alloc_ctx { uint8_t msg_buffer[4096]; bool in_use; }; static void *custom_msg_alloc(size_t size, void *ctx) { struct msg_alloc_ctx *alloc_ctx = (struct msg_alloc_ctx *)ctx; if (!alloc_ctx->in_use && size <= sizeof(alloc_ctx->msg_buffer)) { alloc_ctx->in_use = true; return alloc_ctx->msg_buffer; } return NULL; } static void custom_msg_free(void *ptr, void *ctx) { struct msg_alloc_ctx *alloc_ctx = (struct msg_alloc_ctx *)ctx; if (ptr == alloc_ctx->msg_buffer) { alloc_ctx->in_use = false; } } int setup_custom_allocators(struct mctp *mctp) { struct msg_alloc_ctx *msg_ctx; /* Set custom allocators before any operations */ mctp_set_alloc_ops(custom_alloc, custom_free, custom_msg_alloc, custom_msg_free); /* Allocate and set message context */ msg_ctx = custom_alloc(sizeof(*msg_ctx)); msg_ctx->in_use = false; mctp_set_alloc_ctx(mctp, msg_ctx); printf("Custom allocators configured\n"); return 0; } ``` -------------------------------- ### Handle Multi-Fragment MCTP Messages Source: https://context7.com/openbmc/libmctp/llms.txt Illustrates sending a message larger than the MTU, which the stack automatically fragments and reassembles. The RX callback receives the fully reassembled message. Uses libmctp and libmctp-serial. ```c #include #include /* MCTP BTU (Baseline Transmission Unit) is 64 bytes */ #define LARGE_MESSAGE_SIZE (5 * MCTP_BTU) int send_large_message(struct mctp *mctp, uint8_t dest_eid) { uint8_t *large_msg; int rc; /* Allocate message larger than single packet MTU */ large_msg = malloc(LARGE_MESSAGE_SIZE); if (!large_msg) return -ENOMEM; /* Fill with test data */ for (size_t i = 0; i < LARGE_MESSAGE_SIZE; i++) { large_msg[i] = (uint8_t)(i & 0xFF); } printf("Sending %d byte message (will be fragmented into ~5 packets)\n", LARGE_MESSAGE_SIZE); /* * Stack automatically fragments into packets: * - Packet 1: SOM flag set, sequence 0 * - Packets 2-4: No SOM/EOM, sequence 1,2,3 * - Packet 5: EOM flag set, sequence 0 * All fragments use same message tag */ rc = mctp_message_tx_alloced(mctp, dest_eid, false, 5, large_msg, LARGE_MESSAGE_SIZE); if (rc < 0) { fprintf(stderr, "Large message transmission failed: %d\n", rc); free(large_msg); return rc; } /* Stack owns large_msg buffer now */ return 0; } /* RX callback receives complete reassembled message */ static void rx_reassembled_message(uint8_t src_eid, bool tag_owner, uint8_t msg_tag, void *data, void *msg, size_t len) { printf("Received reassembled message: %zu bytes\n", len); /* * Stack has automatically: * 1. Validated sequence numbers (0,1,2,3,0,...) * 2. Verified fragment sizes are consistent * 3. Assembled fragments into single buffer * 4. Delivered complete message to callback */ if (len == LARGE_MESSAGE_SIZE) { uint8_t *payload = (uint8_t *)msg; printf("First byte: 0x%02x, Last byte: 0x%02x\n", payload[0], payload[len-1]); } } ``` -------------------------------- ### Define LPC Magic Constant Source: https://github.com/openbmc/libmctp/blob/master/docs/bindings/vendor-ibm-astlpc.md Defines the magic value used to mark the beginning of the LPC FW control area. This is an ASCII encoding of 'MCTP'. ```c #define LPC_MAGIC 0x4d435450 ``` -------------------------------- ### Define LPC Buffer Trailer Structure (Protocol Version 3) Source: https://github.com/openbmc/libmctp/blob/master/docs/bindings/vendor-ibm-astlpc.md Defines the structure for the LPC buffer trailer used in protocol version 3. This trailer contains a 32-bit CRC32 checksum of the payload. ```c struct mctp_lpcbuf_tlr { uint32_t crc32; } __attribute__((packed)); ``` -------------------------------- ### Register Message Reception Callback Source: https://github.com/openbmc/libmctp/blob/master/README.md Sets a callback function to be invoked whenever an MCTP message is received by the core. This allows applications to process incoming messages. ```c void my_rx_handler(struct mctp *mctp, struct mctp_msg *msg, void *data) { /* Process the received message */ } mctp_set_rx_all(mctp, my_rx_handler); ``` -------------------------------- ### Packet Capture Handler for libmctp Source: https://context7.com/openbmc/libmctp/llms.txt Implements a handler to capture and log all incoming and outgoing MCTP packets. It logs packet details such as timestamp, direction, header information, and payload. Dependencies include `` and ``. This function writes to a file named 'mctp_capture.log'. ```c #include #include struct capture_ctx { FILE *log_file; uint64_t packet_count; }; static void packet_capture_handler(struct mctp_pktbuf *pkt, bool outgoing, void *user) { struct capture_ctx *ctx = (struct capture_ctx *)user; struct mctp_hdr *hdr; time_t now; char time_buf[64]; hdr = mctp_pktbuf_hdr(pkt); now = time(NULL); ctime_r(&now, time_buf); time_buf[strlen(time_buf) - 1] = '\0'; /* Remove newline */ ctx->packet_count++; fprintf(ctx->log_file, "[%s] Packet #%lu %s\n", time_buf, ctx->packet_count, outgoing ? "OUTGOING" : "INCOMING"); fprintf(ctx->log_file, " Version: 0x%02x\n", hdr->ver); fprintf(ctx->log_file, " Src EID: %d, Dst EID: %d\n", hdr->src, hdr->dest); fprintf(ctx->log_file, " Flags: %s%s\n", (hdr->flags_seq_tag & MCTP_HDR_FLAG_SOM) ? "SOM " : "", (hdr->flags_seq_tag & MCTP_HDR_FLAG_EOM) ? "EOM " : ""); fprintf(ctx->log_file, " Sequence: %d\n", (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK); fprintf(ctx->log_file, " Tag: %d (Owner: %s)\n", hdr->flags_seq_tag & MCTP_HDR_TAG_MASK, (hdr->flags_seq_tag & MCTP_HDR_FLAG_TO) ? "true" : "false"); size_t pkt_size = mctp_pktbuf_size(pkt); fprintf(ctx->log_file, " Payload size: %zu bytes\n", pkt_size); /* Dump packet data */ void *data = mctp_pktbuf_data(pkt); uint8_t *bytes = (uint8_t *)data; fprintf(ctx->log_file, " Data: "); for (size_t i = 0; i < pkt_size && i < 32; i++) { fprintf(ctx->log_file, "%02x ", bytes[i]); } if (pkt_size > 32) { fprintf(ctx->log_file, "..."); } fprintf(ctx->log_file, "\n\n"); fflush(ctx->log_file); } int setup_packet_capture(struct mctp *mctp) { struct capture_ctx *ctx; ctx = malloc(sizeof(*ctx)); ctx->log_file = fopen("mctp_capture.log", "w"); ctx->packet_count = 0; if (!ctx->log_file) { perror("fopen"); free(ctx); return -1; } /* Register capture handler (captures all packets) */ mctp_set_capture_handler(mctp, packet_capture_handler, ctx); printf("Packet capture enabled -> mctp_capture.log\n"); return 0; } ```