/
pvvx
/
TLB2Z
Обзор
Документация
Войти
/
pvvx
/
TLB2Z
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/SDK/stack/zigbee/gp/gp_proxy.c
932 строки
29 KB
Victor
add SDK, new cfg tb03f, add zg-807z
19 фев 2026, 08:55
19 фев 2026, 08:55
627d0d5
Код
Авторство
О чём код?
/******************************************************************************************************** * @file gp_proxy.c * * @brief This is the source file for gp_proxy * * @author Zigbee Group * @date 2021 * * @par Copyright (c) 2021, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK") * All rights reserved. * * 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. * *******************************************************************************************************/ /********************************************************************** * INCLUDES */ #include "../common/includes/zb_common.h" #include "../zcl/zcl_include.h" #include "gp_base.h" #include "gp.h" #include "gp_proxy.h" #if GP_SUPPORT_ENABLE /********************************************************************** * GLOBAL VARIABLES */ gpp_ctx_t g_gppCtx = { .aliasConflictTimeoutEvt = NULL, .commissioningWindowTimeoutEvt = NULL, .gpAliasConflictAddr = NWK_BROADCAST_RESERVED, .gpCommissionerAddr = NWK_BROADCAST_RESERVED, .gpCommissioningWindow = GPP_COMMISSIONING_WINDOW_DEFAULT, .gpCommissioningModeOpt.opts = 0, .gppInCommMode = FALSE, .firstToForward = FALSE, }; /********************************************************************** * FUNCTIONS */ void gp_proxyInit(void) { gpProxyTabInit(); COPY_U24TOBUFFER(zclGpAttr_gppFunc, GPP_FUNCTIONALITY); COPY_U24TOBUFFER(zclGpAttr_gppActiveFunc, GPP_ACTIVE_FUNCTIONALITY); } gpSecRsp_status_t gpProxySecOperation(u8 appId, gpdId_t gpdId, u8 endpoint, u32 gpdSecFrameCnt, u8 gpdfSecurityLevel, u8 gpdfKeyType, u8 *pKeyType, u8 *pKey) { u8 secChkFail = FALSE; u8 epChkFail = FALSE; gpSecRsp_status_t status = GP_SEC_RSP_ERROR; //A.3.7.3.3 gpProxyTabEntry_t *pGpProxyTabEntry = gp_getProxyTabByGpdId(appId, gpdId); //printf("gpProxySecOperation: proxyEntry = %x\n", pGpProxyTabEntry); if(pGpProxyTabEntry){ if(pGpProxyTabEntry->options.bits.entryActive){ if(pGpProxyTabEntry->options.bits.secUse){ //check security level and frame counter. if((gpdfSecurityLevel != pGpProxyTabEntry->secOptions.bits.secLevel) || (gpdSecFrameCnt <= pGpProxyTabEntry->gpdSecFrameCnt)){ secChkFail = TRUE; } //check security key type mapping. else if(gpSecKeyTypeMappingChk(pGpProxyTabEntry->secOptions.bits.secKeyType, gpdfKeyType)){ secChkFail = TRUE; } }else if(gpdfSecurityLevel != GP_SEC_LEVEL_NO_SECURITY){ secChkFail = TRUE; } if(secChkFail == TRUE){ if(g_gppCtx.gppInCommMode == FALSE){ return GP_SEC_RSP_STATUS_DROP_FRAME; }else{ if(gpdfSecurityLevel == GP_SEC_LEVEL_NO_SECURITY){ return GP_SEC_RSP_STATUS_MATCH; }else{ return GP_SEC_RSP_STATUS_PASS_UNPROCESSED; } } }else{//security check success if(appId == GP_APP_ID_GPD){ if((endpoint != pGpProxyTabEntry->endpoint) && (endpoint != 0) && (endpoint != 0xFF)){ epChkFail = TRUE; } } if(epChkFail){ status = GP_SEC_RSP_STATUS_TX_THEN_DROP; }else{ status = GP_SEC_RSP_STATUS_MATCH; } if(gpdfSecurityLevel == GP_SEC_LEVEL_NO_SECURITY){ return status; } //key recovery return gpKeyRecovery(gpdfKeyType, pGpProxyTabEntry->secOptions.bits.secKeyType, pGpProxyTabEntry->gpdKey, status, pKeyType, pKey); } }else{ if(g_gppCtx.gppInCommMode == FALSE){ //TODO: update the SearchCounter return GP_SEC_RSP_STATUS_DROP_FRAME; } } } //inactive or no entry if(gpdfKeyType == 0){//shared key //if GPDF is encrypted and there is no shared key, then pass unprocessed. if((gpdfSecurityLevel != GP_SEC_LEVEL_NO_SECURITY) && ZB_SEC_KEY_IS_NULL(zclGpAttr_gpSharedSecKey)){ return GP_SEC_RSP_STATUS_PASS_UNPROCESSED; } memcpy(pKey, zclGpAttr_gpSharedSecKey, SEC_KEY_LEN); *pKeyType = (gpdfSecurityLevel == GP_SEC_LEVEL_NO_SECURITY) ? GP_SEC_KEY_TYPE_NO_KEY : zclGpAttr_gpSharedSecKeyType; return GP_SEC_RSP_STATUS_MATCH; }else{//individual key *pKeyType = GP_SEC_KEY_TYPE_OUT_OF_THE_BOX_GPD_KEY;//TODO: not sure return GP_SEC_RSP_STATUS_PASS_UNPROCESSED; } } static void gpExitCommissioningMode(void) { g_gppCtx.gpCommissioningModeOpt.opts = 0; g_gppCtx.gppInCommMode = FALSE; g_gppCtx.gpCommissionerAddr = NWK_BROADCAST_RESERVED; g_gppCtx.gpCommissioningWindow = GPP_COMMISSIONING_WINDOW_DEFAULT; //A.3.2.8, release gpTxQueue gpTxQueueFree(); } static void gpCommissioningWindowTimeoutStop(void) { //printf("windowTimeoutStop\n"); if(g_gppCtx.commissioningWindowTimeoutEvt){ TL_ZB_TIMER_CANCEL(&g_gppCtx.commissioningWindowTimeoutEvt); } } static s32 gpCommissioningWindowTimeoutCb(void *arg) { //printf("gpCommWindowTimeoutCb\n"); gpExitCommissioningMode(); //notify up layer the current commissioning mode if(gpAppCb && gpAppCb->gpCommissioningModeCb){ gpAppCb->gpCommissioningModeCb(g_gppCtx.gppInCommMode); } g_gppCtx.commissioningWindowTimeoutEvt = NULL; return -1; } static status_t gp_proxyTabEntryUpdate(gpProxyTabEntry_t *pEntry, zcl_gp_pairingCmd_t *pCmd) { if(pCmd->options.bits.addSink){ if(pCmd->options.bits.commMode == GPS_COMM_MODE_LIGHTWEIGHT_UNICAST){ if(lwSinkAddrListAdd(pEntry, pCmd->sinkIeeeAddr, pCmd->sinkNwkAddr) == FAILURE){ return ZCL_STA_INSUFFICIENT_SPACE; } }else if(pCmd->options.bits.commMode == GPS_COMM_MODE_GROUP_PRE_COMMISSIONED_GROUPID){ u16 alias = pCmd->options.bits.assignedAliasPresent ? pCmd->assignedAlias : 0xffff; if(sinkGroupListAdd(pEntry, pCmd->sinkGroupID, alias) == FAILURE){ return ZCL_STA_INSUFFICIENT_SPACE; } }else if(pCmd->options.bits.commMode == GPS_COMM_MODE_GROUP_DGROUPID){ pEntry->options.bits.assignedAlias = pCmd->options.bits.assignedAliasPresent; pEntry->gpdAssignedAlias = pCmd->assignedAlias; } if(!pEntry->used){ pEntry->used = 1; g_gpProxyTab.gpProxyTabNum++; } pEntry->options.bits.appId = pCmd->options.bits.appId; pEntry->options.bits.entryActive = TRUE; pEntry->options.bits.entryValid = TRUE; pEntry->options.bits.seqNumCap |= pCmd->options.bits.gpdMacSeqNumCap; pEntry->options.bits.lightWeightUnicastGPS |= (pCmd->options.bits.commMode == GPS_COMM_MODE_LIGHTWEIGHT_UNICAST) ? TRUE : FALSE; pEntry->options.bits.derivedGroupGPS |= (pCmd->options.bits.commMode == GPS_COMM_MODE_GROUP_DGROUPID) ? TRUE : FALSE; pEntry->options.bits.commGroupGPS |= (pCmd->options.bits.commMode == GPS_COMM_MODE_GROUP_PRE_COMMISSIONED_GROUPID) ? TRUE : FALSE; pEntry->options.bits.firstToForward = FALSE; pEntry->options.bits.inRange = FALSE; pEntry->options.bits.gpdFixed |= pCmd->options.bits.gpdFixed ? TRUE : FALSE; pEntry->options.bits.hasAllUnicastRoutes |= (pCmd->options.bits.commMode == GPS_COMM_MODE_FULL_UNICAST) ? TRUE : FALSE; //pEntry->options.bits.assignedAlias = pCmd->options.bits.assignedAliasPresent; pEntry->options.bits.secUse = (pCmd->options.bits.secLevel > 1) ? TRUE : FALSE; pEntry->options.bits.optsExtension = FALSE; if(pEntry->options.bits.appId == GP_APP_ID_SRC_ID){ pEntry->gpdId.srcId = pCmd->gpdId.srcId; }else if(pEntry->options.bits.appId == GP_APP_ID_GPD){ ZB_64BIT_ADDR_COPY(pEntry->gpdId.gpdIeeeAddr, pCmd->gpdId.gpdIeeeAddr); } pEntry->endpoint = pCmd->endpoint; //pEntry->gpdAssignedAlias = pCmd->assignedAlias; pEntry->secOptions.bits.secLevel = pCmd->options.bits.secLevel; pEntry->secOptions.bits.secKeyType = pCmd->options.bits.secKeyType; pEntry->gpdSecFrameCnt = pCmd->gpdSecFrameCnt; memcpy(pEntry->gpdKey, pCmd->gpdKey, SEC_KEY_LEN); pEntry->groupcastRadius = pCmd->options.bits.groupcastRadiusPresent ? pCmd->groupcastRadius : pEntry->groupcastRadius; pEntry->searchCnt = 0; }else{ if(pCmd->options.bits.commMode == GPS_COMM_MODE_LIGHTWEIGHT_UNICAST){ if(lwSinkAddrListRemove(pEntry, pCmd->sinkIeeeAddr, pCmd->sinkNwkAddr) == FAILURE){ return ZCL_STA_NOT_FOUND; } if(pEntry->lwSinkCnt == 0){ pEntry->options.bits.lightWeightUnicastGPS = 0; } }else if(pCmd->options.bits.commMode == GPS_COMM_MODE_GROUP_PRE_COMMISSIONED_GROUPID){ if(sinkGroupListRemove(pEntry, pCmd->sinkGroupID) == FAILURE){ return ZCL_STA_NOT_FOUND; } if(pEntry->sinkGroupCnt == 0){ pEntry->options.bits.commGroupGPS = 0; } }else if(pCmd->options.bits.commMode == GPS_COMM_MODE_GROUP_DGROUPID){ pEntry->options.bits.derivedGroupGPS = 0; } if(!pEntry->options.bits.lightWeightUnicastGPS && !pEntry->options.bits.commGroupGPS && !pEntry->options.bits.derivedGroupGPS){ gp_proxyTabEntryClear(pEntry); } } return ZCL_STA_SUCCESS; } static status_t gp_pairingUpdateProxyTab(zcl_gp_pairingCmd_t *pCmd) { gpProxyTabEntry_t *pEntry = gp_getProxyTabByGpdId(pCmd->options.bits.appId, pCmd->gpdId); if(pCmd->options.bits.removeGPD){ if(pEntry){ gp_proxyTabEntryClear(pEntry); return ZCL_STA_SUCCESS; } return ZCL_STA_NOT_FOUND; } if(pCmd->options.bits.commMode == GPS_COMM_MODE_FULL_UNICAST){ //not support return ZCL_STA_INVALID_FIELD; } if(pCmd->options.bits.secLevel == GP_SEC_LEVEL_RESERVED){ return ZCL_STA_INVALID_FIELD; } //not found the entry if(!pEntry){ if(pCmd->options.bits.addSink){ pEntry = gp_proxyTabEntryFreeGet(); if(!pEntry){ return ZCL_STA_INSUFFICIENT_SPACE; } }else{ return ZCL_STA_NOT_FOUND; } } return gp_proxyTabEntryUpdate(pEntry, pCmd); } /********************************************************************* * @fn gpPairingCmdProcess * * @brief Handler for ZCL GP Pairing command. * * @param cmd * * @return None */ static status_t gpPairingCmdProcess(zcl_gp_pairingCmd_t *pCmd) { status_t status = gp_pairingUpdateProxyTab(pCmd); //printf("gpPairingCmdRcv: sta = %x\n", status); if(status == ZCL_STA_SUCCESS){ //update the proxy table gpProxyTabUpdate(); if(g_gppCtx.gppInCommMode && (g_gppCtx.gpCommissioningModeOpt.bits.exitMode & EXIT_ON_FIRST_PAIRING_SUCCESS)){ gpCommissioningWindowTimeoutStop(); gpExitCommissioningMode(); //notify up layer the current commissioning mode if(gpAppCb && gpAppCb->gpCommissioningModeCb){ gpAppCb->gpCommissioningModeCb(g_gppCtx.gppInCommMode); } } } if( (NIB_NETWORK_ADDRESS() == gpAliasSrcAddrDerived(pCmd->options.bits.appId, pCmd->gpdId)) || ((NIB_NETWORK_ADDRESS() == pCmd->assignedAlias) && pCmd->options.bits.assignedAliasPresent) ){ tl_zbNwkAddrConflictStatusSend(NWK_BROADCAST_RX_ON_WHEN_IDLE, NIB_NETWORK_ADDRESS(), TRUE); NIB_NETWORK_ADDRESS() = g_zbMacPib.shortAddress = tl_zbNwkStochasticAddrCal(); u16 ref = 0; tl_zbNwkAddrMapAdd(g_zbMacPib.shortAddress, g_zbMacPib.extAddress, &ref); zb_info_save(NULL); zb_zdoSendDevAnnance(); } return status; } /********************************************************************* * @fn gpProxyCommissioningModeCmdProcess * * @brief Handler for ZCL GP Proxy Commissioning Mode command. * * @param cmd * * @return None */ void gpProxyCommissioningModeCmdProcess(u16 srcAddr, zcl_gp_proxyCommissioningModeCmd_t *pCmd) { if(g_gppCtx.gppInCommMode && (g_gppCtx.gpCommissionerAddr != srcAddr)){ //if we are in commissioning mode and the source address is not the device that set the //proxy in commissioning mode, drop the request. return; } //printf("gppCommMode: srcAddr = %x, action = %x\n", srcAddr, pCmd->options.bits.action); if(pCmd->options.bits.action){ g_gppCtx.gpCommissioningModeOpt = pCmd->options; g_gppCtx.gpCommissionerAddr = srcAddr; g_gppCtx.gppInCommMode = TRUE; if(pCmd->options.bits.channelPresent){ //in the current version of the GP spec, the channel present sub-field shall always be set to 0, //and the channel field shall not be present. A.3.3.5.3 } if(pCmd->options.bits.commWindowPresent){ g_gppCtx.gpCommissioningWindow = pCmd->commissioningWindow; //start the commissioning window timeout gpCommissioningWindowTimeoutStop(); if(g_gppCtx.gpCommissioningWindow){ g_gppCtx.commissioningWindowTimeoutEvt = TL_ZB_TIMER_SCHEDULE(gpCommissioningWindowTimeoutCb, NULL, g_gppCtx.gpCommissioningWindow * 1000); } } }else{ gpCommissioningWindowTimeoutStop(); gpExitCommissioningMode(); } //notify up layer the current commissioning mode if(gpAppCb && gpAppCb->gpCommissioningModeCb){ gpAppCb->gpCommissioningModeCb(g_gppCtx.gppInCommMode); } } /********************************************************************* * @fn gpResponseCmdProcess * * @brief Handler for ZCL GP Response command. * * @param cmd * * @return None */ void gpResponseCmdProcess(zcl_gp_responseCmd_t *pCmd) { //printf("GPP_gpResponseCmdCb: mode = %x\n", g_gppCtx.gppInCommMode); gp_data_req_t gpDataReq; TL_SETSTRUCTCONTENT(gpDataReq, 0); if(pCmd->tempMasterShortAddr == NIB_NETWORK_ADDRESS()){ g_gppCtx.firstToForward = TRUE;//TODO: not sure gpDataReq.action = TRUE; }else{ g_gppCtx.firstToForward = FALSE; gpDataReq.action = FALSE; } gpDataReq.txOptions.useGpTxQueue = 1; gpDataReq.txOptions.txOnMatchingEndpoint = pCmd->options.bits.transmitOnEndpointMatch; gpDataReq.appId = pCmd->options.bits.appId; memcpy((u8 *)&gpDataReq.gpdId, (u8 *)&pCmd->gpdId, sizeof(gpdId_t)); gpDataReq.endpoint = pCmd->endpoint; gpDataReq.gpdCmdId = pCmd->gpdCmdID; gpDataReq.gpdAsduLen = pCmd->payloadLen; gpDataReq.gpdAsdu = pCmd->pGpdCmdPayload; gpTranimitGPDF(&gpDataReq); if(gpDataReq.action){ if(pCmd->gpdCmdID == GPDF_CMD_ID_CHANNEL_CONFIGURATION){ gpd_channelConfigurationCmd_payload_t channel; TL_SETSTRUCTCONTENT(channel, 0); channel.channel = *(pCmd->pGpdCmdPayload); gpSwitchToTransmitChannel((u8)channel.bits.operationChannel, pCmd->tempMasterTxChannel); } } } /********************************************************************* * @fn gpProxyTabReqCmdProcess * * @brief Handler for ZCL GP Proxy Table Request command. * * @param cmd * * @return None */ static void gpProxyTabReqCmdProcess(zclIncomingAddrInfo_t *pAddrInfo, zcl_gp_proxyTabReqCmd_t *pCmd) { epInfo_t dstEpInfo; TL_SETSTRUCTCONTENT(dstEpInfo, 0); dstEpInfo.dstAddrMode = APS_SHORT_DSTADDR_WITHEP; dstEpInfo.dstAddr.shortAddr = pAddrInfo->srcAddr; dstEpInfo.dstEp = pAddrInfo->srcEp; dstEpInfo.profileId = pAddrInfo->profileId; zcl_gp_proxyTabRspCmd_t proxyTabRspCmd; TL_SETSTRUCTCONTENT(proxyTabRspCmd, 0); u8 *pBuf = NULL; proxyTabRspCmd.totalTabEntries = gp_getProxyTabEntryTotalNum(); if(proxyTabRspCmd.totalTabEntries == 0){ proxyTabRspCmd.status = ZCL_STA_NOT_FOUND; proxyTabRspCmd.startIdx = (pCmd->options.bits.reqType == REQUEST_TABLE_ENTRIES_BY_GPD_ID) ? 0xFF : pCmd->index; proxyTabRspCmd.entriesCnt = 0; proxyTabRspCmd.entriesLen = 0; zcl_gp_proxyTableRspCmdSend(GREEN_POWER_ENDPOINT, &dstEpInfo, TRUE, pAddrInfo->seqNum, &proxyTabRspCmd); return; } if(pCmd->options.bits.reqType == REQUEST_TABLE_ENTRIES_BY_GPD_ID){ gpProxyTabEntry_t *pEntry = gp_getProxyTabByGpdId(pCmd->options.bits.appId, pCmd->gpdId); if(pEntry){ u8 len = gp_getProxyTabEntryLen(pEntry); pBuf = (u8 *)ev_buf_allocate(len); if(!pBuf){ return; } memset(pBuf, 0, len); gp_buildProxyTabEntryFormat(pEntry, pBuf); proxyTabRspCmd.status = ZCL_STA_SUCCESS; proxyTabRspCmd.startIdx = 0xFF; proxyTabRspCmd.entriesCnt = 1; proxyTabRspCmd.entriesLen = len; proxyTabRspCmd.proxyTabEntry = pBuf; }else{ proxyTabRspCmd.status = ZCL_STA_NOT_FOUND; proxyTabRspCmd.startIdx = 0xFF; proxyTabRspCmd.entriesCnt = 0; proxyTabRspCmd.entriesLen = 0; } }else if(pCmd->options.bits.reqType == REQUEST_TABLE_ENTRIES_BY_INDEX){ proxyTabRspCmd.status = ZCL_STA_NOT_FOUND; proxyTabRspCmd.startIdx = pCmd->index; u8 entryLen = 0; u8 maxEntryLen = 0; u8 activeEntryCnt = 0; for(u8 i = 0; i < zclGpAttr_gppMaxProxyTabEntries; i++){ maxEntryLen = entryLen; if(g_gpProxyTab.gpProxyTab[i].used){ activeEntryCnt++; if(pCmd->index <= activeEntryCnt - 1){ entryLen += gp_getProxyTabEntryLen(&g_gpProxyTab.gpProxyTab[i]); if(entryLen >= ZCL_GP_MAX_PROXY_TABLE_ATTR_LEN){ entryLen = maxEntryLen; break; }else{ proxyTabRspCmd.entriesCnt++; } } } } activeEntryCnt = 0; proxyTabRspCmd.entriesLen = entryLen; u8 entriesCnt = proxyTabRspCmd.entriesCnt; if(entryLen){ proxyTabRspCmd.status = ZCL_STA_SUCCESS; pBuf = (u8 *)ev_buf_allocate(entryLen); if(!pBuf){ return; } memset(pBuf, 0, entryLen); u8 *ptr = pBuf; for(u8 i = 0; i < zclGpAttr_gppMaxProxyTabEntries; i++){ if(g_gpProxyTab.gpProxyTab[i].used){ activeEntryCnt++; if(pCmd->index <= activeEntryCnt - 1){ if(entriesCnt){ ptr += gp_buildProxyTabEntryFormat(&g_gpProxyTab.gpProxyTab[i], ptr); entriesCnt--; }else{ break; } } } } proxyTabRspCmd.proxyTabEntry = pBuf; } } zcl_gp_proxyTableRspCmdSend(GREEN_POWER_ENDPOINT, &dstEpInfo, TRUE, pAddrInfo->seqNum, &proxyTabRspCmd); if(pBuf){ ev_buf_free(pBuf); } } status_t zcl_gpServerCmdHandler(zclIncomingAddrInfo_t *pAddrInfo, u8 cmdId, void *cmdPayload) { status_t status = ZCL_STA_SUCCESS; switch(cmdId){ case ZCL_CMD_GP_PAIRING: status = gpPairingCmdProcess((zcl_gp_pairingCmd_t *)cmdPayload); break; case ZCL_CMD_GP_PROXY_COMMISSIONING_MODE: gpProxyCommissioningModeCmdProcess(pAddrInfo->srcAddr, (zcl_gp_proxyCommissioningModeCmd_t *)cmdPayload); break; case ZCL_CMD_GP_RESPONSE: gpResponseCmdProcess((zcl_gp_responseCmd_t *)cmdPayload); break; case ZCL_CMD_GP_PROXY_TABLE_REQUEST: gpProxyTabReqCmdProcess(pAddrInfo, (zcl_gp_proxyTabReqCmd_t *)cmdPayload); break; default: status = ZCL_STA_UNSUP_CLUSTER_COMMAND; break; } return status; } static u8 gpParseDataInd(gp_data_ind_t *pGpDataInd, zcl_gp_notificationCmd_t *pCmd) { gpdId_t gpdId; TL_SETSTRUCTCONTENT(gpdId, 0); if(pGpDataInd->appId == GP_APP_ID_SRC_ID){ gpdId.srcId = pGpDataInd->srcId; }else if(pGpDataInd->appId == GP_APP_ID_GPD){ ZB_64BIT_ADDR_COPY(gpdId.gpdIeeeAddr, pGpDataInd->srcAddr.extAddr); } gpProxyTabEntry_t *pGpProxyTabEntry = gp_getProxyTabByGpdId(pGpDataInd->appId, gpdId); if(!pGpProxyTabEntry){ return FAILURE; } #if 0 if(pGpDataInd->appId == GP_APP_ID_GPD){ if((pGpDataInd->endpoint != 0) && (pGpDataInd->endpoint != 0xFF) && (pGpDataInd->endpoint != pGpProxyTabEntry->endpoint)){ return FAILURE; } } #endif if(!pGpProxyTabEntry->options.bits.inRange){ pGpProxyTabEntry->options.bits.inRange = 1; } if((pGpDataInd->status == GP_DATA_IND_STATUS_AUTH_FAILURE) || (pGpDataInd->status == GP_DATA_IND_STATUS_UNPROCESSED)){ return FAILURE; }else{ pGpProxyTabEntry->gpdSecFrameCnt = pGpDataInd->gpdfSecurityLevel ? pGpDataInd->gpdSecFrameCnt : pGpDataInd->seqNum; } #if 0 if(pGpDataInd->gpdCmdId != GPDF_CMD_ID_COMMISSIONING){ if(gpSecFreshnessChk(pGpProxyTabEntry->secOptions.bits.secKeyType, pGpProxyTabEntry->secOptions.bits.secLevel, pGpDataInd->gpdfKeyType, pGpDataInd->gpdfSecurityLevel)){ if((pGpDataInd->status == GP_DATA_IND_STATUS_AUTH_FAILURE) || (pGpDataInd->status == GP_DATA_IND_STATUS_UNPROCESSED)){ return FAILURE; } }else{ pGpProxyTabEntry->gpdSecFrameCnt = pGpDataInd->gpdfSecurityLevel ? pGpDataInd->gpdSecFrameCnt : pGpDataInd->seqNum; } } #endif if(pGpDataInd->appId == GP_APP_ID_SRC_ID){ pCmd->options.bits.appId = GP_APP_ID_SRC_ID; pCmd->gpdId.srcId = pGpDataInd->srcId; }else if(pGpDataInd->appId == GP_APP_ID_GPD){ pCmd->options.bits.appId = GP_APP_ID_GPD; ZB_64BIT_ADDR_COPY(pCmd->gpdId.gpdIeeeAddr, pGpDataInd->srcAddr.extAddr); pCmd->endpoint = pGpDataInd->endpoint; } pCmd->options.bits.alsoUnicast = pGpProxyTabEntry->options.bits.lightWeightUnicastGPS; pCmd->options.bits.alsoDerivedGroup = pGpProxyTabEntry->options.bits.derivedGroupGPS; pCmd->options.bits.alsoCommGroup = pGpProxyTabEntry->options.bits.commGroupGPS; pCmd->options.bits.secLevel = pGpProxyTabEntry->secOptions.bits.secLevel; pCmd->options.bits.secKeyType = pGpProxyTabEntry->secOptions.bits.secKeyType; pCmd->options.bits.rxAfterTx = (pGpDataInd->frameType == GP_NWK_FRAME_TYPE_DATA) ? pGpDataInd->rxAfterTx : 0; pCmd->options.bits.gpTxQueueFull = 1; pCmd->options.bits.bidirectionalCap = 0; pCmd->options.bits.proxyInfoPresent = 1; pCmd->gpdSecFrameCnt = pGpDataInd->gpdSecFrameCnt; pCmd->gpdCmdID = pGpDataInd->gpdCmdId; pCmd->payloadLen = pGpDataInd->gpdAsduLen - 1; if(pCmd->payloadLen){ pCmd->pGpdCmdPayload = &(pGpDataInd->gpdAsdu[1]); } pCmd->gppShortAddr = NWK_NIB().nwkAddr; s8 RSSI = pGpDataInd->rssi; (RSSI > 8) ? RSSI = 8 : (RSSI < -109) ? RSSI = -109 : 0; RSSI += 110; RSSI /= 2; pCmd->gppGpdLink.bits.rssi = RSSI; u8 LQI = pGpDataInd->lqi ? 2 : 0; pCmd->gppGpdLink.bits.lqi = LQI; return SUCCESS; } static void gpNotificationCmdSend(gp_data_ind_t *pGpDataInd, zcl_gp_notificationCmd_t *pCmd) { epInfo_t dstEpInfo; TL_SETSTRUCTCONTENT(dstEpInfo, 0); gpProxyTabEntry_t *pEntry = gp_getProxyTabByGpdId(pCmd->options.bits.appId, pCmd->gpdId); if(!pEntry){ return; } dstEpInfo.dstEp = GREEN_POWER_ENDPOINT; dstEpInfo.profileId = GP_PROFILE_ID; dstEpInfo.radius = (pEntry->groupcastRadius == 0xff) ? 0 : pEntry->groupcastRadius; if(pEntry->options.bits.lightWeightUnicastGPS){ dstEpInfo.dstAddrMode = APS_SHORT_DSTADDR_WITHEP; dstEpInfo.useAlias = FALSE; for(u8 i = 0; i < pEntry->lwSinkCnt; i++){ dstEpInfo.dstAddr.shortAddr = pEntry->lightweightSinkAddrList[i].sinkNwkAddr; zcl_gp_notificationCmdSend(GREEN_POWER_ENDPOINT, &dstEpInfo, TRUE, pCmd); } } if(pEntry->options.bits.derivedGroupGPS){ dstEpInfo.dstAddrMode = APS_SHORT_GROUPADDR_NOEP; dstEpInfo.dstAddr.shortAddr = gpAliasSrcAddrDerived(pEntry->options.bits.appId, pEntry->gpdId); dstEpInfo.useAlias = TRUE; dstEpInfo.aliasSrcAddr = pEntry->options.bits.assignedAlias ? pEntry->gpdAssignedAlias : gpAliasSrcAddrDerived(pEntry->options.bits.appId, pEntry->gpdId); dstEpInfo.aliasSeqNum = pGpDataInd->seqNum; zcl_gp_notificationCmdSend(GREEN_POWER_ENDPOINT, &dstEpInfo, TRUE, pCmd); } if(pEntry->options.bits.commGroupGPS){ dstEpInfo.dstAddrMode = APS_SHORT_GROUPADDR_NOEP; dstEpInfo.useAlias = TRUE; dstEpInfo.aliasSeqNum = (pGpDataInd->seqNum - 9) % 256; for(u8 i = 0; i < pEntry->sinkGroupCnt; i++){ dstEpInfo.dstAddr.shortAddr = pEntry->sinkGroupList[i].groupId; dstEpInfo.aliasSrcAddr = (pEntry->sinkGroupList[i].alias != 0xffff) ? pEntry->sinkGroupList[i].alias : gpAliasSrcAddrDerived(pEntry->options.bits.appId, pEntry->gpdId); zcl_gp_notificationCmdSend(GREEN_POWER_ENDPOINT, &dstEpInfo, TRUE, pCmd); } } } static void gppOperationalModeProcess(gp_data_ind_t *pGpDataInd) { if(pGpDataInd->status == GP_DATA_IND_STATUS_AUTH_FAILURE){ return; } //if the proxy is in operational mode, check the SrcID or GPD IEEE is 0x0, if so, drop it. if(((pGpDataInd->appId == GP_APP_ID_SRC_ID) && (pGpDataInd->srcId == 0)) || ((pGpDataInd->appId == GP_APP_ID_GPD) && (ZB_IEEE_ADDR_IS_ZERO(pGpDataInd->srcAddr.extAddr)))){ return; } if((pGpDataInd->gpdCmdId == GPDF_CMD_ID_CHANNEL_REQ) || (pGpDataInd->gpdCmdId == GPDF_CMD_ID_SUCCESS) ){ return; } zcl_gp_notificationCmd_t gpNotificationCmd; TL_SETSTRUCTCONTENT(gpNotificationCmd, 0); if(gpParseDataInd(pGpDataInd, &gpNotificationCmd) == SUCCESS){ //update the proxy table gpProxyTabUpdate(); //printf("gpNotif: cmdId = %x\n", pGpDataInd->gpdCmdId); if((gpNotificationCmd.gpdCmdID == GPDF_CMD_ID_COMMISSIONING) || (gpNotificationCmd.gpdCmdID == GPDF_CMD_ID_DECOMMISSIONING)){ gpNotificationCmd.options.bits.rxAfterTx = 0; } gpNotificationCmdSend(pGpDataInd, &gpNotificationCmd); } } static u8 gpParseManteinanceInd(gp_data_ind_t *pGpDataInd, zcl_gp_commissioningNotificationCmd_t *pCmd) { if(pGpDataInd->gpdCmdId != GPDF_CMD_ID_CHANNEL_REQ){ if(pGpDataInd->appId == GP_APP_ID_SRC_ID){ pCmd->options.bits.appId = GP_APP_ID_SRC_ID; pCmd->gpdId.srcId = pGpDataInd->srcId; }else if(pGpDataInd->appId == GP_APP_ID_GPD){ pCmd->options.bits.appId = GP_APP_ID_GPD; ZB_64BIT_ADDR_COPY(pCmd->gpdId.gpdIeeeAddr, pGpDataInd->srcAddr.extAddr); pCmd->endpoint = pGpDataInd->endpoint; } } if(pGpDataInd->gpdCmdId == GPDF_CMD_ID_CHANNEL_REQ){ pCmd->options.bits.rxAfterTx = 1; }else if(pGpDataInd->gpdCmdId == GPDF_CMD_ID_COMMISSIONING){ pCmd->options.bits.rxAfterTx = pGpDataInd->rxAfterTx; }else{ pCmd->options.bits.rxAfterTx = pGpDataInd->rxAfterTx; } pCmd->options.bits.secLevel = pGpDataInd->gpdfSecurityLevel; pCmd->options.bits.secKeyType = pGpDataInd->gpdfKeyType; if((pGpDataInd->status == GP_DATA_IND_STATUS_AUTH_FAILURE) || (pGpDataInd->status == GP_DATA_IND_STATUS_UNPROCESSED)){ pCmd->options.bits.secPrcFailed = 1; pCmd->mic = pGpDataInd->mic; }else{ pCmd->options.bits.secPrcFailed = 0; pCmd->mic = 0xFFFFFFFF; } pCmd->options.bits.bidirectionalCap = 0; pCmd->options.bits.proxyInfoPresent = 1; pCmd->gpdSecFrameCnt = pGpDataInd->gpdSecFrameCnt; pCmd->gpdCmdID = pGpDataInd->gpdCmdId; pCmd->payloadLen = pGpDataInd->gpdAsduLen - 1; if(pCmd->payloadLen){ pCmd->pGpdCmdPayload = &(pGpDataInd->gpdAsdu[1]); } pCmd->gppShortAddr = NWK_NIB().nwkAddr; s8 RSSI = pGpDataInd->rssi; (RSSI > 8) ? RSSI = 8 : (RSSI < -109) ? RSSI = -109 : 0; RSSI += 110; RSSI /= 2; pCmd->gppGpdLink.bits.rssi = RSSI; u8 LQI = pGpDataInd->lqi ? 2 : 0; pCmd->gppGpdLink.bits.lqi = LQI; return SUCCESS; } static s32 gpCommissioningNotificationCmdSend(void *arg) { gp_noti_t *buf = (gp_noti_t *)arg; zcl_gp_commissioningNotificationCmdSend(GREEN_POWER_ENDPOINT, &buf->dstEpInfo, TRUE, &buf->gpCommissioningNotificationCmd); epInfo_t *pDstEpInfo = (epInfo_t *)&buf->dstEpInfo; //TODO: need fixed if unicast. if(!aps_duplicate_check(pDstEpInfo->aliasSrcAddr, pDstEpInfo->aliasSeqNum)){ gpCommissioningNotificationCmdFromLocalCb(&buf->gpCommissioningNotificationCmd); } ev_buf_free((u8 *)buf); return -1; } static void gppCommissioningModeProcess(gp_data_ind_t *pGpDataInd) { if(pGpDataInd->gpdCmdId == GPDF_CMD_ID_CHANNEL_REQ){ if(pGpDataInd->frameType == GP_NWK_FRAME_TYPE_DATA){ return; } if(gpAppCb && gpAppCb->gpChangleChannelReqCb){ if(gpAppCb->gpChangleChannelReqCb() == FALSE){ //Not permit return; } } }else if((pGpDataInd->gpdCmdId == GPDF_CMD_ID_CHANNEL_CONFIGURATION) || (pGpDataInd->gpdCmdId == GPDF_CMD_ID_COMMISSIONING_REPLY)){ return; }else if((pGpDataInd->gpdCmdId == GPDF_CMD_ID_COMMISSIONING) || (pGpDataInd->gpdCmdId == GPDF_CMD_ID_SUCCESS)){ //case 5.4.1.10, step 5. if(pGpDataInd->autoCommissioning){ return; } } //case 5.4.1.13, step 4. if((pGpDataInd->frameType == GP_NWK_FRAME_TYPE_DATA) && (((pGpDataInd->appId == GP_APP_ID_SRC_ID) && (pGpDataInd->srcId == 0)) || ((pGpDataInd->appId == GP_APP_ID_GPD) && (ZB_IEEE_ADDR_IS_ZERO(pGpDataInd->srcAddr.extAddr))))){ return; } gp_noti_t *buf = (gp_noti_t *)ev_buf_allocate(sizeof(gp_noti_t)); if(!buf){ return; } memset((u8 *)buf, 0, sizeof(gp_noti_t)); if(gpParseManteinanceInd(pGpDataInd, &buf->gpCommissioningNotificationCmd) == SUCCESS){ //printf("gpCommNotif: cmdId = %x\n", pGpDataInd->gpdCmdId); buf->dstEpInfo.dstAddrMode = APS_SHORT_DSTADDR_WITHEP; buf->dstEpInfo.dstAddr.shortAddr = g_gppCtx.gpCommissioningModeOpt.bits.unicastCommunication ? g_gppCtx.gpCommissionerAddr : NWK_BROADCAST_RX_ON_WHEN_IDLE; buf->dstEpInfo.dstEp = GREEN_POWER_ENDPOINT; buf->dstEpInfo.profileId = GP_PROFILE_ID; if(ZB_NWK_IS_ADDRESS_BROADCAST(buf->dstEpInfo.dstAddr.shortAddr)){ buf->dstEpInfo.useAlias = TRUE; buf->dstEpInfo.aliasSrcAddr = gpAliasSrcAddrDerived(buf->gpCommissioningNotificationCmd.options.bits.appId, buf->gpCommissioningNotificationCmd.gpdId); buf->dstEpInfo.aliasSeqNum = (pGpDataInd->seqNum - 12) % 256; }else{ buf->dstEpInfo.useAlias = FALSE; } u8 gppTunnelingDelay = gppTunnelingDelayGet(buf->gpCommissioningNotificationCmd.options.bits.rxAfterTx, buf->gpCommissioningNotificationCmd.gppGpdLink.bits.lqi, g_gppCtx.firstToForward, FALSE); //printf("delay = %d\n", gppTunnelingDelay); TL_ZB_TIMER_SCHEDULE(gpCommissioningNotificationCmdSend, buf, gppTunnelingDelay); }else{ ev_buf_free((u8 *)buf); } } void gppGpDataIndProcess(gp_data_ind_t *pGpDataInd) { if(!pGpDataInd){ return; } // printf("GPP_dataInd: cmdId = %x, fc = %x, sta = %x, isCommMode = %x\n", // pGpDataInd->gpdCmdId, pGpDataInd->gpdSecFrameCnt, pGpDataInd->status, g_gppCtx.gppInCommMode); if(g_gppCtx.gppInCommMode == FALSE){ gppOperationalModeProcess(pGpDataInd); }else{ gppCommissioningModeProcess(pGpDataInd); } } #endif /* GP_SUPPORT_ENABLE */