/*

 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.

 * 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.

 */



#include <poll.h>

#include <sys/types.h>

#include <securec.h>

#include <unistd.h>

#include <errno.h>

#include <net/if.h>

#include <linux/nl80211.h>

#include <netlink/genl/ctrl.h>

#include <netlink/genl/genl.h>

#include <netlink/handlers.h>

#include <osal_mem.h>



#include "hilog/log.h"

#include "../wifi_common_cmd.h"

#include "netlink_adapter.h"



#define OUI_QCA 0x001374



#define LISTEN_FD_NUMS 2

#define EVENT_SOCKET_INDEX 0

#define CTRL_SOCKET_INDEX 1

#define CTRL_SOCKET_WRITE_SIDE 0

#define CTRL_SOCKET_READ_SIDE 1



#define BUFSIZE 1024

#define POLLTIMEOUT 1000



static inline uint32_t BitLeftShift(uint8_t x)

{

    return 1U << x;

}



#define SCAN_QUAL_INVALID      BitLeftShift(0)

#define SCAN_NOISE_INVALID     BitLeftShift(1)

#define SCAN_LEVEL_INVALID     BitLeftShift(2)

#define SCAN_LEVEL_DBM         BitLeftShift(3)

#define SCAN_ASSOCIATED        BitLeftShift(5)



#define SUCCESS_STATUS 0

#define WLAN_ATTR_SCAN_COOKIE 7

#define WLAN_ATTR_SCAN_STATUS 8

#define WLAN_ATTR_SCAN_MAX 11

#define SCAN_STATUS_MAX 2

#define NL80211_SCAN_DONE 107

#define WLAN_CMD_VDR_COMMON 0xCB

#define DATA_FRAME_MAX_SIZE 1400



typedef struct {

    WifiScanResults *scanResults;

    const char *ifName;

} WifiScanResultArg;



static int g_familyId = 0;



static int NoSeqCheck(struct nl_msg *msg, void *arg)

{

    (void)msg;

    return NL_OK;

}



static void QcaWifiEventScanDoneProcess(const char *ifName, struct nlattr *data, size_t len)

{

    struct nlattr *attr[WLAN_ATTR_SCAN_MAX + 1];

    uint32_t status;



    if (nla_parse(attr, WLAN_ATTR_SCAN_MAX, data, len, NULL) ||

        attr[WLAN_ATTR_SCAN_STATUS] ||

        !attr[WLAN_ATTR_SCAN_COOKIE]) {

        return;

    }



    status = nla_get_u8(attr[WLAN_ATTR_SCAN_STATUS]);

    if (status >= SCAN_STATUS_MAX) {

        HILOG_ERROR(LOG_CORE, "%s: invalid status",  __FUNCTION__);

        return;

    }



    WifiEventReport(ifName, WIFI_EVENT_SCAN_DONE, &status);

}



static void WifiEventVendorProcess(const char *ifName, struct nlattr **attr)

{

    uint32_t vendorId;

    uint32_t subCmd;

    uint8_t *data = NULL;

    uint32_t len;



    if (attr[NL80211_ATTR_VENDOR_ID] == NULL) {

        HILOG_ERROR(LOG_CORE, "%s: failed to get vendor id", __FUNCTION__);

        return;

    }

    if (attr[NL80211_ATTR_VENDOR_SUBCMD] == NULL) {

        HILOG_ERROR(LOG_CORE, "%s: failed to get vendor subcmd", __FUNCTION__);

        return;

    }



    vendorId = nla_get_u32(attr[NL80211_ATTR_VENDOR_ID]);

    subCmd = nla_get_u32(attr[NL80211_ATTR_VENDOR_SUBCMD]);

    if (vendorId != OUI_QCA || subCmd != NL80211_SCAN_DONE) {

        HILOG_ERROR(LOG_CORE, "%s: unsupported vendor event", __FUNCTION__);

        return;

    }



    if (attr[NL80211_ATTR_VENDOR_DATA] == NULL) {

        HILOG_ERROR(LOG_CORE, "%s: get vendor data fail", __FUNCTION__);

        return;

    }

    data = nla_data(attr[NL80211_ATTR_VENDOR_DATA]);

    len = (uint32_t)nla_len(attr[NL80211_ATTR_VENDOR_DATA]);



    QcaWifiEventScanDoneProcess(ifName, (struct nlattr *)data, len);

}



