-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local utils = require 'mc.utils'
local log = require 'mc.logging'
local byte_table_to_string = utils.ByteTablesToString
local ncsi_def = require 'ncsi.ncsi_protocol.ncsi_def'
local ncsi_utils = require 'ncsi.ncsi_protocol.ncsi_utils'
local ncsi_channel = require 'ncsi.ncsi_protocol.ncsi_channel'
local ncsi_broadcast_filter = require 'ncsi.ncsi_protocol.ncsi_broadcast_filter'
local ncsi_multicast_filter = require 'ncsi.ncsi_protocol.ncsi_multicast_filter'
local ncsi_vlan_filter = require 'ncsi.ncsi_protocol.ncsi_vlan_filter'
local ncsi_vlan_mode = require 'ncsi.ncsi_protocol.ncsi_vlan_mode'
local ncsi_package = require 'ncsi.ncsi_protocol.ncsi_package'
local ncsi_clear_state = require 'ncsi.ncsi_protocol.ncsi_clear_state'
local ncsi_init = require 'ncsi.ncsi_protocol.ncsi_init'
local ncsi_get_status = require 'ncsi.ncsi_protocol.ncsi_get_status'
local ncsi_oem_lldp = require 'ncsi.ncsi_protocol.ncsi_oem_lldp'
local ncsi_socket = require 'ncsi.ncsi_protocol.ncsi_socket'
local ncsi_oem_log = require 'ncsi.ncsi_protocol.ncsi_oem_log'
local ncsi_parameter = require 'ncsi.ncsi_protocol.ncsi_parameter'

local ncsi_cmd = {}

local NCSI_CHANNEL_MAX_ID = 4
local NCSI_MAC_LEH = 6
local NCSI_PACKAGE_MAX_ID = 2

local function check_channel_id(channel_id)
    if channel_id > NCSI_CHANNEL_MAX_ID - 1 then
        log:error('channel id is out of range')
        return false
    end
    return true
end

