/****************************************************************************** * @fn isDupSandFFrame * * @brief Have we already stored this frame on behalf of a client? * * input parameters * @param frame - pointer to frame in question * * output parameters * * @return Returns 1 if the frame is a duplicate, otherwise 0. */ uint8_t isDupSandFFrame(mrfiPacket_t *frame) { uint8_t i, plLen = MRFI_GET_PAYLOAD_LEN(frame); frameInfo_t *fiPtr; /* check the input queue for duplicate S&F frame. */ fiPtr = nwk_getQ(INQ); for (i=0; i<SIZE_INFRAME_Q; ++i, fiPtr++) { if (FI_INUSE_UNTIL_FWD == fiPtr->fi_usage) { /* compare everything except the DEVICE INFO byte. */ if (MRFI_GET_PAYLOAD_LEN(&fiPtr->mrfiPkt) == plLen && !memcmp(MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), MRFI_P_DST_ADDR(frame), NET_ADDR_SIZE) && !memcmp(MRFI_P_SRC_ADDR(&fiPtr->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE) && !memcmp(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), MRFI_P_PAYLOAD(frame), 1) && !memcmp(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt)+F_TRACTID_OS, MRFI_P_PAYLOAD(frame)+F_TRACTID_OS, plLen-F_TRACTID_OS) ) { return 1; } } } return 0; }
/****************************************************************************** * @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 mrfiLinkSend * * @brief Send data on the RX link. * * @param pBuf - buffer to be transmitted * * @param len - number of bytes to be transmitted * * @return Return code indicates success or failure of transmit: * MRFI_TX_RESULT_SUCCESS - transmit succeeded * MRFI_TX_RESULT_FAILED - transmit failed because CCA or ACK failed */ uint8 mrfiLinkSend(uint8 *pBuf, uint8 len, uint8 nRetrans) { uint8 v,i,status; v= halIntLock(); MRFI_SET_PAYLOAD_LEN(&pkt, len+2); memcpy(MRFI_P_DST_ADDR(&pkt), dest_addr, 4); memcpy(MRFI_P_SRC_ADDR(&pkt), src_addr, 4); MRFI_P_PAYLOAD(&pkt)[0]= seqSend; MRFI_P_PAYLOAD(&pkt)[1]= MRFI_LINK_DATA; memcpy(MRFI_P_PAYLOAD(&pkt)+2, pBuf, len); halIntUnlock(v); for (i=0;i<nRetrans;i++) { status= MRFI_Transmit(&pkt, MRFI_TX_TYPE_CCA); if (status==MRFI_TX_RESULT_SUCCESS) { if (waitForAck(20)) { seqSend++; break; } else { status= MRFI_TX_RESULT_FAILED; // wait random time if sending is not successful // (20-40 milliseconds) halMcuWaitUs( (20000/255*MRFI_RandomByte()) + 20000 ); } } } return status; }
/****************************************************************************** * @fn change_channel_cmd_is_valid * * @brief Check validity of a change channel command frame. * * input parameters * @param frame - pointer to frame with command context * * @return Returns non-zero if command is valid, otherwise returns 0. * Command is valid if either: * - frame is directed * - frame is from an AP and we know about that AP * * It is possible that either we don't know about an AP or that * we do but this frame comes from another AP in range. */ static uint8_t change_channel_cmd_is_valid(mrfiPacket_t *frame) { uint8_t rc = 0; addr_t const *apAddr; /* If this was a directed frame obey the command. */ if (!memcmp(MRFI_P_DST_ADDR(frame), nwk_getMyAddress(), NET_ADDR_SIZE)) { rc = 1; } else { /* Do we know about an AP? If not assume frame bogus. */ apAddr = nwk_getAPAddress(); if (apAddr) { /* Yes, we know about an AP. Is that who sent it? */ if (!memcmp(apAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE)) { /* OK. We obey. */ rc = 1; } } } return rc; }
/****************************************************************************** * @fn nwk_isConnectionValid * * @brief Do a sanity/validity check on the frame target address by * validating frame against connection info * * input parameters * @param frame - pointer to frame in question * * output parameters * @param lid - link ID of found connection * * @return 0 if connection specified in frame is not valid, otherwise non-zero. */ uint8_t nwk_isConnectionValid(mrfiPacket_t *frame, linkID_t *lid) { uint8_t i; connInfo_t *ptr = sPersistInfo.connStruct; uint8_t port = GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_PORT_OS); for (i=0; i<SYS_NUM_CONNECTIONS; ++i,++ptr) { if (CONNSTATE_CONNECTED == ptr->connState) { /* check port first since we're done if the port is the user bcast port. */ if (port == ptr->portRx) { /* yep...ports match. */ if ((SMPL_PORT_USER_BCAST == port) || !(memcmp(ptr->peerAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE))) { uint8_t rc = 1; /* we're done. */ *lid = ptr->thisLinkID; #ifdef APP_AUTO_ACK /* can't ack the broadcast port... */ if (!(SMPL_PORT_USER_BCAST == port)) { if (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_ACK_REQ)) { /* Ack requested. Send ack now */ nwk_sendAckReply(frame, ptr->portTx); } else if (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_ACK_RPLY)) { /* This is a reply. Signal that it was received by resetting the * saved transaction ID in the connection object if they match. The * main thread is polling this value. The setting here is in the * Rx ISR thread. */ if (ptr->ackTID == GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_TRACTID_OS)) { ptr->ackTID = 0; } /* This causes the frame to be dropped. All ack frames are * dropped. */ rc = 0; } } #endif /* APP_AUTO_ACK */ /* Unconditionally kill the reply delay semaphore. This used to be done * unconditionally in the calling routine. */ MRFI_PostKillSem(); return rc; } } } } /* no matches */ return 0; }
/****************************************************************************** * @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 */ }
/****************************************************************************** * @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_isConnectionValid * * @brief Do a sanity/validity check on the frame target address by * validating frame against connection info * * input parameters * @param frame - pointer to frame in question * * output parameters * @param lid - link ID of found connection * * @return 0 if connection specified in frame is not valid, otherwise non-zero. */ uint8_t nwk_isConnectionValid(mrfiPacket_t *frame, linkID_t *lid) { uint8_t i; connInfo_t *ptr = sConTable.connStruct; uint8_t port = GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_PORT_OS); for (i=0; i<SYS_NUM_CONNECTIONS; ++i,++ptr) { if (ptr->isValid) { /* check port first since we're done if the port is the user bcast port. */ if (port == ptr->portRx) { /* yep...ports match. */ if ((SMPL_PORT_USER_BCAST == port) || !(memcmp(ptr->peerAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE))) { /* we're done. */ *lid = ptr->thisLinkID; return 1; } } } } /* no matches */ return 0; }
/****************************************************************************** * @fn nwk_getSandFFrame * * @brief Get any frame waiting for the client on the port supplied in * the frame payload. * TODO: support returning NWK application frames always. the * port requested in the call should be an user application port. * NWK app ports will never be in the called frame. * TODO: deal with broadcast NWK frames from AP. * * input parameters * @param frame - pointer to frame in question * * output parameters * * @return pointer to frame if there is one, otherwise 0. */ frameInfo_t *nwk_getSandFFrame(mrfiPacket_t *frame, uint8_t osPort) { uint8_t i, port = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+osPort); frameInfo_t *fiPtr; rcvContext_t rcv; rcv.type = RCV_RAW_POLL_FRAME; rcv.t.pkt = frame; /* check the input queue for messages sent by others. */ if (fiPtr=nwk_QfindOldest(INQ, &rcv, USAGE_FWD)) { return fiPtr; } /* Check the output queue to see if we ourselves need to send anything. * TODO: use the cast-out scheme for output queue so this routine finds * the oldest in either queue. */ fiPtr = nwk_getQ(OUTQ); for (i=0; i<SIZE_OUTFRAME_Q; ++i, fiPtr++) { if (FI_INUSE_UNTIL_FWD == fiPtr->fi_usage) { if (!memcmp(MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE)) { if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_PORT_OS) == port) { return fiPtr; } } } } return 0; }
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 sendAck * * @brief Send an acknowledge packet (no payload) * * @param none * * @return none */ static void sendAck(void) { uint8 v; v= halIntLock(); MRFI_SET_PAYLOAD_LEN(&pkt, 2); memcpy(MRFI_P_DST_ADDR(&pkt), dest_addr, 4); memcpy(MRFI_P_SRC_ADDR(&pkt), src_addr, 4); MRFI_P_PAYLOAD(&pkt)[0]= seqRecv; MRFI_P_PAYLOAD(&pkt)[1]= MRFI_LINK_ACK; halIntUnlock(v); MRFI_Transmit(&pkt, MRFI_TX_TYPE_FORCED); }
static void smpl_send_unlink_reply(mrfiPacket_t *frame) { connInfo_t *pCInfo; frameInfo_t *pOutFrame; uint8_t msg[UNLINK_REPLY_FRAME_SIZE]; smplStatus_t rc = SMPL_NO_PEER_UNLINK; /* match the remote port and source address with a connection table entry */ if (pCInfo = nwk_findPeer((addr_t *)MRFI_P_SRC_ADDR(frame), *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + UL_RMT_PORT_OS))) { /* Note we unconditionally free the connection resources */ nwk_freeConnection(pCInfo); rc = SMPL_SUCCESS; } /* set reply bit */ msg[LB_REQ_OS] = LINK_REQ_UNLINK | NWK_APP_REPLY_BIT; /* sender's TID */ msg[LB_TID_OS] = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + LB_TID_OS); /* result of freeing local connection */ msg[ULR_RESULT_OS] = rc; if (pOutFrame = nwk_buildFrame(SMPL_PORT_LINK, msg, sizeof(msg), MAX_HOPS)) { /* 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); # if defined(SMPL_SECURE) nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0); # endif /* SMPL_SECURE */ nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED); } }
/****************************************************************************** * @fn nwk_findAddressMatch * * @brief Used to look for an address match in the Connection table. * Match is based on source address in frame. * * input parameters * @param frame - pointer to frame in question * * output parameters * * @return Returns non-zero if a match is found, otherwise 0. */ uint8_t nwk_findAddressMatch(mrfiPacket_t *frame) { #if NUM_CONNECTIONS > 0 uint8_t i; connInfo_t *ptr = sPersistInfo.connStruct; for (i=0; i<NUM_CONNECTIONS; ++i,++ptr) { if (CONNSTATE_CONNECTED == ptr->connState) { if (!(memcmp(ptr->peerAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE))) { return 1; } } } #endif return 0; }
/****************************************************************************** * @fn nwk_findAddressMatch * * @brief Used to look for a match when a Tx-only device sends to the * Tx-only port. If a match is found the local Rx port will be * substituted for the Tx-only port in the frame so the local * application can receive the payload "normally". Match is based * on source address in frame. * * input parameters * @param frame - pointer to frame in question * * output parameters * * @return Returns pointer to the matching connection info structure if * a match is found, otherwise NULL. */ connInfo_t *nwk_findAddressMatch(mrfiPacket_t *frame) { #if NUM_CONNECTIONS > 0 uint8_t i; connInfo_t *ptr = sConTable.connStruct; for (i=0; i<NUM_CONNECTIONS; ++i,++ptr) { if (ptr->isValid) { if (!(memcmp(ptr->peerAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE))) { return ptr; } } } return (connInfo_t *)0; #else return (connInfo_t *)0; #endif }
/*********************************************************************************** * @fn nwk_findAlreadyJoined * * @brief Used when AP is a data hub to look for an address match in the * Connection table for a device that is already enterd in the joined * state. This means that the Connection Table resource is already * allocated so the link-listen doesn't have to do it again. Match is * based on source address in frame. Thsi shoudl only be called from * the Link-listen context during the link frame reply. * * If found the Connection Table entry is initialized as if it were * found using the nwk_getNextConnection() method. * * input parameters * @param frame - pointer to frame in question * * output parameters * * @return Returns pointer to Connection Table entry if match is found, otherwise * 0. This call will only fail if the Connection Table was full when the * device tried to join initially. */ connInfo_t *nwk_findAlreadyJoined(mrfiPacket_t *frame) { uint8_t i; connInfo_t *ptr = sPersistInfo.connStruct; for (i=0; i<NUM_CONNECTIONS; ++i,++ptr) { /* Look for an entry in the JOINED state */ if (CONNSTATE_JOINED == ptr->connState) { /* Is this it? */ if (!(memcmp(&ptr->peerAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE))) { /* Yes. Initilize tabel entry and return the pointer. */ initializeConnection(ptr); return ptr; } } } /* Nothing found... */ return (connInfo_t *)NULL; }
/****************************************************************************** * @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; }
static uint8_t smpl_send_link_reply(mrfiPacket_t *frame) { #if NUM_CONNECTIONS > 0 frameInfo_t *pOutFrame; connInfo_t *pCInfo; uint8_t remotePort; uint8_t msg[LINK_REPLY_FRAME_SIZE]; /* Is this a legacy frame? If so continue. Otherwise check version.*/ if ((MRFI_GET_PAYLOAD_LEN(frame) - F_APP_PAYLOAD_OS) > LINK_LEGACY_MSG_LENGTH) { /* see if protocol version is correct... */ if (*(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_PROTOCOL_VERSION_OS) != nwk_getProtocolVersion()) { /* Accommodation of protocol version differences can be noted or accomplished here. * This field was also checked in the join transaction but it is checked again here * because that check may not have occurred if thre is no AP in this topology. * Otherwise, no match and the board goes back */ return SENT_NO_REPLY; } } /* see if token is correct */ { uint32_t lt; nwk_getNumObjectFromMsg(MRFI_P_PAYLOAD( frame) + F_APP_PAYLOAD_OS + L_LINK_TOKEN_OS, <, sizeof(lt)); if (lt != sLinkToken) { return SENT_NO_REPLY; } } /* if we get here the token matched. */ /* is this a duplicate request? */ remotePort = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_RMT_PORT_OS); if (pCInfo = nwk_isLinkDuplicate(MRFI_P_SRC_ADDR(frame), remotePort)) { /* resend reply */ msg[LB_REQ_OS] = LINK_REQ_LINK | NWK_APP_REPLY_BIT; /* sender's TID */ msg[LB_TID_OS] = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + LB_TID_OS); /* Send reply with the local port number so the remote device knows where to * send packets. */ msg[LR_RMT_PORT_OS] = pCInfo->portRx; /* put my Rx type in there. used to know how to set hops when sending back. */ msg[LR_MY_RXTYPE_OS] = nwk_getMyRxType(); # if defined(SMPL_SECURE) /* Set the Tx counter value for peer's Rx counter object */ nwk_putNumObjectIntoMsg((void *)&pCInfo->connTxCTR, (void *)&msg[LR_CTR_OS], 4); /* We also need to save the newly generated Rx counter value. */ nwk_getNumObjectFromMsg((void *)(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_CTR_OS), (void *)&pCInfo->connRxCTR, 4); # endif if (pOutFrame = nwk_buildFrame(SMPL_PORT_LINK, msg, sizeof(msg), MAX_HOPS - (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_HOP_COUNT)))) { /* 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); # if defined(SMPL_SECURE) nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0); # endif /* SMPL_SECURE */ nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED); } return SENT_REPLY; } if (!sListenActive) { /* We've checked for duplicate and resent reply. In that case we weren't listening * so just go back`. */ return SENT_NO_REPLY; } /* room to link? */ # if defined(AP_IS_DATA_HUB) pCInfo = nwk_findAlreadyJoined(frame); if (!pCInfo) # endif { pCInfo = nwk_getNextConnection(); } if (pCInfo) { /* yes there's room and it's not a dup. address. */ memcpy(&pCInfo->peerAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE); if (!nwk_allocateLocalRxPort(LINK_REPLY, pCInfo)) { nwk_freeConnection(pCInfo); /* we're done with the packet */ return SENT_REPLY; } /* The local Rx port is the one returned in the connection structure. The * caller is waiting on this to be set. The code here is running in an ISR * thread so the caller will see this change after RETI. */ if (NUM_CONNECTIONS == sNumLinkers) { /* Something is wrong -- no room to stack Link request */ nwk_freeConnection(pCInfo); /* we're done with the packet */ return SENT_REPLY; } sServiceLinkID[sNumLinkers++] = pCInfo->thisLinkID; /* save the remote Tx port */ pCInfo->portTx = remotePort; /* connection is valid... */ pCInfo->connState = CONNSTATE_CONNECTED; /* Set hop count. If it's a polling device set the count to the * distance to the AP. otherwise, set it to the max less the remaining * which will be the path taken for this frame. It will be no worse * then tha max and probably will be better. */ if (F_RX_TYPE_POLLS == *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_MY_RXTYPE_OS)) { /* It polls. so. we'll be sending to the AP which will store the * frame. The AP is only MAX_HOPS_FROM_AP hops away from us. */ pCInfo->hops2target = MAX_HOPS_FROM_AP; } else { /* Can't really use this trick because the device could move. If the * devices are all static this may work unless the initial reception * was marginal. */ # if defined(DEVICE_DOES_NOT_MOVE) pCInfo->hops2target = MAX_HOPS - GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_HOP_COUNT); # else pCInfo->hops2target = MAX_HOPS; # endif } /* Send reply with the local port number so the remote device knows where to * send packets. */ msg[LR_RMT_PORT_OS] = pCInfo->portRx; /* put my Rx type in there. used to know how to set hops when sending back. */ msg[LR_MY_RXTYPE_OS] = nwk_getMyRxType(); msg[LB_REQ_OS] = LINK_REQ_LINK | NWK_APP_REPLY_BIT; /* sender's TID */ msg[LB_TID_OS] = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + LB_TID_OS); # if defined(SMPL_SECURE) nwk_getNumObjectFromMsg((void *)(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_CTR_OS), (void *)&pCInfo->connRxCTR, 4); pCInfo->connTxCTR = MRFI_RandomByte() | \ ((uint32_t)(MRFI_RandomByte()) << 8) | \ ((uint32_t)(MRFI_RandomByte()) << 16) | \ ((uint32_t)(MRFI_RandomByte()) << 24); nwk_putNumObjectIntoMsg((void *)&pCInfo->connTxCTR, (void *)&msg[LR_CTR_OS], 4); # endif if (pOutFrame = nwk_buildFrame(SMPL_PORT_LINK, msg, sizeof(msg), MAX_HOPS - (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_HOP_COUNT)))) { /* 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); # if defined(SMPL_SECURE) nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0); # endif if (SMPL_SUCCESS != nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED)) { /* better release the connection structure */ nwk_freeConnection(pCInfo); } } else { /* better release the connection structure */ nwk_freeConnection(pCInfo); } } /* we're done with the packet */ return SENT_REPLY; #else return SENT_NO_REPLY; #endif /* NUM_CONNECTIONS */ }
/****************************************************************************** * @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 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; }
smplStatus_t nwk_ping(linkID_t lid) { connInfo_t *pCInfo = nwk_getConnInfo(lid); smplStatus_t rc = SMPL_BAD_PARAM; uint8_t done = 0; uint8_t repeatIt = 2; uint8_t msg[MAX_PING_APP_FRAME]; uint8_t radioState = MRFI_GetRadioState(); union { ioctlRawSend_t send; ioctlRawReceive_t recv; } ioctl_info; if (!pCInfo || (SMPL_LINKID_USER_UUD == lid)) { /* either link ID bogus or tried to ping the unconnected user datagram link ID. */ return rc; } do { #if defined(FREQUENCY_AGILITY) && !defined(ACCESS_POINT) uint8_t i, numChan; freqEntry_t channels[NWK_FREQ_TBL_SIZE]; if (repeatIt == 2) { /* If FA enabled, first time through set up so that the 'for' * loop checks the current channel. This saves time (no scan) * and is very likely to succeed. Populate the proper strucure. */ SMPL_Ioctl(IOCTL_OBJ_FREQ, IOCTL_ACT_GET, channels); numChan = 1; } else { /* If we get here we must scan for the channel we're now on */ if (!(numChan = nwk_scanForChannels(channels))) { return SMPL_NO_CHANNEL; } } /* Either we scan next time through or we're done */ repeatIt--; /* this loop Pings on each channel (probably only 1) looking * for peer. */ for (i = 0; i < numChan && !done; ++i) { nwk_setChannel(&channels[i]); #else { repeatIt = 0; #endif /* defined(FREQUENCY_AGILITY) && !defined(ACCESS_POINT) */ ioctl_info.send.addr = (addr_t *)pCInfo->peerAddr; ioctl_info.send.msg = msg; ioctl_info.send.len = sizeof(msg); ioctl_info.send.port = SMPL_PORT_PING; /* fill in msg */ msg[PB_REQ_OS] = PING_REQ_PING; msg[PB_TID_OS] = sTid; SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &ioctl_info.send); ioctl_info.recv.port = SMPL_PORT_PING; ioctl_info.recv.msg = msg; ioctl_info.recv.addr = 0; NWK_CHECK_FOR_SETRX(radioState); NWK_REPLY_DELAY(); NWK_CHECK_FOR_RESTORE_STATE(radioState); if (SMPL_SUCCESS == SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_READ, &ioctl_info.recv)) { repeatIt = 0; done = 1; sTid++; /* guard against duplicates */ } } } while (repeatIt); return done ? SMPL_SUCCESS : SMPL_TIMEOUT; } /****************************************************************************** * @fn smpl_send_ping_reply * * @brief Send a reply to a ping request. * * input parameters * @param frame - pointer to frame containing request * * output parameters * * @return void */ static void smpl_send_ping_reply(mrfiPacket_t *frame) { frameInfo_t *pOutFrame; /* Build the reply frame. The application payload is the one included in the * received frame payload. */ if (pOutFrame = nwk_buildFrame(SMPL_PORT_PING, MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS, MRFI_GET_PAYLOAD_LEN(frame) - F_APP_PAYLOAD_OS, MAX_HOPS)) { /* 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); /* turn on the reply bit in the application payload */ *(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt) + F_APP_PAYLOAD_OS + PB_REQ_OS) |= NWK_APP_REPLY_BIT; #ifdef SMPL_SECURE nwk_setSecureFrame(&pOutFrame->mrfiPkt, MRFI_GET_PAYLOAD_LEN(frame) - F_APP_PAYLOAD_OS, 0); #endif /* SMPL_SECURE */ nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED); } }
/****************************************************************************** * @fn nwk_QfindOldest * * @brief Look through frame queue and find the oldest available frame * in the context in question. Supports connection-based (user), * non-connection based (NWK applications), and the special case * of store-and-forward. * * input parameters * @param which - INQ or OUTQ to adjust * @param rcvContext - context information for finding the oldest * @param usage - normal usage or store-and-forward usage * * output parameters * * @return Pointer to frame that is the oldsest on the requested port, or * 0 if there are none. */ frameInfo_t *nwk_QfindOldest(uint8_t which, rcvContext_t *rcv, uint8_t fi_usage) { uint8_t i, oldest, num, port; uint8_t uType, addr12Compare; bspIState_t intState; frameInfo_t *fPtr = 0, *wPtr; connInfo_t *pCInfo = 0; uint8_t *pAddr1, *pAddr2, *pAddr3 = 0; if (INQ == which) { wPtr = sInFrameQ; num = SIZE_INFRAME_Q; oldest = SIZE_INFRAME_Q+1; } else { /* pFI = sOutFrameQ; */ /* num = SIZE_OUTFRAME_Q; */ return 0; } if (RCV_APP_LID == rcv->type) { pCInfo = nwk_getConnInfo(rcv->t.lid); if (!pCInfo) { return (frameInfo_t *)0; } port = pCInfo->portRx; pAddr2 = pCInfo->peerAddr; } else if (RCV_NWK_PORT == rcv->type) { port = rcv->t.port; } #ifdef ACCESS_POINT else if (RCV_RAW_POLL_FRAME == rcv->type) { port = *(MRFI_P_PAYLOAD(rcv->t.pkt)+F_APP_PAYLOAD_OS+M_POLL_PORT_OS); pAddr2 = MRFI_P_SRC_ADDR(rcv->t.pkt); pAddr3 = MRFI_P_PAYLOAD(rcv->t.pkt)+F_APP_PAYLOAD_OS+M_POLL_ADDR_OS; } #endif else { return (frameInfo_t *)0; } uType = (USAGE_NORMAL == fi_usage) ? FI_INUSE_UNTIL_DEL : FI_INUSE_UNTIL_FWD; for (i=0; i<num; ++i, ++wPtr) { BSP_ENTER_CRITICAL_SECTION(intState); /* protect the frame states */ /* only check entries in use and waiting for this port */ if (uType == wPtr->fi_usage) { wPtr->fi_usage = FI_INUSE_TRANSITION; BSP_EXIT_CRITICAL_SECTION(intState); /* release hold */ /* message sent to this device? */ if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&wPtr->mrfiPkt), F_PORT_OS) == port) { /* Port matches. If the port of interest is a NWK applicaiton we're a * match...the NWK applications are not connection-based. If it is a * NWK application we need to check the source address for disambiguation. * Also need to check source address if it's a raw frame lookup (S&F frame) */ if (RCV_APP_LID == rcv->type) { if (SMPL_PORT_USER_BCAST == port) { /* guarantee a match... */ pAddr1 = pCInfo->peerAddr; } else { pAddr1 = MRFI_P_SRC_ADDR(&wPtr->mrfiPkt); } } #ifdef ACCESS_POINT else if (RCV_RAW_POLL_FRAME == rcv->type) { pAddr1 = MRFI_P_DST_ADDR(&wPtr->mrfiPkt); } #endif addr12Compare = memcmp(pAddr1, pAddr2, NET_ADDR_SIZE); if ( (RCV_NWK_PORT == rcv->type) || (!pAddr3 && !addr12Compare) || (pAddr3 && !memcmp(pAddr3, MRFI_P_SRC_ADDR(&wPtr->mrfiPkt), NET_ADDR_SIZE)) ) { if (wPtr->orderStamp < oldest) { if (fPtr) { /* restore previous oldest one */ fPtr->fi_usage = uType; } oldest = wPtr->orderStamp; fPtr = wPtr; continue; } else { /* not oldest. restore state */ wPtr->fi_usage = uType; } } else { /* not a match. restore state */ wPtr->fi_usage = uType; } } else { /* wrong port. restore state */ wPtr->fi_usage = uType; } } else { BSP_EXIT_CRITICAL_SECTION(intState); } } return fPtr; }
/****************************************************************************** * @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; }