示例#1
0
/******************************************************************************
 * @fn          nwk_QfindSlot
 *
 * @brief       Finds a slot to use to retrieve the frame from the radio. It
 *              uses a LRU cast-out scheme. It is possible that this routine
 *              finds no slot. This can happen if the queue is of size 1 or 2
 *              and the Rx interrupt occurs during a retrieval call from an
 *              application. There are meta-states for frames as the application
 *              looks for the oldest frame on the port being requested.
 *
 *              This routine is running in interrupt context.
 *
 * input parameters
 * @param   which   - INQ or OUTQ to search
 *
 * output parameters
 *
 * @return      Pointer to oldest available frame in the queue
 */
frameInfo_t *nwk_QfindSlot(uint8_t which)
{
  frameInfo_t *pFI, *oldest= 0, *newFI = 0;
  uint8_t        i, num, newOrder = 0, orderTest;

  if (INQ == which)
  {
    pFI  = sInFrameQ;
    num  = SIZE_INFRAME_Q;
  }
  else
  {
    pFI  = sOutFrameQ;
    num  = SIZE_OUTFRAME_Q;
  }

  orderTest = num + 1;

  for (i=0; i<num; ++i, ++pFI)
  {
    /* if frame is available it's a candidate. */
    if (pFI->fi_usage != FI_AVAILABLE)
    {
      if (INQ == which)  /* TODO: do cast-out for Tx as well */
      {

        /* need to know the number of occupied slots so we know the age value
         * for the unoccupied slot (if there is one).
         */
        newOrder++;

        /* make sure nwk_retrieveFrame() is not processing this frame */
        if (FI_INUSE_TRANSITION == pFI->fi_usage)
        {
          continue;
        }
        /* is this frame older than any we've seen? */
        if (orderTest > pFI->orderStamp)
        {
          /* yes. */
          oldest    = pFI;
          orderTest = pFI->orderStamp;
        }
      }
    }
    else
    {
      if (OUTQ == which)  /* TODO: do cast-out for Tx as well */
      {
        return pFI;
      }
      newFI = pFI;
    }
  }

  /* did we find anything? */
  if (!newFI)
  {
    /* queue was full. cast-out happens here...unless... */
    if (!oldest)
    {
      /* This can happen if the queue is only of size 1 or 2 and all
       * the frames are in transition when the Rx interrupt occurs.
       */
      return (frameInfo_t *)0;
    }
    newFI = oldest;
    nwk_QadjustOrder(which, newFI->orderStamp);
    newFI->orderStamp = i;
  }
  else
  {
    /* mark the available slot. */
    newFI->orderStamp = ++newOrder;
  }

  return newFI;
}
/******************************************************************************
 * @fn          nwk_retrieveFrame
 *
 * @brief       Retrieve frame from Rx frame queue. Invoked by application-level
 *              code either app through SMPL_Receive() or IOCTL through raw Rx. This
 *              should run in a user thread, not an ISR thread.
 *
 * input parameters
 * @param    port    - port on which to get a frame
 *
 * output parameters
 * @param    msg     - pointer to where app payload should be copied. Buffer
 *                     allocated should be == MAX_APP_PAYLOAD.
 *
 * @param    len      - pointer to where payload length should be stored. Caller
 *                      can check for non-zero when polling the port. initialized
 *                      to 0 even if no frame is retrieved.
 * @param    srcAddr  - if non-NULL, a pointer to where to copy the source address
 *                      of the retrieved message.
 * @param    hopCount - if non-NULL, a pointer to where to copy the hop count
                        of the retrieved message.
 *
 * @return    SMPL_SUCCESS
 *            SMPL_NO_FRAME  - no frame found for specified destination
 *            SMPL_BAD_PARAM - no valid connection info for the Link ID
 *
 */
smplStatus_t nwk_retrieveFrame(rcvContext_t *rcv, uint8_t *msg, uint8_t *len, addr_t *srcAddr, uint8_t *hopCount)
{
  frameInfo_t *fPtr;
  uint8_t      done;

  do {
    /* look for a frame on requested port. */
    *len = 0;
    done = 1;

    fPtr = nwk_QfindOldest(INQ, rcv, USAGE_NORMAL);
    if (fPtr)
    {
      connInfo_t  *pCInfo = 0;

      if (RCV_APP_LID == rcv->type)
      {
        pCInfo = nwk_getConnInfo(rcv->t.lid);
        if (!pCInfo)
        {
          return SMPL_BAD_PARAM;
        }
#if defined(SMPL_SECURE)
        /* decrypt here...we have all the context we need. */
        {
          uint32_t  ctr  = pCInfo->connRxCTR;
          uint32_t *pctr = &ctr;
          uint8_t   len  = MRFI_GET_PAYLOAD_LEN(&fPtr->mrfiPkt) - F_SEC_CTR_OS;

          if (pCInfo->thisLinkID == SMPL_LINKID_USER_UUD)
          {
            pctr = NULL;
          }
#if defined(RX_POLLS)
          else if ((F_APP_PAYLOAD_OS - F_SEC_CTR_OS) == len)
          {
            /* This was an empty poll reply frame generated by the AP.
             * It uses the single-byte CTR value like network applications.
             * We do not want to use the application layer counter in this case.
             */
            pctr = NULL;
          }
#endif
          if (nwk_getSecureFrame(&fPtr->mrfiPkt, len, pctr))
          {
            if (pctr)
            {
              /* Update connection's counter. */
              pCInfo->connRxCTR = ctr;
            }
          }
          else
          {
            /* Frame bogus. Check for another frame. */
            done = 0;
            continue;
          }
        }
#endif  /* SMPL_SECURE */
      }

      /* it's on the requested port. */
      *len = MRFI_GET_PAYLOAD_LEN(&fPtr->mrfiPkt) - F_APP_PAYLOAD_OS;
      memcpy(msg, MRFI_P_PAYLOAD(&fPtr->mrfiPkt)+F_APP_PAYLOAD_OS, *len);
      /* save signal info */
      if (pCInfo)
      {
        /* Save Rx metrics... */
        pCInfo->sigInfo.rssi = fPtr->mrfiPkt.rxMetrics[MRFI_RX_METRICS_RSSI_OFS];
        pCInfo->sigInfo.lqi  = fPtr->mrfiPkt.rxMetrics[MRFI_RX_METRICS_CRC_LQI_OFS];
      }
      if (srcAddr)
      {
        /* copy source address if requested */
        memcpy(srcAddr, MRFI_P_SRC_ADDR(&fPtr->mrfiPkt), NET_ADDR_SIZE);
      }
      if (hopCount)
      {
        /* copy hop count if requested */
        *hopCount = GET_FROM_FRAME(MRFI_P_PAYLOAD(&fPtr->mrfiPkt), F_HOP_COUNT);
      }
      /* input frame no longer needed. free it. */
      nwk_QadjustOrder(INQ, fPtr->orderStamp);

      fPtr->fi_usage = FI_AVAILABLE;
      return SMPL_SUCCESS;
    }
  } while (!done);

  return SMPL_NO_FRAME;
}
示例#3
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;
}