[WCNCR00147230] acl: add access control list feature

[Description]
Add access control list feature with iwpriv cmd to set accept/deny list
1. add enable/disable acl feature
ex: iwpriv p2p0 driver "set_acl_policy 1" for enable accept list
2. add a mac address entry to specific list depend on policy setting
ex: iwpriv p2p0 driver "add_acl_entry 01:02:03:04:05:06"
3. delete a mac address entry from specific list
depend on policy setting
ex: iwpriv p2p0 driver "del_acl_entry 01:02:03:04:05:06"
4. show all entries in specific list
ex: iwpriv p2p0 driver "show_acl_entry"
5. clear all entries in specific list
ex: iwpriv p2p0 driver "clear_acl_entry"

Change-Id: Id575455e5cae0b6b7131383cb2e87aa3051c67d3
Feature: acl
Signed-off-by: Howie Liu <jen-hao.liu@mediatek.com>
CR-Id: WCNCR00147230
diff --git a/include/mgmt/p2p_role.h b/include/mgmt/p2p_role.h
index b289e03..0a06eb7 100644
--- a/include/mgmt/p2p_role.h
+++ b/include/mgmt/p2p_role.h
@@ -299,6 +299,10 @@
 
 VOID p2pRoleFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo);
 
+VOID p2pRoleUpdateACLEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx);
+
+BOOL p2pRoleProcessACLInspection(IN P_ADAPTER_T prAdapter, IN PUCHAR pMacAddr, IN UINT_8 ucBssIdx);
+
 WLAN_STATUS
 p2pRoleFsmRunEventAAAComplete(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_BSS_INFO_T prP2pBssInfo);
 
diff --git a/include/nic/adapter.h b/include/nic/adapter.h
index 862ae8d..faf317e 100644
--- a/include/nic/adapter.h
+++ b/include/nic/adapter.h
@@ -469,6 +469,7 @@
 	BOOLEAN fgIsGranted;
 	ENUM_BAND_T eBandGranted;
 	UINT_8 ucPrimaryChannelGranted;
+	PARAM_CUSTOM_ACL rACL;
 };
 
 struct _AIS_SPECIFIC_BSS_INFO_T {
diff --git a/include/wlan_oid.h b/include/wlan_oid.h
index 4d87b17..f83f843 100644
--- a/include/wlan_oid.h
+++ b/include/wlan_oid.h
@@ -1356,6 +1356,26 @@
 	UINT_32 u4Mode;
 } PARAM_CUSTOM_P2P_SET_STRUCT_T, *P_PARAM_CUSTOM_P2P_SET_STRUCT_T;
 
