/******************************************************************************
 * @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;
}
Example #2
0
/******************************************************************************
 * @fn          send_poll_reply
 *
 * @brief       Send reply to polling frame.
 *
 * input parameters
 * @param  frame  - Pointer to frame for which reply required.
 *
 * output parameters
 *
 * @return   void
 */
static void send_poll_reply(mrfiPacket_t *frame)
{
  uint8_t         msgtid = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+MB_TID_OS);
  frameInfo_t    *pOutFrame;
  sfClientInfo_t *pClientInfo;
  uint8_t         loc;

  /* Make sure this guy is really a client. We can tell from the source address. */
  if (!(pClientInfo=nwk_isSandFClient(MRFI_P_SRC_ADDR(frame), &loc)))
  {
    /* TODO: maybe send an error frame? */
    return;
  }

  /* If we have to resync the TID then do it based on the first
   * poll frame we see
  */
  if (!sSFMarker[loc])
  {
    /* If the marker flag is null then it has been initialized, i.e.,
     * there has been a reset. In this case infer that we need to update
     * a (probably) stale last TID. The test will always be true the first
     * time through after a client is established even when an NV restore
     * did not take place but this does no harm.
     */
    pClientInfo->lastTID = msgtid;
    sSFMarker[loc]       = 1;
  }
  /* If we've seen this poll frame before ignore it. Otherwise we
   * may send a stored frame when we shouldn't.
   */
  else if (nwk_checkAppMsgTID(pClientInfo->lastTID, msgtid))
  {
    pClientInfo->lastTID = msgtid;
  }
  else
  {
    return;
  }

  if (pOutFrame = nwk_getSandFFrame(frame, M_POLL_PORT_OS))
  {
    /* We need to adjust the order in the queue in this case. Currently
     * we know it is in the input queue and that this adjustment is safe
     * because we're in an ISR thread. This is a fragile fix, though, and
     * should be revisited when time permits.
     */
    nwk_QadjustOrder(INQ, pOutFrame->orderStamp);

    /* reset hop count... */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt), F_HOP_COUNT, MAX_HOPS_FROM_AP);
    /* It's gonna be a forwarded frame. */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt), F_FWD_FRAME, 0x80);

    nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED);
  }
  else
  {
    nwk_SendEmptyPollRspFrame(frame);
  }

  return;
}
Example #3
0
/******************************************************************************
 * @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 */
}
Example #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;
}