blob: 97a6737e500f9ee03534d3fde0386cd4ad25bc28 [file] [log] [blame]
William A. Kennington III7d6fa422021-02-08 17:04:02 -08001#pragma once
2
3#include "platforms/nemora/portable/ncsi.h"
4#include "platforms/nemora/portable/ncsi_fsm.h"
5#include "platforms/nemora/portable/ncsi_server.h"
6
7#include <netinet/in.h>
8
9#include <cstdint>
10#include <cstring>
11#include <vector>
12
13namespace mock
14{
15
16class NCSIFrame
17{
18 public:
19 mac_addr_t get_dst_mac() const
20 {
21 return dst_mac_;
22 }
23
24 mac_addr_t get_src_mac() const
25 {
26 return src_mac_;
27 }
28
29 uint16_t get_ethertype() const
30 {
31 return ethertype_;
32 }
33
34 bool is_ncsi() const
35 {
36 return ethertype_ == NCSI_ETHERTYPE;
37 }
38
39 uint8_t get_control_packet_type() const
40 {
41 return control_packet_type_;
42 }
43
44 void set_conrol_packet_type(uint8_t control_packet_type)
45 {
46 control_packet_type_ = control_packet_type;
47 }
48
49 bool is_oem_command() const
50 {
51 return control_packet_type_ == NCSI_OEM_COMMAND;
52 }
53
54 uint8_t get_channel_id() const
55 {
56 return channel_id_;
57 }
58
59 void set_channel_id(uint8_t channel_id)
60 {
61 channel_id_ = channel_id;
62 }
63
64 uint8_t get_oem_command() const
65 {
66 return oem_command_;
67 }
68
69 void set_oem_command(uint8_t oem_command)
70 {
71 set_conrol_packet_type(NCSI_OEM_COMMAND);
72 oem_command_ = oem_command;
73 }
74
75 uint32_t get_manufacturer_id() const
76 {
77 return manufacturer_id_;
78 }
79
80 std::vector<uint8_t>::size_type get_size() const
81 {
82 return packet_raw_.size();
83 }
84
85 bool is_response() const
86 {
87 return is_response_;
88 }
89
90 uint16_t get_response_code() const
91 {
92 return response_code_;
93 }
94
95 uint16_t get_reason_code() const
96 {
97 return reason_code_;
98 }
99
100 bool parse_ethernet_frame(const ncsi_buf_t& ncsi_buf);
101
102 private:
103 mac_addr_t dst_mac_;
104 mac_addr_t src_mac_;
105 uint16_t ethertype_ = NCSI_ETHERTYPE;
106 uint8_t control_packet_type_;
107 uint8_t channel_id_;
108 uint8_t oem_command_;
109 uint32_t manufacturer_id_;
110 uint16_t response_code_ = 0;
111 uint16_t reason_code_ = 0;
112 bool is_response_ = false;
113 std::vector<uint8_t> packet_raw_;
114};
115
116class NIC
117{
118 public:
119 explicit NIC(bool legacy = false, uint8_t channel_count = 1) :
120 channel_count_{channel_count}
121 {
122 if (legacy)
123 {
124 version_.firmware_version = htonl(0x08000000);
125 }
126 else
127 {
128 version_.firmware_version = 0xabcdef12;
129 }
130
131 is_legacy_ = legacy;
132
133 set_link_up();
134 }
135
136 void set_link_up()
137 {
138 link_status_.link_status |= htonl(NCSI_LINK_STATUS_UP);
139 }
140
141 void set_mac(const mac_addr_t& mac)
142 {
143 mac_ = mac;
144 }
145
146 mac_addr_t get_mac() const
147 {
148 return mac_;
149 }
150
151 uint8_t get_channel_count() const
152 {
153 return channel_count_;
154 }
155
156 // ????? NICs with Google firmware version ????
157 bool is_legacy() const
158 {
159 return is_legacy_;
160 }
161
162 uint32_t handle_request(const ncsi_buf_t& request_buf,
163 ncsi_buf_t* response_buf);
164
165 const std::vector<NCSIFrame>& get_command_log() const
166 {
167 return cmd_log_;
168 }
169
170 bool set_filter(uint8_t channel, const ncsi_oem_filter_t& filter);
171 const ncsi_oem_filter_t& get_filter(uint8_t channel) const;
172
173 void set_hostless(bool is_hostless);
174 void toggle_hostless();
175 bool is_hostless();
176
177 // The NIC itself does not really have a loopback. This is used to emulate
178 // the *absence* of NIC and loopback plug inserted.
179 void set_loopback()
180 {
181 is_loopback_ = true;
182 }
183
184 void reset_loopback()
185 {
186 is_loopback_ = false;
187 }
188
189 bool is_filter_configured(uint8_t channel) const;
190
191 private:
192 static const std::vector<uint8_t> simple_commands_;
193
194 uint32_t handle_oem_request(const ncsi_buf_t& request_buf,
195 ncsi_buf_t* response_buf);
196
197 void save_frame_to_log(const NCSIFrame& frame);
198
199 ncsi_version_id_t version_;
200 ncsi_oem_filter_t ch0_filter_;
201 ncsi_oem_filter_t ch1_filter_;
202 bool is_ch0_filter_configured_ = false;
203 bool is_ch1_filter_configured_ = false;
204 uint8_t channel_count_;
205 mac_addr_t mac_ = {{0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba}};
206 std::vector<NCSIFrame> cmd_log_;
207
208 /* If used in a continuous loop, cmd_log_ may grow too big over time.
209 * This constant determines how many (most recent) commands will be kept. */
210 const uint32_t max_log_size_ = 1000;
211
212 bool is_legacy_;
213 bool is_loopback_ = false;
214
215 // TODO: populate stats somehow.
216 ncsi_passthrough_stats_t stats_;
217 ncsi_passthrough_stats_legacy_t stats_legacy_;
218
219 ncsi_link_status_t link_status_;
220};
221
222} // namespace mock