/************************************************************************************************** * @fn afRecv * * @brief This function de-muxes an incoming AF data message. * * input parameters * * @param pBuf - Pointer to the RPC message buffer. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void afRecv(uint8 *pBuf) { #define ZAP_AF_INC_MSG_HDR 27 #define ZAP_AF_INC_DAT_MAX (MT_RPC_DATA_MAX - ZAP_AF_INC_MSG_HDR) afIncomingMSGPacket_t *pMsg; epList_t *pEP; uint16 tmp; uint8 cmd1 = pBuf[MT_RPC_POS_CMD1]; pBuf += MT_RPC_FRAME_HDR_SZ; if (cmd1 == MT_AF_INCOMING_MSG) { pEP = afFindEndPointDescList(pBuf[7]); tmp = pBuf[16]; } else { pEP = afFindEndPointDescList(pBuf[16]); tmp = BUILD_UINT16(pBuf[25], pBuf[26]); } if ((pEP == NULL) || (NULL == (pMsg = (afIncomingMSGPacket_t *)osal_msg_allocate(sizeof(afIncomingMSGPacket_t) + tmp)))) { return; } pMsg->hdr.event = AF_INCOMING_MSG_CMD; pBuf = afIncMsgPktParse(cmd1, pBuf, pMsg); #if ZAP_AF_DATA_REQ_FRAG if (pMsg->cmd.DataLength > ZAP_AF_INC_DAT_MAX) { afRetrieve(*(pEP->epDesc->task_id), pMsg); } else #endif { if (pMsg->cmd.DataLength) { (void)osal_memcpy(pMsg->cmd.Data, pBuf, pMsg->cmd.DataLength); } else { pMsg->cmd.Data = NULL; } (void)osal_msg_send(*(pEP->epDesc->task_id), (uint8 *)pMsg); } }
/********************************************************************* * @fn afRegister * * @brief Register an Application's EndPoint description. * * @param epDesc - pointer to the Application's endpoint descriptor. * * NOTE: The memory that epDesc is pointing to must exist after this call. * * @return afStatus_SUCCESS - Registered * afStatus_MEM_FAIL - not enough memory to add descriptor * afStatus_INVALID_PARAMETER - duplicate endpoint */ afStatus_t afRegister( endPointDesc_t *epDesc ) { if (afFindEndPointDescList(epDesc->endPoint)) // Look for duplicate endpoint. { return afStatus_INVALID_PARAMETER; } return ((NULL == afRegisterExtended(epDesc, NULL)) ? afStatus_MEM_FAIL : afStatus_SUCCESS); }
/********************************************************************* * @fn afFindEndPointDesc * * @brief Find the endpoint description entry from the endpoint * number. * * @param EndPoint - Application Endpoint to look for * * @return the address to the endpoint/interface description entry */ endPointDesc_t *afFindEndPointDesc( byte EndPoint ) { epList_t *epSearch; // Look for the endpoint epSearch = afFindEndPointDescList( EndPoint ); if ( epSearch ) return ( epSearch->epDesc ); else return ( (endPointDesc_t *)NULL ); }
/********************************************************************* * @fn afRegister * * @brief Register an Application's EndPoint description. * * @param epDesc - pointer to the Application's endpoint descriptor. * * NOTE: The memory that epDesc is pointing to must exist after this call. * * @return afStatus_SUCCESS - Registered * afStatus_MEM_FAIL - not enough memory to add descriptor * afStatus_INVALID_PARAMETER - duplicate endpoint */ afStatus_t afRegister( endPointDesc_t *epDesc ) { epList_t *ep; // Look for duplicate endpoint if ( afFindEndPointDescList( epDesc->endPoint ) ) return ( afStatus_INVALID_PARAMETER ); ep = afRegisterExtended( epDesc, NULL ); return ((ep == NULL) ? afStatus_MEM_FAIL : afStatus_SUCCESS); }
/************************************************************************************************** * @fn afAPSF_ConfigSet * * @brief This function attempts to set the fragmentation configuration that corresponds to * the specified EndPoint. * * input parameters * * @param endPoint - The specific EndPoint for which to set the fragmentation configuration. * @param pCfg - A pointer to an APSF configuration structure to fill with values. * * output parameters * * None. * * @return afStatus_SUCCESS for success. * afStatus_INVALID_PARAMETER if the specified EndPoint is not registered. */ afStatus_t afAPSF_ConfigSet(uint8 endPoint, afAPSF_Config_t *pCfg) { epList_t *pList = afFindEndPointDescList(endPoint); if (pList == NULL) { return afStatus_INVALID_PARAMETER; } (void)osal_memcpy(&pList->apsfCfg, pCfg, sizeof(afAPSF_Config_t)); return afStatus_SUCCESS; }
/************************************************************************************************** * @fn afAPSF_ConfigGet * * @brief This function ascertains the fragmentation configuration that corresponds to * the specified EndPoint. * * input parameters * * @param endPoint - The source EP of a Tx or destination EP of a Rx fragmented message. * * output parameters * * @param pCfg - A pointer to an APSF configuration structure to fill with values. * * @return None. */ void afAPSF_ConfigGet(uint8 endPoint, afAPSF_Config_t *pCfg) { epList_t *pList = afFindEndPointDescList(endPoint); if (pList == NULL) { pCfg->frameDelay = APSF_DEFAULT_INTERFRAME_DELAY; pCfg->windowSize = APSF_DEFAULT_WINDOW_SIZE; } else { (void)osal_memcpy(pCfg, &pList->apsfCfg, sizeof(afAPSF_Config_t)); } }
/********************************************************************* * @fn afGetMatch * * @brief Set the allow response flag. * * @param ep - Application Endpoint to look for * @param action - true - allow response, false - no response * * @return TRUE allow responses, FALSE no response */ uint8 afGetMatch( uint8 ep ) { epList_t *epSearch; // Look for the endpoint epSearch = afFindEndPointDescList( ep ); if ( epSearch ) { if ( epSearch->flags & eEP_AllowMatch ) return ( TRUE ); else return ( FALSE ); } else return ( FALSE ); }
/************************************************************************************************** * @fn afSetApplCB * * @brief Sets the pointer to the Application Callback function for a * specific EndPoint. * * input parameters * * @param endPoint - The specific EndPoint for which to set Application Callback. * @param pApplFn - A pointer to the Application Callback function. * * output parameters * * None. * * @return TRUE if success, FALSE if endpoint not found */ uint8 afSetApplCB( uint8 endPoint, pApplCB pApplFn ) { if ( pApplFn != NULL ) { epList_t *epSearch; // Look for the endpoint epSearch = afFindEndPointDescList( endPoint ); if ( epSearch ) { epSearch->pfnApplCB = pApplFn; return ( TRUE ); } } return ( FALSE ); }
/************************************************************************************************** * @fn afCnf * * @brief This function de-muxes an incoming AF data confirm message. * * input parameters * * @param pBuf - Pointer to the RPC message buffer. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void afCnf(uint8 *pBuf) { pBuf += MT_RPC_FRAME_HDR_SZ; epList_t *pEP = afFindEndPointDescList(pBuf[1]); if (NULL != pEP) { afDataConfirm_t *pMsg = (afDataConfirm_t *)osal_msg_allocate(sizeof(afDataConfirm_t)); if (NULL != pMsg) { pMsg->hdr.event = AF_DATA_CONFIRM_CMD; pMsg->hdr.status = *pBuf++; pMsg->endpoint = *pBuf++; pMsg->transID = *pBuf; osal_msg_send(*(pEP->epDesc->task_id), (uint8 *)pMsg); } } }
/********************************************************************* * @fn afSetMatch * * @brief Set the allow response flag. * * @param ep - Application Endpoint to look for * @param action - true - allow response, false - no response * * @return TRUE if success, FALSE if endpoint not found */ uint8 afSetMatch( uint8 ep, uint8 action ) { epList_t *epSearch; // Look for the endpoint epSearch = afFindEndPointDescList( ep ); if ( epSearch ) { if ( action ) { epSearch->flags |= eEP_AllowMatch; } else { epSearch->flags &= (eEP_AllowMatch ^ 0xFFFF); } return ( TRUE ); } else return ( FALSE ); }
/********************************************************************* * @fn afFindSimpleDesc * * @brief Find the Simple Descriptor from the endpoint number. * * @param EP - Application Endpoint to look for. * * @return Non-zero to indicate that the descriptor memory must be freed. */ byte afFindSimpleDesc( SimpleDescriptionFormat_t **ppDesc, byte EP ) { epList_t *epItem = afFindEndPointDescList( EP ); byte rtrn = FALSE; if ( epItem ) { if ( epItem->pfnDescCB ) { *ppDesc = epItem->pfnDescCB( AF_DESCRIPTOR_SIMPLE, EP ); rtrn = TRUE; } else { *ppDesc = epItem->epDesc->simpleDesc; } } else { *ppDesc = NULL; } return rtrn; }
/********************************************************************* * @fn afIncomingData * * @brief Transfer a data PDU (ASDU) from the APS sub-layer to the AF. * * @param aff - pointer to APS frame format * @param SrcAddress - Source address * @param sig - incoming message's link quality * @param SecurityUse - Security enable/disable * * @return none */ void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId, NLDE_Signal_t *sig, byte SecurityUse, uint32 timestamp ) { endPointDesc_t *epDesc = NULL; uint16 epProfileID = 0xFFFF; // Invalid Profile ID epList_t *pList = epList; #if !defined ( APS_NO_GROUPS ) uint8 grpEp = APS_GROUPS_EP_NOT_FOUND; #endif if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) ) { #if !defined ( APS_NO_GROUPS ) // Find the first endpoint for this group grpEp = aps_FindGroupForEndpoint( aff->GroupID, APS_GROUPS_FIND_FIRST ); if ( grpEp == APS_GROUPS_EP_NOT_FOUND ) return; // No endpoint found epDesc = afFindEndPointDesc( grpEp ); if ( epDesc == NULL ) return; // Endpoint descriptor not found pList = afFindEndPointDescList( epDesc->endPoint ); #else return; // Not supported #endif } else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT ) { // Set the list if ( pList != NULL ) { epDesc = pList->epDesc; } } else if ( (epDesc = afFindEndPointDesc( aff->DstEndPoint )) ) { pList = afFindEndPointDescList( epDesc->endPoint ); } while ( epDesc ) { if ( pList->pfnDescCB ) { uint16 *pID = (uint16 *)(pList->pfnDescCB( AF_DESCRIPTOR_PROFILE_ID, epDesc->endPoint )); if ( pID ) { epProfileID = *pID; osal_mem_free( pID ); } } else if ( epDesc->simpleDesc ) { epProfileID = epDesc->simpleDesc->AppProfId; } if ( (aff->ProfileID == epProfileID) || ((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) ) { { afBuildMSGIncoming( aff, epDesc, SrcAddress, SrcPanId, sig, SecurityUse, timestamp ); } } if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) ) { #if !defined ( APS_NO_GROUPS ) // Find the next endpoint for this group grpEp = aps_FindGroupForEndpoint( aff->GroupID, grpEp ); if ( grpEp == APS_GROUPS_EP_NOT_FOUND ) return; // No endpoint found epDesc = afFindEndPointDesc( grpEp ); if ( epDesc == NULL ) return; // Endpoint descriptor not found pList = afFindEndPointDescList( epDesc->endPoint ); #else return; #endif } else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT ) { pList = pList->nextDesc; if ( pList ) epDesc = pList->epDesc; else epDesc = NULL; } else epDesc = NULL; } }
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP, uint16 cID, uint16 len, uint8 *buf, uint8 *transID, uint8 options, uint8 radius ) { pDescCB pfnDescCB; ZStatus_t stat; APSDE_DataReq_t req; afDataReqMTU_t mtu; epList_t *pList; // Verify source end point if ( srcEP == NULL ) { return afStatus_INVALID_PARAMETER; } #if !defined( REFLECTOR ) if ( dstAddr->addrMode == afAddrNotPresent ) { return afStatus_INVALID_PARAMETER; } #endif // Check if route is available before sending data if ( options & AF_LIMIT_CONCENTRATOR ) { if ( dstAddr->addrMode != afAddr16Bit ) { return ( afStatus_INVALID_PARAMETER ); } // First, make sure the destination is not its self, then check for an existing route. if ( (dstAddr->addr.shortAddr != NLME_GetShortAddr()) && (RTG_CheckRtStatus( dstAddr->addr.shortAddr, RT_ACTIVE, (MTO_ROUTE | NO_ROUTE_CACHE) ) != RTG_SUCCESS) ) { // A valid route to a concentrator wasn't found return ( afStatus_NO_ROUTE ); } } // Validate broadcasting if ( ( dstAddr->addrMode == afAddr16Bit ) || ( dstAddr->addrMode == afAddrBroadcast ) ) { // Check for valid broadcast values if( ADDR_NOT_BCAST != NLME_IsAddressBroadcast( dstAddr->addr.shortAddr ) ) { // Force mode to broadcast dstAddr->addrMode = afAddrBroadcast; } else { // Address is not a valid broadcast type if ( dstAddr->addrMode == afAddrBroadcast ) { return afStatus_INVALID_PARAMETER; } } } else if ( dstAddr->addrMode != afAddr64Bit && dstAddr->addrMode != afAddrGroup && dstAddr->addrMode != afAddrNotPresent ) { return afStatus_INVALID_PARAMETER; } // Set destination address req.dstAddr.addrMode = dstAddr->addrMode; if ( dstAddr->addrMode == afAddr64Bit ) { osal_cpyExtAddr( req.dstAddr.addr.extAddr, dstAddr->addr.extAddr ); } else { req.dstAddr.addr.shortAddr = dstAddr->addr.shortAddr; } // This option is to use Wildcard ProfileID in outgoing packets if ( options & AF_WILDCARD_PROFILEID ) { req.profileID = ZDO_WILDCARD_PROFILE_ID; } else { req.profileID = ZDO_PROFILE_ID; if ( (pfnDescCB = afGetDescCB( srcEP )) ) { uint16 *pID = (uint16 *)(pfnDescCB( AF_DESCRIPTOR_PROFILE_ID, srcEP->endPoint )); if ( pID ) { req.profileID = *pID; osal_mem_free( pID ); } } else if ( srcEP->simpleDesc ) { req.profileID = srcEP->simpleDesc->AppProfId; } } req.txOptions = 0; if ( ( options & AF_ACK_REQUEST ) && ( req.dstAddr.addrMode != AddrBroadcast ) && ( req.dstAddr.addrMode != AddrGroup ) ) { req.txOptions |= APS_TX_OPTIONS_ACK; } if ( options & AF_SKIP_ROUTING ) { req.txOptions |= APS_TX_OPTIONS_SKIP_ROUTING; } if ( options & AF_EN_SECURITY ) { req.txOptions |= APS_TX_OPTIONS_SECURITY_ENABLE; mtu.aps.secure = TRUE; } else { mtu.aps.secure = FALSE; } if ( options & AF_PREPROCESS ) { req.txOptions |= APS_TX_OPTIONS_PREPROCESS; } mtu.kvp = FALSE; if ( options & AF_SUPRESS_ROUTE_DISC_NETWORK ) { req.discoverRoute = DISC_ROUTE_INITIATE; } else { req.discoverRoute = AF_DataRequestDiscoverRoute; } req.transID = *transID; req.srcEP = srcEP->endPoint; req.dstEP = dstAddr->endPoint; req.clusterID = cID; req.asduLen = len; req.asdu = buf; req.radiusCounter = radius; #if defined ( INTER_PAN ) req.dstPanId = dstAddr->panId; #endif // INTER_PAN // Look if there is a Callback function registered for this endpoint // The callback is used to control the AF Transaction ID used when sending messages pList = afFindEndPointDescList( srcEP->endPoint ); if ( ( pList != NULL ) && ( pList->pfnApplCB != NULL ) ) { pList->pfnApplCB( &req ); } #if defined ( INTER_PAN ) if ( StubAPS_InterPan( dstAddr->panId, dstAddr->endPoint ) ) { if ( len > INTERP_DataReqMTU() ) { stat = afStatus_INVALID_PARAMETER; } else { stat = INTERP_DataReq( &req ); } } else #endif // INTER_PAN { if (len > afDataReqMTU( &mtu ) ) { if (apsfSendFragmented) { stat = (*apsfSendFragmented)( &req ); } else { stat = afStatus_INVALID_PARAMETER; } } else { stat = APSDE_DataReq( &req ); } } /* * If this is an EndPoint-to-EndPoint message on the same device, it will not * get added to the NWK databufs. So it will not go OTA and it will not get * a MACCB_DATA_CONFIRM_CMD callback. Thus it is necessary to generate the * AF_DATA_CONFIRM_CMD here. Note that APSDE_DataConfirm() only generates one * message with the first in line TransSeqNumber, even on a multi message. * Also note that a reflected msg will not have its confirmation generated * here. */ if ( (req.dstAddr.addrMode == Addr16Bit) && (req.dstAddr.addr.shortAddr == NLME_GetShortAddr()) ) { afDataConfirm( srcEP->endPoint, *transID, stat ); } if ( stat == afStatus_SUCCESS ) { (*transID)++; } return (afStatus_t)stat; }
/********************************************************************* * @fn afIncomingData * * @brief Transfer a data PDU (ASDU) from the APS sub-layer to the AF. * * @param aff - pointer to APS frame format * @param SrcAddress - Source address * @param SrcPanId - Source PAN ID * @param sig - incoming message's link quality * @param nwkSeqNum - incoming network sequence number (from nwk header frame) * @param SecurityUse - Security enable/disable * @param timestamp - the MAC Timer2 timestamp at Rx. * @param radius - incoming messages received radius * * @return none */ void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId, NLDE_Signal_t *sig, uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp, uint8 radius ) { endPointDesc_t *epDesc = NULL; epList_t *pList = epList; #if !defined ( APS_NO_GROUPS ) uint8 grpEp = APS_GROUPS_EP_NOT_FOUND; #endif if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) ) { #if !defined ( APS_NO_GROUPS ) // Find the first endpoint for this group grpEp = aps_FindGroupForEndpoint( aff->GroupID, APS_GROUPS_FIND_FIRST ); if ( grpEp == APS_GROUPS_EP_NOT_FOUND ) return; // No endpoint found epDesc = afFindEndPointDesc( grpEp ); if ( epDesc == NULL ) return; // Endpoint descriptor not found pList = afFindEndPointDescList( epDesc->endPoint ); #else return; // Not supported #endif } else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT ) { // Set the list if ( pList != NULL ) { epDesc = pList->epDesc; } } else if ( (epDesc = afFindEndPointDesc( aff->DstEndPoint )) ) { pList = afFindEndPointDescList( epDesc->endPoint ); } while ( epDesc ) { uint16 epProfileID = 0xFFFE; // Invalid Profile ID if ( pList->pfnDescCB ) { uint16 *pID = (uint16 *)(pList->pfnDescCB( AF_DESCRIPTOR_PROFILE_ID, epDesc->endPoint )); if ( pID ) { epProfileID = *pID; osal_mem_free( pID ); } } else if ( epDesc->simpleDesc ) { epProfileID = epDesc->simpleDesc->AppProfId; } // First part of verification is to make sure that: // the local Endpoint ProfileID matches the received ProfileID OR // the message is specifically send to ZDO (this excludes the broadcast endpoint) OR // if the Wildcard ProfileID is received the message should not be sent to ZDO endpoint if ( (aff->ProfileID == epProfileID) || ((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) || ((epDesc->endPoint != ZDO_EP) && ( aff->ProfileID == ZDO_WILDCARD_PROFILE_ID )) ) { // Save original endpoint uint8 endpoint = aff->DstEndPoint; // overwrite with descriptor's endpoint aff->DstEndPoint = epDesc->endPoint; afBuildMSGIncoming( aff, epDesc, SrcAddress, SrcPanId, sig, nwkSeqNum, SecurityUse, timestamp, radius ); // Restore with original endpoint aff->DstEndPoint = endpoint; } if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) ) { #if !defined ( APS_NO_GROUPS ) // Find the next endpoint for this group grpEp = aps_FindGroupForEndpoint( aff->GroupID, grpEp ); if ( grpEp == APS_GROUPS_EP_NOT_FOUND ) return; // No endpoint found epDesc = afFindEndPointDesc( grpEp ); if ( epDesc == NULL ) return; // Endpoint descriptor not found pList = afFindEndPointDescList( epDesc->endPoint ); #else return; #endif } else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT ) { pList = pList->nextDesc; if ( pList ) epDesc = pList->epDesc; else epDesc = NULL; } else epDesc = NULL; } }