/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 *
 * This software may be distributed under the terms of the BSD license.
 * See README for more details.
 */
#include "includes.h"
#include "driver_nl80211_hisi.h"
#include "driver_nl80211.h"
#include "wpa_supplicant_i.h"
#include "config.h"
#include "android_drv.h"
#include "securec.h"

#if defined(HISI_CONNECTIVITY_PATCH) && defined(HISI_MIRACAST_SINK_OPT)
#include "hisi_miracast_sink.h"
#endif

#define WPA_PS_ENABLED		0
#define WPA_PS_DISABLED		1

int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
		       int (*valid_handler)(struct nl_msg *, void *),
		       void *valid_data);

static int drv_errors = 0;

static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
{
	drv_errors++;
	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
		drv_errors = 0;
		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
	}
}

static int wpa_driver_set_power_save(void *priv, int state)
{
	struct i802_bss *bss = priv;
	struct wpa_driver_nl80211_data *drv = bss->drv;
	struct nl_msg *msg;
	int ret = -1;
	enum nl80211_ps_state ps_state;

	msg = nlmsg_alloc();
	if (!msg)
		return -1;

	genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0,
		    NL80211_CMD_SET_POWER_SAVE, 0);

	if (state == WPA_PS_ENABLED)
		ps_state = NL80211_PS_ENABLED;
	else
		ps_state = NL80211_PS_DISABLED;

	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
	NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);

	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
	msg = NULL;
	if (ret < 0)
		wpa_printf(MSG_ERROR, "nl80211: Set power mode fail: %d", ret);
nla_put_failure:
	nlmsg_free(msg);
	return ret;
}

static int get_power_mode_handler(struct nl_msg *msg, void *arg)
{
	struct nlattr *tb[NL80211_ATTR_MAX + 1];
	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
	int *state = (int *)arg;

	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
		  genlmsg_attrlen(gnlh, 0), NULL);

	if (!tb[NL80211_ATTR_PS_STATE])
		return NL_SKIP;

	if (state) {
		*state = (int)nla_get_u32(tb[NL80211_ATTR_PS_STATE]);
		wpa_printf(MSG_DEBUG, "nl80211: Get power mode = %d", *state);
		*state = (*state == NL80211_PS_ENABLED) ?
				WPA_PS_ENABLED : WPA_PS_DISABLED;
	}

	return NL_SKIP;
}

static int wpa_driver_get_power_save(void *priv, int *state)
{
	struct i802_bss *bss = priv;
	struct wpa_driver_nl80211_data *drv = bss->drv;
	struct nl_msg *msg;
	int ret = -1;

	msg = nlmsg_alloc();
	if (!msg)
		return -1;

	genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0,
		    NL80211_CMD_GET_POWER_SAVE, 0);

	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);

	ret = send_and_recv_msgs(drv, msg, get_power_mode_handler, state);
	msg = NULL;
	if (ret < 0)
		wpa_printf(MSG_ERROR, "nl80211: Get power mode fail: %d", ret);
nla_put_failure:
	nlmsg_free(msg);
	return ret;
}

