/****************************************************************************** * @fn nwk_nwkInit * * @brief Initialize NWK conext. * * input parameters * * output parameters * * @return Status of operation. */ smplStatus_t nwk_nwkInit(uint8_t (*f)(linkID_t)) { /* initialize globals */ nwk_globalsInit(); /* initialize frame processing */ nwk_frameInit(f); /* added for CCE port */ memset(sConTable.connStruct, 0, sizeof(sConTable.connStruct)); nwk_QInit(); /* initialize each network application. */ nwk_freqInit(); nwk_pingInit(); nwk_joinInit(f); nwk_mgmtInit(); nwk_linkInit(); nwk_securityInit(); /* set up the last connection as the broadcast port mapped to the broadcast Link ID */ sConTable.connStruct[NUM_CONNECTIONS].isValid = 1; sConTable.connStruct[NUM_CONNECTIONS].hops2target = MAX_HOPS; sConTable.connStruct[NUM_CONNECTIONS].portRx = SMPL_PORT_USER_BCAST; sConTable.connStruct[NUM_CONNECTIONS].portTx = SMPL_PORT_USER_BCAST; sConTable.connStruct[NUM_CONNECTIONS].thisLinkID = SMPL_LINKID_USER_UUD; /* set peer address to broadcast so it is used when Application sends to the broadcast Link ID */ memcpy(sConTable.connStruct[NUM_CONNECTIONS].peerAddr, nwk_getBCastAddress(), NET_ADDR_SIZE); return SMPL_SUCCESS; }
/****************************************************************************** * @fn broadcast_channel_change * * @brief For Access Point only: broadcast a channel change frame. * * input parameters * @param idx - index into channel table of new (logical) channel * * @return none. */ #ifdef ACCESS_POINT #define CC_REDUNDANCY 1 /* Change-channel redundancy count */ static void broadcast_channel_change(uint8_t idx) { ioctlRawSend_t send; uint8_t msg[FREQ_REQ_MOVE_FRAME_SIZE]; uint8_t repeat = CC_REDUNDANCY; if (idx >= NWK_FREQ_TBL_SIZE) { return; } msg[FB_APP_INFO_OS] = FREQ_REQ_MOVE; msg[F_CHAN_OS] = idx; send.addr = (addr_t *)nwk_getBCastAddress(); send.msg = msg; send.len = sizeof(msg); send.port = SMPL_PORT_FREQ; SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &send); /* Redundancy addresses the fact that an RE (or any always-listening * device) might miss the command */ while (repeat--) { NWK_DELAY(250); SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &send); } }
/****************************************************************************** * @fn nwk_nwkInit * * @brief Initialize NWK conext. * * input parameters * * output parameters * * @return Status of operation. */ smplStatus_t nwk_nwkInit(uint8_t (*f)(linkID_t)) { /* Truly ugly initialization because CCE won't initialize properly. Must * skip first const element. Yuk. */ memset((((uint8_t *)&sPersistInfo)+1), 0x0, (sizeof(sPersistInfo)-1)); /* OK. The zeroed elements are set. Now go back and do fixups... */ sPersistInfo.numConnections = SYS_NUM_CONNECTIONS; sPersistInfo.curNextLinkPort = SMPL_PORT_USER_MAX; sPersistInfo.curMaxReplyPort = PORT_BASE_NUMBER; sPersistInfo.nextLinkID = 1; /* initialize globals */ nwk_globalsInit(); /* initialize frame processing */ nwk_frameInit(f); /* initialize queue manager */ nwk_QInit(); /* initialize each network application. */ nwk_freqInit(); nwk_pingInit(); nwk_joinInit(f); nwk_mgmtInit(); nwk_linkInit(); nwk_securityInit(); #ifdef NWK_PLL nwk_PLLInit(); #endif /* set up the last connection as the broadcast port mapped to the broadcast Link ID */ if (CONNSTATE_FREE == sPersistInfo.connStruct[NUM_CONNECTIONS].connState) { sPersistInfo.connStruct[NUM_CONNECTIONS].connState = CONNSTATE_CONNECTED; sPersistInfo.connStruct[NUM_CONNECTIONS].hops2target = MAX_HOPS; sPersistInfo.connStruct[NUM_CONNECTIONS].portRx = SMPL_PORT_USER_BCAST; sPersistInfo.connStruct[NUM_CONNECTIONS].portTx = SMPL_PORT_USER_BCAST; sPersistInfo.connStruct[NUM_CONNECTIONS].thisLinkID = SMPL_LINKID_USER_UUD; /* set peer address to broadcast so it is used when Application sends to the broadcast Link ID */ memcpy(sPersistInfo.connStruct[NUM_CONNECTIONS].peerAddr, nwk_getBCastAddress(), NET_ADDR_SIZE); } return SMPL_SUCCESS; }
static void broadcast_channel_change(uint8_t idx) { ioctlRawSend_t send; uint8_t msg[FREQ_REQ_MOVE_FRAME_SIZE]; if (idx >= NWK_FREQ_TBL_SIZE) { return; } msg[FB_APP_INFO_OS] = FREQ_REQ_MOVE; msg[F_CHAN_OS] = idx; send.addr = (addr_t *)nwk_getBCastAddress(); send.msg = msg; send.len = sizeof(msg); send.port = SMPL_PORT_FREQ; SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &send); }
/****************************************************************************** * @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_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; }
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 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 {