/****************************************************************************** * @fn nwk_QfindSlot * * @brief Finds a slot to use to retrieve the frame from the radio. It * uses a LRU cast-out scheme. It is possible that this routine * finds no slot. This can happen if the queue is of size 1 or 2 * and the Rx interrupt occurs during a retrieval call from an * application. There are meta-states for frames as the application * looks for the oldest frame on the port being requested. * * This routine is running in interrupt context. * * input parameters * @param which - INQ or OUTQ to search * * output parameters * * @return Pointer to oldest available frame in the queue */ frameInfo_t *nwk_QfindSlot(uint8_t which) { frameInfo_t *pFI, *oldest= 0, *newFI = 0; uint8_t i, num, newOrder = 0, orderTest; if (INQ == which) { pFI = sInFrameQ; num = SIZE_INFRAME_Q; } else { pFI = sOutFrameQ; num = SIZE_OUTFRAME_Q; } orderTest = num + 1; for (i=0; i<num; ++i, ++pFI) { /* if frame is available it's a candidate. */ if (pFI->fi_usage != FI_AVAILABLE) { if (INQ == which) /* TODO: do cast-out for Tx as well */ { /* need to know the number of occupied slots so we know the age value * for the unoccupied slot (if there is one). */ newOrder++; /* make sure nwk_retrieveFrame() is not processing this frame */ if (FI_INUSE_TRANSITION == pFI->fi_usage) { continue; } /* is this frame older than any we've seen? */ if (orderTest > pFI->orderStamp) { /* yes. */ oldest = pFI; orderTest = pFI->orderStamp; } } } else { if (OUTQ == which) /* TODO: do cast-out for Tx as well */ { return pFI; } newFI = pFI; } } /* did we find anything? */ if (!newFI) { /* queue was full. cast-out happens here...unless... */ if (!oldest) { /* This can happen if the queue is only of size 1 or 2 and all * the frames are in transition when the Rx interrupt occurs. */ return (frameInfo_t *)0; } newFI = oldest; nwk_QadjustOrder(which, newFI->orderStamp); newFI->orderStamp = i; } else { /* mark the available slot. */ newFI->orderStamp = ++newOrder; } return newFI; }
/****************************************************************************** * @fn nwk_retrieveFrame * * @brief Retrieve frame from Rx frame queue. Invoked by application-level * code either app through SMPL_Receive() or IOCTL through raw Rx. This * should run in a user thread, not an ISR thread. * * input parameters * @param port - port on which to get a frame * * output parameters * @param msg - pointer to where app payload should be copied. Buffer * allocated should be == MAX_APP_PAYLOAD. * * @param len - pointer to where payload length should be stored. Caller * can check for non-zero when polling the port. initialized * to 0 even if no frame is retrieved. * @param srcAddr - if non-NULL, a pointer to where to copy the source address * of the retrieved message. * @param hopCount - if non-NULL, a pointer to where to copy the hop count of the retrieved message. * * @return SMPL_SUCCESS * SMPL_NO_FRAME - no frame found for specified destination * SMPL_BAD_PARAM - no valid connection info for the Link ID * */ smplStatus_t nwk_retrieveFrame(rcvContext_t *rcv, uint8_t *msg, uint8_t *len, addr_t *srcAddr, uint8_t *hopCount) { frameInfo_t *fPtr; uint8_t done; do { /* look for a frame on requested port. */ *len = 0; done = 1; fPtr = nwk_QfindOldest(INQ, rcv, USAGE_NORMAL); if (fPtr) { connInfo_t *pCInfo = 0; if (RCV_APP_LID == rcv->type) { pCInfo = nwk_getConnInfo(rcv->t.lid); if (!pCInfo) { return SMPL_BAD_PARAM; } #if defined(SMPL_SECURE) /* decrypt here...we have all the context we need. */ { uint32_t ctr = pCInfo->connRxCTR; uint32_t *pctr = &ctr; uint8_t len = MRFI_GET_PAYLOAD_LEN(&fPtr->mrfiPkt) - F_SEC_CTR_OS; if (pCInfo->thisLinkID == SMPL_LINKID_USER_UUD) { pctr = NULL; } #if defined(RX_POLLS) else if ((F_APP_PAYLOAD_OS - F_SEC_CTR_OS) == len) { /* This was an empty poll reply frame generated by the AP. * It uses the single-byte CTR value like network applications. * We do not want to use the application layer counter in this case. */ pctr = NULL; } #endif if (nwk_getSecureFrame(&fPtr->mrfiPkt, len, pctr)) { if (pctr) { /* Update connection's counter. */ pCInfo->connRxCTR = ctr; } } else { /* Frame bogus. Check for another frame. */ done = 0; continue; } } #endif /* SMPL_SECURE */ } /* it's on the requested port. */ *len = MRFI_GET_PAYLOAD_LEN(&fPtr->mrfiPkt) - F_APP_PAYLOAD_OS; memcpy(msg, MRFI_P_PAYLOAD(&fPtr->mrfiPkt)+F_APP_PAYLOAD_OS, *len); /* save signal info */ if (pCInfo) { /* Save Rx metrics... */ pCInfo->sigInfo.rssi = fPtr->mrfiPkt.rxMetrics[MRFI_RX_METRICS_RSSI_OFS]; pCInfo->sigInfo.lqi = fPtr->mrfiPkt.rxMetrics[MRFI_RX_METRICS_CRC_LQI_OFS]; } if (srcAddr) { /* copy source address if requested */ memcpy(srcAddr, MRFI_P_SRC_ADDR(&fPtr->mrfiPkt), NET_ADDR_SIZE); } if (hopCount) { /* copy hop count if requested */ *hopCount = GET_FROM_FRAME(MRFI_P_PAYLOAD(&fPtr->mrfiPkt), F_HOP_COUNT); } /* input frame no longer needed. free it. */ nwk_QadjustOrder(INQ, fPtr->orderStamp); fPtr->fi_usage = FI_AVAILABLE; return SMPL_SUCCESS; } } while (!done); return SMPL_NO_FRAME; }
/****************************************************************************** * @fn send_poll_reply * * @brief Send reply to polling frame. * * input parameters * @param frame - Pointer to frame for which reply required. * * output parameters * * @return void */ static void send_poll_reply(mrfiPacket_t *frame) { uint8_t msgtid = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+MB_TID_OS); frameInfo_t *pOutFrame; sfClientInfo_t *pClientInfo; uint8_t loc; /* Make sure this guy is really a client. We can tell from the source address. */ if (!(pClientInfo=nwk_isSandFClient(MRFI_P_SRC_ADDR(frame), &loc))) { /* TODO: maybe send an error frame? */ return; } /* If we have to resync the TID then do it based on the first * poll frame we see */ if (!sSFMarker[loc]) { /* If the marker flag is null then it has been initialized, i.e., * there has been a reset. In this case infer that we need to update * a (probably) stale last TID. The test will always be true the first * time through after a client is established even when an NV restore * did not take place but this does no harm. */ pClientInfo->lastTID = msgtid; sSFMarker[loc] = 1; } /* If we've seen this poll frame before ignore it. Otherwise we * may send a stored frame when we shouldn't. */ else if (nwk_checkAppMsgTID(pClientInfo->lastTID, msgtid)) { pClientInfo->lastTID = msgtid; } else { return; } if (pOutFrame = nwk_getSandFFrame(frame, M_POLL_PORT_OS)) { /* We need to adjust the order in the queue in this case. Currently * we know it is in the input queue and that this adjustment is safe * because we're in an ISR thread. This is a fragile fix, though, and * should be revisited when time permits. */ nwk_QadjustOrder(INQ, pOutFrame->orderStamp); /* reset hop count... */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt), F_HOP_COUNT, MAX_HOPS_FROM_AP); /* It's gonna be a forwarded frame. */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt), F_FWD_FRAME, 0x80); nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED); } else { nwk_SendEmptyPollRspFrame(frame); } return; }