| /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ |
| |
| #define _GNU_SOURCE |
| |
| #if HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "libmctp-log.h" |
| #include "libmctp-serial.h" |
| |
| #ifdef NDEBUG |
| #undef NDEBUG |
| #endif |
| |
| #include <assert.h> |
| #include <fcntl.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| struct mctp_binding_serial_pipe { |
| int ingress; |
| int egress; |
| |
| struct mctp_binding_serial *serial; |
| }; |
| |
| static int mctp_binding_serial_pipe_tx(void *data, void *buf, size_t len) |
| { |
| struct mctp_binding_serial_pipe *ctx = data; |
| ssize_t rc; |
| |
| rc = write(ctx->egress, buf, len); |
| assert(rc >= 0); |
| assert((size_t)rc == len); |
| |
| return rc; |
| } |
| |
| uint8_t mctp_msg_src[2 * MCTP_BTU]; |
| |
| static bool seen; |
| |
| #define __unused __attribute__((unused)) |
| |
| static void rx_message(uint8_t eid __unused, void *data __unused, void *msg, |
| size_t len) |
| { |
| uint8_t type; |
| |
| type = *(uint8_t *)msg; |
| |
| mctp_prdebug("MCTP message received: len %zd, type %d", len, type); |
| |
| assert(sizeof(mctp_msg_src) == len); |
| assert(!memcmp(mctp_msg_src, msg, len)); |
| |
| seen = true; |
| } |
| |
| struct serial_test { |
| struct mctp_binding_serial_pipe binding; |
| struct mctp *mctp; |
| }; |
| |
| int main(void) |
| { |
| struct serial_test scenario[2]; |
| |
| struct mctp_binding_serial_pipe *a; |
| struct mctp_binding_serial_pipe *b; |
| int p[2][2]; |
| int rc; |
| |
| mctp_set_log_stdio(MCTP_LOG_DEBUG); |
| |
| memset(&mctp_msg_src[0], 0x5a, MCTP_BTU); |
| memset(&mctp_msg_src[MCTP_BTU], 0xa5, MCTP_BTU); |
| |
| rc = pipe(p[0]); |
| assert(!rc); |
| |
| rc = pipe(p[1]); |
| assert(!rc); |
| |
| /* Instantiate the A side of the serial pipe */ |
| scenario[0].mctp = mctp_init(); |
| assert(scenario[0].mctp); |
| scenario[0].binding.serial = mctp_serial_init(); |
| assert(scenario[0].binding.serial); |
| a = &scenario[0].binding; |
| a->ingress = p[0][0]; |
| a->egress = p[1][1]; |
| mctp_serial_open_fd(a->serial, a->ingress); |
| mctp_serial_set_tx_fn(a->serial, mctp_binding_serial_pipe_tx, a); |
| mctp_register_bus(scenario[0].mctp, mctp_binding_serial_core(a->serial), 8); |
| |
| /* Instantiate the B side of the serial pipe */ |
| scenario[1].mctp = mctp_init(); |
| assert(scenario[1].mctp); |
| mctp_set_rx_all(scenario[1].mctp, rx_message, NULL); |
| scenario[1].binding.serial = mctp_serial_init(); |
| assert(scenario[1].binding.serial); |
| b = &scenario[1].binding; |
| b->ingress = p[1][0]; |
| b->egress = p[0][1]; |
| mctp_serial_open_fd(b->serial, b->ingress); |
| mctp_serial_set_tx_fn(b->serial, mctp_binding_serial_pipe_tx, a); |
| mctp_register_bus(scenario[1].mctp, mctp_binding_serial_core(b->serial), 9); |
| |
| /* Transmit a message from A to B */ |
| rc = mctp_message_tx(scenario[0].mctp, 9, mctp_msg_src, sizeof(mctp_msg_src)); |
| assert(rc == 0); |
| |
| /* Read the message at B from A */ |
| seen = false; |
| mctp_serial_read(b->serial); |
| assert(seen); |
| |
| mctp_serial_destroy(scenario[1].binding.serial); |
| mctp_destroy(scenario[1].mctp); |
| mctp_serial_destroy(scenario[0].binding.serial); |
| mctp_destroy(scenario[0].mctp); |
| |
| return 0; |
| } |