/****************************************************************************** * @fn SMPL_Ioctl * * @brief This routine supplies the SimpliciTI IOCTL support. * * input parameters * @param object - The IOCTL target object * @param action - The IOCTL target action on the object * @param val - pointer to value. exact forn depends on object type. * * output parameters * * @return Status of action. Value depends on object, action, and result. * * SMPL_BAD_PARAM is returned if this API is called before * initialization and the object is not one of * the valid exceptions. */ smplStatus_t SMPL_Ioctl(ioctlObject_t object, ioctlAction_t action, void *val) { smplStatus_t rc; /* if init hasn't occurred see if access is still valid */ if (!sInit_done && !ioctlPreInitAccessIsOK(object)) { return SMPL_BAD_PARAM; } switch (object) { #if defined(EXTENDED_API) case IOCTL_OBJ_TOKEN: { ioctlToken_t *t = (ioctlToken_t *)val; rc = SMPL_SUCCESS; if (TT_LINK == t->tokenType) { if (IOCTL_ACT_SET == action) { nwk_setLinkToken(t->token.linkToken); } else if (IOCTL_ACT_GET == action) { nwk_getLinkToken(&t->token.linkToken); } else { rc = SMPL_BAD_PARAM; } } else if (TT_JOIN == t->tokenType) { if (IOCTL_ACT_SET == action) { nwk_setJoinToken(t->token.joinToken); } else if (IOCTL_ACT_GET == action) { nwk_getJoinToken(&t->token.joinToken); } else { rc = SMPL_BAD_PARAM; } } else { rc = SMPL_BAD_PARAM; } } break; case IOCTL_OBJ_NVOBJ: rc = nwk_NVObj(action, (ioctlNVObj_t *)val); break; #endif /* EXTENDED_API */ case IOCTL_OBJ_CONNOBJ: rc = nwk_connectionControl(action, val); break; case IOCTL_OBJ_ADDR: if ((IOCTL_ACT_GET == action) || (IOCTL_ACT_SET == action)) { rc = nwk_deviceAddress(action, (addr_t *)val); } else { rc = SMPL_BAD_PARAM; } break; case IOCTL_OBJ_RAW_IO: if (IOCTL_ACT_WRITE == action) { rc = nwk_rawSend((ioctlRawSend_t *)val); } else if (IOCTL_ACT_READ == action) { rc = nwk_rawReceive((ioctlRawReceive_t *)val); } else { rc = SMPL_BAD_PARAM; } break; case IOCTL_OBJ_RADIO: rc = nwk_radioControl(action, val); break; #if defined(ACCESS_POINT) case IOCTL_OBJ_AP_JOIN: rc = nwk_joinContext(action); break; #endif #if defined(FREQUENCY_AGILITY) case IOCTL_OBJ_FREQ: rc = nwk_freqControl(action, val); break; #endif case IOCTL_OBJ_FWVER: if (IOCTL_ACT_GET == action) { memcpy(val, nwk_getFWVersion(), SMPL_FWVERSION_SIZE); rc = SMPL_SUCCESS; } else { rc = SMPL_BAD_PARAM; } break; case IOCTL_OBJ_PROTOVER: if (IOCTL_ACT_GET == action) { *((uint8_t *)val) = nwk_getProtocolVersion(); rc = SMPL_SUCCESS; } else { rc = SMPL_BAD_PARAM; } break; default: rc = SMPL_BAD_PARAM; break; } return rc; }
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 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 {
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; }
/****************************************************************************** * @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; }