//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*++


 Module Name:    tdiutil.c

 Abstract:       Utility for converting connection and address object handles
                 into pointers to the objects with added reference count to
                 ensure that object doesn't disappear while in use.

 Contents:
 
    IrdaAcquireAddrObj
    IrdaAcquireConnObj

--*/

#include "irdatdi.h"

#ifdef DEBUG
    static DWORD dwAddrId = 1;
#endif 

PIRLMP_ADDR_OBJ
IrdaAllocAddrObj(
    OUT PHANDLE phAddr
    )
{
    PIRLMP_ADDR_OBJ pAddr;

    EnterCriticalSection(&csIrObjList);

    pAddr = IrdaAlloc(sizeof(IRLMP_ADDR_OBJ), MT_TDI_ADDRESS);

    if (pAddr)
    {
        pAddr->cRefs = 1;
    #ifdef DEBUG
        pAddr->Sig  = TDIADDRSIG;
        pAddr->dwId = dwAddrId++;
    #endif // DEBUG
    
        DEBUGMSG(ZONE_ALLOC,
            (TEXT("IrDA: Allocate Address - %#x (%d)\r\n"), pAddr, pAddr->dwId));
        
        // Put address in address list.
        InsertHeadList(&IrAddrObjList, (PLIST_ENTRY)pAddr);
    
        // For now the handle is just the pointer.
        *phAddr = (HANDLE)pAddr;
    }

    LeaveCriticalSection(&csIrObjList);
    
    return (pAddr);
}

/*++                      

 Function:       IrdaAcquireAddrObj

 Description:    Converts address object handle to address object pointer.

 Arguments:
 
    hAddr - Handle to address object.

 Returns:
 
    pAddr - Pointer to address object. NULL if invalid handle.

 Comments:
 
    For now the handle is the pointer, but we verify that we can find the 
    object in the address list.
    
    Caller must call REFDEL to free reference acquired by this function.

--*/

PIRLMP_ADDR_OBJ   
IrdaAcquireAddrObj(
    IN HANDLE hAddr
    )
{
    PIRLMP_ADDR_OBJ pAddr = NULL;
    PLIST_ENTRY     pEntry; 

    EnterCriticalSection(&csIrObjList);

    for (pEntry = IrAddrObjList.Flink;
         pEntry != &IrAddrObjList;
         pEntry = pEntry->Flink)
    {
        if ((PIRLMP_ADDR_OBJ)pEntry == (PIRLMP_ADDR_OBJ)hAddr)
        {
            pAddr = (PIRLMP_ADDR_OBJ)pEntry;
            REFADDADDR(pAddr);
            break;
        }
    }

    LeaveCriticalSection(&csIrObjList);

    return (pAddr);
}

/*++                      

 Function:       IrdaAcquireConnObj

 Description:    Converts connection object handle to connection object pointer.

 Arguments:
 
    hConn - Handle to connection object.

 Returns:
 
    pConn - Pointer to connection object. NULL if invalid handle.

 Comments:
 
    For now the handle is the pointer, but we verify that we can find the 
    object associated with an address or in the unassociated connection
    list.
    
    Caller must call REFDEL to free reference acquired by this function.

--*/

PIRLMP_CONNECTION 
IrdaAcquireConnObj(
    IN HANDLE hConn
    )
{
    PIRLMP_CONNECTION pConn = NULL;
    PIRLMP_ADDR_OBJ   pAddr = NULL;
    PLIST_ENTRY       pAddrEntry;
    PLIST_ENTRY       pConnEntry;

    EnterCriticalSection(&csIrObjList);

    for (pAddrEntry = IrAddrObjList.Flink;
         pAddrEntry != &IrAddrObjList;
         pAddrEntry = pAddrEntry->Flink)
    {
        pAddr = (PIRLMP_ADDR_OBJ)pAddrEntry;

        GET_ADDR_LOCK(pAddr);

        for (pConnEntry = pAddr->ConnList.Flink;
             pConnEntry != &pAddr->ConnList;
             pConnEntry = pConnEntry->Flink)
        {
            if ((PIRLMP_CONNECTION)pConnEntry == (PIRLMP_CONNECTION)hConn)
            {
                pConn = (PIRLMP_CONNECTION)pConnEntry;
                REFADDCONN(pConn);
                break;
            }
        }

        FREE_ADDR_LOCK(pAddr);

        if (pConn) break;
    }

    // If not associated with an address, then it must be on the 
    // unassociated connection list.
    if (pConn == NULL)
    {
        for (pConnEntry = IrConnObjList.Flink;
             pConnEntry != &IrConnObjList;
             pConnEntry = pConnEntry->Flink)
        {
            if ((PIRLMP_CONNECTION)pConnEntry == (PIRLMP_CONNECTION)hConn)
            {
                pConn = (PIRLMP_CONNECTION)pConnEntry;
                REFADDCONN(pConn);
                break;
            }
        }
    }

    LeaveCriticalSection(&csIrObjList);

    return (pConn);
}