static int32_t GetNlaDataScanResult(struct nlattr *attr[], int len, WifiScanResult *scanResult)

{

    uint8_t *ie;

    uint8_t *beaconIe;

    uint8_t *bssid;



    (void)len;

    if (attr[NL80211_BSS_INFORMATION_ELEMENTS]) {

        ie = nla_data(attr[NL80211_BSS_INFORMATION_ELEMENTS]);

        scanResult->ieLen = (uint32_t)nla_len(attr[NL80211_BSS_INFORMATION_ELEMENTS]);

        if (ie != NULL && scanResult->ieLen != 0) {

            scanResult->ie = OsalMemCalloc(scanResult->ieLen);

            if (scanResult->ie == NULL || memcpy_s(scanResult->ie, scanResult->ieLen, ie, scanResult->ieLen) != EOK) {

                HILOG_ERROR(LOG_CORE, "%s: fill ie data fail", __FUNCTION__);

                return RET_CODE_FAILURE;

            }

        }

    }

    if (attr[NL80211_BSS_BEACON_IES]) {

        beaconIe = nla_data(attr[NL80211_BSS_INFORMATION_ELEMENTS]);

        scanResult->beaconIeLen = (uint32_t)nla_len(attr[NL80211_BSS_INFORMATION_ELEMENTS]);

        if (beaconIe != NULL && scanResult->beaconIeLen != 0) {

            scanResult->beaconIe = OsalMemCalloc(scanResult->beaconIeLen);

            if (scanResult->beaconIe == NULL ||

                memcpy_s(scanResult->beaconIe, scanResult->beaconIeLen, beaconIe, scanResult->beaconIeLen) != EOK) {

                HILOG_ERROR(LOG_CORE, "%s: fill beacon ie data fail", __FUNCTION__);

                return RET_CODE_FAILURE;

            }

        }

    }

    if (attr[NL80211_BSS_BSSID]) {

        bssid = nla_data(attr[NL80211_BSS_BSSID]);

        if (bssid != NULL) {

            scanResult->bssid = OsalMemCalloc(ETH_ADDR_LEN);

            if (scanResult->bssid == NULL || memcpy_s(scanResult->bssid, ETH_ADDR_LEN, bssid, ETH_ADDR_LEN) != EOK) {

                HILOG_ERROR(LOG_CORE, "%s: fill bssid fail", __FUNCTION__);

                return RET_CODE_FAILURE;

            }

        }

    }

    return RET_CODE_SUCCESS;

}



static int32_t DoGetScanResult(struct nlattr *attr[], int len, WifiScanResult *scanResult)

{

    if (GetNlaDataScanResult(attr, len, scanResult) != RET_CODE_SUCCESS) {

        return RET_CODE_FAILURE;

    }

    if (attr[NL80211_BSS_FREQUENCY]) {

        scanResult->freq = nla_get_u32(attr[NL80211_BSS_FREQUENCY]);

    }

    if (attr[NL80211_BSS_BEACON_INTERVAL]) {

        scanResult->beaconInt = nla_get_u16(attr[NL80211_BSS_BEACON_INTERVAL]);

    }

    if (attr[NL80211_BSS_CAPABILITY]) {

        scanResult->caps = nla_get_u16(attr[NL80211_BSS_CAPABILITY]);

    }

    if (attr[NL80211_BSS_SIGNAL_MBM]) {

         /* mBm to dBm */

        scanResult->level = (int32_t)nla_get_u32(attr[NL80211_BSS_SIGNAL_MBM]) / SIGNAL_LEVEL_CONFFICIENT;

        scanResult->flags |= SCAN_LEVEL_DBM | SCAN_QUAL_INVALID;

    } else if (attr[NL80211_BSS_SIGNAL_UNSPEC]) {

        scanResult->level = (int32_t)nla_get_u8(attr[NL80211_BSS_SIGNAL_UNSPEC]);

        scanResult->flags |= SCAN_QUAL_INVALID;

    } else {

        scanResult->flags |= SCAN_LEVEL_INVALID | SCAN_QUAL_INVALID;

    }

    if (attr[NL80211_BSS_TSF]) {

        scanResult->tsf = nla_get_u64(attr[NL80211_BSS_TSF]);

    }

    if (attr[NL80211_BSS_BEACON_TSF]) {

        uint64_t tsf = nla_get_u64(attr[NL80211_BSS_BEACON_TSF]);

        if (tsf > scanResult->tsf) {

            scanResult->tsf = tsf;

        }

    }

    if (attr[NL80211_BSS_SEEN_MS_AGO]) {

        scanResult->age = nla_get_u32(attr[NL80211_BSS_SEEN_MS_AGO]);

    }

    return RET_CODE_SUCCESS;

}