int g_is_jp = 0;
int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len )
{
    struct i802_bss *bss = priv;
    struct wpa_driver_nl80211_data *drv = bss->drv;
    struct ifreq ifr;
    int ret = 0;
    int ret_s;

    wpa_printf(MSG_ERROR, "wpa_driver_nl80211_driver_cmd:cmd = %s", cmd);
    if (os_strcasecmp(cmd, "STOP") == 0)
    {
        linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
        wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
    }
    else if (os_strcasecmp(cmd, "START") == 0)
    {
        linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
        wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
    }
    else if (os_strcasecmp(cmd, "MACADDR") == 0)
    {
        u8 macaddr[ETH_ALEN] = {};

        ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr);
        if (!ret)
        {
            ret_s = snprintf_s(buf, buf_len, buf_len - 1,
                      "Macaddr = " MACSTR "\n", MAC2STR(macaddr));
            if (ret_s == -1) {
                wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, ret_s);
            }
        }
    }
    else if (os_strcasecmp(cmd, "RELOAD") == 0)
    {
        wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
    }
    else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0)
    {
        int state;

        state = atoi(cmd + 10);
        ret = wpa_driver_set_power_save(priv, state);
        if (ret < 0)
        {
            wpa_driver_send_hang_msg(drv);
        }
        else
        {
            drv_errors = 0;
        }
    }
    else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0)
    {
        int state = -1;

        ret = wpa_driver_get_power_save(priv, &state);
        if (!ret && (state != -1))
        {
            ret_s = snprintf_s(buf, buf_len, buf_len - 1, "POWERMODE = %d\n", state);
            if (ret_s == -1) {
                wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, ret_s);
            }
            drv_errors = 0;
        }
        else
        {
            wpa_driver_send_hang_msg(drv);
        }
    }
    else
    {
        /* Use private command */
        wifi_priv_cmd priv_cmd = {0};
        uint32 ret_len = 0;
        size_t buf_len_tmp;

        if (buf_len > MAX_PRIV_CMD_SIZE || strlen(cmd) >= MAX_PRIV_CMD_SIZE)
        {
            wpa_printf(MSG_ERROR, "%s: too long priavte command, strlen(cmd)=%zu buf_len=%zu", __func__, strlen(cmd), buf_len);
            return -1;
        }
        buf_len_tmp = buf_len;
        if (MAX_PRIV_CMD_SIZE == buf_len)
        {
            buf_len = strlen(cmd); /* default driver xxx cmd */
        }

        /* Hisi private data structure cmd should use buf_len, rather than strlen(cmd) */
        ret_s = memcpy_s(buf, buf_len_tmp, cmd, buf_len);
        if (ret_s != EOK) {
            wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s);
        }

        ret_s = memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr));
        if (ret_s != EOK) {
            wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s);
        }

        ret_s = memcpy_s(priv_cmd.buf, MAX_PRIV_CMD_SIZE, buf, buf_len);
        if (ret_s != EOK) {
            wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s);
        }

        priv_cmd.total_len = buf_len; /* MAX_PRIV_CMD_SIZE */
        priv_cmd.used_len = buf_len; /* strlen(cmd) */

        ifr.ifr_data = (void *)&priv_cmd;
        os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);

        wpa_printf(MSG_EXCESSIVE, "%s: 1:ifr_name=%s, len=%zu, buf_len=%zu", __func__, ifr.ifr_name, strlen(buf), buf_len);

        ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
        if (ret < 0)
        {
            wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__);
            wpa_driver_send_hang_msg(drv);
        }
        else
        {
            drv_errors = 0;
            ret_len = os_strlen(priv_cmd.buf);
            ret_len = (ret_len < MAX_PRIV_CMD_SIZE) ? ret_len : (MAX_PRIV_CMD_SIZE - 1);
            /* SET Command return 0 which means OK, GET Command return string length */
            if (os_strncasecmp(buf, priv_cmd.buf, ret_len) != 0)
            {
                ret = ret_len;
            }
            ret_s = memset_s(buf, buf_len, 0, buf_len);
            if (ret_s != EOK) {
                wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s);
            }

            ret_s = memcpy_s(buf, buf_len, priv_cmd.buf, ret_len); /* copy kernel space return string to user space */
            if (ret_s != EOK) {
                wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s);
            }
            buf[ret_len] = '\0';

            if (os_strncasecmp(cmd, "COUNTRY", 7) == 0)
            {
                union wpa_event_data event = {0};
                g_is_jp = (os_strncasecmp(cmd + 8, "JP", 2) == 0) ? 1 : 0 ;

                event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
                event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
                wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &event);

                wpa_printf(MSG_DEBUG, "%s:set country code end. len=%zu, ret_len=%d ret=%d", __func__, strlen(buf), ret_len, ret);
                return ret;
            }
#ifdef HISI_MIRACAST_SINK_OPT
            hisi_miracast_sink_log("%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret);
#else
#ifdef HW_WPA_REDUCE_LOG
            wpa_printf(MSG_EXCESSIVE, "%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret);
#else
            wpa_printf(MSG_DEBUG, "%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret);
#endif
#endif
        }
    }
    return ret;
}

