/******************************************************************************
 * @fn          nwk_buildFrame
 *
 * @brief       Builds an output frame for the port and message enclosed.
 *              This routine prepends the frame header and populates the
 *              frame in the output queue.
 *
 * input parameters
 * @param   port    - port from application
 * @param   msg     - pointer to message from app to be sent
 * @param   len     - length of enclosed message
 * @param   hops    - number of hops allowed. this is less than MAX_HOPS
 *                    whenever the frame is being sent to the AP. this is to
 *                    help mitigate the (short) broadcast storms
 *
 * output parameters
 *
 * @return   pointer to frameInfo_t structure created. NULL if there is
 *           no room in output queue.
 */
frameInfo_t *nwk_buildFrame(uint8_t port, uint8_t *msg, uint8_t len, uint8_t hops)
{
  frameInfo_t  *fInfoPtr;

  if (!(fInfoPtr=nwk_QfindSlot(OUTQ)))
  {
    return (frameInfo_t *)NULL;
  }

  MRFI_SET_PAYLOAD_LEN(&fInfoPtr->mrfiPkt, len+F_APP_PAYLOAD_OS);

  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_ENCRYPT_OS, 0);
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_PORT_OS, port);
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_TRACTID_OS, sTRACTID);
  while (!(++sTRACTID)) ;  /* transaction ID can't be 0 */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_RX_TYPE, sMyRxType);
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_HOP_COUNT, hops);

  /* reset ack-relevant bits */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_ACK_REQ, 0);
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_ACK_RPLY, 0);

  /* reset forwarding bit */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_FWD_FRAME, 0);

  memcpy(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt)+F_APP_PAYLOAD_OS, msg, len);
  memcpy(MRFI_P_SRC_ADDR(&fInfoPtr->mrfiPkt), sMyAddr, NET_ADDR_SIZE);

  return fInfoPtr;
}
/******************************************************************************
 * @fn          nwk_sendAckReply
 *
 * @brief       Send an acknowledgement reply frame.
 *
 * input parameters
 * @param   frame   - pointer to frame with ack request.
 * @param   port    - port on whcih reply expected.
 *
 * output parameters
 *
 * @return      void
 */
void nwk_sendAckReply(mrfiPacket_t *frame, uint8_t port)
{
  mrfiPacket_t dFrame;
  uint8_t      tid = GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_TRACTID_OS);

  /* set the type of device sending the frame in the header */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TX_DEVICE, sMyTxType);

  /* set the listen type of device sending the frame in the header. */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_RX_TYPE, sMyRxType);

  /* destination address from received frame */
  memcpy(MRFI_P_DST_ADDR(&dFrame), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);

  /* source address */
  memcpy(MRFI_P_SRC_ADDR(&dFrame), sMyAddr, NET_ADDR_SIZE);

  /* port is the source the Tx port from the connection object */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_PORT_OS, port);

  /* frame length... */
  MRFI_SET_PAYLOAD_LEN(&dFrame,F_APP_PAYLOAD_OS);

  /* transaction ID taken from source frame */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TRACTID_OS, tid);

  /* hop count... */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_HOP_COUNT, MAX_HOPS);

  /* set ACK field */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_RPLY, F_ACK_RPLY_TYPE);
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_REQ, 0);

   /* This is not a forwarded frame */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_FWD_FRAME, 0);

  /* Encryption state */
#if !defined(SMPL_SECURE)
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, 0);
#else
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, F_ENCRYPT_OS_MSK);
  nwk_setSecureFrame(&dFrame, 0, 0);
#endif

  MRFI_Transmit(&dFrame, MRFI_TX_TYPE_FORCED);

  return;
}
/******************************************************************************
 * @fn          nwk_replayFrame
 *
 * @brief       Deal with hop count on a Range Extender or Access Point replay.
 *              Queue entry usage always left as available when done.
 *
 * input parameters
 * @param   pFrameInfo   - pointer to frame information structure
 *
 * output parameters
 *
 * @return      void
 */
void nwk_replayFrame(frameInfo_t *pFrameInfo)
{
  uint8_t  hops = GET_FROM_FRAME(MRFI_P_PAYLOAD(&pFrameInfo->mrfiPkt), F_HOP_COUNT);

  /* if hops are zero, drop frame. othewise send it. */
  if (hops--)
  {
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pFrameInfo->mrfiPkt),F_HOP_COUNT,hops);
    /* Don't care if the Tx fails because of TO. Either someone else
     * will retransmit or the application itself will recover.
     */
#if defined(SMPL_SECURE)
    /* If the frame was targeted to a NWK port it was decrypted on spec in
     * the 'dispatchFrame()' method. It must be re-encypted in this case.
     */
    if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&pFrameInfo->mrfiPkt), F_PORT_OS) <= SMPL_PORT_NWK_BCAST)
    {
      nwk_setSecureFrame(&pFrameInfo->mrfiPkt, MRFI_GET_PAYLOAD_LEN(&pFrameInfo->mrfiPkt)-F_APP_PAYLOAD_OS, 0);
    }
#endif
    MRFI_DelayMs(1);
    nwk_sendFrame(pFrameInfo, MRFI_TX_TYPE_CCA);
  }
  else
  {
    pFrameInfo->fi_usage = FI_AVAILABLE;
  }
  return;
}
/******************************************************************************
 * @fn          send_ping_reply
 *
 * @brief       Send Frequency application ping reply.
 *
 * input parameters
 * @param   frame     - pointer to frame from pinger.
 *
 * @return   FHS_RELEASE unless this isn't an Access Point. In this case for
 *           flow to et this far it is a Range Extender, so replay the frame
 *           by returning FHW_REPLAY
 */
