/****************************************************************************** * @fn dispatchFrame * * @brief Received frame looks OK so far. Dispatch to either NWK app by * invoking the handler or the user's app by simply leaving the * frame in the queue and letting the app poll the port. * * input parameters * @param fiPtr - frameInfo_t pointer to received frame * * output parameters * * @return void */ static void dispatchFrame(frameInfo_t *fiPtr) { uint8_t port = GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_PORT_OS); uint8_t nwkAppSize = sizeof(func)/sizeof(func[0]); fhStatus_t rc; linkID_t lid; #if defined(ACCESS_POINT) uint8_t loc; #endif #if !defined(END_DEVICE) uint8_t isForMe; #endif /* be sure it's not an echo... */ if (!memcmp(MRFI_P_SRC_ADDR(&fiPtr->mrfiPkt), sMyAddr, NET_ADDR_SIZE)) { fiPtr->fi_usage = FI_AVAILABLE; return; } /* Make sure encyrption bit conforms to our security support context. */ #if defined(SMPL_SECURE) if (!(GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ENCRYPT_OS))) { /* Encyrption bit is not on when when it should be */ fiPtr->fi_usage = FI_AVAILABLE; return; } #else if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ENCRYPT_OS)) { /* Encyrption bit is on when when it should not be */ fiPtr->fi_usage = FI_AVAILABLE; return; } #endif /* SMPL_SECURE */ /* If it's a network application port dispatch to service routine. Dispose * of frame depending on return code. */ if (port && (port <= nwkAppSize)) { #if defined(SMPL_SECURE) /* Non-connection-based frame. We can decode here if it was encrypted */ if (!nwk_getSecureFrame(&fiPtr->mrfiPkt, MRFI_GET_PAYLOAD_LEN(&fiPtr->mrfiPkt) - F_SEC_CTR_OS, 0)) { fiPtr->fi_usage = FI_AVAILABLE; return; } #endif rc = func[port-1](&fiPtr->mrfiPkt); if (FHS_KEEP == rc) { fiPtr->fi_usage = FI_INUSE_UNTIL_DEL; } #if !defined(END_DEVICE) else if (FHS_REPLAY == rc) { /* an AP or an RE could be relaying a NWK application frame... */ nwk_replayFrame(fiPtr); } #endif else /* rc == FHS_RELEASE (default...) */ { fiPtr->fi_usage = FI_AVAILABLE; } return; } /* sanity check */ else if ((port != SMPL_PORT_USER_BCAST) && ((port < PORT_BASE_NUMBER) || (port > SMPL_PORT_STATIC_MAX))) { /* bogus port. drop frame */ fiPtr->fi_usage = FI_AVAILABLE; return; } /* At this point we know the target is a user app. If this is an end device * and we got this far save the frame and we're done. If we're an AP there * are 3 cases: it's for us, it's for s store-and-forward client, or we need * to replay the frame. If we're and RE and the frame didn't come from an RE * and it's not for us, replay the frame. */ #if defined(END_DEVICE) /* If we're s polling end device we only accept application frames from * the AP. This prevents duplicate reception if we happen to be on when * a linked peer sends. */ #if defined(RX_POLLS) if (F_TX_DEVICE_ED != GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE)) { if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid)) { fiPtr->fi_usage = FI_INUSE_UNTIL_DEL; } else { fiPtr->fi_usage = FI_AVAILABLE; } } else { fiPtr->fi_usage = FI_AVAILABLE; } #else /* it's destined for a user app. */ if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid)) { fiPtr->fi_usage = FI_INUSE_UNTIL_DEL; if (spCallback && spCallback(lid)) { fiPtr->fi_usage = FI_AVAILABLE; return; } } else { fiPtr->fi_usage = FI_AVAILABLE; } #endif /* RX_POLLS */ #else /* END_DEVICE */ /* We have an issue if the frame is broadcast to the UUD port. The AP (or RE) must * handle this frame as if it were the target in case there is an application * running that is listening on that port. But if it's a broadcast it must also be * replayed. It isn't enough just to test for the UUD port because it could be a * directed frame to another device. We must check explicitly for broadcast * destination address. */ isForMe = !memcmp(sMyAddr, MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), NET_ADDR_SIZE); if (isForMe || ((port == SMPL_PORT_USER_BCAST) && !memcmp(nwk_getBCastAddress(), MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), NET_ADDR_SIZE))) { /* The folllowing test will succeed for the UUD port regardless of the * source address. */ if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid)) { /* If this is for the UUD port and we are here then the device is either * an AP or an RE. In either case it must replay the UUD port frame if the * frame is not "for me". But it also must handle it since it could have a * UUD-listening application. Do the reply first and let the subsequent code * correctly set the frame usage state. Note that the routine return can be * from this code block. If not it will drop through to the bottom without * doing a replay. */ /* Do I need to replay it? */ if (!isForMe) { /* must be a broadcast for the UUD port */ nwk_replayFrame(fiPtr); } /* OK. Now I handle it... */ fiPtr->fi_usage = FI_INUSE_UNTIL_DEL; if (spCallback && spCallback(lid)) { fiPtr->fi_usage = FI_AVAILABLE; return; } } else { fiPtr->fi_usage = FI_AVAILABLE; } } #if defined( ACCESS_POINT ) /* Check to see if we need to save this for a S and F client. Otherwise, * if it's not for us, get rid of it. */ else if (nwk_isSandFClient(MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), &loc)) { /* Don't bother if it is a duplicate frame or if it's a forwarded frame * echoed back from an RE. */ if (!isDupSandFFrame(&fiPtr->mrfiPkt) && !(GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_FWD_FRAME)) ) { #if defined(APP_AUTO_ACK) /* Make sure ack request bit is off. Sender will have gone away. */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ACK_REQ, 0); #endif fiPtr->fi_usage = FI_INUSE_UNTIL_FWD; } else { fiPtr->fi_usage = FI_AVAILABLE; } } else if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE) == F_TX_DEVICE_AP) { /* I'm an AP and this frame came from an AP. Don't replay. */ fiPtr->fi_usage = FI_AVAILABLE; } #elif defined( RANGE_EXTENDER ) else if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE) == F_TX_DEVICE_RE) { /* I'm an RE and this frame came from an RE. Don't replay. */ fiPtr->fi_usage = FI_AVAILABLE;//////ojooooo descomentar!!! //nwk_replayFrame(fiPtr);//ojoooooooooo borrar!!! } #endif else { /* It's not for me and I'm either an AP or I'm an RE and the frame * didn't come from an RE. Replay the frame. */ nwk_replayFrame(fiPtr); } #endif /* !END_DEVICE */ return; }
/****************************************************************************** * @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; }
/****************************************************************************** * @fn SMPL_SendOpt * * @brief Send a message to a peer application. * * input parameters * @param lid - Link ID (port) from application * @param msg - pointer to message from app to be sent * @param len - length of enclosed message * @param options - Transmit options (bit map) * * output parameters * * @return Status of operation. On a filaure the frame buffer is discarded * and the Send call must be redone by the app. * SMPL_SUCCESS * SMPL_BAD_PARAM No valid Connection Table entry for Link ID * Data in Connection Table entry bad * No message or message too long * SMPL_NOMEM No room in output frame queue * SMPL_TX_CCA_FAIL CCA failure. * SMPL_NO_ACK If application auto acknowledgement enabled * and no acknowledgement is received */ smplStatus_t SMPL_SendOpt(linkID_t lid, uint8_t *msg, uint8_t len, txOpt_t options) { frameInfo_t *pFrameInfo; connInfo_t *pCInfo = nwk_getConnInfo(lid); smplStatus_t rc = SMPL_BAD_PARAM; uint8_t radioState; uint8_t ackreq = 0; #if defined(ACCESS_POINT) uint8_t loc; #endif radioState = MRFI_GetRadioState(); /* we have the connection info for this Link ID. make sure it is valid. */ if (!pCInfo || ((rc=nwk_checkConnInfo(pCInfo, CHK_TX)) != SMPL_SUCCESS)) { return rc; } /* parameter sanity check... */ if (!msg || (len > MAX_APP_PAYLOAD)) { return rc; } /* Build an outgoing message frame destined for the port from the * connection info using the destination address also from the * connection info. */ if (SMPL_TXOPTION_NONE == options) { pFrameInfo = nwk_buildFrame(pCInfo->portTx, msg, len, pCInfo->hops2target); } #if defined(APP_AUTO_ACK) else if (options & SMPL_TXOPTION_ACKREQ) { if (SMPL_LINKID_USER_UUD != lid) { pFrameInfo = nwk_buildAckReqFrame(pCInfo->portTx, msg, len, pCInfo->hops2target, &pCInfo->ackTID); ackreq = 1; } else { /* can't request an ack on the UUD link ID */ return SMPL_BAD_PARAM; } } #endif /* APP_AUTO_ACK */ else { return SMPL_BAD_PARAM; } if (!pFrameInfo) { return SMPL_NOMEM; } memcpy(MRFI_P_DST_ADDR(&pFrameInfo->mrfiPkt), pCInfo->peerAddr, NET_ADDR_SIZE); #if defined(SMPL_SECURE) { uint32_t *pUL = 0; if (pCInfo->thisLinkID != SMPL_LINKID_USER_UUD) { pUL = &pCInfo->connTxCTR; } nwk_setSecureFrame(&pFrameInfo->mrfiPkt, len, pUL); } #endif /* SMPL_SECURE */ #if defined(ACCESS_POINT) /* If we are an AP trying to send to a polling device, don't do it. * See if the target is a store-and-forward client. */ if (nwk_isSandFClient(MRFI_P_DST_ADDR(&pFrameInfo->mrfiPkt), &loc)) { pFrameInfo->fi_usage = FI_INUSE_UNTIL_FWD; return SMPL_SUCCESS; } else #endif /* ACCESS_POINT */ { rc = nwk_sendFrame(pFrameInfo, MRFI_TX_TYPE_CCA); } #if !defined(APP_AUTO_ACK) /* save a little code space with this #if */ (void) ackreq; /* keep compiler happy */ return rc; #else /* we're done if the send failed or no ack requested. */ if (SMPL_SUCCESS != rc || !ackreq) { return rc; } NWK_CHECK_FOR_SETRX(radioState); NWK_REPLY_DELAY(); NWK_CHECK_FOR_RESTORE_STATE(radioState); { bspIState_t intState; /* If the saved TID hasn't been reset then we never got the ack. */ BSP_ENTER_CRITICAL_SECTION(intState); if (pCInfo->ackTID) { pCInfo->ackTID = 0; rc = SMPL_NO_ACK; } BSP_EXIT_CRITICAL_SECTION(intState); } return rc; #endif /* APP_AUTO_ACK */ }
/****************************************************************************** * @fn smpl_send_join_reply * * @brief Send the Join reply. Include the Link token. If the device is * a polling sleeper put it into the list of store-and-forward * clients. * * input parameters * @param frame - join frame for which a reply is needed...maybe * * output parameters * * @return void */ static void smpl_send_join_reply(mrfiPacket_t *frame) { frameInfo_t *pOutFrame; uint8_t msg[JOIN_REPLY_FRAME_SIZE]; /* Is this a legacy frame? If so continue. Otherwise check verion.*/ if ((MRFI_GET_PAYLOAD_LEN(frame) - F_APP_PAYLOAD_OS) > JOIN_LEGACY_MSG_LENGTH) { /* see if protocol version is correct... */ if (*(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+J_PROTOCOL_VERSION_OS) != nwk_getProtocolVersion()) { /* Accommodation of protocol version differences can be noted or accomplished here. * Otherwise, no match and the board goes back */ return; } } /* see if join token is correct */ { uint32_t jt; nwk_getNumObjectFromMsg(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+J_JOIN_TOKEN_OS, &jt, sizeof(jt)); if (jt != sJoinToken) { return; } } /* send reply with tid, the link token, and the encryption context */ { uint32_t linkToken; nwk_getLinkToken(&linkToken); nwk_putNumObjectIntoMsg((void *)&linkToken, msg+JR_LINK_TOKEN_OS, sizeof(linkToken)); } msg[JR_CRYPTKEY_SIZE_OS] = SEC_CRYPT_KEY_SIZE; msg[JB_REQ_OS] = JOIN_REQ_JOIN | NWK_APP_REPLY_BIT; /* sender's tid... */ msg[JB_TID_OS] = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+JB_TID_OS); if (pOutFrame = nwk_buildFrame(SMPL_PORT_JOIN, msg, sizeof(msg), MAX_HOPS_FROM_AP)) { /* destination address is the source adddress of the received frame. */ memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE); #ifdef AP_IS_DATA_HUB /* if source device supports ED objects save source address to detect duplicate joins */ if (*(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+J_NUMCONN_OS)) { if (nwk_saveJoinedDevice(frame) && spCallback) { spCallback(0); } } #endif } else { /* oops -- no room left for Tx frame. Don't send reply. */ return; } /* If this device polls we need to provide store-and-forward support */ if (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame),F_RX_TYPE) == F_RX_TYPE_POLLS) { uint8_t loc; /* Check duplicate status */ if (!nwk_isSandFClient(MRFI_P_SRC_ADDR(frame), &loc)) { uint8_t *pNumc = &spSandFContext->curNumSFClients; sfClientInfo_t *pClient = &spSandFContext->sfClients[*pNumc]; /* It's not a duplicate. Save it if there's room */ if (*pNumc < NUM_STORE_AND_FWD_CLIENTS) { memcpy(pClient->clientAddr.addr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE); *pNumc = *pNumc + 1; } else { /* No room left. Just return and don't send reply. */ return; } } else { /* We get here if it's a duplicate. We drop through and send reply. * Reset the S&F marker in the Management application -- we should * assume that the Client reset so the TID will be random. If this is * simply a duplicate frame it causes no harm. */ nwk_resetSFMarker(loc); } } #ifdef SMPL_SECURE nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0); #endif /* SMPL_SECURE */ /* It's not S&F or it is but we're OK to send reply. */ nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED); return; }