smplStatus_t SMPL_LinkListen(linkID_t *linkID) { uint8_t radioState = MRFI_GetRadioState(); uint16_t i; linkID_t locLinkID; /* Set the context. We want to reject any link frames received if * we're not listening. For example if we're an AP we are in * promiscuous mode and we'll see any broadcast link frames. */ nwk_setListenContext(LINK_LISTEN_ON); NWK_CHECK_FOR_SETRX(radioState); for (i=0; i<LINKLISTEN_POLL_COUNT; ++i) { /* check the semaphore. local port is assigned when the reply is sent. */ if ((locLinkID=nwk_getLocalLinkID())) { break; } NWK_DELAY(LINKLISTEN_POLL_PERIOD_MS); } NWK_CHECK_FOR_RESTORE_STATE(radioState); /* If the listen is terminated without hearing a message and setting a * link ID the listen context must be explicitly turned off. */ if (!(locLinkID)) { nwk_setListenContext(LINK_LISTEN_OFF); return SMPL_TIMEOUT; } *linkID = locLinkID; return SMPL_SUCCESS; }
/****************************************************************************** * @fn nwk_scanForChannels * * @brief Scan for channels by sending a ping frame on each channel in the * channel table and listen for a reply. * * input parameters * @param channels - pointer to area to receive list of channels from which * ping replies were received. * * output parameters * @param channels - populated list of channels. * * @return statuis of operation.. */ uint8_t nwk_scanForChannels(freqEntry_t *channels) { uint8_t msg[FREQ_REQ_PING_FRAME_SIZE], i, num=0, notBcast = 1; addr_t *apAddr, retAddr; uint8_t radioState = MRFI_GetRadioState(); freqEntry_t chan; freqEntry_t curChan; union { ioctlRawSend_t send; ioctlRawReceive_t recv; } ioctl_info; nwk_getChannel(&curChan); /* send to AP. If we don't know AP address, broadcast. */ apAddr = (addr_t *)nwk_getAPAddress(); if (!apAddr) { apAddr = (addr_t *)nwk_getBCastAddress(); notBcast = 0; } for (i=0; i<NWK_FREQ_TBL_SIZE; ++i) { chan.logicalChan = i; nwk_setChannel(&chan); ioctl_info.send.addr = apAddr; ioctl_info.send.msg = msg; ioctl_info.send.len = sizeof(msg); ioctl_info.send.port = SMPL_PORT_FREQ; msg[FB_APP_INFO_OS] = FREQ_REQ_PING; msg[FB_TID_OS] = sTid; SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &ioctl_info.send); ioctl_info.recv.port = SMPL_PORT_FREQ; ioctl_info.recv.msg = msg; ioctl_info.recv.addr = &retAddr; 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)) { /* Once we know the Access Point we're related to we only accept * ping replies from that one. */ if (!notBcast || (notBcast && !memcmp(&retAddr, apAddr, NET_ADDR_SIZE))) { channels[num++].logicalChan = i; } } sTid++; if (num && notBcast) { /* we're done...only one possible channel if we know the AP address. */ break; } /* TODO: process encryption stuff */ } /* reset original channel */ nwk_setChannel(&curChan); return num; }
/************************************************************************************** * @fn SMPL_Receive * * @brief Receive a message from a peer application. * * input parameters * @param lid - Link ID (port) from application * * * output parameters * @param msg - pointer to where received message should be copied. * buffer should be of size == MAX_APP_PAYLOAD * @param len - pointer to receive length of received message * * @return Status of operation. * Caller should not use the value returned in 'len' to decide * whether there is a frame or not. It could be useful to the * Caller to distinguish between no frame and a frame with no data. * For example, in the polling case a frame with no application payload * is the way the AP conveys that there are no frames waiting. * * SMPL_SUCCESS * * SMPL_BAD_PARAM No valid Connection Table entry for Link ID * Data in Connection Table entry bad * SMPL_NO_FRAME No frame received. * SMPL_NO_PAYLOAD Frame received with no payload (not necessarily * an error and could be deduced by application * because the returned length will be 0) * * Polling device only: * * SMPL_TIMEOUT No response from Access Point * SMPL_NO_AP_ADDRESS Access Point address unknown * SMPL_TX_CCA_FAIL Could not send poll frame * SMPL_NOMEM No memory in output frame queue * SMPL_NO_CHANNEL Frequency Agility enabled and could not find channel */ smplStatus_t SMPL_Receive(linkID_t lid, uint8_t *msg, uint8_t *len) { connInfo_t *pCInfo = nwk_getConnInfo(lid); smplStatus_t rc = SMPL_BAD_PARAM; rcvContext_t rcv; if (!pCInfo || ((rc=nwk_checkConnInfo(pCInfo, CHK_RX)) != SMPL_SUCCESS)) { return rc; } rcv.type = RCV_APP_LID; rcv.t.lid = lid; #if defined(RX_POLLS) { uint8_t numChans = 1; #if defined(FREQUENCY_AGILITY) freqEntry_t chans[NWK_FREQ_TBL_SIZE]; uint8_t scannedB4 = 0; #endif do { uint8_t radioState = MRFI_GetRadioState(); /* I'm polling. Do the poll to stimulate the sending of a frame. If the * frame has application length of 0 it means there were no frames. If * no reply is received infer that the channel is changed. We then need * to scan and then retry the poll on each channel returned. */ if (SMPL_SUCCESS != (rc=nwk_poll(pCInfo->portRx, pCInfo->peerAddr))) { /* for some reason couldn't send the poll out. */ return rc; } /* do this before code block below which may reset it. */ numChans--; /* Wait until there's a frame. if the len is 0 then return SMPL_NO_FRAME * to the caller. In the poll case the AP always sends something. */ NWK_CHECK_FOR_SETRX(radioState); NWK_REPLY_DELAY(); NWK_CHECK_FOR_RESTORE_STATE(radioState); /* TODO: deal with pending */ rc = nwk_retrieveFrame(&rcv, msg, len, 0, 0); #if defined(FREQUENCY_AGILITY) if (SMPL_SUCCESS == rc) { /* we received something... */ return (*len) ? SMPL_SUCCESS : SMPL_NO_PAYLOAD; } /* No reply. scan for other channel(s) if we haven't already. Then set * one and try again. */ if (!scannedB4) { numChans = nwk_scanForChannels(chans); scannedB4 = 1; } if (numChans) { nwk_setChannel(&chans[numChans-1]); } #else /* FREQUENCY_AGILITY */ return (*len) ? rc : ((SMPL_SUCCESS == rc) ? SMPL_NO_PAYLOAD : SMPL_TIMEOUT); #endif } while (numChans); } #if defined(FREQUENCY_AGILITY) return SMPL_NO_CHANNEL; #endif #else /* RX_POLLS */ return nwk_retrieveFrame(&rcv, msg, len, 0, 0); #endif /* RX_POLLS */ }
/****************************************************************************** * @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); } }
smplStatus_t nwk_link(linkID_t *lid) { uint8_t msg[LINK_FRAME_SIZE]; connInfo_t *pCInfo = nwk_getNextConnection(); smplStatus_t rc; if (pCInfo) { addr_t addr; union { ioctlRawSend_t send; ioctlRawReceive_t recv; } ioctl_info; if (!nwk_allocateLocalRxPort(LINK_SEND, pCInfo)) { nwk_freeConnection(pCInfo); return SMPL_NOMEM; } memcpy(addr.addr, nwk_getBCastAddress(), NET_ADDR_SIZE); ioctl_info.send.addr = &addr; ioctl_info.send.msg = msg; ioctl_info.send.len = sizeof(msg); ioctl_info.send.port = SMPL_PORT_LINK; /* Put link token in */ nwk_putNumObjectIntoMsg((void *)&sLinkToken, msg + L_LINK_TOKEN_OS, sizeof(sLinkToken)); /* set port to which the remote device should send */ msg[L_RMT_PORT_OS] = pCInfo->portRx; /* set the transaction ID. this allows target to figure out duplicates */ msg[LB_TID_OS] = sTid; /* set my Rx type */ msg[L_MY_RXTYPE_OS] = nwk_getMyRxType(); /* set request byte */ msg[LB_REQ_OS] = LINK_REQ_LINK; /* protocol version number */ msg[L_PROTOCOL_VERSION_OS] = nwk_getProtocolVersion(); #if defined(SMPL_SECURE) 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[L_CTR_OS], 4); #endif if (SMPL_SUCCESS != (rc = SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &ioctl_info.send))) { return rc; } { uint8_t radioState = MRFI_GetRadioState(); ioctl_info.recv.port = SMPL_PORT_LINK; ioctl_info.recv.msg = msg; ioctl_info.recv.addr = (addr_t *)pCInfo->peerAddr; 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)) { uint8_t firstByte = msg[LB_REQ_OS] & (~NWK_APP_REPLY_BIT); /* Sanity check for correct reply frame. Older version * has the length instead of the request as the first byte. */ if ((firstByte != LINK_REQ_LINK) && (firstByte != LINK_REPLY_LEGACY_MSG_LENGTH) ) { /* invalidate connection object */ nwk_freeConnection(pCInfo); return SMPL_NO_LINK; } } else { /* no successful receive */ nwk_freeConnection(pCInfo); return SMPL_TIMEOUT; } pCInfo->connState = CONNSTATE_CONNECTED; pCInfo->portTx = msg[LR_RMT_PORT_OS]; /* link reply returns remote port */ *lid = pCInfo->thisLinkID; /* return our local port number */ /* 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 == msg[LR_MY_RXTYPE_OS]) { 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 - ioctl_info.recv.hopCount; #else pCInfo->hops2target = MAX_HOPS; #endif } #if defined(SMPL_SECURE) nwk_getNumObjectFromMsg((void *)&msg[LR_CTR_OS], (void *)&pCInfo->connRxCTR, 4); #endif } /* guard against duplicates... */ ++sTid; if (!sTid) { sTid = 1; } return SMPL_SUCCESS; } return SMPL_NOMEM; }
smplStatus_t nwk_unlink(linkID_t lid) { uint8_t msg[UNLINK_FRAME_SIZE]; connInfo_t *pCInfo = nwk_getConnInfo(lid); smplStatus_t rc = SMPL_SUCCESS; addr_t addr; union { ioctlRawSend_t send; ioctlRawReceive_t recv; } ioctl_info; /* is there connection info? */ if (!pCInfo || (lid == SMPL_LINKID_USER_UUD)) { return SMPL_BAD_PARAM; } /* set request byte */ msg[LB_REQ_OS] = LINK_REQ_UNLINK; /* set the transaction ID. this allows target to figure out duplicates */ msg[LB_TID_OS] = sTid; /* remote port to be sent in message to help match connection */ msg[UL_RMT_PORT_OS] = pCInfo->portRx; /* setup for ioctl raw I/O */ memcpy(addr.addr, pCInfo->peerAddr, NET_ADDR_SIZE); ioctl_info.send.addr = &addr; ioctl_info.send.msg = msg; ioctl_info.send.len = sizeof(msg); ioctl_info.send.port = SMPL_PORT_LINK; SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &ioctl_info.send); { uint8_t spin = NWK_RX_RETRY_COUNT; uint8_t radioState = MRFI_GetRadioState(); ioctl_info.recv.port = SMPL_PORT_LINK; ioctl_info.recv.msg = msg; ioctl_info.recv.addr = (addr_t *)0; do { 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)) { if ((msg[LB_REQ_OS] & (~NWK_APP_REPLY_BIT)) == LINK_REQ_UNLINK) { rc = (smplStatus_t)msg[ULR_RESULT_OS]; break; } } if (!spin) { rc = SMPL_TIMEOUT; break; } --spin; } while (1); /* it's ok to unconditionally invalidate connection object */ nwk_freeConnection(pCInfo); } return rc; }
/****************************************************************************** * @fn nwk_join * * @brief Join functioanlity for non-AP devices. Send the Join token * and wait for the reply. * * input parameters * * output parameters * * @return Status of operation. */ smplStatus_t nwk_join(void) { uint8_t msg[JOIN_FRAME_SIZE]; uint32_t linkToken; addr_t apAddr; uint8_t radioState = MRFI_GetRadioState(); smplStatus_t rc = SMPL_NO_JOIN; union { ioctlRawSend_t send; ioctlRawReceive_t recv; } ioctl_info; #if defined( FREQUENCY_AGILITY ) uint8_t i, numChan; freqEntry_t channels[NWK_FREQ_TBL_SIZE]; if (!(numChan=nwk_scanForChannels(channels))) { return SMPL_NO_CHANNEL; } for (i=0; i<numChan; ++i) { nwk_setChannel(&channels[i]); #else { #endif ioctl_info.send.addr = (addr_t *)nwk_getBCastAddress(); ioctl_info.send.msg = msg; ioctl_info.send.len = sizeof(msg); ioctl_info.send.port = SMPL_PORT_JOIN; /* Put join token in */ nwk_putNumObjectIntoMsg((void *)&sJoinToken, msg+J_JOIN_TOKEN_OS, sizeof(sJoinToken)); /* set app info byte */ msg[JB_REQ_OS] = JOIN_REQ_JOIN; msg[JB_TID_OS] = sTid; /* Set number of connections supported. Used only by AP if it is * a data hub. */ msg[J_NUMCONN_OS] = NUM_CONNECTIONS; /* protocol version number */ msg[J_PROTOCOL_VERSION_OS] = nwk_getProtocolVersion(); SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &ioctl_info.send); ioctl_info.recv.port = SMPL_PORT_JOIN; ioctl_info.recv.msg = msg; ioctl_info.recv.addr = &apAddr; /* save AP address from reply */ 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)) { uint8_t firstByte = msg[JB_REQ_OS] & (~NWK_APP_REPLY_BIT); /* Sanity check for correct reply frame. Older version * has the length instead of the request as the first byte. */ if ((firstByte == JOIN_REQ_JOIN) || (firstByte == JOIN_REPLY_LEGACY_MSG_LENGTH) ) { /* join reply returns link token */ memcpy(&linkToken, msg+JR_LINK_TOKEN_OS, sizeof(linkToken)); nwk_setLinkToken(linkToken); /* save AP address */ nwk_setAPAddress(&apAddr); sTid++; /* guard against duplicates */ rc = SMPL_SUCCESS; #if defined( FREQUENCY_AGILITY ) break; #endif } } /* TODO: process encryption stuff */ } return rc; } #endif /* ACCESS_POINT */ /****************************************************************************** * @fn nwk_processJoin * * @brief Processes a Join frame. If this is a reply let it go to the * application. Otherwise generate and send the reply. * * input parameters * @param frame - Pointer to Join frame * * output parameters * * @return Keep frame for application, release frame, or replay frame. */ fhStatus_t nwk_processJoin(mrfiPacket_t *frame) { fhStatus_t rc = FHS_RELEASE; uint8_t replyType; /* Make sure this is a reply and see if we sent this. Validate the * packet for reception by client app. */ if (SMPL_MY_REPLY == (replyType=nwk_isValidReply(frame, sTid, JB_REQ_OS, JB_TID_OS))) { /* It's a match and it's a reply. Validate the received packet by * returning a 1 so it can be received by the client app. */ MRFI_PostKillSem(); rc = FHS_KEEP; } #if defined(ACCESS_POINT) else if (SMPL_A_REPLY == replyType) { /* No match. If I'm not an ED this is a reply that should be passed on. */ rc = FHS_REPLAY; } else { /* Send reply if we're an Access Point otherwise ignore the frame. */ if ((SMPL_NOT_REPLY == replyType) && sJoinOK) { handleJoinRequest(frame); } } #elif defined(RANGE_EXTENDER) else {