static fhStatus_t send_ping_reply(mrfiPacket_t *frame)
{
#ifdef ACCESS_POINT
  uint8_t      msg[FREQ_REQ_PING_FRAME_SIZE];
  frameInfo_t *pOutFrame;

  /* original request with reply bit on */
  msg[FB_APP_INFO_OS] = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS) | NWK_APP_REPLY_BIT;
  msg[FB_TID_OS]      = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+FB_TID_OS);

  pOutFrame = nwk_buildFrame(SMPL_PORT_FREQ, msg, sizeof(msg), MAX_HOPS_FROM_AP);
  if (pOutFrame)
  {
    /* destination address is the source address of the received frame. */
    memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);
    /* must use transaction ID of source frame */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt), F_TRACTID_OS, (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_TRACTID_OS)));
#ifdef SMPL_SECURE
    nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0);
#endif  /* SMPL_SECURE */
    nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED);
  }

  return FHS_RELEASE;
#else
  return FHS_REPLAY;
#endif  /* ACCESS_POINT */
}
Beispiel #5
0
void nwk_SendEmptyPollRspFrame(mrfiPacket_t *frame)
{
    mrfiPacket_t dFrame;
    uint8_t port = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + M_POLL_PORT_OS);

    /* set the type of device sending the frame in the header. we know it's an AP */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TX_DEVICE, F_TX_DEVICE_AP);

    /* set the listen type of device sending the frame in the header. we know it's
     * an AP is is probably always on...but use the static variable anyway.
     */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_RX_TYPE, sMyRxType);
    /* destination address from received frame (polling device) */
    memcpy(MRFI_P_DST_ADDR(&dFrame), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);
    /* source address */
    memcpy(MRFI_P_SRC_ADDR(&dFrame), MRFI_P_PAYLOAD(
               frame) + F_APP_PAYLOAD_OS + M_POLL_ADDR_OS, NET_ADDR_SIZE);
    /* port is the port requested */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_PORT_OS, port);
    /* frame length... */
    MRFI_SET_PAYLOAD_LEN(&dFrame, F_APP_PAYLOAD_OS);
    /* transaction ID... */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TRACTID_OS, sTRACTID);
    sTRACTID++;
    /* hop count... */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_HOP_COUNT, MAX_HOPS_FROM_AP);

    /* Ack fields */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_RPLY, 0);
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_REQ, 0);

    /* This is logically a forwarded frame */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_FWD_FRAME, F_FRAME_FWD_TYPE);

    /* Encryption state */
#        if !defined(SMPL_SECURE)
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, 0);
#        else
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, F_ENCRYPT_OS_MSK);
    nwk_setSecureFrame(&dFrame, 0, 0);
#        endif

    MRFI_Transmit(&dFrame, MRFI_TX_TYPE_FORCED);

    return;
}
/******************************************************************************
 * @fn          nwk_buildAckReqFrame
 *
 * @brief       Builds an output frame for the port and message enclosed.
 *              This routine prepends the frame header and populates the
 *              frame in the output queue. The frame is set to request that
 *              an ack frame be sent by the peer.
 *
 * input parameters
 * @param   port    - port from application
 * @param   msg     - pointer to message from app to be sent
 * @param   len     - length of enclosed message
 * @param   hops    - number of hops allowed. this is less than MAX_HOPS
 *                    whenever the frame is being sent to the AP. this is to
 *                    help mitigate the (short) broadcast storms
 * @param   tid     - Transaction ID to insert in NWK header used to match
 *                    the ack reply.
 *
 * output parameters
 *
 * @return   pointer to frameInfo_t structure created. NULL if there is
 *           no room in output queue.
 */
frameInfo_t *nwk_buildAckReqFrame(uint8_t port, uint8_t *msg, uint8_t len, uint8_t hops, volatile uint8_t *tid)
{
  frameInfo_t *fInfoPtr;

  /* Build a normal frame first. */
  if (!(fInfoPtr=nwk_buildFrame(port, msg, len, hops)))
  {
    return (frameInfo_t *)NULL;
  }

  /* save TID  */
  *tid = GET_FROM_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_TRACTID_OS);
  /* Set REQ_ACK bit */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fInfoPtr->mrfiPkt), F_ACK_REQ, F_ACK_REQ_TYPE);

  return fInfoPtr;
}
/******************************************************************************
 * @fn          nwk_sendFrame
 *
 * @brief       Send a frame by copying it to the radio Tx FIFO.
 *
 * input parameters
 * @param   pFrameInfo   - pointer to frame to be sent
 * @param   txOption     - do CCA or force frame out.
 *
 * output parameters
 *
 * @return    SMPL_SUCCESS
 *            SMPL_TX_CCA_FAIL Tx failed because of CCA failure.
 *                             Tx FIFO flushed in this case.
 */
smplStatus_t nwk_sendFrame(frameInfo_t *pFrameInfo, uint8_t txOption)
{
  smplStatus_t rc;

  /* set the type of device sending the frame in the header */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pFrameInfo->mrfiPkt), F_TX_DEVICE, sMyTxType);

  if (MRFI_TX_RESULT_SUCCESS == MRFI_Transmit(&pFrameInfo->mrfiPkt, txOption))
  {
    rc = SMPL_SUCCESS;
  }
  else
  {
    /* Tx failed -- probably CCA. free up frame buffer. We do not have NWK
     * level retries. Let application do it.
     */
    rc = SMPL_TX_CCA_FAIL;
  }

  /* TX is done. free up the frame buffer */
  pFrameInfo->fi_usage = FI_AVAILABLE;

  return rc;
}
/******************************************************************************
 * @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;
}
Beispiel #9
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;
}