int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
{
    char buf[MAX_DRV_CMD_SIZE] = {0};
    char *pbuf;
    oal_p2p_noa_param_stru *pst_p2p_noa = NULL;
    char *_cmd = "P2P_SET_NOA";
    int ret_s;

    wpa_printf(MSG_ERROR, "%s: Entry", __func__);
    pbuf = buf;
    ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd);
    if (ret_s == -1) {
        wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s);
    }
    pbuf += ret_s;
    *pbuf++ = '\0';
    pst_p2p_noa = (oal_p2p_noa_param_stru *)pbuf;
    pst_p2p_noa->uc_count = count;
    pst_p2p_noa->ul_duration= duration;
    pst_p2p_noa->ul_start_time= start;

    return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_p2p_noa_param_stru));

}

int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
{
	/* Return 0 till we handle p2p_presence request completely in the device side */
	return 0;
}

int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
{
    char buf[MAX_DRV_CMD_SIZE] = {0};
    char *pbuf;
    oal_p2p_ops_param_stru *pst_p2p_ops = NULL;
    char *_cmd = "P2P_SET_PS";
    int ret_s;

	wpa_printf(MSG_ERROR, "%s: Entry", __func__);
    pbuf = buf;
    ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd);
    if (ret_s == -1) {
        wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s);
    }
    pbuf += ret_s;
    *pbuf++ = '\0';
    pst_p2p_ops = (oal_p2p_ops_param_stru *)pbuf;
    pst_p2p_ops->en_ops_ctrl = opp_ps;
    pst_p2p_ops->uc_ct_window = ctwindow;

	return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_p2p_ops_param_stru));
}

int wpa_driver_set_ap_wps_p2p_ie(void *priv,
                 const struct wpabuf *beacon,
				 const struct wpabuf *proberesp,
				 const struct wpabuf *assocresp)
{
	char buf[MAX_WPSP2PIE_CMD_SIZE] = {0};
	struct wpabuf *ap_wps_p2p_ie = NULL;
	char *_cmd = "SET_AP_WPS_P2P_IE";
	char *pbuf;
	int ret = 0;
	int i;
	int ret_s;
	oal_app_ie_stru *pst_app_ie = NULL;
	struct cmd_desc {
		int cmd;
		const struct wpabuf *src;
	} cmd_arr[] = {
		{0x0, beacon},
		{0x2, proberesp},
		{0x4, assocresp},
		{-1, NULL}
	};

	wpa_printf(MSG_ERROR, "%s: Entry", __func__);
	for (i = 0; cmd_arr[i].cmd != -1; i++) {
		ret_s = memset_s(buf, sizeof(buf), 0, sizeof(buf));
		if (ret_s != EOK) {
			wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s);
		}
		pbuf = buf;
		ret_s = sprintf_s(pbuf, MAX_WPSP2PIE_CMD_SIZE, "%s", _cmd);
		if (ret_s == -1) {
			wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s);
		}
		pbuf += ret_s;
		*pbuf++ = '\0';
		ap_wps_p2p_ie = cmd_arr[i].src ?
			wpabuf_dup(cmd_arr[i].src) : NULL;
		if (ap_wps_p2p_ie) {
            if (wpabuf_len(ap_wps_p2p_ie) > WLAN_WPS_IE_MAX_SIZE)
            {
                wpa_printf(MSG_ERROR, "%s: app ie too large to wifi driver buffer.app_ie_len %d, auc_ie len %ul",
                            __func__, (int)wpabuf_len(ap_wps_p2p_ie), WLAN_WPS_IE_MAX_SIZE);
                wpabuf_free(ap_wps_p2p_ie);
                return -1;
            }

			pst_app_ie = (oal_app_ie_stru *)pbuf;
			pst_app_ie->en_app_ie_type = cmd_arr[i].cmd;
			pst_app_ie->ul_ie_len = wpabuf_len(ap_wps_p2p_ie);

			ret_s = memcpy_s(pst_app_ie->auc_ie, sizeof(pst_app_ie->auc_ie), wpabuf_head(ap_wps_p2p_ie), wpabuf_len(ap_wps_p2p_ie));
			if (ret_s != EOK) {
				wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s);
			}
