/*
 * Copyright (c) 2014-2015 2018 The Linux Foundation. All rights reserved.
 *
 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for
 * any purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * This file was originally distributed by Qualcomm Atheros, Inc.
 * under proprietary terms before Copyright ownership was assigned
 * to the Linux Foundation.
 */

/**=============================================================================

  vos_list.c

  \brief

  Description...

  ==============================================================================**/
/* $HEADER$ */

/**-----------------------------------------------------------------------------
  Include files
  ----------------------------------------------------------------------------*/
#include <vos_list.h>
#include <vos_trace.h>

/**-----------------------------------------------------------------------------
  Preprocessor definitions and constants
  ----------------------------------------------------------------------------*/
#define VOS_LIST_COOKIE 0xabadfeed


/**-----------------------------------------------------------------------------
  Type declarations
  ----------------------------------------------------------------------------*/

/**-----------------------------------------------------------------------------
  Function declarations and documenation
  ----------------------------------------------------------------------------*/
VOS_STATUS vos_list_init( vos_list_t *pList )
{
   if ( pList == NULL)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie == VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: already initialized list", __func__);
      return VOS_STATUS_E_BUSY;
   }

   mutex_init(&pList->lock);

   INIT_LIST_HEAD( &pList->anchor );

   pList->count = 0;
   pList->cookie = VOS_LIST_COOKIE;

   return( VOS_STATUS_SUCCESS );
}


VOS_STATUS vos_list_destroy( vos_list_t *pList )
{
   int rc;
   if (pList == NULL)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->count !=0 )
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list length not equal to zero", __func__);
      return VOS_STATUS_E_BUSY;
   }

   // clear the cookie. This indicates the list is destroyed.
   pList->cookie = 0;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}