static int32_t WifiGetScanResultHandler(struct nl_msg *msg, void *arg)

{

    WifiScanResult *scanResult = NULL;

    WifiScanResults *scanResults = NULL;

    struct genlmsghdr *hdr = nlmsg_data(nlmsg_hdr(msg));

    WifiScanResultArg *handlerArg = (WifiScanResultArg *)arg;

    struct nlattr *attr[NL80211_ATTR_MAX + 1], *bssAttr[NL80211_BSS_MAX + 1];

    static struct nla_policy bssPolicy[NL80211_BSS_MAX + 1];

    memset_s(bssPolicy, sizeof(bssPolicy), 0, sizeof(bssPolicy));

    bssPolicy[NL80211_BSS_FREQUENCY].type = NLA_U32;

    bssPolicy[NL80211_BSS_TSF].type = NLA_U64;

    bssPolicy[NL80211_BSS_BEACON_INTERVAL].type = NLA_U16;

    bssPolicy[NL80211_BSS_CAPABILITY].type = NLA_U16;

    bssPolicy[NL80211_BSS_SIGNAL_MBM].type = NLA_U32;

    bssPolicy[NL80211_BSS_SIGNAL_UNSPEC].type = NLA_U8;

    bssPolicy[NL80211_BSS_STATUS].type = NLA_U32;

    bssPolicy[NL80211_BSS_SEEN_MS_AGO].type = NLA_U32;



    if (handlerArg == NULL || handlerArg->scanResults == NULL || handlerArg->ifName == NULL) {

        HILOG_ERROR(LOG_CORE, "%s: Invalid param",  __FUNCTION__);

        return NL_SKIP;

    }

    scanResults = handlerArg->scanResults;

    scanResult = &scanResults->scanResult[scanResults->num];

    nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(hdr, 0), genlmsg_attrlen(hdr, 0), NULL);

    if (!attr[NL80211_ATTR_BSS]) {

        HILOG_ERROR(LOG_CORE, "%s: bss info missing",  __FUNCTION__);

        return NL_SKIP;

    }

    if (nla_parse_nested(bssAttr, NL80211_BSS_MAX, attr[NL80211_ATTR_BSS], bssPolicy)) {

        HILOG_ERROR(LOG_CORE, "%s: failed to parse nested attributes",  __FUNCTION__);

        return NL_SKIP;

    }

    if (DoGetScanResult(bssAttr, NL80211_BSS_MAX + 1, scanResult) != RET_CODE_SUCCESS) {

        HILOG_ERROR(LOG_CORE, "%s: DoGetScanResult fail",  __FUNCTION__);

        FreeScanResult(scanResult);

        return NL_SKIP;

    }

    HILOG_DEBUG(LOG_CORE, "%{public}s, line:%{public}d num:%{public}u scanResultCapacity:%{public}u", __FUNCTION__,

        __LINE__, scanResults->num, scanResults->scanResultCapacity);

    scanResults->num++;

    if (scanResults->num == scanResults->scanResultCapacity) {

        scanResults->scanResultCapacity += INIT_SCAN_RES_NUM;

        WifiScanResult *newScanResult = NULL;

        newScanResult = (WifiScanResult *)OsalMemCalloc(sizeof(WifiScanResult) * (scanResults->scanResultCapacity));

        if (newScanResult == NULL) {

            HILOG_ERROR(LOG_CORE, "%{public}s: newscanResult is NULL",  __FUNCTION__);

            scanResults->scanResultCapacity -= INIT_SCAN_RES_NUM;

            scanResults->num = 0;

            return NL_SKIP;

        }

        if (memcpy_s((void *)newScanResult, sizeof(WifiScanResult) * (scanResults->scanResultCapacity),

            (void *)scanResults->scanResult, sizeof(WifiScanResult) * (scanResults->num)) != RET_CODE_SUCCESS) {

            HILOG_ERROR(LOG_CORE, "%{public}s: memcpy_s fail",  __FUNCTION__);

        }

        OsalMemFree(scanResults->scanResult);

        scanResults->scanResult = newScanResult;

        newScanResult = NULL;

    }

    return NL_SKIP;

}