-- 启用NCSI通道，是使用NCSI功能的前提，必须先执行此操作
function ncsi_cmd.ncsi_enable_channel(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_channel.ncsi_enable_channel(package_id, channel_id, eth_name)
end

-- 禁用NCSI通道，停止NCSI通信
function ncsi_cmd.ncsi_disable_channel(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_channel.ncsi_disable_channel(package_id, channel_id, eth_name)
end

-- 启用通道传输功能，允许通道将穿透数据包发送到网络
function ncsi_cmd.ncsi_enable_channelTX(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_channel.ncsi_enable_channel_tx(package_id, channel_id, eth_name)
end

-- 禁用通道传输功能，阻止通道将穿透数据包发送到网络
function ncsi_cmd.ncsi_disable_channelTX(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_channel.ncsi_disable_channel_tx(package_id, channel_id, eth_name)
end

-- 初始化NCSI以太网MAC地址，设置NCSI通信使用的源MAC地址
function ncsi_cmd.ncsi_eth_mac_init(mac_str)
    local hex_numbers = {}
    for hex in string.gmatch(mac_str, '%x%x') do
        table.insert(hex_numbers, tonumber(hex, 16))
    end
    if #hex_numbers ~= NCSI_MAC_LEH then
        return false
    end
    ncsi_utils.src_addr = byte_table_to_string(hex_numbers)
    return true
end

-- 启用广播过滤，不过滤ARP、DHCP客户端/服务器的广播包
function ncsi_cmd.ncsi_enable_brdcast_filter(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_broadcast_filter.ncsi_enable_brdcast_filter(package_id, channel_id, eth_name)
end

-- 禁用广播过滤，ARP、DHCP客户端/服务器的广播包将被过滤
function ncsi_cmd.ncsi_disable_brdcast_filter(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_broadcast_filter.ncsi_disable_brdcast_filter(package_id, channel_id, eth_name)
end

-- 启用多播过滤，过滤掉所有多播数据包
function ncsi_cmd.ncsi_enable_multi_filter(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_multicast_filter.ncsi_enable_multicast_filter(package_id, channel_id, eth_name)
end

-- 禁用多播过滤，接收所有多播数据包
function ncsi_cmd.ncsi_disable_multi_filter(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_multicast_filter.ncsi_disable_multicast_filter(package_id, channel_id, eth_name)
end

-- 启用VLAN模式，需要先设置VLAN过滤器后再启用此功能
function ncsi_cmd.ncsi_enable_vlan_req(package_id, channel_id, eth_name, vlan_mode)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_vlan_mode.ncsi_enable_vlan_req(package_id, channel_id, eth_name, vlan_mode)
end

-- 禁用VLAN模式，禁用后将接收所有VLAN和非VLAN数据包
function ncsi_cmd.ncsi_disable_vlan_req(package_id, channel_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_vlan_mode.ncsi_disable_vlan_req(package_id, channel_id, eth_name)
end

-- 设置VLAN过滤器，配置要过滤的VLAN ID，需要与启用VLAN模式配合使用
function ncsi_cmd.ncsi_set_vlan_filter(_, channel_id, vlan_filter, vlan_state, vlan_id, eth_name)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end

    return ncsi_vlan_filter.ncsi_set_vlan_filter(0, channel_id, vlan_filter, vlan_state, vlan_id, eth_name)
end

-- 选择NCSI包，用于切换不同的NCSI包
function ncsi_cmd.ncsi_select_package(package_id, eth_name)
    return ncsi_package.ncsi_select_package(package_id, eth_name)
end

-- 清除NCSI通道的初始状态，重置通道到默认配置
function ncsi_cmd.ncsi_clear_initial_state(package_id, channel_id, eth_name)
    return ncsi_clear_state.ncsi_clear_initial_state(package_id, channel_id, eth_name)
end

-- 初始化ncsi_parameter
function ncsi_cmd.ncsi_common_init()
    ncsi_parameter.get_instance():init_ncsi_parameter()
end

-- 初始化NCSI参数，设置通道的基本参数和状态
function ncsi_cmd.ncsi_paramter_init(channel_id, eth_name, state)
    local package_id = NCSI_PACKAGE_MAX_ID
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL, package_id
    end
    return ncsi_init.ncsi_paramter_init(channel_id, eth_name, state)
end

-- 获取通道数
function ncsi_cmd.get_ncsi_channel_cnt()
    return ncsi_parameter.get_instance():get_ncsi_parameter().channel_cnt
end

-- 获取连接状态
function ncsi_cmd.ncsi_get_link_status(package_id, channel_id, eth_name, eth_id)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL, 0
    end

    local ret = ncsi_get_status.ncsi_get_link_status(package_id, channel_id, eth_name, eth_id)
    local link_status = ncsi_parameter.get_instance():get_ncsi_parameter().link_status[eth_id][channel_id].link_flag
    return ret, link_status
end

-- 获取日志
function ncsi_cmd.ncsi_get_log(package_id, eth_name, log_dir, time)
    local ret = ncsi_oem_log.get_log_by_ncsi_hw(package_id, eth_name, log_dir, time)
    return ret
end

-- 获取新日志
function ncsi_cmd.ncsi_get_log_new(package_id, eth_name, log_dir, time)
    local ret = ncsi_oem_log.get_log_by_ncsi_hw_new(package_id, eth_name, log_dir, time)
    return ret
end

-- 获取黑匣子
function ncsi_cmd.ncsi_get_blackbox(package_id, eth_name, log_name)
    local ret = ncsi_oem_log.get_blackbox_by_ncsi_hw(package_id, eth_name, log_name)
    return ret
end

-- 获取lldp状态
function ncsi_cmd.ncsi_set_lldp_status(eth_name, package_id, channel_id, status)
    if not check_channel_id(channel_id) then
        return ncsi_def.NCSI_FAIL
    end
    local ret = ncsi_oem_lldp.update_lldp_over_ncsi_status(eth_name, package_id, channel_id, status)
    return ret
end

function ncsi_cmd.ncsi_receive_packet(fd, eth_name)
    if fd < 0 then
        log:error('ncsi receive packet fd is invalid')
        return ncsi_def.NCSI_FAIL
    end

    local aen_oem_status, data = ncsi_socket.ncsi_receive_packet(fd, eth_name)
    return ncsi_def.NCSI_SUCCESS, aen_oem_status, data
end

function ncsi_cmd.ncsi_new_parameter()
    ncsi_parameter.new()
end

return ncsi_cmd