/****************************************************************************** * @fn nwk_buildFrame * * @brief Builds an output frame for the port and message enclosed. * This routine prepends the frame header and populates the * frame in the output queue. * * input parameters * @param port - port from application * @param msg - pointer to message from app to be sent * @param len - length of enclosed message * @param hops - number of hops allowed. this is less than MAX_HOPS * whenever the frame is being sent to the AP. this is to * help mitigate the (short) broadcast storms * * output parameters * * @return pointer to frameInfo_t structure created. NULL if there is * no room in output queue. */ frameInfo_t *nwk_buildFrame(uint8_t port, uint8_t *msg, uint8_t len, uint8_t hops) { frameInfo_t *fInfoPtr; if (!(fInfoPtr=nwk_QfindSlot(OUTQ))) { return (frameInfo_t *)NULL; } MRFI_SET_PAYLOAD_LEN(&fInfoPtr->mrfiPkt, len+F_APP_PAYLOAD_OS); PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_ENCRYPT_OS, 0); PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_PORT_OS, port); PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_TRACTID_OS, sTRACTID); while (!(++sTRACTID)) ; /* transaction ID can't be 0 */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_RX_TYPE, sMyRxType); PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_HOP_COUNT, hops); /* reset ack-relevant bits */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_ACK_REQ, 0); PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_ACK_RPLY, 0); /* reset forwarding bit */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_FWD_FRAME, 0); memcpy(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt)+F_APP_PAYLOAD_OS, msg, len); memcpy(MRFI_P_SRC_ADDR(&fInfoPtr->mrfiPkt), sMyAddr, NET_ADDR_SIZE); return fInfoPtr; }
/****************************************************************************** * @fn nwk_sendAckReply * * @brief Send an acknowledgement reply frame. * * input parameters * @param frame - pointer to frame with ack request. * @param port - port on whcih reply expected. * * output parameters * * @return void */ void nwk_sendAckReply(mrfiPacket_t *frame, uint8_t port) { mrfiPacket_t dFrame; uint8_t tid = GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_TRACTID_OS); /* set the type of device sending the frame in the header */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TX_DEVICE, sMyTxType); /* set the listen type of device sending the frame in the header. */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_RX_TYPE, sMyRxType); /* destination address from received frame */ memcpy(MRFI_P_DST_ADDR(&dFrame), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE); /* source address */ memcpy(MRFI_P_SRC_ADDR(&dFrame), sMyAddr, NET_ADDR_SIZE); /* port is the source the Tx port from the connection object */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_PORT_OS, port); /* frame length... */ MRFI_SET_PAYLOAD_LEN(&dFrame,F_APP_PAYLOAD_OS); /* transaction ID taken from source frame */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TRACTID_OS, tid); /* hop count... */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_HOP_COUNT, MAX_HOPS); /* set ACK field */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_RPLY, F_ACK_RPLY_TYPE); PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_REQ, 0); /* This is not a forwarded frame */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_FWD_FRAME, 0); /* Encryption state */ #if !defined(SMPL_SECURE) PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, 0); #else PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, F_ENCRYPT_OS_MSK); nwk_setSecureFrame(&dFrame, 0, 0); #endif MRFI_Transmit(&dFrame, MRFI_TX_TYPE_FORCED); return; }
/****************************************************************************** * @fn nwk_replayFrame * * @brief Deal with hop count on a Range Extender or Access Point replay. * Queue entry usage always left as available when done. * * input parameters * @param pFrameInfo - pointer to frame information structure * * output parameters * * @return void */ void nwk_replayFrame(frameInfo_t *pFrameInfo) { uint8_t hops = GET_FROM_FRAME(MRFI_P_PAYLOAD(&pFrameInfo->mrfiPkt), F_HOP_COUNT); /* if hops are zero, drop frame. othewise send it. */ if (hops--) { PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pFrameInfo->mrfiPkt),F_HOP_COUNT,hops); /* Don't care if the Tx fails because of TO. Either someone else * will retransmit or the application itself will recover. */ #if defined(SMPL_SECURE) /* If the frame was targeted to a NWK port it was decrypted on spec in * the 'dispatchFrame()' method. It must be re-encypted in this case. */ if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&pFrameInfo->mrfiPkt), F_PORT_OS) <= SMPL_PORT_NWK_BCAST) { nwk_setSecureFrame(&pFrameInfo->mrfiPkt, MRFI_GET_PAYLOAD_LEN(&pFrameInfo->mrfiPkt)-F_APP_PAYLOAD_OS, 0); } #endif MRFI_DelayMs(1); nwk_sendFrame(pFrameInfo, MRFI_TX_TYPE_CCA); } else { pFrameInfo->fi_usage = FI_AVAILABLE; } return; }
/****************************************************************************** * @fn send_ping_reply * * @brief Send Frequency application ping reply. * * input parameters * @param frame - pointer to frame from pinger. * * @return FHS_RELEASE unless this isn't an Access Point. In this case for * flow to et this far it is a Range Extender, so replay the frame * by returning FHW_REPLAY */ static fhStatus_t send_ping_reply(mrfiPacket_t *frame) { #ifdef ACCESS_POINT uint8_t msg[FREQ_REQ_PING_FRAME_SIZE]; frameInfo_t *pOutFrame; /* original request with reply bit on */ msg[FB_APP_INFO_OS] = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS) | NWK_APP_REPLY_BIT; msg[FB_TID_OS] = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+FB_TID_OS); pOutFrame = nwk_buildFrame(SMPL_PORT_FREQ, msg, sizeof(msg), MAX_HOPS_FROM_AP); if (pOutFrame) { /* destination address is the source address of the received frame. */ memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE); /* must use transaction ID of source frame */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt), F_TRACTID_OS, (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_TRACTID_OS))); #ifdef SMPL_SECURE nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0); #endif /* SMPL_SECURE */ nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED); } return FHS_RELEASE; #else return FHS_REPLAY; #endif /* ACCESS_POINT */ }
void nwk_SendEmptyPollRspFrame(mrfiPacket_t *frame) { mrfiPacket_t dFrame; uint8_t port = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + M_POLL_PORT_OS); /* set the type of device sending the frame in the header. we know it's an AP */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TX_DEVICE, F_TX_DEVICE_AP); /* set the listen type of device sending the frame in the header. we know it's * an AP is is probably always on...but use the static variable anyway. */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_RX_TYPE, sMyRxType); /* destination address from received frame (polling device) */ memcpy(MRFI_P_DST_ADDR(&dFrame), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE); /* source address */ memcpy(MRFI_P_SRC_ADDR(&dFrame), MRFI_P_PAYLOAD( frame) + F_APP_PAYLOAD_OS + M_POLL_ADDR_OS, NET_ADDR_SIZE); /* port is the port requested */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_PORT_OS, port); /* frame length... */ MRFI_SET_PAYLOAD_LEN(&dFrame, F_APP_PAYLOAD_OS); /* transaction ID... */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TRACTID_OS, sTRACTID); sTRACTID++; /* hop count... */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_HOP_COUNT, MAX_HOPS_FROM_AP); /* Ack fields */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_RPLY, 0); PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_REQ, 0); /* This is logically a forwarded frame */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_FWD_FRAME, F_FRAME_FWD_TYPE); /* Encryption state */ # if !defined(SMPL_SECURE) PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, 0); # else PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, F_ENCRYPT_OS_MSK); nwk_setSecureFrame(&dFrame, 0, 0); # endif MRFI_Transmit(&dFrame, MRFI_TX_TYPE_FORCED); return; }
/****************************************************************************** * @fn nwk_buildAckReqFrame * * @brief Builds an output frame for the port and message enclosed. * This routine prepends the frame header and populates the * frame in the output queue. The frame is set to request that * an ack frame be sent by the peer. * * input parameters * @param port - port from application * @param msg - pointer to message from app to be sent * @param len - length of enclosed message * @param hops - number of hops allowed. this is less than MAX_HOPS * whenever the frame is being sent to the AP. this is to * help mitigate the (short) broadcast storms * @param tid - Transaction ID to insert in NWK header used to match * the ack reply. * * output parameters * * @return pointer to frameInfo_t structure created. NULL if there is * no room in output queue. */ frameInfo_t *nwk_buildAckReqFrame(uint8_t port, uint8_t *msg, uint8_t len, uint8_t hops, volatile uint8_t *tid) { frameInfo_t *fInfoPtr; /* Build a normal frame first. */ if (!(fInfoPtr=nwk_buildFrame(port, msg, len, hops))) { return (frameInfo_t *)NULL; } /* save TID */ *tid = GET_FROM_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_TRACTID_OS); /* Set REQ_ACK bit */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_ACK_REQ, F_ACK_REQ_TYPE); return fInfoPtr; }
/****************************************************************************** * @fn nwk_sendFrame * * @brief Send a frame by copying it to the radio Tx FIFO. * * input parameters * @param pFrameInfo - pointer to frame to be sent * @param txOption - do CCA or force frame out. * * output parameters * * @return SMPL_SUCCESS * SMPL_TX_CCA_FAIL Tx failed because of CCA failure. * Tx FIFO flushed in this case. */ smplStatus_t nwk_sendFrame(frameInfo_t *pFrameInfo, uint8_t txOption) { smplStatus_t rc; /* set the type of device sending the frame in the header */ PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pFrameInfo->mrfiPkt), F_TX_DEVICE, sMyTxType); if (MRFI_TX_RESULT_SUCCESS == MRFI_Transmit(&pFrameInfo->mrfiPkt, txOption)) { rc = SMPL_SUCCESS; } else { /* Tx failed -- probably CCA. free up frame buffer. We do not have NWK * level retries. Let application do it. */ rc = SMPL_TX_CCA_FAIL; } /* TX is done. free up the frame buffer */ pFrameInfo->fi_usage = FI_AVAILABLE; return rc; }
/****************************************************************************** * @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; }