ncsid: Import from gBMC

This is the initial code drop from gBMC.

Google-Bug-Id: 179618516
Upstream: 1e71af914bc8c54d8b91d0a1cf377e2696713c2f
Change-Id: Ic653e8271dacd205e04f2bc713071ef2ec5936a4
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/ncsid/test/nic_mock.h b/ncsid/test/nic_mock.h
new file mode 100644
index 0000000..97a6737
--- /dev/null
+++ b/ncsid/test/nic_mock.h
@@ -0,0 +1,222 @@
+#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