1 #include "net_iface_mock.h" 2 #include "nic_mock.h" 3 #include "platforms/nemora/portable/default_addresses.h" 4 #include "platforms/nemora/portable/ncsi.h" 5 #include "platforms/nemora/portable/ncsi_fsm.h" 6 #include "platforms/nemora/portable/net_types.h" 7 8 #include <ncsi_state_machine.h> 9 #include <net_config.h> 10 #include <net_sockio.h> 11 #include <netinet/ether.h> 12 #include <netinet/in.h> 13 14 #include <gmock/gmock.h> 15 16 namespace 17 { 18 19 constexpr uint32_t ETHER_NCSI = 0x88f8; 20 21 class MockConfig : public net::ConfigBase 22 { 23 public: 24 int get_mac_addr(mac_addr_t* mac) override 25 { 26 std::memcpy(mac, &mac_addr, sizeof(mac_addr_t)); 27 28 return 0; 29 } 30 31 int set_mac_addr(const mac_addr_t& mac) override 32 { 33 mac_addr = mac; 34 35 return 0; 36 } 37 38 int set_nic_hostless(bool is_hostless) override 39 { 40 is_nic_hostless = is_hostless; 41 42 return 0; 43 } 44 45 mac_addr_t mac_addr; 46 bool is_nic_hostless = true; 47 }; 48 49 class NICConnection : public net::SockIO 50 { 51 public: 52 int write(const void* buf, size_t len) override 53 { 54 conseq_reads = 0; 55 ++n_writes; 56 std::memcpy(last_write.data, buf, len); 57 last_write.len = len; 58 const auto* hdr = reinterpret_cast<const struct ether_header*>(buf); 59 if (ETHER_NCSI == ntohs(hdr->ether_type)) 60 { 61 ++n_handles; 62 next_read.len = nic_mock.handle_request(last_write, &next_read); 63 } 64 65 return len; 66 } 67 68 int recv(void* buf, size_t maxlen) override 69 { 70 ++n_reads; 71 ++conseq_reads; 72 73 if (read_timeout > 0) 74 { 75 if (conseq_reads > read_timeout) 76 { 77 return 0; 78 } 79 } 80 81 if (maxlen < next_read.len) 82 { 83 ++n_read_errs; 84 return 0; 85 } 86 87 std::memcpy(buf, next_read.data, next_read.len); 88 89 return next_read.len; 90 } 91 92 mock::NIC nic_mock{false, 2}; 93 int n_writes = 0; 94 int n_reads = 0; 95 int n_handles = 0; 96 int n_read_errs = 0; 97 98 // Max number of consequitive reads without writes. 99 int read_timeout = -1; 100 int conseq_reads = 0; 101 102 ncsi_buf_t last_write = {}; 103 ncsi_buf_t next_read = {}; 104 }; 105 106 } // namespace 107 108 class TestNcsi : public testing::Test 109 { 110 public: 111 void SetUp() override 112 { 113 ncsi_sm.set_sockio(&ncsi_sock); 114 ncsi_sm.set_net_config(&net_config_mock); 115 ncsi_sm.set_retest_delay(0); 116 ncsi_sock.nic_mock.set_mac(nic_mac); 117 ncsi_sock.nic_mock.set_hostless(true); 118 ncsi_sock.read_timeout = 10; 119 } 120 121 protected: 122 void ExpectFiltersNotConfigured() 123 { 124 for (uint8_t i = 0; i < ncsi_sock.nic_mock.get_channel_count(); ++i) 125 { 126 EXPECT_FALSE(ncsi_sock.nic_mock.is_filter_configured(i)); 127 } 128 } 129 130 void ExpectFiltersConfigured() 131 { 132 // Check that filters are configured on all channels. 133 for (uint8_t i = 0; i < ncsi_sock.nic_mock.get_channel_count(); ++i) 134 { 135 EXPECT_TRUE(ncsi_sock.nic_mock.is_filter_configured(i)); 136 const ncsi_oem_filter_t& ch_filter = 137 ncsi_sock.nic_mock.get_filter(i); 138 139 for (unsigned i = 0; i < sizeof(nic_mac.octet); ++i) 140 { 141 EXPECT_EQ(nic_mac.octet[i], ch_filter.mac[i]); 142 } 143 144 EXPECT_EQ(ch_filter.ip, 0); 145 const uint16_t filter_port = ntohs(ch_filter.port); 146 EXPECT_EQ(filter_port, DEFAULT_ADDRESSES_RX_PORT); 147 } 148 } 149 150 MockConfig net_config_mock; 151 NICConnection ncsi_sock; 152 ncsi::StateMachine ncsi_sm; 153 const mac_addr_t nic_mac = {{0xde, 0xca, 0xfb, 0xad, 0x01, 0x02}}; 154 155 // Number of states in each state machine 156 static constexpr int l2_num_states = 26; 157 static constexpr int l3l4_num_states = 2; 158 static constexpr int test_num_states = 9; 159 160 // Total number of states in all three state machines. 161 static constexpr int total_num_states = 162 l2_num_states + l3l4_num_states + test_num_states; 163 }; 164 165 TEST_F(TestNcsi, TestMACAddrPropagation) 166 { 167 ncsi_sm.run(total_num_states); 168 EXPECT_EQ(ncsi_sock.n_read_errs, 0); 169 EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes); 170 EXPECT_EQ(0, std::memcmp(nic_mac.octet, net_config_mock.mac_addr.octet, 171 sizeof(nic_mac.octet))); 172 173 // Since network is not configured, the filters should not be configured 174 // either. 175 ExpectFiltersNotConfigured(); 176 } 177 178 TEST_F(TestNcsi, TestFilterConfiguration) 179 { 180 ncsi_sm.run(total_num_states); 181 EXPECT_EQ(ncsi_sock.n_read_errs, 0); 182 EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes); 183 184 ExpectFiltersConfigured(); 185 } 186 187 TEST_F(TestNcsi, TestFilterReset) 188 { 189 ncsi_sm.run(total_num_states); 190 EXPECT_EQ(ncsi_sock.n_read_errs, 0); 191 EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes); 192 193 // Since network is not configured, the filters should not be configured 194 // either. 195 ExpectFiltersNotConfigured(); 196 197 ncsi_sm.run(total_num_states); 198 199 ExpectFiltersConfigured(); 200 } 201 202 TEST_F(TestNcsi, TestRetest) 203 { 204 ncsi_sm.run(total_num_states + test_num_states); 205 206 // Verify that the test state machine was stepped through twice, 207 // by counting how many times the last command of the state machine 208 // has been executed. 209 const uint8_t last_test_command = NCSI_GET_LINK_STATUS; 210 const auto& cmd_log = ncsi_sock.nic_mock.get_command_log(); 211 int num_test_runs = 0; 212 for (const auto& ncsi_frame : cmd_log) 213 { 214 if (ncsi_frame.get_control_packet_type() == last_test_command) 215 { 216 ++num_test_runs; 217 } 218 } 219 220 EXPECT_EQ(num_test_runs, 2); 221 } 222 223 TEST_F(TestNcsi, TestHostlessSwitch) 224 { 225 // By default the NIC is in hostless mode. 226 // Verify that net config flag changes after FSM run. 227 net_config_mock.is_nic_hostless = false; 228 ncsi_sm.run(total_num_states); 229 EXPECT_EQ(ncsi_sock.n_read_errs, 0); 230 EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes); 231 EXPECT_TRUE(net_config_mock.is_nic_hostless); 232 233 // Now disable the hostless mode and verify that net config 234 // flag changes to false. 235 ncsi_sock.nic_mock.set_hostless(false); 236 ncsi_sm.run(total_num_states); 237 EXPECT_EQ(ncsi_sock.n_read_errs, 0); 238 EXPECT_EQ(ncsi_sock.n_handles, ncsi_sock.n_writes); 239 EXPECT_FALSE(net_config_mock.is_nic_hostless); 240 } 241