static void WifiEventScanResultProcess(const char *ifName)

{

    HILOG_DEBUG(LOG_CORE, "hal enter %{public}s", __FUNCTION__);

    int32_t ret;

    WifiScanResults scanResults = {0};

    WifiScanResultArg arg;

    uint32_t ifaceId = if_nametoindex(ifName);

    struct nl_msg *msg = nlmsg_alloc();

    if (NULL == msg) {

        HILOG_ERROR(LOG_CORE, "%s: msg is NULL.",  __FUNCTION__);

        return;

    }

    if (InitScanResults(&scanResults) != RET_CODE_SUCCESS) {

        HILOG_ERROR(LOG_CORE, "%s: InitScanResults failed",  __FUNCTION__);

        nlmsg_free(msg);

        return;

    }

    arg.scanResults = &scanResults;

    arg.ifName = ifName;

    genlmsg_put(msg, 0, 0, g_familyId, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);

    nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifaceId);

    ret = NetlinkSendCmdSync(msg, WifiGetScanResultHandler, (void *)&arg);

    if (ret != RET_CODE_SUCCESS) {

        HILOG_ERROR(LOG_CORE, "%s: send cmd failed",  __FUNCTION__);

    }

    WifiEventReport(ifName, WIFI_EVENT_SCAN_RESULTS, &scanResults);

    HILOG_INFO(LOG_CORE, "%s: scanResults.num = %u", __FUNCTION__, scanResults.num);

    FreeScanResults(&scanResults);

    nlmsg_free(msg);

    HILOG_DEBUG(LOG_CORE, "hal exit %{public}s", __FUNCTION__);

}



static void WifiEventScanAbortedProcess(const char *ifName)

{

    WifiScanResults scanResults = {0};



    if (ifName == NULL) {

        HILOG_ERROR(LOG_CORE, "%s: ifName is NULL.",  __FUNCTION__);

        return;

    }

    WifiEventReport(ifName, WIFI_EVENT_SCAN_ABORTED, &scanResults);

}



static void WifiEventDataFrameProcess(const char *ifName, struct nlattr **attr)

{

    WifiDataFrame dataFrame;

    /* The outer function can ensure that attr is not empty */

    if (ifName == NULL || attr[NL80211_ATTR_FRAME] == NULL) {

        HILOG_ERROR(LOG_CORE, "%{public}s: ifName is invalid or failed to get frame data", __FUNCTION__);

        return;

    }



    (void)memset_s(&dataFrame, sizeof(WifiDataFrame), 0, sizeof(WifiDataFrame));



    dataFrame.data = nla_data(attr[NL80211_ATTR_FRAME]);

    dataFrame.dataLen = (uint32_t)nla_len(attr[NL80211_ATTR_FRAME]);

    HILOG_INFO(LOG_CORE, "%{public}s: receive data frame len %{public}u", __FUNCTION__, dataFrame.dataLen);

    if (dataFrame.dataLen > DATA_FRAME_MAX_SIZE) {

        return;

    }



    WifiEventReport(ifName, WIFI_EVENT_DATA_FRAME_RECEIVED, &dataFrame);

}



static void DoProcessEvent(const char *ifName, int cmd, struct nlattr **attr)

