/*================================================================================================= * @fn rxSecurityHdrIsr * * @brief Receive ISR state for reading out and storing the auxiliary security header. * * @param none * * @return none *================================================================================================= */ static void rxSecurityHdrIsr(void) { uint8 buf[MAC_FRAME_COUNTER_LEN + MAC_KEY_ID_8_LEN]; /* read out frame counter and key ID */ MAC_RADIO_READ_RX_FIFO(buf, rxNextLen); /* Incoming frame counter */ pRxBuf->frameCounter = BUILD_UINT32(buf[0], buf[1], buf[2], buf[3]); if (rxNextLen - MAC_FRAME_COUNTER_LEN > 0) { /* Explicit mode */ osal_memcpy(pRxBuf->sec.keySource, &buf[MAC_FRAME_COUNTER_LEN], rxNextLen - MAC_FRAME_COUNTER_LEN - 1); pRxBuf->sec.keyIndex = buf[rxNextLen - MAC_KEY_INDEX_LEN]; } /* Copy security fields to RX buffer */ osal_memcpy(pRxBuf->mhr.p, buf, rxNextLen); pRxBuf->mhr.p += rxNextLen; pRxBuf->mhr.len += rxNextLen; /* Update payload pointer and payload length. The rxPayloadLen includes security header length * and SCF byte. The security header and SCF length must be deducted from the rxPayloadLen. */ rxPayloadLen -= (rxNextLen + MAC_SEC_CONTROL_FIELD_LEN); pRxBuf->msdu.len = rxPayloadLen; pRxBuf->mhr.len += rxPayloadLen; /*------------------------------------------------------------------------------- * Prepare for payload interrupts. */ pFuncRxState = &rxPayloadIsr; rxPrepPayload(); }
/*================================================================================================= * @fn rxPayloadIsr * * @brief Receive ISR state for reading out and storing the packet payload. * * @param none * * @return none *================================================================================================= */ static void rxPayloadIsr(void) { MAC_RADIO_READ_RX_FIFO(pRxBuf->msdu.p, rxNextLen); pRxBuf->msdu.p += rxNextLen; rxPayloadLen -= rxNextLen; rxPrepPayload(); }
/*================================================================================================= * @fn rxAddrIsr * * @brief Receive ISR state for decoding address. Reads and stores the address information * from the incoming packet. * * @param none * * @return none *================================================================================================= */ static void rxAddrIsr(void) { uint8 buf[MAX_ADDR_FIELDS_LEN]; uint8 dstAddrMode; uint8 srcAddrMode; uint8 * p; MAC_ASSERT(rxNextLen != 0); /* logic assumes at least one address byte in buffer */ /* read out address fields into local buffer in one shot */ MAC_RADIO_READ_RX_FIFO(buf, rxNextLen); /* set pointer to buffer with addressing fields */ p = buf; /* destination address */ dstAddrMode = MAC_DEST_ADDR_MODE(&rxBuf[1]); if (dstAddrMode != SADDR_MODE_NONE) { pRxBuf->mac.srcPanId = pRxBuf->mac.dstPanId = BUILD_UINT16(p[0], p[1]); p += MAC_PAN_ID_FIELD_LEN; if (dstAddrMode == SADDR_MODE_EXT) { sAddrExtCpy(pRxBuf->mac.dstAddr.addr.extAddr, p); p += MAC_EXT_ADDR_FIELD_LEN; } else { pRxBuf->mac.dstAddr.addr.shortAddr = BUILD_UINT16(p[0], p[1]); p += MAC_SHORT_ADDR_FIELD_LEN; } } /* sources address */ srcAddrMode = MAC_SRC_ADDR_MODE(&rxBuf[1]); if (srcAddrMode != SADDR_MODE_NONE) { if (!(pRxBuf->internal.flags & MAC_RX_FLAG_INTRA_PAN)) { pRxBuf->mac.srcPanId = BUILD_UINT16(p[0], p[1]); p += MAC_PAN_ID_FIELD_LEN; } if (srcAddrMode == SADDR_MODE_EXT) { sAddrExtCpy(pRxBuf->mac.srcAddr.addr.extAddr, p); } else { pRxBuf->mac.srcAddr.addr.shortAddr = BUILD_UINT16(p[0], p[1]); } } /*------------------------------------------------------------------------------- * Prepare for payload interrupts. */ pFuncRxState = &rxPayloadIsr; rxPrepPayload(); }
/*================================================================================================= * @fn rxAddrIsr * * @brief Receive ISR state for decoding address. Reads and stores the address information * from the incoming packet. * * @param none * * @return none *================================================================================================= */ static void rxAddrIsr(void) { uint8 buf[MAX_ADDR_FIELDS_LEN]; uint8 dstAddrMode; uint8 srcAddrMode; #ifdef FEATURE_MAC_SECURITY uint8 securityControl; #endif /* MAC_SECURITY */ uint8 * p; MAC_ASSERT(rxNextLen != 0); /* logic assumes at least one address byte in buffer */ /* read out address fields into local buffer in one shot */ MAC_RADIO_READ_RX_FIFO(buf, rxNextLen); /* set pointer to buffer with addressing fields */ p = buf; /* destination address */ dstAddrMode = MAC_DEST_ADDR_MODE(&rxBuf[1]); if (dstAddrMode != SADDR_MODE_NONE) { pRxBuf->mac.srcPanId = pRxBuf->mac.dstPanId = BUILD_UINT16(p[0], p[1]); p += MAC_PAN_ID_FIELD_LEN; if (dstAddrMode == SADDR_MODE_EXT) { sAddrExtCpy(pRxBuf->mac.dstAddr.addr.extAddr, p); p += MAC_EXT_ADDR_FIELD_LEN; } else { pRxBuf->mac.dstAddr.addr.shortAddr = BUILD_UINT16(p[0], p[1]); p += MAC_SHORT_ADDR_FIELD_LEN; } } /* sources address */ srcAddrMode = MAC_SRC_ADDR_MODE(&rxBuf[1]); if (srcAddrMode != SADDR_MODE_NONE) { if (!(pRxBuf->internal.flags & MAC_RX_FLAG_INTRA_PAN)) { pRxBuf->mac.srcPanId = BUILD_UINT16(p[0], p[1]); p += MAC_PAN_ID_FIELD_LEN; } if (srcAddrMode == SADDR_MODE_EXT) { sAddrExtCpy(pRxBuf->mac.srcAddr.addr.extAddr, p); } else { pRxBuf->mac.srcAddr.addr.shortAddr = BUILD_UINT16(p[0], p[1]); } } #ifdef FEATURE_MAC_SECURITY if (MAC_SEC_ENABLED(&rxBuf[1])) { uint8 keyIdMode; if (MAC_FRAME_VERSION(&rxBuf[1]) == 0) { /* MAC_UNSUPPORTED_LEGACY - Cancel the outgoing TX ACK. * It may be too late but we have to try. */ MAC_RADIO_CANCEL_TX_ACK(); /* clean up after unsupported security legacy */ macRxHaltCleanup(); return; } /* Copy addressing fields to RX buffer */ osal_memcpy(pRxBuf->mhr.p, buf, rxNextLen); pRxBuf->mhr.p += rxNextLen; pRxBuf->mhr.len += rxNextLen; /*------------------------------------------------------------------------------- * Prepare for auxiliary security header interrupts. */ /* read out security control field from FIFO (threshold set so bytes are guaranteed to be there) */ MAC_RADIO_READ_RX_FIFO(&securityControl, MAC_SEC_CONTROL_FIELD_LEN); /* Copy security fields to MHR buffer */ *pRxBuf->mhr.p = securityControl; pRxBuf->mhr.p += MAC_SEC_CONTROL_FIELD_LEN; pRxBuf->mhr.len += MAC_SEC_CONTROL_FIELD_LEN; /* store security level and key ID mode */ pRxBuf->sec.securityLevel = SECURITY_LEVEL(securityControl); pRxBuf->sec.keyIdMode = keyIdMode = KEY_IDENTIFIER_MODE(securityControl); /* Corrupted RX frame, should never occur. */ if ((keyIdMode > MAC_KEY_ID_MODE_8) /* Get the next RX length according to AuxLen table minus security control field. * The security control length is counted already. */ || ((macKeySourceLen[keyIdMode] + MAC_FRAME_COUNTER_LEN) >= rxPayloadLen) /* Security Enabled subfield is one, but the Security Level in the header is zero: * MAC_UNSUPPORTED_SECURITY - Cancel the outgoing TX ACK. */ || (pRxBuf->sec.securityLevel == MAC_SEC_LEVEL_NONE)) { /* It may be too late but we have to try. */ MAC_RADIO_CANCEL_TX_ACK(); /* clean up after unsupported security or corrupted RX frame. */ macRxHaltCleanup(); return; } /* get the next RX length according to AuxLen table minus security control field. * The sceurity control length is counted already. */ rxNextLen = macKeySourceLen[keyIdMode] + MAC_FRAME_COUNTER_LEN; MAC_RADIO_SET_RX_THRESHOLD(rxNextLen); pFuncRxState = &rxSecurityHdrIsr; } else #endif /* MAC_SECURITY */ { /* clear security level */ pRxBuf->sec.securityLevel = MAC_SEC_LEVEL_NONE; /*------------------------------------------------------------------------------- * Prepare for payload interrupts. */ pFuncRxState = &rxPayloadIsr; rxPrepPayload(); } }
/*================================================================================================= * @fn rxStartIsr * * @brief First ISR state for receiving a packet - compute packet length, allocate * buffer, initialize buffer. Acknowledgements are handled immediately without * allocating a buffer. * * @param none * * @return none *================================================================================================= */ static void rxStartIsr(void) { uint8 addrLen; uint8 ackWithPending; uint8 dstAddrMode; uint8 srcAddrMode; uint8 mhrLen = 0; MAC_ASSERT(!macRxActive); /* receive on top of receive */ /* indicate rx is active */ macRxActive = MAC_RX_ACTIVE_STARTED; /* * For bullet proof functionality, need to see if the receiver was just turned off. * The logic to request turning off the receiver, disables interrupts and then checks * the value of macRxActive. If it is TRUE, the receiver will not be turned off. * * There is a small hole though. It's possible to attempt turning off the receiver * in the window from when the receive interrupt fires and the point where macRxActive * is set to TRUE. To plug this hole, the on/off status must be tested *after* * macRxActive has been set. If the receiver is off at this point, there is nothing * in the RX fifo and the receive is simply aborted. * * Also, there are some considerations in case a hard disable just happened. Usually, * the receiver will just be off at this point after a hard disable. The check described * above will account for this case too. However, if a hard disable were immediately * followed by an enable, the receiver would be on. To catch this case, the receive * FIFO is also tested to see if it is empty. Recovery is identical to the other cases. */ if (!macRxOnFlag || MAC_RADIO_RX_FIFO_IS_EMPTY()) { /* reset active flag */ macRxActive = MAC_RX_ACTIVE_NO_ACTIVITY; /* * To be absolutely bulletproof, must make sure no transmit queue'ed up during * the tiny, tiny window when macRxActive was not zero. */ rxPostRxUpdates(); /* return immediately from here */ return; } /* * If interrupts are held off for too long it's possible the previous "transmit done" * callback is pending. If this is the case, it needs to be completed before * continuing with the receive logic. */ MAC_RADIO_FORCE_TX_DONE_IF_PENDING(); /* * It's possible receive logic is still waiting for confirmation of an ACK that went out * for the previous receive. This is OK but the callback needs to be canceled at this point. * That callback execute receive cleanup logic that will run at the completion * of *this* receive. Also, it is important the flag for the outgoing ACK to be cleared. */ MAC_RADIO_CANCEL_ACK_TX_DONE_CALLBACK(); macRxOutgoingAckFlag = 0; /* * Make a module-local copy of macRxFilter. This prevents the selected * filter from changing in the middle of a receive. */ rxFilter = macRxFilter; /*------------------------------------------------------------------------------- * Read initial frame information from FIFO. * * This code is not triggered until the following are in the RX FIFO: * frame length - one byte containing length of MAC frame (excludes this field) * frame control field - two bytes defining frame type, addressing fields, control flags * sequence number - one byte unique sequence identifier * additional two bytes - these bytes are available in case the received frame is an ACK, * if so, the frame can be verified and responded to immediately, * if not an ACK, these bytes will be processed normally */ /* read frame length, frame control field, and sequence number from FIFO */ MAC_RADIO_READ_RX_FIFO(rxBuf, MAC_PHY_PHR_LEN + MAC_FCF_FIELD_LEN + MAC_SEQ_NUM_FIELD_LEN); /* bytes to read from FIFO equals frame length minus length of MHR fields just read from FIFO */ rxUnreadLen = (rxBuf[0] & PHY_PACKET_SIZE_MASK) - MAC_FCF_FIELD_LEN - MAC_SEQ_NUM_FIELD_LEN; /* * Workaround for chip bug #1547. The receive buffer can sometimes be corrupted by hardware. * This usually occurs under heavy traffic. If a corrupted receive buffer is detected * the entire receive buffer is flushed. */ if ((rxUnreadLen > (MAC_A_MAX_PHY_PACKET_SIZE - MAC_FCF_FIELD_LEN - MAC_SEQ_NUM_FIELD_LEN)) || (MAC_FRAME_TYPE(&rxBuf[1]) > MAC_FRAME_TYPE_MAX_VALID)) { MAC_RADIO_FLUSH_RX_FIFO(); rxDone(); return; } /*------------------------------------------------------------------------------- * Process ACKs. * * If this frame is an ACK, process it immediately and exit from here. * If this frame is not an ACK and transmit is listening for an ACK, let * the transmit logic know an non-ACK was received so transmit can complete. * * In promiscuous mode ACKs are treated like any other frame. */ if ((MAC_FRAME_TYPE(&rxBuf[1]) == MAC_FRAME_TYPE_ACK) && (rxPromiscuousMode == PROMISCUOUS_MODE_OFF)) { halIntState_t s; uint8 fcsBuf[MAC_FCF_FIELD_LEN]; /* * There are guaranteed to be two unread bytes in the FIFO. By defintion, for ACK frames * these two bytes will be the FCS. */ /* read FCS from FIFO (threshold set so bytes are guaranteed to be there) */ MAC_RADIO_READ_RX_FIFO(fcsBuf, MAC_FCS_FIELD_LEN); /* * This critical section ensures that the ACK timeout won't be triggered in the * middle of receiving the ACK frame. */ HAL_ENTER_CRITICAL_SECTION(s); /* see if transmit is listening for an ACK */ if (macTxActive == MAC_TX_ACTIVE_LISTEN_FOR_ACK) { MAC_ASSERT(pMacDataTx != NULL); /* transmit buffer must be present */ /* record link quality metrics for the receive ACK */ { int8 rssiDbm; uint8 corr; rssiDbm = PROPRIETARY_FCS_RSSI(fcsBuf) + MAC_RADIO_RSSI_OFFSET; MAC_RADIO_RSSI_LNA_OFFSET(rssiDbm); corr = PROPRIETARY_FCS_CORRELATION_VALUE(fcsBuf); pMacDataTx->internal.mpduLinkQuality = macRadioComputeLQI(rssiDbm, corr); pMacDataTx->internal.correlation = corr; pMacDataTx->internal.rssi= rssiDbm; } /* * It's okay if the ACK timeout is triggered here. The callbacks for ACK received * or ACK not received will check "macTxActive" flag before taking any actions. */ HAL_EXIT_CRITICAL_SECTION(s); /* * An ACK was received so transmit logic needs to know. If the FCS failed, * the transmit logic still needs to know. In that case, treat the frame * as a non-ACK to complete the active transmit. */ if (PROPRIETARY_FCS_CRC_OK(fcsBuf)) { /* call transmit logic to indicate ACK was received */ macTxAckReceivedCallback(MAC_SEQ_NUMBER(&rxBuf[1]), MAC_FRAME_PENDING(&rxBuf[1])); } else { macTxAckNotReceivedCallback(); } } else { HAL_EXIT_CRITICAL_SECTION(s); } /* receive is done, exit from here */ rxDone(); return; } else if (macTxActive == MAC_TX_ACTIVE_LISTEN_FOR_ACK) { macTxAckNotReceivedCallback(); } /*------------------------------------------------------------------------------- * Apply filtering. * * For efficiency, see if filtering is even 'on' before processing. Also test * to make sure promiscuous mode is disabled. If promiscuous mode is enabled, * do not apply filtering. */ if ((rxFilter != RX_FILTER_OFF) && !rxPromiscuousMode) { if (/* filter all frames */ (rxFilter == RX_FILTER_ALL) || /* filter non-beacon frames */ ((rxFilter == RX_FILTER_NON_BEACON_FRAMES) && (MAC_FRAME_TYPE(&rxBuf[1]) != MAC_FRAME_TYPE_BEACON)) || /* filter non-command frames */ ((rxFilter == RX_FILTER_NON_COMMAND_FRAMES) && ((MAC_FRAME_TYPE(&rxBuf[1]) != MAC_FRAME_TYPE_COMMAND)))) { /* discard rest of frame */ rxDiscardFrame(); return; } } /*------------------------------------------------------------------------------- * Compute length of addressing fields. Compute payload length. */ /* decode addressing modes */ dstAddrMode = MAC_DEST_ADDR_MODE(&rxBuf[1]); srcAddrMode = MAC_SRC_ADDR_MODE(&rxBuf[1]); /* * Workaround for chip bug #1547. The receive buffer can sometimes be corrupted by hardware. * This usually occurs under heavy traffic. If a corrupted receive buffer is detected * the entire receive buffer is flushed. */ if (macChipVersion == REV_A) { if ((srcAddrMode == ADDR_MODE_RESERVERED) || (dstAddrMode == ADDR_MODE_RESERVERED)) { MAC_RADIO_FLUSH_RX_FIFO(); rxDone(); return; } } /* * Compute the addressing field length. A lookup table based on addressing * mode is used for efficiency. If the source address is present and the * frame is intra-PAN, the PAN Id is not repeated. In this case, the address * length is adjusted to match the smaller length. */ addrLen = macRxAddrLen[dstAddrMode] + macRxAddrLen[srcAddrMode]; if ((srcAddrMode != SADDR_MODE_NONE) && MAC_INTRA_PAN(&rxBuf[1])) { addrLen -= MAC_PAN_ID_FIELD_LEN; } /* * If there are not enough unread bytes to include the computed address * plus FCS field, the frame is corrupted and must be discarded. */ if ((addrLen + MAC_FCS_FIELD_LEN) > rxUnreadLen) { /* discard frame and exit */ rxDiscardFrame(); return; } /* aux security header plus payload length is equal to unread bytes minus * address length, minus the FCS */ rxPayloadLen = rxUnreadLen - addrLen - MAC_FCS_FIELD_LEN; /*------------------------------------------------------------------------------- * Allocate memory for the incoming frame. */ if (MAC_SEC_ENABLED(&rxBuf[1])) { /* increase the allocation size of MAC header for security */ mhrLen = MAC_MHR_LEN; } pRxBuf = (macRx_t *) MEM_ALLOC(sizeof(macRx_t) + mhrLen + rxPayloadLen); if (pRxBuf == NULL) { /* Cancel the outgoing TX ACK */ MAC_RADIO_CANCEL_TX_ACK(); /* buffer allocation failed, discard the frame and exit*/ rxDiscardFrame(); return; } /*------------------------------------------------------------------------------- * Set up to process ACK request. Do not ACK if in promiscuous mode. */ ackWithPending = 0; if (!rxPromiscuousMode) { macRxOutgoingAckFlag = MAC_ACK_REQUEST(&rxBuf[1]); } /*------------------------------------------------------------------------------- * Process any ACK request. */ if (macRxOutgoingAckFlag) { halIntState_t s; /* * This critical section ensures that the callback ISR is initiated within time * to guarantee correlation with the strobe. */ HAL_ENTER_CRITICAL_SECTION(s); /* Do not ack data packet with pending more data */ if( MAC_FRAME_TYPE(&rxBuf[1]) == MAC_FRAME_TYPE_COMMAND ) { if( macRxCheckMACPendingCallback()) { /* Check is any mac data pending for end devices */ ackWithPending = MAC_RX_FLAG_ACK_PENDING; } else { if( macSrcMatchIsEnabled ) { /* When autopend is enabled, check if allpending is set to true */ if( MAC_SrcMatchCheckAllPending() == MAC_AUTOACK_PENDING_ALL_ON ) { ackWithPending = MAC_RX_FLAG_ACK_PENDING; } } else { /* When autopend is disabled, check the application pending callback */ if( macRxCheckPendingCallback() ) { ackWithPending = MAC_RX_FLAG_ACK_PENDING; } } } } if( ackWithPending == MAC_RX_FLAG_ACK_PENDING ) { MAC_RADIO_TX_ACK_PEND(); } else { MAC_RADIO_TX_ACK(); } /* request a callback to macRxAckTxDoneCallback() when the ACK transmit has finished */ MAC_RADIO_REQUEST_ACK_TX_DONE_CALLBACK(); HAL_EXIT_CRITICAL_SECTION(s); } /*------------------------------------------------------------------------------- * Populate the receive buffer going up to high-level. */ /* configure the payload buffer * save MAC header pointer regardless of security status. */ pRxBuf->mhr.p = pRxBuf->msdu.p = (uint8 *) (pRxBuf + 1); pRxBuf->mhr.len = pRxBuf->msdu.len = rxPayloadLen; if (MAC_SEC_ENABLED(&rxBuf[1])) { /* Copy FCF and sequence number to RX buffer */ pRxBuf->mhr.len = MAC_FCF_FIELD_LEN + MAC_SEQ_NUM_FIELD_LEN; osal_memcpy(pRxBuf->mhr.p, &rxBuf[1], pRxBuf->mhr.len); pRxBuf->mhr.p += pRxBuf->mhr.len; } /* set internal values */ pRxBuf->mac.srcAddr.addrMode = srcAddrMode; pRxBuf->mac.dstAddr.addrMode = dstAddrMode; pRxBuf->mac.timestamp = MAC_RADIO_BACKOFF_CAPTURE(); pRxBuf->mac.timestamp2 = MAC_RADIO_TIMER_CAPTURE(); /* Special Case for Enhanced Beacon Request which has a different * frame version */ #ifdef FEATURE_ENHANCED_BEACON if( MAC_FRAME_VERSION(&rxBuf[1]) == 2 ) { pRxBuf->internal.frameType = MAC_FRAME_TYPE_INTERNAL_MAC_VERSION_E | \ MAC_FRAME_TYPE(&rxBuf[1]); } else #endif { pRxBuf->internal.frameType = MAC_FRAME_TYPE(&rxBuf[1]); } pRxBuf->mac.dsn = MAC_SEQ_NUMBER(&rxBuf[1]); pRxBuf->internal.flags = INTERNAL_FCF_FLAGS(&rxBuf[1]) | ackWithPending; /*------------------------------------------------------------------------------- * If the processing the addressing fields does not require more bytes from * the FIFO go directly address processing function. Otherwise, configure * interrupt to jump there once bytes are received. */ if (addrLen == 0) { /* no addressing fields to read, prepare for payload interrupts */ pFuncRxState = &rxPayloadIsr; rxPrepPayload(); } else { /* need to read and process addressing fields, prepare for address interrupt */ rxNextLen = addrLen; if (MAC_SEC_ENABLED(&rxBuf[1])) { /* When security is enabled, read off security control field as well */ MAC_RADIO_SET_RX_THRESHOLD(rxNextLen + MAC_SEC_CONTROL_FIELD_LEN); } else { MAC_RADIO_SET_RX_THRESHOLD(rxNextLen); } pFuncRxState = &rxAddrIsr; } }