+#define MAX_NUMBER_OF_ACL 20
+
+typedef enum _ENUM_PARAM_CUSTOM_ACL_POLICY_T {
+	PARAM_CUSTOM_ACL_POLICY_DISABLE,
+	PARAM_CUSTOM_ACL_POLICY_ACCEPT,
+	PARAM_CUSTOM_ACL_POLICY_DENY,
+	PARAM_CUSTOM_ACL_POLICY_NUM
+} ENUM_PARAM_CUSTOM_ACL_POLICY_T, *P_ENUM_PARAM_CUSTOM_ACL_POLICY_T;
+
+typedef struct _PARAM_CUSTOM_ACL_ENTRY {
+	UINT_8 aucAddr[MAC_ADDR_LEN];
+	UINT_16 u2Rsv;
+} PARAM_CUSTOM_ACL_ENTRY, *PPARAM_CUSTOM_ACL_ENTRY;
+
+typedef struct _PARAM_CUSTOM_ACL {
+	ENUM_PARAM_CUSTOM_ACL_POLICY_T ePolicy;
+	UINT_32 u4Num;
+	PARAM_CUSTOM_ACL_ENTRY rEntry[MAX_NUMBER_OF_ACL];
+} PARAM_CUSTOM_ACL, *PPARAM_CUSTOM_ACL;
+
 typedef enum _ENUM_CFG_SRC_TYPE_T {
 	CFG_SRC_TYPE_EEPROM,
 	CFG_SRC_TYPE_NVRAM,
diff --git a/mgmt/p2p_func.c b/mgmt/p2p_func.c
index 805b6b6..162ce5c 100644
--- a/mgmt/p2p_func.c
+++ b/mgmt/p2p_func.c
@@ -1624,6 +1624,7 @@
 		}
 
 		if (bssGetClientCount(prAdapter, prP2pBssInfo) >= P2P_MAXIMUM_CLIENT_COUNT
+			|| !p2pRoleProcessACLInspection(prAdapter, prStaRec->aucMacAddr, prP2pBssInfo->ucBssIndex)
 #if CFG_SUPPORT_HOTSPOT_WPS_MANAGER
 			|| kalP2PMaxClients(prAdapter->prGlueInfo, bssGetClientCount(prAdapter, prP2pBssInfo),
 			(UINT_8) prP2pBssInfo->u4PrivateData)
diff --git a/mgmt/p2p_role_fsm.c b/mgmt/p2p_role_fsm.c
index 4317332..4d93803 100644
--- a/mgmt/p2p_role_fsm.c
+++ b/mgmt/p2p_role_fsm.c
@@ -1784,6 +1784,120 @@
 
 /*----------------------------------------------------------------------------*/
 /*!
+* @	This routine update the current MAC table based on the current ACL.
+*	If ACL change causing an associated STA become un-authorized. This STA
+*	will be kicked out immediately.
+*
+* @param[in] prAdapter          Pointer to the Adapter structure.
+* @param[in] ucBssIdx            Bss index.
+*
+* @return (none)
+*/
+/*----------------------------------------------------------------------------*/
+VOID p2pRoleUpdateACLEntry(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx)
+{
+	BOOLEAN drop = FALSE, Matched = FALSE;
+	INT_32 i = 0, i4Ret = 0;
+	P_LINK_T prClientList;
+	P_STA_RECORD_T prCurrStaRec;
+	P_BSS_INFO_T prP2pBssInfo;
+
+	if ((!prAdapter) || (ucBssIdx > HW_BSSID_NUM))
+		return;
+	DBGLOG(P2P, TRACE, "Update ACL Entry ucBssIdx = %d\n", ucBssIdx);
+	prP2pBssInfo = prAdapter->aprBssInfo[ucBssIdx];
+
+	/* ACL is disabled. Do nothing about the MAC table. */
+	if (prP2pBssInfo->rACL.ePolicy == 0)
+		return;
+
+	prClientList = &prP2pBssInfo->rStaRecOfClientList;
+
+	LINK_FOR_EACH_ENTRY(prCurrStaRec, prClientList, rLinkEntry, STA_RECORD_T) {
+		if (!prCurrStaRec) {
+			DBGLOG(P2P, WARN, "NULL STA_REC ptr in BSS client list\n");
+			bssDumpClientList(prAdapter, prP2pBssInfo);
+			break;
+		}
+
+		Matched = FALSE;
+		drop = FALSE;
+		for (i = 0; i < prP2pBssInfo->rACL.u4Num; i++) {
+			if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, prP2pBssInfo->rACL.rEntry[i].aucAddr)) {
+				Matched = TRUE;
+				break;
+			}
+		}
+
+		if ((Matched == FALSE) && (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_ACCEPT)) {
+			drop = TRUE;
+			DBGLOG(P2P, WARN, "the client is not on accept ACL and kick out it.\n");
+		} else if ((Matched == TRUE) && (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_DENY)) {
+			drop = TRUE;
+			DBGLOG(P2P, WARN, "the client is on deny ACL and kick out it.\n");
+		} else {
+			DBGLOG(P2P, TRACE, "the client is authorized.\n");
+			continue;
+		}
+
+		if (drop == TRUE) {
+			DBGLOG(P2P, TRACE, "ucBssIdx=%d, ACL Policy=%d\n", ucBssIdx, prP2pBssInfo->rACL.ePolicy);
+
+			i4Ret = assocSendDisAssocFrame(prAdapter, prCurrStaRec, STATUS_CODE_REQ_DECLINED);
+			if (!i4Ret)
+				DBGLOG(P2P, WARN, "Send DISASSOC to [" MACSTR "], Reason = %d\n",
+					MAC2STR(prCurrStaRec->aucMacAddr), STATUS_CODE_REQ_DECLINED);
+			LINK_REMOVE_KNOWN_ENTRY(prClientList, &prCurrStaRec->rLinkEntry);
+		}
+	}
+} /* p2pRoleUpdateACLEntry */
+
+/*----------------------------------------------------------------------------*/
+/*!
+* @ Check if the specified STA pass the Access Control List inspection.
+*	If fails to pass the checking, then no authentication or association is allowed.
+*
+* @param[in] prAdapter          Pointer to the Adapter structure.
+* @param[in] pMacAddr           Pointer to the mac address.
+* @param[in] ucBssIdx            Bss index.
+*
+* @return TRUE - pass ACL inspection, FALSE - ACL inspection fail
+*/
+/*----------------------------------------------------------------------------*/
+BOOL p2pRoleProcessACLInspection(IN P_ADAPTER_T prAdapter, IN PUCHAR pMacAddr, IN UINT_8 ucBssIdx)
+{
+	BOOLEAN bPassACL = TRUE;
+	INT_32 i = 0;
+	P_BSS_INFO_T prP2pBssInfo;
+
+	if ((!prAdapter) || (!pMacAddr) || (ucBssIdx > HW_BSSID_NUM))
+		return FALSE;
+
+	prP2pBssInfo = prAdapter->aprBssInfo[ucBssIdx];
+
+	if (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_DISABLE)
+		return TRUE;
+
+	if (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_ACCEPT)
+		bPassACL = FALSE;
+	else
+		bPassACL = TRUE;
+
+	for (i = 0; i < prP2pBssInfo->rACL.u4Num; i++) {
+		if (EQUAL_MAC_ADDR(pMacAddr, prP2pBssInfo->rACL.rEntry[i].aucAddr)) {
+			bPassACL = !bPassACL;
+			break;
+		}
+	}
+
+	if (bPassACL == FALSE)
+		DBGLOG(P2P, WARN, "this mac [" MACSTR "] is fail to pass ACL inspection.\n", MAC2STR(pMacAddr));
+
+	return bPassACL;
+} /* p2pRoleProcessACLInspection */
+
+/*----------------------------------------------------------------------------*/
+/*!
 * @brief This function will indicate the Event of Successful Completion of AAA Module.
 *
 * @param[in] prAdapter          Pointer to the Adapter structure.
@@ -1806,6 +1920,7 @@
 		bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec);
 
 		if (prP2pBssInfo->rStaRecOfClientList.u4NumElem >= P2P_MAXIMUM_CLIENT_COUNT
+			|| !p2pRoleProcessACLInspection(prAdapter, prStaRec->aucMacAddr, prP2pBssInfo->ucBssIndex)
 #if CFG_SUPPORT_HOTSPOT_WPS_MANAGER
 			|| kalP2PMaxClients(prAdapter->prGlueInfo, prP2pBssInfo->rStaRecOfClientList.u4NumElem,
 			(UINT_8) prP2pBssInfo->u4PrivateData)
diff --git a/os/linux/gl_wext_priv.c b/os/linux/gl_wext_priv.c
index 64f1a13..96bae3c 100644
--- a/os/linux/gl_wext_priv.c
+++ b/os/linux/gl_wext_priv.c
@@ -2291,6 +2291,11 @@
 #define CMD_GET_STA_STAT        "STAT"
 #define CMD_GET_STA_STAT2       "STAT2"
 #define CMD_GET_STA_RX_STAT		"RX_STAT"
+#define CMD_SET_ACL_POLICY      "SET_ACL_POLICY"
+#define CMD_ADD_ACL_ENTRY       "ADD_ACL_ENTRY"
+#define CMD_DEL_ACL_ENTRY       "DEL_ACL_ENTRY"
+#define CMD_SHOW_ACL_ENTRY      "SHOW_ACL_ENTRY"
+#define CMD_CLEAR_ACL_ENTRY     "CLEAR_ACL_ENTRY"
 
 #if CFG_WOW_SUPPORT
 #define CMD_WOW_START			"WOW_START"
@@ -5145,6 +5150,368 @@
 	return i4BytesWritten;
 }
 
+/*----------------------------------------------------------------------------*/
+/*
+* @ The function will set policy of ACL.
+*  0: disable ACL
+*  1: enable accept list
+*  2: enable deny list
+* example: iwpriv p2p0 driver "set_acl_policy 1"
+*/
+/*----------------------------------------------------------------------------*/
+static int priv_driver_set_acl_policy(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
+{
+	P_GLUE_INFO_T prGlueInfo = NULL;
+	P_ADAPTER_T prAdapter = NULL;
+	P_BSS_INFO_T prBssInfo = NULL;
+	PCHAR apcArgv[WLAN_CFG_ARGV_MAX];
+	INT_32 i4Argc = 0, i4BytesWritten = 0, i4Ret = 0, i4Policy = 0;
+	UINT_8 ucRoleIdx = 0, ucBssIdx = 0;
+
+	ASSERT(prNetDev);
+	if (GLUE_CHK_PR2(prNetDev, pcCommand) == FALSE)
+		return -1;
+	prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+	prAdapter = prGlueInfo->prAdapter;
+
+	/* get Bss Index from ndev */
+	if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0)
+		return -1;
+	if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) !=
+		WLAN_STATUS_SUCCESS)
+		return -1;
+
+	prBssInfo = prAdapter->aprBssInfo[ucBssIdx];
+
+	DBGLOG(REQ, LOUD, "ucRoleIdx %hhu ucBssIdx %hhu\n", ucRoleIdx, ucBssIdx);
+	DBGLOG(REQ, LOUD, "command is %s\n", pcCommand);
+	wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv);
+	DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc);
+
+	if (i4Argc < 2)
+		return -1;
+
+	i4Ret = kalkStrtou32(apcArgv[1], 0, &i4Policy);
+	if (i4Ret) {
+		DBGLOG(REQ, ERROR, "integer format error i4Ret=%d\n", i4Ret);
+		return -1;
+	}
+
+	switch (i4Policy) {
+	case PARAM_CUSTOM_ACL_POLICY_DISABLE:
+	case PARAM_CUSTOM_ACL_POLICY_ACCEPT:
+	case PARAM_CUSTOM_ACL_POLICY_DENY:
+		prBssInfo->rACL.ePolicy = i4Policy;
+		break;
+	default: /*Invalid argument */
+		DBGLOG(REQ, ERROR, "Invalid ACL Policy=%d\n", i4Policy);
+		return -1;
+	}
+
+	DBGLOG(REQ, TRACE, "ucBssIdx[%hhu] ACL Policy=%d\n", ucBssIdx, prBssInfo->rACL.ePolicy);
+
+	i4BytesWritten += kalSnprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+		"ucBssIdx[%hhu] ACL Policy=%d\n", ucBssIdx, prBssInfo->rACL.ePolicy);
+
+	/* check if the change in ACL affects any existent association */
+	p2pRoleUpdateACLEntry(prAdapter, ucBssIdx);
+
+	DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand);
+
+	return i4BytesWritten;
+} /* priv_driver_set_acl_policy */
+
+static INT_32 priv_driver_inspect_mac_addr(IN char *pcMacAddr)
+{
+	INT_32 i = 0;
+
+	if (pcMacAddr == NULL)
+		return -1;
+
+	for (i = 0; i < 17; i++) {
+		if ((i % 3 != 2) && (!kalIsXdigit(pcMacAddr[i]))) {
+			DBGLOG(REQ, ERROR, "[%c] is not hex digit\n", pcMacAddr[i]);
+			return -1;
+		}
+		if ((i % 3 == 2) && (pcMacAddr[i] != ':')) {
+			DBGLOG(REQ, ERROR, "[%c]separate symbol is error\n", pcMacAddr[i]);
+			return -1;
+		}
+	}
+
+	if (pcMacAddr[17] != '\0') {
+		DBGLOG(REQ, ERROR, "no null-terminated character\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+* @ The function will add entry to ACL for accept or deny list.
+*  example: iwpriv p2p0 driver "add_acl_entry 01:02:03:04:05:06"
+*/
+/*----------------------------------------------------------------------------*/
+static int priv_driver_add_acl_entry(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
+{
+	P_GLUE_INFO_T prGlueInfo = NULL;
+	P_ADAPTER_T prAdapter = NULL;
+	P_BSS_INFO_T prBssInfo = NULL;
+	PCHAR apcArgv[WLAN_CFG_ARGV_MAX];
+	UINT_8 aucMacAddr[MAC_ADDR_LEN] = {0};
+	INT_32 i = 0, i4Argc = 0, i4BytesWritten = 0, i4Ret = 0;
+	UINT_8 ucRoleIdx = 0, ucBssIdx = 0;
+
+	ASSERT(prNetDev);
+	if (GLUE_CHK_PR2(prNetDev, pcCommand) == FALSE)
+		return -1;
+	prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+	prAdapter = prGlueInfo->prAdapter;
+
+	/* get Bss Index from ndev */
+	if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0)
+		return -1;
+	if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) !=
+		WLAN_STATUS_SUCCESS)
+		return -1;
+
+	prBssInfo = prAdapter->aprBssInfo[ucBssIdx];
+
+	DBGLOG(REQ, LOUD, "ucRoleIdx %hhu ucBssIdx %hhu\n", ucRoleIdx, ucBssIdx);
+	DBGLOG(REQ, LOUD, "command is %s\n", pcCommand);
+	wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv);
+	DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc);
+
+	if (i4Argc < 2)
+		return -1;
+
+	i4Ret = priv_driver_inspect_mac_addr(apcArgv[1]);
+	if (i4Ret) {
+		DBGLOG(REQ, ERROR, "inspect mac format error u4Ret=%d\n", i4Ret);
+		return -1;
+	}
+
+	i4Ret = sscanf(apcArgv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+		&aucMacAddr[0], &aucMacAddr[1], &aucMacAddr[2],
+		&aucMacAddr[3], &aucMacAddr[4], &aucMacAddr[5]);
+
+	if (i4Ret != MAC_ADDR_LEN) {
+		DBGLOG(REQ, ERROR, "sscanf mac format fail u4Ret=%d\n", i4Ret);
+		return -1;
+	}
+
+	for (i = 0; i <= prBssInfo->rACL.u4Num; i++) {
+		if (memcmp(prBssInfo->rACL.rEntry[i].aucAddr, &aucMacAddr, MAC_ADDR_LEN) == 0) {
+			DBGLOG(REQ, ERROR, "add this mac [" MACSTR "] is duplicate.\n", MAC2STR(aucMacAddr));
+			return -1;
+		}
+	}
+
+	if ((i < 1) || (i > MAX_NUMBER_OF_ACL)) {
+		DBGLOG(REQ, ERROR, "idx[%d] error or ACL is full.\n", i);
+		return -1;
+	}
+
+	memcpy(prBssInfo->rACL.rEntry[i-1].aucAddr, &aucMacAddr, MAC_ADDR_LEN);
+	prBssInfo->rACL.u4Num = i;
+	DBGLOG(REQ, TRACE, "add mac addr [" MACSTR "] to ACL(%d).\n",
+		MAC2STR(prBssInfo->rACL.rEntry[i-1].aucAddr), i);
+
+	i4BytesWritten += kalSnprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+		"add mac addr [" MACSTR "] to ACL(%d)\n", MAC2STR(prBssInfo->rACL.rEntry[i-1].aucAddr), i);
+
+	/* Check if the change in ACL affects any existent association. */
+	p2pRoleUpdateACLEntry(prAdapter, ucBssIdx);
+
+	DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand);
+
+	return i4BytesWritten;
+} /* priv_driver_add_acl_entry */
+
+/*----------------------------------------------------------------------------*/
+/*
+* @ The function will delete entry to ACL for accept or deny list.
+*  example: iwpriv p2p0 driver "add_del_entry 01:02:03:04:05:06"
+*/
+/*----------------------------------------------------------------------------*/
+static int priv_driver_del_acl_entry(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
+{
+	P_GLUE_INFO_T prGlueInfo = NULL;
+	P_ADAPTER_T prAdapter = NULL;
+	P_BSS_INFO_T prBssInfo = NULL;
+	PCHAR apcArgv[WLAN_CFG_ARGV_MAX];
+	UINT_8 aucMacAddr[MAC_ADDR_LEN] = {0};
+	INT_32 i = 0, j = 0, i4Argc = 0, i4BytesWritten = 0, i4Ret = 0;
+	UINT_8 ucRoleIdx = 0, ucBssIdx = 0;
+
+	ASSERT(prNetDev);
+	if (GLUE_CHK_PR2(prNetDev, pcCommand) == FALSE)
+		return -1;
+	prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+	prAdapter = prGlueInfo->prAdapter;
+
+	/* get Bss Index from ndev */
+	if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0)
+		return -1;
+	if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) !=
+		WLAN_STATUS_SUCCESS)
+		return -1;
+
+	prBssInfo = prAdapter->aprBssInfo[ucBssIdx];
+
+	DBGLOG(REQ, LOUD, "ucRoleIdx %hhu ucBssIdx %hhu\n", ucRoleIdx, ucBssIdx);
+	DBGLOG(REQ, LOUD, "command is %s\n", pcCommand);
+	wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv);
+	DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc);
+
+	if (i4Argc < 2)
+		return -1;
+
+	i4Ret = priv_driver_inspect_mac_addr(apcArgv[1]);
+	if (i4Ret) {
+		DBGLOG(REQ, ERROR, "inspect mac format error u4Ret=%d\n", i4Ret);
+		return -1;
+	}
+
+	i4Ret = sscanf(apcArgv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+		&aucMacAddr[0], &aucMacAddr[1], &aucMacAddr[2],
+		&aucMacAddr[3], &aucMacAddr[4], &aucMacAddr[5]);
+
+	if (i4Ret != MAC_ADDR_LEN) {
+		DBGLOG(REQ, ERROR, "sscanf mac format fail u4Ret=%d\n", i4Ret);
+		return -1;
+	}
+
+	for (i = 0; i < prBssInfo->rACL.u4Num; i++) {
+		if (memcmp(prBssInfo->rACL.rEntry[i].aucAddr, &aucMacAddr, MAC_ADDR_LEN) == 0) {
+			memset(&prBssInfo->rACL.rEntry[i], 0x00, sizeof(PARAM_CUSTOM_ACL_ENTRY));
+			DBGLOG(REQ, TRACE, "delete this mac [" MACSTR "]\n", MAC2STR(aucMacAddr));
+
+			i4BytesWritten += kalSnprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+				"delete this mac [" MACSTR "] from ACL(%d)\n", MAC2STR(aucMacAddr), i+1);
+			break;
+		}
+	}
+
+	if ((prBssInfo->rACL.u4Num == 0) || (i == MAX_NUMBER_OF_ACL)) {
+		DBGLOG(REQ, ERROR, "delete entry fail, num of entries=%d\n", i);
+		return -1;
+	}
+
+	for (j = i+1; j < prBssInfo->rACL.u4Num; j++)
+		memcpy(prBssInfo->rACL.rEntry[j-1].aucAddr, prBssInfo->rACL.rEntry[j].aucAddr, MAC_ADDR_LEN);
+
+	prBssInfo->rACL.u4Num = j-1;
+	memset(prBssInfo->rACL.rEntry[j-1].aucAddr, 0x00, MAC_ADDR_LEN);
+
+	/* check if the change in ACL affects any existent association */
+	p2pRoleUpdateACLEntry(prAdapter, ucBssIdx);
+
+	DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand);
+
+	return i4BytesWritten;
+} /* priv_driver_del_acl_entry */
+
+/*----------------------------------------------------------------------------*/
+/*
+* @ The function will show all entries to ACL for accept or deny list.
+*  example: iwpriv p2p0 driver "show_acl_entry"
+*/
+/*----------------------------------------------------------------------------*/
+static int priv_driver_show_acl_entry(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
+{
+	P_GLUE_INFO_T prGlueInfo = NULL;
+	P_ADAPTER_T prAdapter = NULL;
+	P_BSS_INFO_T prBssInfo = NULL;
+	PCHAR apcArgv[WLAN_CFG_ARGV_MAX];
+	INT_32 i = 0, i4Argc = 0, i4BytesWritten = 0;
+	UINT_8 ucRoleIdx = 0, ucBssIdx = 0;
+
+	ASSERT(prNetDev);
+	if (GLUE_CHK_PR2(prNetDev, pcCommand) == FALSE)
+		return -1;
+	prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+	prAdapter = prGlueInfo->prAdapter;
+
+	/* get Bss Index from ndev */
+	if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0)
+		return -1;
+	if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) !=
+		WLAN_STATUS_SUCCESS)
+		return -1;
+
+	prBssInfo = prAdapter->aprBssInfo[ucBssIdx];
+
+	DBGLOG(REQ, LOUD, "command is %s\n", pcCommand);
+	wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv);
+	DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc);
+	DBGLOG(REQ, TRACE, "ACL Policy = %d\n", prBssInfo->rACL.ePolicy);
+	DBGLOG(REQ, TRACE, "Total ACLs = %d\n", prBssInfo->rACL.u4Num);
+
+	i4BytesWritten += kalSnprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+		"ACL Policy = %d, Total ACLs = %d\n", prBssInfo->rACL.ePolicy, prBssInfo->rACL.u4Num);
+
+	for (i = 0; i < prBssInfo->rACL.u4Num; i++) {
+		DBGLOG(REQ, TRACE, "ACL(%d): [" MACSTR "]\n", i+1, MAC2STR(prBssInfo->rACL.rEntry[i].aucAddr));
+
+		i4BytesWritten += kalSnprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+			"ACL(%d): [" MACSTR "]\n", i+1, MAC2STR(prBssInfo->rACL.rEntry[i].aucAddr));
+	}
+
+	return i4BytesWritten;
+} /* priv_driver_show_acl_entry */
+
+/*----------------------------------------------------------------------------*/
+/*
+* @ The function will clear all entries to ACL for accept or deny list.
+*  example: iwpriv p2p0 driver "clear_acl_entry"
+*/
+/*----------------------------------------------------------------------------*/
+static int priv_driver_clear_acl_entry(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
+{
+	P_GLUE_INFO_T prGlueInfo = NULL;
+	P_ADAPTER_T prAdapter = NULL;
+	P_BSS_INFO_T prBssInfo = NULL;
+	PCHAR apcArgv[WLAN_CFG_ARGV_MAX];
+	INT_32 i4Argc = 0, i4BytesWritten = 0;
+	UINT_8 ucRoleIdx = 0, ucBssIdx = 0;
+
+	ASSERT(prNetDev);
+	if (GLUE_CHK_PR2(prNetDev, pcCommand) == FALSE)
+		return -1;
+	prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+	prAdapter = prGlueInfo->prAdapter;
+
+	/* get Bss Index from ndev */
+	if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0)
+		return -1;
+	if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) !=
+		WLAN_STATUS_SUCCESS)
+		return -1;
+
+	prBssInfo = prAdapter->aprBssInfo[ucBssIdx];
+
+	DBGLOG(REQ, LOUD, "command is %s\n", pcCommand);
+	wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv);
+	DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc);
+
+	if (prBssInfo->rACL.u4Num) {
+		memset(&prBssInfo->rACL.rEntry[0], 0x00, sizeof(PARAM_CUSTOM_ACL_ENTRY)*MAC_ADDR_LEN);
+		prBssInfo->rACL.u4Num = 0;
+	}
+
+	DBGLOG(REQ, TRACE, "ACL Policy = %d\n", prBssInfo->rACL.ePolicy);
+	DBGLOG(REQ, TRACE, "Total ACLs = %d\n", prBssInfo->rACL.u4Num);
+
+	i4BytesWritten += kalSnprintf(pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten,
+		"ACL Policy = %d, Total ACLs = %d\n", prBssInfo->rACL.ePolicy, prBssInfo->rACL.u4Num);
+
+	/* check if the change in ACL affects any existent association */
+	p2pRoleUpdateACLEntry(prAdapter, ucBssIdx);
+
+	return i4BytesWritten;
+} /* priv_driver_clear_acl_entry */
 
 static int priv_driver_get_drv_mcr(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
 {
@@ -7557,6 +7924,16 @@
 			i4BytesWritten = priv_driver_get_sta_stat(prNetDev, pcCommand, i4TotalLen);
 		} else if (strnicmp(pcCommand, CMD_GET_STA_RX_STAT, strlen(CMD_GET_STA_RX_STAT)) == 0) {
 			i4BytesWritten = priv_driver_show_rx_stat(prNetDev, pcCommand, i4TotalLen);
+		} else if (strnicmp(pcCommand, CMD_SET_ACL_POLICY, strlen(CMD_SET_ACL_POLICY)) == 0) {
+			i4BytesWritten = priv_driver_set_acl_policy(prNetDev, pcCommand, i4TotalLen);
+		} else if (strnicmp(pcCommand, CMD_ADD_ACL_ENTRY, strlen(CMD_ADD_ACL_ENTRY)) == 0) {
+			i4BytesWritten = priv_driver_add_acl_entry(prNetDev, pcCommand, i4TotalLen);
+		} else if (strnicmp(pcCommand, CMD_DEL_ACL_ENTRY, strlen(CMD_DEL_ACL_ENTRY)) == 0) {
+			i4BytesWritten = priv_driver_del_acl_entry(prNetDev, pcCommand, i4TotalLen);
+		} else if (strnicmp(pcCommand, CMD_SHOW_ACL_ENTRY, strlen(CMD_SHOW_ACL_ENTRY)) == 0) {
+			i4BytesWritten = priv_driver_show_acl_entry(prNetDev, pcCommand, i4TotalLen);
+		} else if (strnicmp(pcCommand, CMD_CLEAR_ACL_ENTRY, strlen(CMD_CLEAR_ACL_ENTRY)) == 0) {
+			i4BytesWritten = priv_driver_clear_acl_entry(prNetDev, pcCommand, i4TotalLen);
 		}
 #if CFG_SUPPORT_CAL_RESULT_BACKUP_TO_HOST
 		else if (strnicmp(pcCommand,
diff --git a/os/linux/include/gl_kal.h b/os/linux/include/gl_kal.h
index 00d4d97..78701b2 100644
--- a/os/linux/include/gl_kal.h
+++ b/os/linux/include/gl_kal.h
@@ -603,10 +603,11 @@
 #define kalSnprintf(buf, size, fmt, ...)            snprintf(buf, size, fmt, ##__VA_ARGS__)
 #define kalSprintf(buf, fmt, ...)                   sprintf(buf, fmt, __VA_ARGS__)
 /* remove for AOSP */
-/* #define kalSScanf(buf, fmt, ...)                      sscanf(buf, fmt, __VA_ARGS__) */
+/* #define kalSScanf(buf, fmt, ...)                    sscanf(buf, fmt, __VA_ARGS__) */
 #define kalStrStr(ct, cs)                           strstr(ct, cs)
 #define kalStrSep(s, ct)                            strsep(s, ct)
 #define kalStrCat(dest, src)                        strcat(dest, src)
+#define kalIsXdigit(c)                              isxdigit(c)
 
 /* defined for wince sdio driver only */
 #if defined(_HIF_SDIO)
diff --git a/os/linux/include/gl_os.h b/os/linux/include/gl_os.h
index f91e630..5b95752 100644
--- a/os/linux/include/gl_os.h
+++ b/os/linux/include/gl_os.h
@@ -151,6 +151,8 @@
 #include <linux/cdev.h>		/* for cdev interface */
 
 #include <linux/firmware.h>	/* for firmware download */
+#include <linux/ctype.h>
+
 
 #if defined(_HIF_USB)
 #include <linux/usb.h>