/************************************************************************************************** Filename: stub_aps.c Revised: $Date: 2011-04-20 10:16:44 -0700 (Wed, 20 Apr 2011) $ Revision: $Revision: 25771 $ Description: Stub APS processing functions Copyright 2008 - 2011 Texas Instruments Incorporated. All rights reserved. IMPORTANT: Your use of this Software is limited to those specific rights granted under the terms of a software license agreement between the user who downloaded the software, his/her employer (which must be your employer) and Texas Instruments Incorporated (the "License"). You may not use this Software unless you agree to abide by the terms of the License. The License limits your use, and you acknowledge, that the Software may not be modified, copied or distributed unless embedded on a Texas Instruments microcontroller or used solely and exclusively in conjunction with a Texas Instruments radio frequency transceiver, which is integrated into your product. Other than for the foregoing purpose, you may not use, reproduce, copy, prepare derivative works of, modify, distribute, perform, display or sell this Software and/or its documentation for any purpose. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. Should you have any questions regarding your right to use this Software, contact Texas Instruments Incorporated at www.TI.com. **************************************************************************************************/ /********************************************************************* * INCLUDES */ #include "osal.h" #include "mac_spec.h" #include "nwk_util.h" #include "AF.h" #include "stub_aps.h" /********************************************************************* * MACROS */ /********************************************************************* * CONSTANTS */ // Stub NWK header length #define STUB_NWK_HDR_LEN 2 // Start of the Stub APS header in the Inter-PAN frame #define STUB_APS_HDR_FRAME_CTRL STUB_NWK_HDR_LEN // Stub APS event identifiers #define CHANNEL_CHANGE_EVT 0x0001 #define CHANNEL_CHANGE_RETRY_TIMEOUT 100 /********************************************************************* * TYPEDEFS */ typedef struct { zAddrType_t addr; uint16 panId; } pan_t; /********************************************************************* * GLOBAL VARIABLES */ uint8 StubAPS_TaskID = 0xFF; // Task ID for internal task/event processing /********************************************************************* * EXTERNAL VARIABLES */ /********************************************************************* * EXTERNAL FUNCTIONS */ /********************************************************************* * LOCAL VARIABLES */ static uint8 newChannel; static uint8 channelChangeInProgress = FALSE; // Application info static uint8 appTaskID = 0xFF; // Application task id static uint8 appEndPoint = 0; // Application endpoint /********************************************************************* * LOCAL FUNCTIONS */ static void StubNWK_ParseMsg( uint8 *buf, uint8 bufLength, NLDE_FrameFormat_t *snff ); static void StubAPS_ParseMsg( NLDE_FrameFormat_t *snff, aps_FrameFormat_t *saff ); static void StubNWK_BuildMsg( uint8 *nwkHdr ); static void StubAPS_BuildMsg( uint8 *apsHdr, uint8 frmCtrl, uint16 groupID, APSDE_DataReq_t *req ); static ZStatus_t StubAPS_BuildFrameControl( uint8 *frmCtrl, zAddrType_t *dstAddr, uint16 *groupID, APSDE_DataReq_t *req ); static ZStatus_t StubAPS_SetNewChannel( uint8 channel ); static void StubAPS_NotifyApp( uint8 status ); uint8 StubAPS_ZMacCallback( uint8 *msgPtr ); /********************************************************************* * @fn StubAPS_Init() * * @brief Initialize stub APS layer * * @param task_id - Task identifier for the desired task * * @return none */ void StubAPS_Init( uint8 task_id ) { StubAPS_TaskID = task_id; // register with ZMAC pZMac_AppCallback = StubAPS_ZMacCallback; } /* StubAPS_Init() */ /********************************************************************* * @fn StubAPS_ProcessEvent() * * @brief Main event loop for Stub APS task. This function should be called * at periodic intervals when event occur. * * @param task_id - Task ID * @param events - Bitmap of events * * @return none */ UINT16 StubAPS_ProcessEvent( uint8 task_id, uint16 events ) { (void)task_id; // Intentionally unreferenced parameter if ( events & SYS_EVENT_MSG ) { osal_event_hdr_t *msg_ptr; while ( (msg_ptr = (osal_event_hdr_t *)osal_msg_receive( StubAPS_TaskID )) != NULL ) { if ( msg_ptr->event == MAC_MCPS_DATA_CNF ) { INTERP_DataConfirm( (ZMacDataCnf_t *)msg_ptr ); } else if ( msg_ptr->event == MAC_MCPS_DATA_IND ) { INTERP_DataIndication( (macMcpsDataInd_t *)msg_ptr ); } osal_msg_deallocate( (uint8 *)msg_ptr ); } // Return unproccessed events return ( events ^ SYS_EVENT_MSG ); } if ( events & CHANNEL_CHANGE_EVT ) { // try to change to the new channel ZStatus_t status = StubAPS_SetNewChannel( newChannel ); if ( status != ZSuccess ) { // turn MAC receiver back on uint8 rxOnIdle = true; ZMacSetReq( ZMacRxOnIdle, &rxOnIdle ); // set NWK task to run nwk_setStateIdle( FALSE ); channelChangeInProgress = FALSE; } // notify the application StubAPS_NotifyApp( status ); return ( events ^ CHANNEL_CHANGE_EVT ); } // If reach here, the events are unknown // Discard or make more handlers return 0; } /* StubAPS_ProcessEvent() */ /********************************************************************* * @fn StubNWK_ParseMsg * * @brief Call this function to parse an incoming Stub NWK frame. * * @param buf - pointer incoming message buffer * @param bufLength - length of incoming message * @param snff - pointer Frame Format Parameters * * @return pointer to network packet, NULL if error */ static void StubNWK_ParseMsg( uint8 *buf, uint8 bufLength, NLDE_FrameFormat_t *snff ) { uint16 fc; osal_memset( snff, 0, sizeof(NLDE_FrameFormat_t) ); snff->bufLength = bufLength; // get the frame control fc = BUILD_UINT16( buf[NWK_HDR_FRAME_CTRL_LSB], buf[NWK_HDR_FRAME_CTRL_MSB] ); // parse the frame control NLDE_ParseFrameControl( fc, snff ); snff->hdrLen = STUB_NWK_HDR_LEN; // Stub NWK payload snff->nsdu = buf + snff->hdrLen; snff->nsduLength = snff->bufLength - snff->hdrLen; } /* StubNWK_ParseMsg */ /********************************************************************* * @fn StubAPS_ParseMsg * * @brief Call this function to parse an incoming Stub APS frame. * * @param naff - pointer Stub NWK Frame Format Parameters * @param saff - pointer Stub APS Format Parameters * * @return none */ static void StubAPS_ParseMsg( NLDE_FrameFormat_t *snff, aps_FrameFormat_t *saff ) { uint8 fcb; uint8 *asdu; osal_memset( saff, 0, sizeof(aps_FrameFormat_t) ); saff->asduLength = snff->nsduLength; asdu = snff->nsdu; saff->macDestAddr = snff->macDstAddr; // First byte is Frame Control. saff->FrmCtrl = *asdu++; fcb = saff->FrmCtrl & APS_FRAME_TYPE_MASK; if ( fcb == STUB_APS_FRAME ) { fcb = saff->FrmCtrl & APS_DELIVERYMODE_MASK; if ( fcb == APS_FC_DM_BROADCAST ) saff->wasBroadcast = true; else saff->wasBroadcast = false; if ( fcb == APS_FC_DM_GROUP ) { saff->GroupID = BUILD_UINT16( asdu[0], asdu[1] ); asdu += sizeof( uint16 ); } // Pull out the Cluster ID saff->ClusterID = BUILD_UINT16( asdu[0], asdu[1] ); asdu += sizeof( uint16 ); // Pull out the profile ID saff->ProfileID = BUILD_UINT16( asdu[0], asdu[1] ); asdu += 2; } saff->asdu = asdu; saff->asduLength -= (uint8) (asdu - snff->nsdu); saff->apsHdrLen = snff->nsduLength - saff->asduLength; } /* StubAPS_ParseMsg */ /****************************************************************************** * @fn StubAPS_BuildFrameControl * * @brief This function builds Stub APS Frame Control and the destination * address parameter for the MCPS-DATA Request. * * @param frmCtrl - frame control * @param dstAddr - destination address for MCPS-DATA Request * @param groupID - group id * @param req - APSDE_DataReq_t * * @return ZStatus_t */ static ZStatus_t StubAPS_BuildFrameControl( uint8 *frmCtrl, zAddrType_t *dstAddr, uint16 *groupID, APSDE_DataReq_t *req ) { // Security if ( req->txOptions & APS_TX_OPTIONS_SECURITY_ENABLE ) return ( ZApsNotSupported ); // Ack request if ( req->txOptions & APS_TX_OPTIONS_ACK ) return ( ZApsNotSupported ); // Fragmentation if ( req->txOptions & APS_TX_OPTIONS_PERMIT_FRAGMENT ) return ( ZApsNotSupported ); // set delivery mode if ( req->dstAddr.addrMode == AddrNotPresent ) return ( ZApsNotSupported ); // No REFLECTOR // set frame type *frmCtrl = STUB_APS_FRAME; // set DstAddrMode of MCPS-DATA Request to DstAddrMode of INTERP-Data Request dstAddr->addrMode = req->dstAddr.addrMode; // set DstAddr of MCPS-DATA Request to DstAddr of INTERP-Data Request if ( req->dstAddr.addrMode == AddrBroadcast ) { *frmCtrl |= APS_FC_DM_BROADCAST; // set DstAddrMode of MCPS-DATA Request to short address dstAddr->addrMode = Addr16Bit; dstAddr->addr.shortAddr = req->dstAddr.addr.shortAddr; } else if ( req->dstAddr.addrMode == Addr16Bit ) { *frmCtrl |= APS_FC_DM_UNICAST; dstAddr->addr.shortAddr = req->dstAddr.addr.shortAddr; } else if ( req->dstAddr.addrMode == Addr64Bit ) { *frmCtrl |= APS_FC_DM_UNICAST; osal_cpyExtAddr( dstAddr->addr.extAddr, req->dstAddr.addr.extAddr ); } else if ( req->dstAddr.addrMode == AddrGroup ) { *frmCtrl |= APS_FC_DM_GROUP; // set DstAddrMode of MCPS-DATA Request to short address dstAddr->addrMode = Addr16Bit; // set DstAddr of MCPS-DATA Request to 0xFFFF dstAddr->addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVALL; // set Group ID to DstAddr of INTERP-Data Request *groupID = req->dstAddr.addr.shortAddr; } return ( ZSuccess ); } /* StubAPS_BuildFrameControl */ /****************************************************************************** * @fn StubNWK_BuildMsg * * @brief This function builds a Stub NWK frame. * * @param nwkHdr - stub NWK header * * @return none */ static void StubNWK_BuildMsg( uint8 *nwkHdr ) { uint16 frmCtrl = 0; uint8 protoVer = NLME_GetProtocolVersion(); // frame type frmCtrl |= (STUB_NWK_FRAME_TYPE << NWK_FC_FRAME_TYPE); // protocol version frmCtrl |= (protoVer << NWK_FC_PROT_VERSION); // set Stub NWK header *nwkHdr++ = LO_UINT16( frmCtrl ); *nwkHdr++ = HI_UINT16( frmCtrl ); } /* StubNWK_BuildMsg */ /****************************************************************************** * @fn StubAPS_BuildMsg * * @brief This function builds a Stub APS frame. * * @param apsHdr - stub APS header * @param frmCtrl - stub APS frame control * @param groupID - group id * @param req - APSDE_DataReq_t * * @return none */ static void StubAPS_BuildMsg( uint8 *apsHdr, uint8 frmCtrl, uint16 groupID, APSDE_DataReq_t *req ) { // add frame type *apsHdr++ = frmCtrl; // add Group ID if ( ( frmCtrl & APS_DELIVERYMODE_MASK ) == APS_FC_DM_GROUP ) { *apsHdr++ = LO_UINT16( groupID ); *apsHdr++ = HI_UINT16( groupID ); } // add clusterID *apsHdr++ = LO_UINT16( req->clusterID ); *apsHdr++ = HI_UINT16( req->clusterID ); // add profile ID *apsHdr++ = LO_UINT16( req->profileID ); *apsHdr++ = HI_UINT16( req->profileID ); // copy ASDU data into frame osal_memcpy ( apsHdr, req->asdu, req->asduLen ); } /* StubAPS_BuildMsg */ /****************************************************************************** * @fn StubAPS_setNewChannel * * @brief This function changes the device's channel. * * @param none * * @return ZStatus_t */ static ZStatus_t StubAPS_SetNewChannel( uint8 channel ) { uint8 rxOnIdle; // make sure MAC has nothing to transmit if ( ( nwkDB_CountTypes( NWK_DATABUF_SENT ) == 0 ) && ZMacStateIdle() ) { // set the new channel ZMacSetReq( ZMacChannel, &channel ); // turn MAC receiver back on rxOnIdle = true; ZMacSetReq( ZMacRxOnIdle, &rxOnIdle ); channelChangeInProgress = FALSE; return ( ZSuccess ); } return ( ZFailure ); } /* StubAPS_setNewChannel */ /****************************************************************************** * @fn StubAPS_NotifyApp * * @brief This function sends an OSAL message to the Application task. * * @param status - command status * * @return none */ static void StubAPS_NotifyApp( uint8 status ) { osal_event_hdr_t *msgPtr; // Notify the application task msgPtr = (osal_event_hdr_t *)osal_msg_allocate( sizeof(osal_event_hdr_t) ); if ( msgPtr ) { msgPtr->event = SAPS_CHANNEL_CHANGE; msgPtr->status = status; osal_msg_send( appTaskID, (uint8 *)msgPtr ); } } /* StubAPS_NotifyApp */ /****************************************************************************** * * External APIs provided to the Application. */ /****************************************************************************** * @fn StubAPS_SetInterPanChannel * * @brief This function changes the device's channel for inter-PAN communication. * * @param channel - new channel * * @return ZStatus_t */ ZStatus_t StubAPS_SetInterPanChannel( uint8 channel ) { uint8 currChannel; uint8 rxOnIdle; if ( channelChangeInProgress ) return ( ZFailure ); ZMacGetReq( ZMacChannel, &currChannel ); if ( currChannel == channel ) { // inter PANs communication within the same channel return ( ZSuccess ); } // go into channel transition state channelChangeInProgress = TRUE; // set NWK task to idle nwk_setStateIdle( TRUE ); // turn MAC receiver off rxOnIdle = false; ZMacSetReq( ZMacRxOnIdle, &rxOnIdle ); // try to change to the new channel if ( StubAPS_SetNewChannel( channel ) == ZSuccess ) return ( ZSuccess ); // save the new channel for retry newChannel = channel; // ask StubAPS task to retry it later osal_start_timerEx( StubAPS_TaskID, CHANNEL_CHANGE_EVT, CHANNEL_CHANGE_RETRY_TIMEOUT ); return ( ZApsNotAllowed ); } /* StubAPS_SetInterPanChannel */ /****************************************************************************** * @fn StubAPS_SetIntraPanChannel * * @brief This function sets the device's channel back to the NIB channel. * * @param none * * @return ZStatus_t */ ZStatus_t StubAPS_SetIntraPanChannel( void ) { uint8 currChannel; uint8 rxOnIdle; if ( channelChangeInProgress ) return ( ZFailure ); ZMacGetReq( ZMacChannel, &currChannel ); if ( currChannel == _NIB.nwkLogicalChannel ) return ( ZSuccess ); channelChangeInProgress = TRUE; // turn MAC receiver off rxOnIdle = false; ZMacSetReq( ZMacRxOnIdle, &rxOnIdle ); // set the NIB channel ZMacSetReq( ZMacChannel, &(_NIB.nwkLogicalChannel) ); // turn MAC receiver back on rxOnIdle = true; ZMacSetReq( ZMacRxOnIdle, &rxOnIdle ); // set NWK task to run nwk_setStateIdle( FALSE ); channelChangeInProgress = FALSE; return ( ZSuccess ); } /* StubAPS_SetIntraPanChannel */ /****************************************************************************** * @fn StubAPS_InterPan * * @brief This function checks to see if a PAN is an Inter-PAN. * * @param panId - PAN ID * @param endPoint - endpoint * * @return TRUE if PAN is Inter-PAN, FALSE otherwise */ uint8 StubAPS_InterPan( uint16 panId, uint8 endPoint ) { (void)panId; // Intentionally unreferenced parameter // No need to check the MAC/NIB Channels or Source/Destination PAN IDs // since it's possible to send Inter-PAN messages within the same network. if ( endPoint == STUBAPS_INTER_PAN_EP ) { // Inter-PAN endpoint return ( TRUE ); } return ( FALSE ); } /* StubAPS_InterPan */ /****************************************************************************** * @fn StubAPS_RegisterApp * * @brief This function registers the Application with the Stub APS layer. * * NOTE: Since Stub APS messages don't include the application * endpoint, the application has to register its endpoint * with Stub APS. * * @param epDesc - application's endpoint descriptor * * @return none */ void StubAPS_RegisterApp( endPointDesc_t *epDesc ) { appTaskID = *epDesc->task_id; appEndPoint = epDesc->endPoint; } /* StubAPS_RegisterApp */ /****************************************************************************** * @fn StubAPS_ZMacCallback * * @brief This function accepts an inter-PAN message from ZMac. * * @param msgPtr - received message * * @return TRUE if message is processed. FALSE otherwise. */ uint8 StubAPS_ZMacCallback( uint8 *msgPtr ) { uint16 nwk_fc; uint8 aps_fc; uint8 frameType; uint8 *buf = NULL; uint8 event = ((osal_event_hdr_t *)msgPtr)->event; if ( event == MAC_MCPS_DATA_IND ) { buf = ((macMcpsDataInd_t *)msgPtr)->msdu.p; } else if ( event == MAC_MCPS_DATA_CNF ) { buf = ((macMcpsDataCnf_t *)msgPtr)->pDataReq->msdu.p; } if ( buf ) { // get the NWK frame control nwk_fc = BUILD_UINT16( buf[NWK_HDR_FRAME_CTRL_LSB], buf[NWK_HDR_FRAME_CTRL_MSB] ); // frame type frameType = (uint8)((nwk_fc >> NWK_FC_FRAME_TYPE) & NWK_FC_FRAME_TYPE_MASK); // check if incoming frame is of the right type if ( frameType != STUB_NWK_FRAME_TYPE ) { // message doesn't belong to Stub APS return ( FALSE ); } // get the APS frame control aps_fc = buf[STUB_APS_HDR_FRAME_CTRL]; // frame type frameType = aps_fc & APS_FRAME_TYPE_MASK; // check if incoming frame is of the right type if ( frameType != STUB_APS_FRAME ) { // message doesn't belong to Stub APS return ( FALSE ); } // message belongs to Stub APS osal_msg_send( StubAPS_TaskID, (uint8 *)msgPtr ); return ( TRUE ); } // message doesn't belong to Stub APS return ( FALSE ); } /* StubAPS_ZMacCallback */ /****************************************************************************** * * Stub APS Inter-PAN interface INTERP and its callbacks. */ /****************************************************************************** * @fn INTERP_DataReq * * @brief This function requests the transfer of data from the next * higher layer to a single peer entity. * * @param req - APSDE_DataReq_t * * @return ZStatus_t */ ZStatus_t INTERP_DataReq( APSDE_DataReq_t *req ) { uint8 apsFrmCtrl; uint16 groupID = 0; uint8 *buf; uint8 hdrLen; ZMacDataReq_t dataReq; ZStatus_t status; if ( channelChangeInProgress || !StubAPS_InterPan( req->dstPanId, req->dstEP ) ) return ( ZFailure ); osal_memset( &dataReq, 0, sizeof( ZMacDataReq_t ) ); // Build Stub APS header status = StubAPS_BuildFrameControl( &apsFrmCtrl, &(dataReq.DstAddr), &groupID, req ); if ( status != ZSuccess ) return ( status ); // set default Stub APS header length hdrLen = APS_FRAME_CTRL_FIELD_LEN; // add group ID length if ( ( apsFrmCtrl & APS_DELIVERYMODE_MASK ) == APS_FC_DM_GROUP ) hdrLen += APS_GROUP_ID_FIELD_LEN; // add cluster ID length hdrLen += APS_CLUSTERID_FIELD_LEN; // add profile ID length hdrLen += APS_PROFILEID_FIELD_LEN; // add default Stub NWK header length hdrLen += STUB_NWK_HDR_LEN; // calculate MSDU length dataReq.msduLength = hdrLen + req->asduLen; // allocate buffer buf = osal_mem_alloc( dataReq.msduLength ); if ( buf != NULL ) { dataReq.msdu = buf; // Add Stub APS header and data StubAPS_BuildMsg( &buf[STUB_APS_HDR_FRAME_CTRL], apsFrmCtrl, groupID, req ); // Add Stub NWK header StubNWK_BuildMsg( buf ); // Set ZMac data request dataReq.DstPANId = req->dstPanId; dataReq.SrcAddrMode = Addr64Bit; dataReq.Handle = req->transID; if ( ( apsFrmCtrl & APS_DELIVERYMODE_MASK ) == APS_FC_DM_UNICAST ) dataReq.TxOptions = NWK_TXOPTIONS_ACK; else dataReq.TxOptions = 0; // send the frame status = ZMacDataReq( &dataReq ); // free the frame osal_mem_free( buf ); } else { // flag a memory error status = ZMemError; } return ( status ); } /* INTERP_DataReq */ /****************************************************************************** * @fn INTERP_DataReqMTU * * @brief This function requests the MTU (Max Transport Unit) of the * Inter-PAN Data Service. * * @param none * * @return uint8 - MTU */ uint8 INTERP_DataReqMTU( void ) { uint8 mtu; uint8 hdrLen; // Use maximum header size for Stub APS header hdrLen = APS_FRAME_CTRL_FIELD_LEN + APS_GROUP_ID_FIELD_LEN + APS_CLUSTERID_FIELD_LEN + APS_PROFILEID_FIELD_LEN; mtu = MAC_A_MAX_FRAME_SIZE - STUB_NWK_HDR_LEN - hdrLen; return ( mtu ); } /* INTERP_DataReqMTU */ /**************************************************************************** * @fn INTERP_DataConfirm * * @brief This function processes the data confirm from the MAC layer. * * @param dataCnf - data confirm primitive * * @return none */ void INTERP_DataConfirm( ZMacDataCnf_t *dataCnf ) { afDataConfirm( appEndPoint, dataCnf->msduHandle, dataCnf->hdr.Status ); } /* INTERP_DataConfirm */ /**************************************************************************** * @fn INTERP_DataIndication * * @brief This function indicates the transfer of a data SPDU (MSDU) * from the MAC layer to the local application layer entity. * * @param dataInd - data indicate primitive * * @return none */ void INTERP_DataIndication( macMcpsDataInd_t *dataInd ) { NLDE_FrameFormat_t snff; aps_FrameFormat_t saff; zAddrType_t srcAddr; NLDE_Signal_t sig; // parse the Stub NWK header StubNWK_ParseMsg( dataInd->msdu.p, dataInd->msdu.len, &snff ); // Fill in MAC destination address snff.macDstAddr = dataInd->mac.dstAddr.addr.shortAddr; // fill in MAC source address (Stub NWK frame doesn't have address fields) osal_copyAddress( &srcAddr, (zAddrType_t *)&(dataInd->mac.srcAddr) ); // check if incoming frame is of the right type if ( snff.frameType != STUB_NWK_FRAME_TYPE ) return; // check if incoming frame is of the right version if ( snff.protocolVersion != NLME_GetProtocolVersion() ) return; // check if the remaining sun-fields are zero if ( ( snff.discoverRoute != 0 ) || ( snff.multicast != 0 ) || ( snff.secure != 0 ) || ( snff.srcRouteSet != 0 ) || ( snff.dstExtAddrSet != 0 ) || ( snff.srcExtAddrSet != 0 ) ) { return; } // parse the Stub APS header StubAPS_ParseMsg( &snff, &saff ); // check if incoming frame is of the right type if ( ( saff.FrmCtrl & APS_FRAME_TYPE_MASK ) != STUB_APS_FRAME ) return; // check if delivery mode is of the right type if ( ( saff.FrmCtrl & APS_DELIVERYMODE_MASK ) == APS_FC_DM_INDIRECT ) return; // check if incoming frame is unsecured if ( saff.FrmCtrl & APS_FC_SECURITY ) return; // check if there's no extended header if ( saff.FrmCtrl & APS_FC_EXTENDED ) return; // Set the endpoints saff.DstEndPoint = appEndPoint; saff.SrcEndPoint = STUBAPS_INTER_PAN_EP; // Set the signal strength information sig.LinkQuality = dataInd->mac.mpduLinkQuality; sig.correlation = dataInd->mac.correlation; sig.rssi = dataInd->mac.rssi; APSDE_DataIndication( &saff, &srcAddr, dataInd->mac.srcPanId, &sig, snff.broadcastId, FALSE, dataInd->mac.timestamp ); } /* INTERP_DataIndication */ /********************************************************************* *********************************************************************/