{

    HILOG_DEBUG(LOG_CORE, "hal enter %{public}s cmd=%{public}d ifName=%{public}s", __FUNCTION__, cmd, ifName);

    switch (cmd) {

        case NL80211_CMD_VENDOR:

            HILOG_INFO(LOG_CORE, "receive cmd NL80211_CMD_VENDOR");

            WifiEventVendorProcess(ifName, attr);

            break;

        case NL80211_CMD_START_SCHED_SCAN:

            HILOG_INFO(LOG_CORE, "receive cmd NL80211_CMD_START_SCHED_SCAN");

            break;

        case NL80211_CMD_SCHED_SCAN_RESULTS:

            HILOG_INFO(LOG_CORE, "receive cmd NL80211_CMD_SCHED_SCAN_RESULTS");

            WifiEventScanResultProcess(ifName);

            break;

        case NL80211_CMD_SCHED_SCAN_STOPPED:

            HILOG_INFO(LOG_CORE, "receive cmd NL80211_CMD_SCHED_SCAN_STOPPED");

            break;

        case NL80211_CMD_NEW_SCAN_RESULTS:

            HILOG_INFO(LOG_CORE, "receive cmd NL80211_CMD_NEW_SCAN_RESULTS");

            WifiEventScanResultProcess(ifName);

            break;

        case NL80211_CMD_SCAN_ABORTED:

            HILOG_INFO(LOG_CORE, "receive cmd NL80211_CMD_SCAN_ABORTED");

            WifiEventScanAbortedProcess(ifName);

            break;

        case NL80211_CMD_TRIGGER_SCAN:

            HILOG_INFO(LOG_CORE, "receive cmd NL80211_CMD_TRIGGER_SCAN");

            break;

        case NL80211_CMD_FRAME_TX_STATUS:

            HILOG_INFO(LOG_CORE, "receive cmd NL80211_CMD_FRAME_TX_STATUS");

            WifiEventTxStatus(ifName, attr);

            break;

        case WLAN_CMD_VDR_COMMON:

            HILOG_INFO(LOG_CORE, "receive cmd WLAN_CMD_VDR_COMMON");

            WifiEventDataFrameProcess(ifName, attr);

            break;

        default:

            HILOG_DEBUG(LOG_CORE, "not supported cmd");

            break;

    }

    HILOG_DEBUG(LOG_CORE, "hal exit %{public}s", __FUNCTION__);

}



static int32_t ProcessEvent(struct nl_msg *msg, void *arg)

{

    HILOG_DEBUG(LOG_CORE, "hal enter %{public}s", __FUNCTION__);

    struct genlmsghdr *hdr = nlmsg_data(nlmsg_hdr(msg));

    struct nlattr *attr[NL80211_ATTR_MAX + 1];

    struct NetworkInfoResult networkInfo;

    uint32_t ifidx = -1;

    uint32_t i;

    int ret;



    nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(hdr, 0),

        genlmsg_attrlen(hdr, 0), NULL);



    if (attr[NL80211_ATTR_IFINDEX]) {

        ifidx = nla_get_u32(attr[NL80211_ATTR_IFINDEX]);

    }

    HILOG_INFO(LOG_CORE, "ifidx = %{public}d", ifidx);



    ret = GetUsableNetworkInfo(&networkInfo);

    if (ret != RET_CODE_SUCCESS) {

        HILOG_ERROR(LOG_CORE, "%s: get usable network information failed", __FUNCTION__);

        return NL_SKIP;

    }



    for (i = 0; i < networkInfo.nums; i++) {

        HILOG_DEBUG(LOG_CORE, "name=%{public}s index=%{public}d mode=%{public}s",

            networkInfo.infos[i].name, if_nametoindex(networkInfo.infos[i].name), networkInfo.infos[i].supportMode);

        if (ifidx == if_nametoindex(networkInfo.infos[i].name)) {

            DoProcessEvent(networkInfo.infos[i].name, hdr->cmd, attr);

            return NL_SKIP;

        }

    }

    HILOG_DEBUG(LOG_CORE, "hal exit %{public}s", __FUNCTION__);

    return NL_SKIP;

}



