/****************************************************************************** * @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 */ }
smplStatus_t nwk_rawSend(ioctlRawSend_t *info) { frameInfo_t *pOutFrame; uint8_t hops; /* If we know frame is going to or from the AP then we can reduce the hop * count. */ switch (info->port) { case SMPL_PORT_JOIN: case SMPL_PORT_FREQ: case SMPL_PORT_MGMT: hops = MAX_HOPS_FROM_AP; break; default: hops = MAX_HOPS; break; } if (pOutFrame = nwk_buildFrame(info->port, info->msg, info->len, hops)) { memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), info->addr, NET_ADDR_SIZE); #ifdef SMPL_SECURE nwk_setSecureFrame(&pOutFrame->mrfiPkt, info->len, 0); #endif /* SMPL_SECURE */ return nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_CCA); } return SMPL_NOMEM; }
/****************************************************************************** * @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_rawSend * * @brief Builds an outut frame based on information provided by the * caller. This function allows a raw transmission to the target * if the network address is known. this function is used a lot * to support NWK applications. * * input parameters * @param info - pointer to strcuture containing info on how to build * the outgoing frame. * output parameters * * @return SMPL_SUCCESS * SMPL_NOMEM - no room in output frame queue * SMPL_TX_CCA_FAIL - CCA failure */ smplStatus_t nwk_rawSend(ioctlRawSend_t *info) { frameInfo_t *pOutFrame; uint8_t hops; /* If we know frame is going to or from the AP then we can reduce the hop * count. */ switch (info->port) { case SMPL_PORT_JOIN: case SMPL_PORT_FREQ: case SMPL_PORT_MGMT: hops = MAX_HOPS_FROM_AP; break; default: hops = MAX_HOPS; break; } if ((pOutFrame = nwk_buildFrame(info->port, info->msg, info->len, hops))) { #ifdef NWK_PLL // get access to the packet data void* pkt = MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt)+F_APP_PAYLOAD_OS; // get a data logging command const uint8_t cmd = ( pll_cmd_LocateReference | pll_cmd_LocateResponse | pll_cmd_PumpRequest | pll_cmd_PumpResponse ); if( info->port == SMPL_PORT_PLL // if sending to a pll port // and its not a data logging packet && ( ((pll_Packet_t*)pkt)->Cmd & cmd ) != cmd ) { // update the transmit time stamp address to point // into where the message was copied to MRFI_SetTxTimeStampAddr( &(((pll_Packet_t*)pkt)->Time) ); } #endif memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), info->addr, NET_ADDR_SIZE); #ifdef SMPL_SECURE nwk_setSecureFrame(&pOutFrame->mrfiPkt, info->len, 0); #endif /* SMPL_SECURE */ return nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_CCA); } return SMPL_NOMEM; }
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 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 */ }
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); } }
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 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; }