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, &lt, 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 */
}
Пример #2
0
/******************************************************************************
 * @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;
}
Пример #4
0
/******************************************************************************
 * @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;
}