1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 3 #if HAVE_CONFIG_H 4 #include "config.h" 5 #endif 6 7 #include "compiler.h" 8 #include "range.h" 9 #include "libmctp-log.h" 10 #include "libmctp-i2c.h" 11 #include "libmctp-sizes.h" 12 #include "libmctp-alloc.h" 13 14 /* For access to mctp_bninding_i2c internals */ 15 #include "i2c-internal.h" 16 17 #ifdef NDEBUG 18 #undef NDEBUG 19 #endif 20 21 #include <assert.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <stdbool.h> 25 #include <stdio.h> 26 #include <string.h> 27 #include <unistd.h> 28 #include <stdlib.h> 29 30 struct mctp_binding_serial_pipe { 31 int ingress; 32 int egress; 33 34 struct mctp_binding_serial *serial; 35 }; 36 37 // Sized to test fragmentation and >8 bit length 38 #define TEST_MSG_LEN 300 39 static uint8_t mctp_msg_src[TEST_MSG_LEN]; 40 41 struct i2c_test { 42 struct mctp_binding_i2c *i2c; 43 struct mctp *mctp; 44 45 uint8_t rx_msg[TEST_MSG_LEN]; 46 size_t rx_len; 47 48 /* Physical addresses. These get set regardless of whether the packet 49 * is dropped by the stack (no match etc) */ 50 uint8_t last_rx_i2c_src; 51 uint8_t last_tx_i2c_dst; 52 }; 53 54 static const uint8_t I2C_ADDR_A = 0x20; 55 static const uint8_t I2C_ADDR_B = 0x21; 56 static const uint8_t EID_A = 50; 57 static const uint8_t EID_B = 51; 58 59 static int test_i2c_tx(const void *buf, size_t len, void *ctx) 60 { 61 struct i2c_test *test_pair = ctx; 62 struct i2c_test *tx_test = &test_pair[0]; 63 struct i2c_test *rx_test = &test_pair[1]; 64 65 mctp_prdebug("test_i2c_tx len %zu", len); 66 67 const struct mctp_i2c_hdr *hdr = buf; 68 tx_test->last_tx_i2c_dst = hdr->dest >> 1; 69 rx_test->last_rx_i2c_src = hdr->source >> 1; 70 71 mctp_i2c_rx(rx_test->i2c, buf, len); 72 return 0; 73 } 74 75 static void test_i2c_rxmsg(uint8_t src_eid, bool tag_owner, uint8_t msg_tag, 76 void *ctx, void *msg, size_t len) 77 { 78 struct i2c_test *test_pair = ctx; 79 // struct i2c_test *tx_test = &test_pair[0]; 80 struct i2c_test *rx_test = &test_pair[1]; 81 82 mctp_prdebug("test_i2c_rx src %d len %zu tag %d owner %d", src_eid, len, 83 msg_tag, tag_owner); 84 85 // Must be cleared by previous test runs 86 assert(rx_test->rx_len == 0); 87 memcpy(rx_test->rx_msg, msg, len); 88 rx_test->rx_len = len; 89 } 90 91 /* Transmits a MCTP message and checks the received message matches */ 92 static void run_tx_test(struct i2c_test *tx_test, uint8_t dest_eid, 93 size_t tx_len, struct i2c_test *rx_test) 94 { 95 int rc; 96 const uint8_t msg_tag = 2; 97 const bool tag_owner = false; 98 99 assert(tx_len <= sizeof(mctp_msg_src)); 100 rc = mctp_message_tx(tx_test->mctp, dest_eid, tag_owner, msg_tag, 101 mctp_msg_src, tx_len); 102 assert(rc == 0); 103 104 while (!mctp_is_tx_ready(tx_test->mctp, dest_eid)) { 105 mctp_i2c_tx_poll(tx_test->i2c); 106 } 107 108 assert(rx_test->rx_len == tx_len); 109 assert(memcmp(rx_test->rx_msg, mctp_msg_src, tx_len) == 0); 110 111 rx_test->rx_len = 0; 112 } 113 114 static void test_neigh_expiry(struct i2c_test *tx_test, 115 struct i2c_test *rx_test) 116 { 117 const uint8_t msg_tag = 2; 118 const bool tag_owner = true; 119 const size_t msg_len = 5; 120 int rc; 121 122 (void)rx_test; 123 124 /* Clear the tx neighbour table */ 125 memset(tx_test->i2c->neigh, 0x0, sizeof(tx_test->i2c->neigh)); 126 127 /* Check that all EIDs fail */ 128 rx_test->rx_len = 0; 129 for (size_t eid = 8; eid < 254; eid++) { 130 mctp_message_tx(tx_test->mctp, eid, tag_owner, msg_tag, 131 mctp_msg_src, msg_len); 132 /* Not received */ 133 assert(rx_test->rx_len == 0); 134 } 135 136 /* Add one entry */ 137 rc = mctp_i2c_set_neighbour(tx_test->i2c, EID_B, 138 rx_test->i2c->own_addr); 139 assert(rc == 0); 140 rx_test->rx_len = 0; 141 mctp_message_tx(tx_test->mctp, EID_B, tag_owner, msg_tag, mctp_msg_src, 142 msg_len); 143 assert(rx_test->rx_len == msg_len); 144 assert(tx_test->last_tx_i2c_dst == rx_test->i2c->own_addr); 145 146 /* Replace the entry */ 147 rx_test->i2c->own_addr++; 148 rc = mctp_i2c_set_neighbour(tx_test->i2c, EID_B, 149 rx_test->i2c->own_addr); 150 assert(rc == 0); 151 rx_test->rx_len = 0; 152 mctp_message_tx(tx_test->mctp, EID_B, tag_owner, msg_tag, mctp_msg_src, 153 msg_len); 154 assert(rc == 0); 155 assert(rx_test->rx_len == msg_len); 156 assert(tx_test->last_tx_i2c_dst == rx_test->i2c->own_addr); 157 158 /* Check only one entry is set */ 159 size_t count = 0; 160 for (size_t i = 0; i < MCTP_I2C_NEIGH_COUNT; i++) { 161 struct mctp_i2c_neigh *n = &tx_test->i2c->neigh[i]; 162 if (n->used) { 163 assert(n->eid == EID_B); 164 count++; 165 } 166 } 167 assert(count == 1); 168 169 /* Ensure we can iterate without overflow. 170 * If MCTP_I2C_NEIGH_COUNT increases too large this test would need rethinking 171 * (and eviction may become impossible) */ 172 assert((int)EID_B + MCTP_I2C_NEIGH_COUNT < 254); 173 assert((int)I2C_ADDR_B + MCTP_I2C_NEIGH_COUNT < 0x7f); 174 175 /* Fill entries. -1 because one was already filled. */ 176 for (size_t i = 0; i < MCTP_I2C_NEIGH_COUNT - 1; i++) { 177 /* Unused addresses */ 178 uint8_t addr = rx_test->i2c->own_addr + i + 1; 179 uint8_t eid = EID_B + i + 1; 180 rc = mctp_i2c_set_neighbour(tx_test->i2c, eid, addr); 181 assert(rc == 0); 182 } 183 184 /* Check all are used */ 185 for (size_t i = 0; i < MCTP_I2C_NEIGH_COUNT; i++) { 186 struct mctp_i2c_neigh *n = &tx_test->i2c->neigh[i]; 187 assert(n->used); 188 } 189 190 /* Test eviction */ 191 { 192 uint8_t addr = 193 rx_test->i2c->own_addr + MCTP_I2C_NEIGH_COUNT + 1; 194 uint8_t eid = EID_B + MCTP_I2C_NEIGH_COUNT + 1; 195 rc = mctp_i2c_set_neighbour(tx_test->i2c, eid, addr); 196 assert(rc == 0); 197 198 /* EID_B got evicted, send should fail */ 199 rx_test->rx_len = 0; 200 mctp_message_tx(tx_test->mctp, EID_B, tag_owner, msg_tag, 201 mctp_msg_src, msg_len); 202 /* Not received */ 203 assert(rx_test->rx_len == 0); 204 } 205 206 /* Add EID_B again */ 207 rc = mctp_i2c_set_neighbour(tx_test->i2c, EID_B, 208 rx_test->i2c->own_addr); 209 assert(rc == 0); 210 rx_test->rx_len = 0; 211 mctp_message_tx(tx_test->mctp, EID_B, tag_owner, msg_tag, mctp_msg_src, 212 msg_len); 213 /* Is received */ 214 assert(rx_test->rx_len == msg_len); 215 } 216 217 int main(void) 218 { 219 struct i2c_test scenario[2]; 220 struct i2c_test *tx_test = &scenario[0]; 221 struct i2c_test *rx_test = &scenario[1]; 222 223 mctp_set_log_stdio(MCTP_LOG_DEBUG); 224 225 memset(scenario, 0x0, sizeof(scenario)); 226 227 /* Setup a source buffer */ 228 for (size_t i = 0; i < sizeof(mctp_msg_src); i++) { 229 mctp_msg_src[i] = i & 0xff; 230 } 231 232 tx_test->mctp = mctp_init(); 233 assert(tx_test->mctp); 234 tx_test->i2c = malloc(MCTP_SIZEOF_BINDING_I2C); 235 assert(tx_test->i2c); 236 rx_test->mctp = mctp_init(); 237 assert(rx_test->mctp); 238 rx_test->i2c = malloc(MCTP_SIZEOF_BINDING_I2C); 239 assert(rx_test->i2c); 240 241 /* TX side */ 242 mctp_i2c_setup(tx_test->i2c, I2C_ADDR_A, test_i2c_tx, scenario); 243 mctp_register_bus(tx_test->mctp, mctp_binding_i2c_core(tx_test->i2c), 244 EID_A); 245 mctp_set_rx_all(tx_test->mctp, NULL, NULL); 246 mctp_i2c_set_neighbour(tx_test->i2c, EID_B, I2C_ADDR_B); 247 248 /* RX side */ 249 mctp_i2c_setup(rx_test->i2c, I2C_ADDR_B, NULL, NULL); 250 mctp_register_bus(rx_test->mctp, mctp_binding_i2c_core(rx_test->i2c), 251 EID_B); 252 mctp_set_rx_all(rx_test->mctp, test_i2c_rxmsg, scenario); 253 // mctp_i2c_set_neighbour(rx_test->i2c, EID_A, I2C_ADDR_A); 254 255 /* Try all message sizes */ 256 for (size_t i = 1; i < sizeof(mctp_msg_src); i++) { 257 run_tx_test(tx_test, EID_B, i, rx_test); 258 } 259 260 test_neigh_expiry(tx_test, rx_test); 261 262 return 0; 263 } 264