VOS_STATUS vos_list_insert_front( vos_list_t *pList, vos_list_node_t *pNode )
{
   int rc;

   if ( ( pList == NULL) || ( pNode == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   list_add( pNode, &pList->anchor );

   pList->count++;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

VOS_STATUS vos_list_insert_back( vos_list_t *pList, vos_list_node_t *pNode )
{
   int rc;

   if ( ( pList == NULL) || ( pNode == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   list_add_tail( pNode, &pList->anchor );

   pList->count++;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

VOS_STATUS vos_list_insert_back_no_mutex(vos_list_t *pList,
					 vos_list_node_t *pNode)
{
   if ( ( pList == NULL) || ( pNode == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   list_add_tail( pNode, &pList->anchor );

   pList->count++;

   return VOS_STATUS_SUCCESS;
}


VOS_STATUS vos_list_insert_back_size( vos_list_t *pList, vos_list_node_t *pNode, v_SIZE_t *pSize )
{
   int rc;
   if ( ( pList == NULL) || ( pNode == NULL) || (pSize == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   list_add_tail( pNode, &pList->anchor );

   pList->count++;
   *pSize = pList->count;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}


VOS_STATUS vos_list_remove_front( vos_list_t *pList, vos_list_node_t **ppNode )
{
   struct list_head * listptr;
   int rc;

   // the assumption here is that pList is the head of the list (dummy
   // node) and points to first and last element in circular linked list
   if ( ( pList == NULL ) || ( ppNode == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( list_empty( &pList->anchor ) )
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   listptr = pList->anchor.next;

   *ppNode = listptr;

   list_del(pList->anchor.next);

   pList->count--;
   mutex_unlock(&pList->lock);
   return VOS_STATUS_SUCCESS;
}



VOS_STATUS vos_list_remove_back( vos_list_t *pList, vos_list_node_t **ppNode )
{
   struct list_head * listptr;
   int rc;

   // the assumption here is that pList is the head of the list (dummy node) and points to first and
   // last element in circular linked list
   if ( ( pList == NULL ) || ( ppNode == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( list_empty( &pList->anchor ) )
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   listptr = pList->anchor.prev;

   *ppNode = listptr;

   list_del(pList->anchor.prev);

   pList->count--;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

VOS_STATUS vos_list_size( vos_list_t *pList, v_SIZE_t *pSize )
{
   int rc;
   if ( ( pList ==NULL) || ( pSize == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                 "%s: list not initialized", __func__);
       VOS_ASSERT(0);
       return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   *pSize = pList->count;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

VOS_STATUS vos_list_size_no_mutex( vos_list_t *pList, v_SIZE_t *pSize )
{
   if ( ( pList ==NULL) || ( pSize == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                 "%s: list not initialized", __func__);
       VOS_ASSERT(0);
       return VOS_STATUS_E_INVAL;
   }

   *pSize = pList->count;

   return VOS_STATUS_SUCCESS;
}


/*----------------------------------------------------------------------------

  \brief vos_list_peek_front() - peek at the node at front of a linked list

  The vos_list_peek_front() API will return a pointer to the node at the
  front of a properly initialized vOS List object.  The node will *not* be
  removed from the list.

  \param pList - Pointer to list object of the list to be 'peeked'

  \param ppNode - Pointer to a pointer to the list node that exists at
  the front of the list.

  \return VOS_STATUS_SUCCESS - list node at the front of the list was
          successfully returned.

          VOS_STATUS_E_INVAL - The value specified by pList is not a valid,
          initialized list object.

          VOS_STATUS_E_EMPTY - The specified is empty so nodes cannot be
          removed.

          VOS_STATUS_E_FAULT  - pList or or ppNode is an invalid pointer.

  \sa vos_list_remove_back()

  --------------------------------------------------------------------------*/

VOS_STATUS vos_list_peek_front( vos_list_t *pList, vos_list_node_t **ppNode )
{
   struct list_head * listptr;
   int rc;

   if ( ( pList == NULL) || ( ppNode == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                 "%s: list not initialized", __func__);
       VOS_ASSERT(0);
       return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( list_empty(&pList->anchor) )
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }
   listptr = pList->anchor.next;
   *ppNode = listptr;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------

  \brief vos_list_peek_back() - peek at the node at back of a linked list

  The vos_list_peek_back() API will return a pointer to the node at the
  back of a properly initialized vOS List object.  The node will *not* be
  removed from the list.

  \param pList - Pointer to list object of the list to be 'peeked'

  \param ppNode - Pointer to a pointer to the list node that exists at
  the back of the list.

  \return VOS_STATUS_SUCCESS - list node at the back of the list was
          successfully returned.

          VOS_STATUS_E_INVAL - The value specified by pList is not a valid,
          initialized list object.

          VOS_STATUS_E_EMPTY - The specified is empty so nodes cannot be
          removed.

          VOS_STATUS_E_FAULT  - pList or or ppNode is an invalid pointer.

  \sa vos_list_peek_back(), vos_list_remove_back(), vos_list_peek_front(),
      vos_list_remove_front()

  --------------------------------------------------------------------------*/

VOS_STATUS vos_list_peek_back( vos_list_t *pList, vos_list_node_t **ppNode )
{
   struct list_head * listptr;
   int rc;

   if ( ( pList == NULL) || ( ppNode == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( list_empty(&pList->anchor) )
   {
       mutex_unlock(&pList->lock);
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
                 "%s: list empty", __func__);
       return VOS_STATUS_E_EMPTY;
   }
   listptr = pList->anchor.prev;
   *ppNode = listptr;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------

  \brief vos_list_peek_next() - peek at the node after the specified node

  The vos_list_peek_next() API will return a pointer to the node following the
  specified node on a properly initialized vOS List object.  The node will
  *not* be removed from the list.

  \param pList - Pointer to list object of the list to be 'peeked'

  \param pNode - Pointer to the node that is being 'peeked'

  \param ppNode - Pointer to a pointer to the list node that follows the
         pNode node on the list.

  \return VOS_STATUS_SUCCESS - list node following pNode on the properly
          initialized list is successfully returned.

          VOS_STATUS_E_INVAL - The value specified by pList is not a valid,
          initialized list object.

          VOS_STATUS_E_EMPTY - There is no 'next' node (the input node is
          at the back of the list).

          VOS_STATUS_E_FAULT  - pList, pNode or ppNode is an invalid pointer.

  \sa vos_list_remove_back()

  --------------------------------------------------------------------------*/

VOS_STATUS vos_list_peek_next( vos_list_t *pList, vos_list_node_t *pNode,
                               vos_list_node_t **ppNode )
{
   struct list_head * listptr;
   int rc, found = 0;
   vos_list_node_t *tmp;

   if ( ( pList == NULL) || ( pNode == NULL) || (ppNode == NULL))
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( list_empty(&pList->anchor) )
   {
       mutex_unlock(&pList->lock);
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                 "%s: list empty", __func__);
       return VOS_STATUS_E_EMPTY;
   }

   // verify that pNode is indeed part of list pList
   list_for_each(tmp, &pList->anchor)
   {
      if (tmp == pNode)
      {
         found = 1;
         break;
      }
   }
   if (found == 0) {
      mutex_unlock(&pList->lock);
      return VOS_STATUS_E_INVAL;
   }

   listptr = pNode->next;
   if (listptr == &pList->anchor)
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   *ppNode =  listptr;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------

  \brief vos_list_peek_prev() - peek at the node before the specified node

  The vos_list_peek_prev() API will return a pointer to the node before the
  specified node on a properly initialized vOS List object.  The node will
  *not* be removed from the list.

  \param pList - Pointer to list object of the list to be 'peeked'

  \param pNode - Pointer to the node that is being 'peeked'

  \param ppNode - Pointer to a pointer to the list node before the
  pNode node on the list.

  \return VOS_STATUS_SUCCESS - list node before pNode on the properly
          initialized list is successfully returned.

          VOS_STATUS_E_INVAL - The value specified by pList is not a valid,
          initialized list object.

          VOS_STATUS_E_EMPTY - There is no 'previous' node (the input node is
          at the front of the list).

          VOS_STATUS_E_FAULT  - pList, pNode or ppNode is an invalid pointer.

  \sa vos_list_remove_back()

  --------------------------------------------------------------------------*/

VOS_STATUS vos_list_peek_prev( vos_list_t *pList, vos_list_node_t *pNode,
                               vos_list_node_t **ppNode )
{
   struct list_head * listptr;
   int rc, found = 0;
   vos_list_node_t *tmp;

   if ( ( pList == NULL) || ( pNode == NULL) || (ppNode == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( list_empty(&pList->anchor) )
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   // verify that pNode is indeed part of list pList
   list_for_each(tmp, &pList->anchor)
   {
      if (tmp == pNode)
      {
         found = 1;
         break;
      }
   }
   if (found == 0) {
      mutex_unlock(&pList->lock);
      return VOS_STATUS_E_INVAL;
   }

   listptr = pNode->prev;

   if (listptr == &pList->anchor)
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   *ppNode = listptr;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------

  \brief vos_list_insert_before() - insert node at front of a specified
  list node

  The vos_list_insert_before() API will insert a node onto a properly
  initialized vOS List object in front of the specified list node.

  \param pList - Pointer to list object where the node will be inserted

  \param pNodeToInsert - Pointer to the list node to be inserted into the list.

  \param pNode - Pointer to the list node where pNodeToInsert will be inserted
  in front of.

  \return VOS_STATUS_SUCCESS - list node was successfully inserted onto
          the front of the list.

          VOS_STATUS_E_INVAL - The value specified by pList is not a valid,
          initialized list object.

          VOS_STATUS_E_FAULT  - pList, pNodeToInsert, or pNode are
          invalid pointer(s)

  \sa

  --------------------------------------------------------------------------*/
VOS_STATUS vos_list_insert_before( vos_list_t *pList, vos_list_node_t *pNodeToInsert,
                                   vos_list_node_t *pNode )
{
   int rc, found = 0;
   vos_list_node_t *tmp;

   if ( ( pList == NULL) || ( pNode == NULL) || (pNodeToInsert == NULL))
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
         "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( list_empty(&pList->anchor) )
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   // verify that pNode is indeed part of list pList
   list_for_each(tmp, &pList->anchor)
   {
      if (tmp == pNode)
      {
         found = 1;
         break;
      }
   }
   if (found == 0) {
      mutex_unlock(&pList->lock);
      return VOS_STATUS_E_INVAL;
   }

   list_add(pNodeToInsert, pNode);
   pList->count++;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}


/*----------------------------------------------------------------------------

  \brief vos_list_insert_after() - insert node behind a specified list node

  The vos_list_insert_after() API will insert a node onto a properly
  initialized vOS List object after the specified list node.

  \param pList - Pointer to list object where the node will be inserted

  \param pNodeToInsert - Pointer to the list node to be inserted into the list.

  \param pNode - Pointer to the list node where pNodeToInsert will be inserted
  after.

  \return VOS_STATUS_SUCCESS - list node was successfully inserted onto
          the front of the list.

          VOS_STATUS_E_INVAL - The value specified by pList is not a valid,
          initialized list object.

          VOS_STATUS_E_FAULT  - pList, pNodeToInsert, or pNode are
          invalid pointer(s)

  \sa

  --------------------------------------------------------------------------*/
VOS_STATUS vos_list_insert_after( vos_list_t *pList, vos_list_node_t *pNodeToInsert,
                                  vos_list_node_t *pNode )
{
   int rc, found = 0;
   vos_list_node_t *tmp;

   if ( ( pList == NULL) || ( pNode == NULL) || (pNodeToInsert == NULL))
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }


   if ( list_empty(&pList->anchor) )
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   // verify that pNode is indeed part of list pList
   list_for_each(tmp, &pList->anchor)
   {
      if (tmp == pNode)
      {
         found = 1;
         break;
      }
   }
   if (found == 0) {
      mutex_unlock(&pList->lock);
      return VOS_STATUS_E_INVAL;
   }

   list_add_tail(pNodeToInsert, pNode);
   pList->count++;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

/*----------------------------------------------------------------------------

  \brief vos_list_remove_node() - remove specified node from vOS list list

  The vos_list_remove_node() API will remove a specified node from the
  properly initialized vOS List object.

  \param pList - Pointer to list object where the node will be removed

  \param ppNode - Pointer to the node to be removed from the list.

  \return VOS_STATUS_SUCCESS - list node was successfully removed from
          the list.

          VOS_STATUS_E_INVAL - The value specified by pList is not a valid,
          initialized list object.

          VOS_STATUS_E_EMPTY - The specified is empty so nodes cannot be
          removed.


          VOS_STATUS_E_FAULT  - pList or pNodeToRemove is not a valid pointer

  \sa

  --------------------------------------------------------------------------*/
VOS_STATUS vos_list_remove_node( vos_list_t *pList, vos_list_node_t *pNodeToRemove )
{
   int rc, found = 0;
   vos_list_node_t *tmp;

   if ( ( pList == NULL ) || ( pNodeToRemove == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   rc = mutex_lock_interruptible(&pList->lock);
   if (rc)
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock list", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( list_empty(&pList->anchor) )
   {
      mutex_unlock(&pList->lock);
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   // verify that pNodeToRemove is indeed part of list pList
   list_for_each(tmp, &pList->anchor)
   {
      if (tmp == pNodeToRemove)
      {
         found = 1;
         break;
      }
   }
   if (found == 0) {
      mutex_unlock(&pList->lock);
      return VOS_STATUS_E_INVAL;
   }

   list_del(pNodeToRemove);
   pList->count--;
   mutex_unlock(&pList->lock);

   return VOS_STATUS_SUCCESS;
}

VOS_STATUS vos_list_remove_node_no_mutex(vos_list_t *pList,
					 vos_list_node_t *pNodeToRemove)
{
   int found = 0;
   vos_list_node_t *tmp;

   if ( ( pList == NULL ) || ( pNodeToRemove == NULL) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: NULL pointer passed in", __func__);
      return VOS_STATUS_E_FAULT;
   }

   if ( pList->cookie != VOS_LIST_COOKIE )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list not initialized", __func__);
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   if ( list_empty(&pList->anchor) )
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: list empty", __func__);
      return VOS_STATUS_E_EMPTY;
   }

   // verify that pNodeToRemove is indeed part of list pList
   list_for_each(tmp, &pList->anchor)
   {
      if (tmp == pNodeToRemove)
      {
         found = 1;
         break;
      }
   }
   if (found == 0)
      return VOS_STATUS_E_INVAL;

   list_del(pNodeToRemove);
   pList->count--;

   return VOS_STATUS_SUCCESS;
}