static struct nl_cb *CreateCb(void)

{

    struct nl_cb *cb;



    cb = nl_cb_alloc(NL_CB_DEFAULT);

    if (cb == NULL) {

        HILOG_ERROR(LOG_CORE, "%s: alloc cb failed", __FUNCTION__);

        return NULL;

    }



    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, NoSeqCheck, NULL);

    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, ProcessEvent, NULL);



    return cb;

}



static int HandleEvent(struct nl_sock *sock)

{

    HILOG_DEBUG(LOG_CORE, "hal enter %{public}s", __FUNCTION__);

    int ret;

    struct nl_cb *cb = CreateCb();

    if (cb == NULL) {

        HILOG_ERROR(LOG_CORE, "%{public}s: Create cb failed", __FUNCTION__);

        return RET_CODE_FAILURE;

    }



    ret = nl_recvmsgs(sock, cb);

    HILOG_DEBUG(LOG_CORE, "nl_recvmsgs ret:%{public}d, errno:%{public}d %{public}s", ret, errno, strerror(errno));

    nl_cb_put(cb);

    cb = NULL;

    HILOG_DEBUG(LOG_CORE, "hal exit %{public}s", __FUNCTION__);

    return ret;

}



static int32_t CtrlNoSeqCheck(struct nl_msg *msg, void *arg)

{

    struct genlmsghdr *hdr = nlmsg_data(nlmsg_hdr(msg));

    struct nlattr *attr[NL80211_ATTR_MAX + 1];



    nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(hdr, 0),

        genlmsg_attrlen(hdr, 0), NULL);

    

    if (hdr->cmd != NL80211_CMD_FRAME) {

        return NL_OK;

    }

    if (attr[NL80211_ATTR_FRAME] == NULL) {

        HILOG_ERROR(LOG_CORE, "%s: failed to get frame data", __FUNCTION__);

        return NL_OK;

    }

    uint32_t dataLen = (uint32_t)nla_len(attr[NL80211_ATTR_FRAME]);

    if (dataLen == 0 || dataLen > BUFSIZE) {

        return NL_OK;

    }

    uint8_t *tempData = OsalMemCalloc(dataLen + 1);

    if (tempData == NULL) {

        return NL_OK;

    }

    (void)memset_s(tempData, dataLen + 1, 0, dataLen + 1);

    do {

        if (memcpy_s(tempData, dataLen + 1, nla_data(attr[NL80211_ATTR_FRAME]), dataLen) != EOK) {

            break;

        }

        uint32_t rssi = 0;

        if (attr[NL80211_ATTR_RX_SIGNAL_DBM]) {

            rssi = nla_get_u32(attr[NL80211_ATTR_RX_SIGNAL_DBM]);

            uint8_t tempRssi = (uint8_t)(rssi & 0xFF);

            tempData[dataLen] = tempRssi;

        }

        WifiActionData actionData;

        actionData.data = tempData;

        actionData.dataLen = dataLen + 1;

        HILOG_INFO(LOG_CORE, "%s: receive data len = %{public}d, rssi = %{public}d", __FUNCTION__,

            actionData.dataLen, rssi);

        WifiEventReport("p2p0", WIFI_EVENT_ACTION_RECEIVED, &actionData);

    } while (0);

    OsalMemFree(tempData);

    tempData = NULL;

    return NL_OK;

}



static int32_t CtrlSocketErrorHandler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)

{

    int32_t *ret = (int32_t *)arg;

    *ret = err->error;

    HILOG_ERROR(LOG_CORE, "%s: ctrl sock error ret = %{public}d", __FUNCTION__, *ret);

    return NL_SKIP;

}



static int32_t CtrlSocketFinishHandler(struct nl_msg *msg, void *arg)

{

    int32_t *ret = (int32_t *)arg;

    HILOG_ERROR(LOG_CORE, "%s: ctrl sock finish ret = %{public}d", __FUNCTION__, *ret);

    *ret = 0;

    return NL_SKIP;

}



static int32_t CtrlSocketAckHandler(struct nl_msg *msg, void *arg)