#if defined(HISI_CONNECTIVITY_PATCH) && defined(HISI_MIRACAST_SINK_OPT)
			hisi_miracast_sink_log("cmd:%s, type %d, ie_len %d\r\n",
						_cmd,
						pst_app_ie->en_app_ie_type,
						pst_app_ie->ul_ie_len);
#else
#ifdef HW_WPA_REDUCE_LOG
			wpa_printf(MSG_EXCESSIVE, "cmd:%s, type %d, ie_len %d\r\n",
						_cmd,
						pst_app_ie->en_app_ie_type,
						pst_app_ie->ul_ie_len);
#else
			wpa_printf(MSG_DEBUG, "cmd:%s, type %d, ie_len %d\r\n",
						_cmd,
						pst_app_ie->en_app_ie_type,
						pst_app_ie->ul_ie_len);
#endif /* HW_WPA_REDUCE_LOG */
#endif
			wpa_printf(MSG_EXCESSIVE, "ie %p\r\n",
						pst_app_ie->auc_ie);

		    wpa_hexdump(MSG_EXCESSIVE, "P2P: set p2p wps ie", (const char *)pbuf, pst_app_ie->ul_ie_len + 8);

			if (strlen(_cmd) + sizeof(oal_app_ie_stru) + 1 < sizeof(buf))
			{
				ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf,
					strlen(_cmd) + sizeof(oal_app_ie_stru) + 1);
			}
			else
			{
				wpa_printf(MSG_ERROR, "%s:error.app total length to large!, cmd_len = %zu, buffer = %d", __func__, strlen(_cmd) + sizeof(oal_app_ie_stru) + 1, (int)sizeof(buf));
				ret = -1;
			}
			wpabuf_free(ap_wps_p2p_ie);
			if (ret < 0)
				break;
		}
	}
	return ret;
}

int wpa_driver_set_power_on(void *priv, int on)
{
    char buf[MAX_PRIV_CMD_SIZE] = {0};
    char *pbuf;
    char *_cmd = "SET_POWER_ON";
    int ret_s;

	wpa_printf(MSG_DEBUG, "%s: Entry,power flag:%d", __func__, on);
    pbuf = buf;
    ret_s = sprintf_s(pbuf, MAX_PRIV_CMD_SIZE, "%s %d", _cmd, on);
    if (ret_s == -1) {
        wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s);
    }
    wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf);

	return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf));
}

int wpa_driver_set_powermgmt_on(void *priv, int powermgmt_on)
{
    char buf[MAX_PRIV_CMD_SIZE] = {0};
    char *pbuf;
    char *_cmd = "SET_POWER_MGMT_ON";
    int ret_s;

    wpa_printf(MSG_DEBUG, "%s: Entry,power mgmt flag:%d", __func__, powermgmt_on);
    pbuf = buf;
    ret_s = sprintf_s(pbuf, MAX_PRIV_CMD_SIZE, "%s %d", _cmd, powermgmt_on);
    if (ret_s == -1) {
        wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s);
    }
    wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf);

    return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf));
}

int wpa_driver_set_qos_map(void *priv, const u8 *qos_map_set,
			                         u8 qos_map_set_len)
{
    char  buf[MAX_DRV_CMD_SIZE] = {0};
    char *pbuf;
    int   i, up_start;
    int   ret = 0;
    int   ret_s;
    oal_qos_map_param_stru *pst_qos_map = NULL;
    char *_cmd = "SET_QOS_MAP";

    if (qos_map_set_len < 16 || qos_map_set_len > 58 || qos_map_set_len & 1)
       {
           wpa_printf(MSG_ERROR, "Invalid QoS Map");
           return -1;
       }

	wpa_printf(MSG_ERROR, "%s: Entry,set_qos_map", __func__);
    pbuf = buf;
    ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd);
    if (ret_s == -1) {
        wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s);
    }
	pbuf += ret_s;
	*pbuf++ = '\0';

    pst_qos_map= (oal_qos_map_param_stru *)pbuf;
    pst_qos_map->valid = 1;
    pst_qos_map->num_dscp_except = (qos_map_set_len - 16) / 2;
    if (pst_qos_map->num_dscp_except)
    {
        for (i = 0; i < pst_qos_map->num_dscp_except; i++)
        {
            pst_qos_map->dscp_exception[i] = qos_map_set[i * 2];
            pst_qos_map->dscp_exception_up[i]   = qos_map_set[i * 2 + 1];
        }
    }
    up_start = qos_map_set_len - 16;
	for (i = 0; i < MAX_QOS_UP_RANGE; i++)
	{
		pst_qos_map->up_low[i]  = qos_map_set[up_start + (i * 2)];
		pst_qos_map->up_high[i] = qos_map_set[up_start + (i * 2) + 1];
	}

	ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_qos_map_param_stru));
	return ret;
}

