blob: 13e59590f3bb588cd46e3ac8115969e5711b1ab5 [file] [log] [blame]
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "platforms/nemora/portable/ncsi.h"
#include "platforms/nemora/portable/ncsi_fsm.h"
#include "platforms/nemora/portable/ncsi_server.h"
#include <netinet/in.h>
#include <cstdint>
#include <cstring>
#include <vector>
namespace mock
{
class NCSIFrame
{
public:
mac_addr_t get_dst_mac() const
{
return dst_mac_;
}
mac_addr_t get_src_mac() const
{
return src_mac_;
}
uint16_t get_ethertype() const
{
return ethertype_;
}
bool is_ncsi() const
{
return ethertype_ == NCSI_ETHERTYPE;
}
uint8_t get_control_packet_type() const
{
return control_packet_type_;
}
void set_conrol_packet_type(uint8_t control_packet_type)
{
control_packet_type_ = control_packet_type;
}
bool is_oem_command() const
{
return control_packet_type_ == NCSI_OEM_COMMAND;
}
uint8_t get_channel_id() const
{
return channel_id_;
}
void set_channel_id(uint8_t channel_id)
{
channel_id_ = channel_id;
}
uint8_t get_oem_command() const
{
return oem_command_;
}
void set_oem_command(uint8_t oem_command)
{
set_conrol_packet_type(NCSI_OEM_COMMAND);
oem_command_ = oem_command;
}
uint32_t get_manufacturer_id() const
{
return manufacturer_id_;
}
std::vector<uint8_t>::size_type get_size() const
{
return packet_raw_.size();
}
bool is_response() const
{
return is_response_;
}
uint16_t get_response_code() const
{
return response_code_;
}
uint16_t get_reason_code() const
{
return reason_code_;
}
bool parse_ethernet_frame(const ncsi_buf_t& ncsi_buf);
private:
mac_addr_t dst_mac_;
mac_addr_t src_mac_;
uint16_t ethertype_ = NCSI_ETHERTYPE;
uint8_t control_packet_type_;
uint8_t channel_id_;
uint8_t oem_command_;
uint32_t manufacturer_id_;
uint16_t response_code_ = 0;
uint16_t reason_code_ = 0;
bool is_response_ = false;
std::vector<uint8_t> packet_raw_;
};
class NIC
{
public:
explicit NIC(bool legacy = false, uint8_t channel_count = 1) :
channel_count_{channel_count}
{
if (legacy)
{
version_.firmware_version = htonl(0x08000000);
}
else
{
version_.firmware_version = 0xabcdef12;
}
is_legacy_ = legacy;
set_link_up();
}
void set_link_up()
{
link_status_.link_status |= htonl(NCSI_LINK_STATUS_UP);
}
void set_mac(const mac_addr_t& mac)
{
mac_ = mac;
}
mac_addr_t get_mac() const
{
return mac_;
}
uint8_t get_channel_count() const
{
return channel_count_;
}
// ????? NICs with Google firmware version ????
bool is_legacy() const
{
return is_legacy_;
}
uint32_t handle_request(const ncsi_buf_t& request_buf,
ncsi_buf_t* response_buf);
const std::vector<NCSIFrame>& get_command_log() const
{
return cmd_log_;
}
bool set_filter(uint8_t channel, const ncsi_oem_filter_t& filter);
const ncsi_oem_filter_t& get_filter(uint8_t channel) const;
void set_hostless(bool is_hostless);
void toggle_hostless();
bool is_hostless();
// The NIC itself does not really have a loopback. This is used to emulate
// the *absence* of NIC and loopback plug inserted.
void set_loopback()
{
is_loopback_ = true;
}
void reset_loopback()
{
is_loopback_ = false;
}
bool is_filter_configured(uint8_t channel) const;
private:
static const std::vector<uint8_t> simple_commands_;
uint32_t handle_oem_request(const ncsi_buf_t& request_buf,
ncsi_buf_t* response_buf);
void save_frame_to_log(const NCSIFrame& frame);
ncsi_version_id_t version_;
ncsi_oem_filter_t ch0_filter_;
ncsi_oem_filter_t ch1_filter_;
bool is_ch0_filter_configured_ = false;
bool is_ch1_filter_configured_ = false;
uint8_t channel_count_;
mac_addr_t mac_ = {{0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba}};
std::vector<NCSIFrame> cmd_log_;
/* If used in a continuous loop, cmd_log_ may grow too big over time.
* This constant determines how many (most recent) commands will be kept. */
const uint32_t max_log_size_ = 1000;
bool is_legacy_;
bool is_loopback_ = false;
// TODO: populate stats somehow.
ncsi_passthrough_stats_t stats_;
ncsi_passthrough_stats_legacy_t stats_legacy_;
ncsi_link_status_t link_status_;
};
} // namespace mock