{

    int32_t *err = (int32_t *)arg;

    HILOG_ERROR(LOG_CORE, "%s: ctrl sock ack ret = %{public}d", __FUNCTION__, *err);

    *err = 0;

    return NL_STOP;

}



static int HandleCtrlEvent(struct nl_sock *sock)

{

    HILOG_INFO(LOG_CORE, "hal enter %{public}s", __FUNCTION__);

    int ret;

    struct nl_cb *cb;

    int error;



    cb = nl_cb_alloc(NL_CB_DEFAULT);

    if (cb == NULL) {

        HILOG_ERROR(LOG_CORE, "%{public}s: alloc ctrl cb failed", __FUNCTION__);

        return RET_CODE_FAILURE;

    }



    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, CtrlNoSeqCheck, NULL);

    nl_cb_err(cb, NL_CB_CUSTOM, CtrlSocketErrorHandler, &error);

    nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, CtrlSocketFinishHandler, &error);

    nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, CtrlSocketAckHandler, &error);



    ret = nl_recvmsgs(sock, cb);

    HILOG_INFO(LOG_CORE, "nl_recvmsgs ret:%{public}d, errno:%{public}d %{public}s", ret, errno, strerror(errno));

    nl_cb_put(cb);

    cb = NULL;

    HILOG_INFO(LOG_CORE, "hal exit %{public}s", __FUNCTION__);

    return ret;

}



void *EventThread(void *para)

{

    HILOG_INFO(LOG_CORE, "hal enter %{public}s", __FUNCTION__);

    struct nl_sock *eventSock = NULL;

    struct nl_sock *ctrlSock = NULL;

    struct pollfd pollFds[LISTEN_FD_NUMS] = {0};

    struct WifiThreadParam *threadParam = NULL;

    int ret;

    enum ThreadStatus *status = NULL;



    if (para == NULL) {

        HILOG_ERROR(LOG_CORE, "%s: para is null", __FUNCTION__);

        return NULL;

    } else {

        threadParam = (struct WifiThreadParam *)para;

        eventSock = threadParam->eventSock;

        ctrlSock = threadParam->ctrlSock;

        g_familyId = threadParam->familyId;

        status = threadParam->status;

        *status = THREAD_RUN;

    }



    pollFds[EVENT_SOCKET_INDEX].fd = nl_socket_get_fd(eventSock);

    pollFds[EVENT_SOCKET_INDEX].events = POLLIN | POLLERR;

    pollFds[CTRL_SOCKET_INDEX].fd = nl_socket_get_fd(ctrlSock);

    pollFds[CTRL_SOCKET_INDEX].events = POLLIN;



    while (*status == THREAD_RUN) {

        ret = TEMP_FAILURE_RETRY(poll(pollFds, LISTEN_FD_NUMS, POLLTIMEOUT));

        HILOG_DEBUG(LOG_CORE, "EventThread TEMP_FAILURE_RETRY ret:%{public}d status:%{public}d", ret, *status);

        if (ret < 0) {

            HILOG_ERROR(LOG_CORE, "%{public}s: fail poll", __FUNCTION__);

            break;

        } else if ((uint32_t)pollFds[EVENT_SOCKET_INDEX].revents & POLLERR) {

            HILOG_ERROR(LOG_CORE, "%{public}s: event socket get POLLERR event", __FUNCTION__);

            break;

        } else if ((uint32_t)pollFds[EVENT_SOCKET_INDEX].revents & POLLIN) {

            if (HandleEvent(eventSock) != RET_CODE_SUCCESS) {

                HILOG_ERROR(LOG_CORE, "EventThread HandleEvent break");

                break;

            }

        } else if ((uint32_t)pollFds[CTRL_SOCKET_INDEX].revents & POLLIN) {

            if (HandleCtrlEvent(ctrlSock) != RET_CODE_SUCCESS) {

                HILOG_ERROR(LOG_CORE, "EventThread HandleCtrlEvent break");

                break;

            }

        }

    }



    *status = THREAD_STOP;

    HILOG_INFO(LOG_CORE, "hal exit %{public}s", __FUNCTION__);

    return NULL;

}