int wpa_driver_set_tx_power(void *priv, int power)
{
    char    buf[MAX_PRIV_CMD_SIZE] = {0};
    int     len = 0;

    wpa_printf(MSG_ERROR, "%s: Entry,power limit:%d", __func__, power);
    if (power <= 0 || power > 100)
    {
        wpa_printf(MSG_ERROR, "%s: Entry,invalid power, valid power should in range(0,100]!", __func__);
        return -1;
    }
    len = snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "TX_POWER %d", power);
    if (len == -1) {
        wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, len);
    }
    buf[len] = '\0';
    wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf);

    return wpa_driver_nl80211_driver_cmd(priv, buf, buf, len);
}

#ifdef CONFIG_OWE
int wpa_driver_nl80211_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
			  int reassoc, u16 status, const u8 *pst_assoc_rsp_ie, size_t len)
{
    char buf[MAX_WPSP2PIE_CMD_SIZE] = {0};
    char *pbuf;
    char *_cmd = "SET_MLME_IE";
    int ret = 0;
    int ret_s;
    set_mlme_stru *pst_mlme_ie = NULL;

    if (NULL == pst_assoc_rsp_ie)
    {
        wpa_printf(MSG_WARNING, "%s[%d]: buf is null.\n", __FUNCTION__, __LINE__);
        return -1;
    }

	if (len > WLAN_WPS_IE_MAX_SIZE)
	{
		/* ����·�ie ���ȴ����¼��ڴ��С����ʾ���� */
		wpa_printf(MSG_ERROR, "%s[%d]: assoc rsp ie too large to wifi driver buffer. ie_len %zu, MAX len %d",
				  __FUNCTION__, __LINE__, len, WLAN_WPS_IE_MAX_SIZE);
		return -1;
	}

    pbuf = buf;
    ret_s = sprintf_s(pbuf, MAX_WPSP2PIE_CMD_SIZE, "%s", _cmd);
    if (ret_s == -1) {
        wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s);
    }
    pbuf += ret_s;
    *pbuf++ = '\0';

	pst_mlme_ie = (set_mlme_stru *)pbuf;
	if (reassoc)
	{
		pst_mlme_ie->en_mlme_type = OAL_IEEE80211_MLME_REASSOC_RSP;
	}
	else
	{
		pst_mlme_ie->en_mlme_type = OAL_IEEE80211_MLME_ASSOC_RSP;
	}
	pst_mlme_ie->us_status = status;
	ret_s = memcpy_s(pst_mlme_ie->uc_macaddr, sizeof(pst_mlme_ie->uc_macaddr), addr, ETH_ALEN);
	if (ret_s != EOK) {
		wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s);
	}

	pst_mlme_ie->us_ie_len = len;
	ret_s = memcpy_s(pst_mlme_ie->auc_ie, sizeof(pst_mlme_ie->auc_ie), pst_assoc_rsp_ie, len);
	if (ret_s != EOK) {
		wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s);
	}

	wpa_printf(MSG_ERROR, "%s[%d]: sta_assoc begin send assoc rsp ie len[%zu] to driver", __FUNCTION__, __LINE__, len);

	wpa_printf(MSG_ERROR, "cmd:%s, type %d, status %d, ie_len %d",
				_cmd,
				pst_mlme_ie->en_mlme_type,
				pst_mlme_ie->us_status,
				pst_mlme_ie->us_ie_len);

	wpa_hexdump(MSG_ERROR, "MLME: set sta_assoc ie", (const char *)pbuf, pst_mlme_ie->us_ie_len + 8);

	if (os_strlen(_cmd) + sizeof(set_mlme_stru) + 1 < sizeof(buf))
	{
		ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf,
					os_strlen(_cmd) + sizeof(set_mlme_stru) + 1);
	}
	else
	{
		wpa_printf(MSG_ERROR, "%s:error. app total length to large! cmd_len = %zu, buffer = %d",
				   __func__, os_strlen(_cmd) + sizeof(set_mlme_stru) + 1, (int)sizeof(buf));
		ret = -1;
	}

	return ret;
}
#endif

