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