#ifdef CONFIG_HW_GET_P2P_SIGNAL_POLL
int wpa_drv_get_p2p_link_noise(void *priv, struct wpa_signal_info *si)
{
    if (priv == NULL || si == NULL) {
        return -1;
    }
    struct i802_bss *bss = priv;
    struct wpa_driver_nl80211_data *drv = bss->drv;
    os_memset(si, 0, sizeof(struct wpa_signal_info));
    return nl80211_get_link_noise(drv, si);
}
#endif /* CONFIG_HW_GET_P2P_SIGNAL_POLL */

static int wpa_sockets_open(void)
{
    int skfd;

    skfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (skfd < 0)
    {
        wpa_printf(MSG_ERROR,
                "nl80211: socket open failed.");
        return -1;
    }
    return skfd;
}
static void wpa_sockets_close(int32 skfd)
{
    close(skfd);
}
static int wpa_send_cmd_to_driver(int skfd, s8* ifname, wifi_priv_cmd* ioctl_data)
{
    struct ifreq ifr;
    int ret;
    int ret_s;

    ret_s = memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr));
    if (ret_s != EOK) {
        wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s);
    }

    ret_s = strncpy_s(ifr.ifr_name, IFNAMSIZ, "wlan0", strlen("wlan0"));
    if (ret_s != EOK) {
        wpa_printf(MSG_ERROR, "%s:%d, strncpy failed, ret=%d", __func__, __LINE__, ret_s);
    }
    ifr.ifr_name[IFNAMSIZ-1] = '\0';
    ifr.ifr_data = (void*)ioctl_data;

    ret = ioctl(skfd, SIOCDEVPRIVATE+1, &ifr);

    if (ret < 0)
    {
        wpa_printf(MSG_ERROR,
                "%s: failed to issue ioctl cmd.\n", __func__);
    }

    return ret;
}

static cust_data_stru global_cust_data = {0,0};

static void get_cust_config_params(void)
{
    int skfd;
    wifi_priv_cmd ioctl_data = {0};
    int ret;
    int len;

    if (-1 == (skfd = wpa_sockets_open()))
    {
        wpa_printf(MSG_ERROR,
                "%s: failed create socket.\n", __func__);
        return;
    }

    len = snprintf_s(ioctl_data.buf, MAX_PRIV_CMD_SIZE, MAX_PRIV_CMD_SIZE - 1, "WPAS_GET_CUST");
    if (len == -1) {
        wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, len);
    }
    ioctl_data.total_len = MAX_PRIV_CMD_SIZE;
    ioctl_data.used_len = len;
#ifdef HW_WPA_REDUCE_LOG
    wpa_printf(MSG_ERROR, "%s:ioctl_data cmd is %s", __func__, ioctl_data.buf);
#else
    wpa_printf(MSG_ERROR, "%s:ioctl_data cmd is %s", __func__, ioctl_data.buf);
#endif

    ret = wpa_send_cmd_to_driver(skfd, (s8 *)"wlan0", &ioctl_data);

    if (ret < 0)
    {
        wpa_printf(MSG_ERROR,
                "%s: send cmd to driver failed.\n", __func__);
        wpa_sockets_close(skfd);
        return;
    }

    drv_errors = 0;

    global_cust_data.read = 1;
    global_cust_data.disable_capab_2ght40 = (u32)(*ioctl_data.buf);
    wpa_printf(MSG_ERROR,
                "%s: update wps global cust data: [disable_capab_2ght40:%d]\n", __func__, global_cust_data.disable_capab_2ght40);

    wpa_sockets_close(skfd);
}

u32 get_cust_disable_capab_2ght40(void)
{
    if (!global_cust_data.read)
    {
        get_cust_config_params();
    }

    return global_cust_data.disable_capab_2ght40;
}