1531 lines
43 KiB
C
1531 lines
43 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-1994 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Winsif.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements all the code surrounding the WINS interface to
|
|||
|
netbt that allows WINS to share the same 137 socket as netbt.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jim Stewart (Jimst) 1-30-94
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
|
|||
|
VOID
|
|||
|
NbtCancelWinsIrp(
|
|||
|
IN PDEVICE_OBJECT DeviceContext,
|
|||
|
IN PIRP pIrp
|
|||
|
);
|
|||
|
VOID
|
|||
|
NbtCancelWinsSendIrp(
|
|||
|
IN PDEVICE_OBJECT DeviceContext,
|
|||
|
IN PIRP pIrp
|
|||
|
);
|
|||
|
VOID
|
|||
|
WinsDgramCompletion(
|
|||
|
IN tDGRAM_SEND_TRACKING *pTracker,
|
|||
|
IN NTSTATUS status,
|
|||
|
IN ULONG Length
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
CheckIfLocalNameActive(
|
|||
|
IN tREM_ADDRESS *pSendAddr
|
|||
|
);
|
|||
|
|
|||
|
PVOID
|
|||
|
WinsAllocMem(
|
|||
|
IN tWINS_INFO *pWinsContext,
|
|||
|
IN ULONG Size,
|
|||
|
IN BOOLEAN Rcv
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
WinsFreeMem(
|
|||
|
IN tWINS_INFO *pWinsContext,
|
|||
|
IN PVOID pBuffer,
|
|||
|
IN ULONG Size,
|
|||
|
IN BOOLEAN Rcv
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
InitiateRefresh (
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN RefreshedYet;
|
|||
|
|
|||
|
//
|
|||
|
// take this define from Winsock.h since including winsock.h causes
|
|||
|
// redefinition problems with various types.
|
|||
|
//
|
|||
|
#define AF_UNIX 1
|
|||
|
#define AF_INET 2
|
|||
|
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma CTEMakePageable(PAGENBT, NTCloseWinsAddr)
|
|||
|
#pragma CTEMakePageable(PAGENBT, InitiateRefresh)
|
|||
|
#pragma CTEMakePageable(PAGENBT, PassNamePduToWins)
|
|||
|
#pragma CTEMakePageable(PAGENBT, NbtCancelWinsIrp)
|
|||
|
#pragma CTEMakePageable(PAGENBT, NbtCancelWinsSendIrp)
|
|||
|
#pragma CTEMakePageable(PAGENBT, CheckIfLocalNameActive)
|
|||
|
#pragma CTEMakePageable(PAGENBT, WinsDgramCompletion)
|
|||
|
#pragma CTEMakePageable(PAGENBT, WinsFreeMem)
|
|||
|
#pragma CTEMakePageable(PAGENBT, WinsAllocMem)
|
|||
|
#endif
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
|
|||
|
tWINS_INFO *pWinsInfo;
|
|||
|
LIST_ENTRY FreeWinsList;
|
|||
|
HANDLE NbtDiscardableCodeHandle={0};
|
|||
|
tDEVICECONTEXT *pWinsDeviceContext = NULL;
|
|||
|
ULONG LastWinsSignature = 0x8000;
|
|||
|
|
|||
|
#define COUNT_MAX 10
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NTOpenWinsAddr(
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN tIPADDRESS IpAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This Routine handles opening the Wins Object that is used by
|
|||
|
by WINS to send and receive name service datagrams on port 137.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIrp - a ptr to an IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - status of the request
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
NTSTATUS status;
|
|||
|
tWINS_INFO *pWins;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
|
|||
|
//
|
|||
|
// Page in the Wins Code, if it hasn't already been paged in.
|
|||
|
//
|
|||
|
if ((!NbtDiscardableCodeHandle) &&
|
|||
|
(!(NbtDiscardableCodeHandle = MmLockPagableCodeSection (NTCloseWinsAddr))))
|
|||
|
{
|
|||
|
return (STATUS_UNSUCCESSFUL);
|
|||
|
}
|
|||
|
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|||
|
|
|||
|
//
|
|||
|
// if the WINs endpoint structure is not allocated, then allocate it
|
|||
|
// and initialize it.
|
|||
|
//
|
|||
|
if (pWinsInfo)
|
|||
|
{
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
else if (!(pWins = NbtAllocMem(sizeof(tWINS_INFO),NBT_TAG('v'))))
|
|||
|
{
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTEZeroMemory(pWins,sizeof(tWINS_INFO));
|
|||
|
pWins->Verify = NBT_VERIFY_WINS_ACTIVE;
|
|||
|
InitializeListHead(&pWins->Linkage);
|
|||
|
InitializeListHead(&pWins->RcvList);
|
|||
|
InitializeListHead(&pWins->SendList);
|
|||
|
|
|||
|
pWins->RcvMemoryMax = NbtConfig.MaxDgramBuffering;
|
|||
|
pWins->SendMemoryMax = NbtConfig.MaxDgramBuffering;
|
|||
|
pWins->IpAddress = IpAddress;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
pWins->pDeviceContext= GetDeviceWithIPAddress(IpAddress);
|
|||
|
pWins->WinsSignature = LastWinsSignature++;
|
|||
|
pWinsInfo = pWins;
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
pIrpSp->FileObject->FsContext = (PVOID) pWinsInfo;
|
|||
|
pIrpSp->FileObject->FsContext2 = (PVOID) NBT_WINS_TYPE;
|
|||
|
|
|||
|
RefreshedYet = FALSE;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Open Wins Address Rcvd, status= %X\n",status));
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NTCleanUpWinsAddr(
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN PIRP pIrp
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This Routine handles closing the Wins Object that is used by
|
|||
|
by WINS to send and receive name service datagrams on port 137.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIrp - a ptr to an IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - status of the request
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
NTSTATUS status;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
PLIST_ENTRY pHead, pEntry;
|
|||
|
tWINSRCV_BUFFER *pRcv;
|
|||
|
tWINS_INFO *pWins = NULL;
|
|||
|
PIRP pSendIrp, pRcvIrp;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|||
|
pWins = pIrpSp->FileObject->FsContext;
|
|||
|
|
|||
|
if (pWinsInfo && (pWins == pWinsInfo))
|
|||
|
{
|
|||
|
ASSERT (NBT_VERIFY_HANDLE (pWins, NBT_VERIFY_WINS_ACTIVE));
|
|||
|
pWins->Verify = NBT_VERIFY_WINS_DOWN;
|
|||
|
|
|||
|
//
|
|||
|
// prevent any more dgram getting queued up
|
|||
|
//
|
|||
|
pWinsInfo = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// free any rcv buffers that may be queued up
|
|||
|
//
|
|||
|
pHead = &pWins->RcvList;
|
|||
|
while (!IsListEmpty(pHead))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt.NTCleanUpWinsAddr: Freeing Rcv buffered for Wins\n"));
|
|||
|
|
|||
|
pEntry = RemoveHeadList(pHead);
|
|||
|
pRcv = CONTAINING_RECORD(pEntry,tWINSRCV_BUFFER,Linkage);
|
|||
|
|
|||
|
WinsFreeMem (pWins, pRcv, pRcv->DgramLength,TRUE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// return any Send buffers that may be queued up
|
|||
|
//
|
|||
|
pHead = &pWins->SendList;
|
|||
|
while (!IsListEmpty(pHead))
|
|||
|
{
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt.NTCleanUpWinsAddr: Freeing Send Wins Address!\n"));
|
|||
|
|
|||
|
pEntry = RemoveHeadList(pHead);
|
|||
|
pSendIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
|
|||
|
|
|||
|
CTESpinFree (&NbtConfig. JointLock, OldIrq);
|
|||
|
NbtCancelCancelRoutine (pSendIrp);
|
|||
|
CTEIoComplete (pSendIrp, STATUS_CANCELLED, 0);
|
|||
|
CTESpinLock (&NbtConfig.JointLock, OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
pWins->pDeviceContext = NULL;
|
|||
|
InsertTailList (&FreeWinsList, &pWins->Linkage);
|
|||
|
|
|||
|
//
|
|||
|
// Complete any Rcv Irps that may be hanging on this request
|
|||
|
//
|
|||
|
if (pRcvIrp = pWins->RcvIrp)
|
|||
|
{
|
|||
|
pWins->RcvIrp = NULL;
|
|||
|
pRcvIrp->IoStatus.Status = STATUS_CANCELLED;
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
NbtCancelCancelRoutine (pRcvIrp);
|
|||
|
CTEIoComplete (pRcvIrp, STATUS_CANCELLED, 0);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT (0);
|
|||
|
status = STATUS_INVALID_HANDLE;
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt.NTCleanUpWinsAddr: pWins=<%p>, status=<%x>\n", pWins, status));
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
NTCloseWinsAddr(
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN PIRP pIrp
|
|||
|
)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This Routine handles closing the Wins Object that is used by
|
|||
|
by WINS to send and receive name service datagrams on port 137.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIrp - a ptr to an IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - status of the request
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
NTSTATUS status;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
tWINS_INFO *pWins = NULL;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
//
|
|||
|
// if the WINs endpoint structure is allocated, then deallocate it
|
|||
|
//
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|||
|
pWins = pIrpSp->FileObject->FsContext;
|
|||
|
|
|||
|
if (NBT_VERIFY_HANDLE (pWins, NBT_VERIFY_WINS_DOWN))
|
|||
|
{
|
|||
|
pWins->Verify += 10;
|
|||
|
RemoveEntryList (&pWins->Linkage);
|
|||
|
CTEMemFree (pWins);
|
|||
|
|
|||
|
pIrpSp->FileObject->FsContext2 = (PVOID)NBT_CONTROL_TYPE;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT (0);
|
|||
|
status = STATUS_INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt.NTCloseWinsAddr: pWins=<%p>, status=<%x>\n", pWins, status));
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
WinsSetInformation(
|
|||
|
IN tWINS_INFO *pWins,
|
|||
|
IN tWINS_SET_INFO *pWinsSetInfo
|
|||
|
)
|
|||
|
{
|
|||
|
CTELockHandle OldIrq;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if ((pWins == pWinsInfo) &&
|
|||
|
(pWinsSetInfo->IpAddress))
|
|||
|
{
|
|||
|
pWins->IpAddress = pWinsSetInfo->IpAddress;
|
|||
|
pWins->pDeviceContext = GetDeviceWithIPAddress (pWinsSetInfo->IpAddress);
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
InitiateRefresh (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine tries to refresh all names with WINS on THIS node.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIrp - Wins Rcv Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_PENDING if the buffer is to be held on to , the normal case.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
CTELockHandle OldIrq;
|
|||
|
PLIST_ENTRY pHead;
|
|||
|
PLIST_ENTRY pEntry;
|
|||
|
ULONG Count;
|
|||
|
ULONG NumberNames;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// be sure all net cards have this card as the primary wins
|
|||
|
// server since Wins has to answer name queries for this
|
|||
|
// node.
|
|||
|
//
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
if (!(NodeType & BNODE))
|
|||
|
{
|
|||
|
LONG i;
|
|||
|
|
|||
|
Count = 0;
|
|||
|
NumberNames = 0;
|
|||
|
|
|||
|
for (i=0 ;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
|
|||
|
{
|
|||
|
pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
|
|||
|
pEntry = pHead;
|
|||
|
while ((pEntry = pEntry->Flink) != pHead)
|
|||
|
{
|
|||
|
NumberNames++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
while (Count < COUNT_MAX)
|
|||
|
{
|
|||
|
if (!(NbtConfig.GlobalRefreshState & NBT_G_REFRESHING_NOW))
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
ReRegisterLocalNames(NULL, FALSE);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LARGE_INTEGER Timout;
|
|||
|
NTSTATUS Locstatus;
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Waiting for Refresh to finish, so names can be reregistered\n"));
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
//
|
|||
|
// set a timeout that should be long enough to wait
|
|||
|
// for all names to fail registration with a down
|
|||
|
// wins server.
|
|||
|
//
|
|||
|
// 2 sec*3 retries * 8 names / 5 = 9 seconds a shot.
|
|||
|
// for a total of 90 seconds max.
|
|||
|
//
|
|||
|
Timout.QuadPart = Int32x32To64(
|
|||
|
MILLISEC_TO_100NS/(COUNT_MAX/2),
|
|||
|
(NbtConfig.uRetryTimeout*NbtConfig.uNumRetries)
|
|||
|
*NumberNames);
|
|||
|
|
|||
|
Timout.QuadPart = -(Timout.QuadPart);
|
|||
|
|
|||
|
//
|
|||
|
// wait for a few seconds and try again.
|
|||
|
//
|
|||
|
Locstatus = KeDelayExecutionThread(
|
|||
|
KernelMode,
|
|||
|
FALSE, // Alertable
|
|||
|
&Timout); // Timeout
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Count++;
|
|||
|
if (Count < COUNT_MAX)
|
|||
|
{
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
RcvIrpFromWins(
|
|||
|
IN PCTE_IRP pIrp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function takes the rcv irp posted by WINS and decides if there are
|
|||
|
any datagram queued waiting to go up to WINS. If so then the datagram
|
|||
|
is copied to the WINS buffer and passed back up. Otherwise the irp is
|
|||
|
held by Netbt until a datagram does come in.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIrp - Wins Rcv Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_PENDING if the buffer is to be held on to , the normal case.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
NTSTATUS Locstatus;
|
|||
|
tREM_ADDRESS *pWinsBuffer;
|
|||
|
tWINSRCV_BUFFER *pBuffer;
|
|||
|
PLIST_ENTRY pEntry;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
tWINS_INFO *pWins;
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
PMDL pMdl;
|
|||
|
ULONG CopyLength;
|
|||
|
ULONG DgramLength;
|
|||
|
ULONG BufferLength;
|
|||
|
|
|||
|
status = STATUS_INVALID_HANDLE;
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|||
|
pWins = pIrpSp->FileObject->FsContext;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (!RefreshedYet)
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
InitiateRefresh();
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
RefreshedYet = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if ((!pWins) || (pWins != pWinsInfo))
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
NTIoComplete(pIrp,status,0);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
if (!IsListEmpty(&pWins->RcvList))
|
|||
|
{
|
|||
|
//
|
|||
|
// There is at least one datagram waiting to be received
|
|||
|
//
|
|||
|
pEntry = RemoveHeadList(&pWins->RcvList);
|
|||
|
pBuffer = CONTAINING_RECORD(pEntry,tWINSRCV_BUFFER,Linkage);
|
|||
|
|
|||
|
//
|
|||
|
// Copy the datagram and the source address to WINS buffer and return to WINS
|
|||
|
//
|
|||
|
if ((pMdl = pIrp->MdlAddress) &&
|
|||
|
(pWinsBuffer = MmGetSystemAddressForMdlSafe (pIrp->MdlAddress, HighPagePriority)))
|
|||
|
{
|
|||
|
BufferLength = MmGetMdlByteCount(pMdl);
|
|||
|
DgramLength = pBuffer->DgramLength;
|
|||
|
CopyLength = (DgramLength <= BufferLength) ? DgramLength : BufferLength;
|
|||
|
|
|||
|
CTEMemCopy ((PVOID)pWinsBuffer, (PVOID)&pBuffer->Address.Family, CopyLength);
|
|||
|
|
|||
|
ASSERT(pWinsBuffer->Port);
|
|||
|
ASSERT(pWinsBuffer->IpAddress);
|
|||
|
|
|||
|
if (CopyLength < DgramLength)
|
|||
|
{
|
|||
|
Locstatus = STATUS_BUFFER_OVERFLOW;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Locstatus = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CopyLength = 0;
|
|||
|
Locstatus = STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// subtract from the total amount buffered for WINS since we are
|
|||
|
// passing a datagram up to WINS now.
|
|||
|
//
|
|||
|
pWins->RcvMemoryAllocated -= pBuffer->DgramLength;
|
|||
|
CTEMemFree(pBuffer);
|
|||
|
|
|||
|
//
|
|||
|
// pass the irp up to WINS
|
|||
|
//
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Returning Wins rcv Irp immediately with queued dgram, status=%X,pIrp=%X\n"
|
|||
|
,status,pIrp));
|
|||
|
|
|||
|
pIrp->IoStatus.Information = CopyLength;
|
|||
|
pIrp->IoStatus.Status = Locstatus;
|
|||
|
|
|||
|
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
if (pWins->RcvIrp)
|
|||
|
{
|
|||
|
status = STATUS_NOT_SUPPORTED;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
status = NTCheckSetCancelRoutine(pIrp, NbtCancelWinsIrp, NULL);
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Holding onto Wins Rcv Irp, pIrp =%Xstatus=%X\n", status,pIrp));
|
|||
|
|
|||
|
pWins->RcvIrp = pIrp;
|
|||
|
status = STATUS_PENDING;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
NTIoComplete(pIrp,status,0);
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
PassNamePduToWins (
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN PVOID pSrcAddress,
|
|||
|
IN tNAMEHDR UNALIGNED *pNameSrv,
|
|||
|
IN ULONG uNumBytes
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is used to allow NBT to pass name query service Pdu's to
|
|||
|
WINS. Wins posts a Rcv irp to Netbt. If the Irp is here then simply
|
|||
|
copy the data to the irp and return it, otherwise buffer the data up
|
|||
|
to a maximum # of bytes. Beyond that limit the datagrams are discarded.
|
|||
|
|
|||
|
If Retstatus is not success then the pdu will also be processed by
|
|||
|
nbt. This allows nbt to process packets when wins pauses and
|
|||
|
its list of queued buffers is exceeded.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pDeviceContext - card that the request can in on
|
|||
|
pSrcAddress - source address
|
|||
|
pNameSrv - ptr to the datagram
|
|||
|
uNumBytes - length of datagram
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_PENDING if the buffer is to be held on to , the normal case.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Retstatus;
|
|||
|
NTSTATUS status;
|
|||
|
tREM_ADDRESS *pWinsBuffer;
|
|||
|
PCTE_IRP pIrp;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
PTRANSPORT_ADDRESS pSourceAddress;
|
|||
|
ULONG SrcAddress;
|
|||
|
SHORT SrcPort;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get the source port and ip address, since WINS needs this information.
|
|||
|
//
|
|||
|
pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
|
|||
|
SrcAddress = ((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr;
|
|||
|
SrcPort = ((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->sin_port;
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
Retstatus = STATUS_SUCCESS;
|
|||
|
if (pWinsInfo)
|
|||
|
{
|
|||
|
if (!pWinsInfo->RcvIrp)
|
|||
|
{
|
|||
|
//
|
|||
|
// Queue the name query pdu if we have not exeeded our current queue
|
|||
|
// length
|
|||
|
//
|
|||
|
if (pWinsInfo->RcvMemoryAllocated < pWinsInfo->RcvMemoryMax)
|
|||
|
{
|
|||
|
tWINSRCV_BUFFER *pBuffer;
|
|||
|
|
|||
|
pBuffer = NbtAllocMem(uNumBytes + sizeof(tWINSRCV_BUFFER)+8,NBT_TAG('v'));
|
|||
|
if (pBuffer)
|
|||
|
{
|
|||
|
//
|
|||
|
// check if it is a name reg from this node
|
|||
|
//
|
|||
|
if (pNameSrv->AnCount == WINS_SIGNATURE)
|
|||
|
{
|
|||
|
pNameSrv->AnCount = 0;
|
|||
|
pBuffer->Address.Family = AF_UNIX;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pBuffer->Address.Family = AF_INET;
|
|||
|
}
|
|||
|
|
|||
|
CTEMemCopy((PUCHAR)((PUCHAR)pBuffer + sizeof(tWINSRCV_BUFFER)),
|
|||
|
(PVOID)pNameSrv,uNumBytes);
|
|||
|
|
|||
|
pBuffer->Address.Port = SrcPort;
|
|||
|
pBuffer->Address.IpAddress = SrcAddress;
|
|||
|
pBuffer->Address.LengthOfBuffer = uNumBytes;
|
|||
|
|
|||
|
ASSERT(pBuffer->Address.Port);
|
|||
|
ASSERT(pBuffer->Address.IpAddress);
|
|||
|
|
|||
|
// total amount allocated
|
|||
|
pBuffer->DgramLength = uNumBytes + sizeof(tREM_ADDRESS);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Keep track of the total amount buffered so that we don't
|
|||
|
// eat up all non-paged pool buffering for WINS
|
|||
|
//
|
|||
|
pWinsInfo->RcvMemoryAllocated += pBuffer->DgramLength;
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Buffering Wins Rcv - no Irp, status=%X\n"));
|
|||
|
InsertTailList(&pWinsInfo->RcvList,&pBuffer->Linkage);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// this ret status will allow netbt to process the packet.
|
|||
|
//
|
|||
|
Retstatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PMDL pMdl;
|
|||
|
ULONG CopyLength;
|
|||
|
ULONG BufferLength;
|
|||
|
|
|||
|
//
|
|||
|
// The recv irp is here so copy the data to its buffer and
|
|||
|
// pass it up to WINS
|
|||
|
//
|
|||
|
pIrp = pWinsInfo->RcvIrp;
|
|||
|
pWinsInfo->RcvIrp = NULL;
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
//
|
|||
|
// Copy the datagram and the source address to WINS buffer and return to WINS
|
|||
|
//
|
|||
|
if ((!(pMdl = pIrp->MdlAddress)) ||
|
|||
|
((BufferLength = MmGetMdlByteCount(pMdl)) < sizeof(tREM_ADDRESS)) ||
|
|||
|
(!(pWinsBuffer = MmGetSystemAddressForMdlSafe (pIrp->MdlAddress, HighPagePriority))))
|
|||
|
{
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
CopyLength = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (BufferLength >= (uNumBytes + sizeof(tREM_ADDRESS)))
|
|||
|
{
|
|||
|
CopyLength = uNumBytes;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CopyLength = BufferLength - sizeof(tREM_ADDRESS);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// check if it is a name reg from this node
|
|||
|
//
|
|||
|
if (pNameSrv->AnCount == WINS_SIGNATURE)
|
|||
|
{
|
|||
|
pNameSrv->AnCount = 0;
|
|||
|
pWinsBuffer->Family = AF_UNIX;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pWinsBuffer->Family = AF_INET;
|
|||
|
}
|
|||
|
CTEMemCopy((PVOID)((PUCHAR)pWinsBuffer + sizeof(tREM_ADDRESS)), (PVOID)pNameSrv, CopyLength);
|
|||
|
|
|||
|
pWinsBuffer->Port = SrcPort;
|
|||
|
pWinsBuffer->IpAddress = SrcAddress;
|
|||
|
pWinsBuffer->LengthOfBuffer = uNumBytes;
|
|||
|
|
|||
|
ASSERT(pWinsBuffer->Port);
|
|||
|
ASSERT(pWinsBuffer->IpAddress);
|
|||
|
|
|||
|
//
|
|||
|
// pass the irp up to WINS
|
|||
|
//
|
|||
|
if (CopyLength < uNumBytes)
|
|||
|
{
|
|||
|
status = STATUS_BUFFER_OVERFLOW;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Returning Wins Rcv Irp - data from net, Length=%X,pIrp=%X\n"
|
|||
|
,uNumBytes,pIrp));
|
|||
|
}
|
|||
|
|
|||
|
NTIoComplete(pIrp,status,CopyLength);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// this ret status will allow netbt to process the packet.
|
|||
|
//
|
|||
|
Retstatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
return(Retstatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
NbtCancelWinsIrp(
|
|||
|
IN PDEVICE_OBJECT DeviceContext,
|
|||
|
IN PIRP pIrp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles the cancelling a WinsRcv Irp. It must release the
|
|||
|
cancel spin lock before returning re: IoCancelIrp().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The final status from the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL OldIrq;
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
tWINS_INFO *pWins;
|
|||
|
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt.NbtCancelWinsIrp: Got a Cancel !!! *****************\n"));
|
|||
|
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|||
|
|
|||
|
pWins = (tWINS_INFO *)pIrpSp->FileObject->FsContext;
|
|||
|
|
|||
|
IoReleaseCancelSpinLock(pIrp->CancelIrql);
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
//
|
|||
|
// Be sure that PassNamePduToWins has not taken the RcvIrp for a
|
|||
|
// Rcv just now.
|
|||
|
//
|
|||
|
if ((NBT_VERIFY_HANDLE (pWins, NBT_VERIFY_WINS_ACTIVE)) &&
|
|||
|
(pWins->RcvIrp == pIrp))
|
|||
|
{
|
|||
|
pWins->RcvIrp = NULL;
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
pIrp->IoStatus.Status = STATUS_CANCELLED;
|
|||
|
IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
NbtCancelWinsSendIrp(
|
|||
|
IN PDEVICE_OBJECT DeviceContext,
|
|||
|
IN PIRP pIrp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles the cancelling a WinsRcv Irp. It must release the
|
|||
|
cancel spin lock before returning re: IoCancelIrp().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The final status from the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL OldIrq;
|
|||
|
PLIST_ENTRY pHead;
|
|||
|
PLIST_ENTRY pEntry;
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
tWINS_INFO *pWins;
|
|||
|
BOOLEAN Found;
|
|||
|
PIRP pIrpList;
|
|||
|
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt.NbtCancelWinsSendIrp: Got a Cancel !!! *****************\n"));
|
|||
|
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|||
|
pWins = (tWINS_INFO *)pIrpSp->FileObject->FsContext;
|
|||
|
|
|||
|
IoReleaseCancelSpinLock(pIrp->CancelIrql);
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (pWins == pWinsInfo)
|
|||
|
{
|
|||
|
//
|
|||
|
// find the matching irp on the list and remove it
|
|||
|
//
|
|||
|
pHead = &pWinsInfo->SendList;
|
|||
|
pEntry = pHead;
|
|||
|
Found = FALSE;
|
|||
|
|
|||
|
while ((pEntry = pEntry->Flink) != pHead)
|
|||
|
{
|
|||
|
pIrpList = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
|
|||
|
if (pIrp == pIrpList)
|
|||
|
{
|
|||
|
RemoveEntryList(pEntry);
|
|||
|
Found = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
if (Found)
|
|||
|
{
|
|||
|
pIrp->IoStatus.Status = STATUS_CANCELLED;
|
|||
|
IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
}
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
WinsSendDatagram(
|
|||
|
IN tDEVICECONTEXT *pDeviceContext,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN BOOLEAN MustSend)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This Routine handles sending a datagram down to the transport. MustSend
|
|||
|
it set true by the Send Completion routine when it attempts to send
|
|||
|
one of the queued datagrams, in case we still don't pass the memory
|
|||
|
allocated check and refuse to do the send - sends will just stop then without
|
|||
|
this boolean.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIrp - a ptr to an IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - status of the request
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
NTSTATUS status;
|
|||
|
tWINS_INFO *pWins;
|
|||
|
tREM_ADDRESS *pSendAddr;
|
|||
|
PVOID pDgram;
|
|||
|
ULONG DgramLength;
|
|||
|
tDGRAM_SEND_TRACKING *pTracker;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
BOOLEAN fIsWinsDevice = FALSE;
|
|||
|
ULONG DataSize;
|
|||
|
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|||
|
pWins = (tWINS_INFO *)pIrpSp->FileObject->FsContext;
|
|||
|
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
|
|||
|
if (!(pSendAddr = (tREM_ADDRESS *) MmGetSystemAddressForMdlSafe (pIrp->MdlAddress, HighPagePriority)))
|
|||
|
{
|
|||
|
pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Bug# 234600: Check if the DataSize is correct
|
|||
|
//
|
|||
|
DataSize = MmGetMdlByteCount (pIrp->MdlAddress);
|
|||
|
if ((DataSize < sizeof(tREM_ADDRESS)) ||
|
|||
|
((DataSize - sizeof(tREM_ADDRESS)) < pSendAddr->LengthOfBuffer))
|
|||
|
{
|
|||
|
pIrp->IoStatus.Status = STATUS_INVALID_BLOCK_LENGTH;
|
|||
|
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
|
|||
|
return STATUS_INVALID_BLOCK_LENGTH;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// check if it is a name that is registered on this machine
|
|||
|
//
|
|||
|
if (pSendAddr->Family == AF_UNIX)
|
|||
|
{
|
|||
|
status = CheckIfLocalNameActive(pSendAddr);
|
|||
|
}
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
if ((pWins) &&
|
|||
|
(pWins == pWinsInfo))
|
|||
|
{
|
|||
|
if (pDeviceContext == pWinsDeviceContext)
|
|||
|
{
|
|||
|
fIsWinsDevice = TRUE;
|
|||
|
if (!(pDeviceContext = pWinsInfo->pDeviceContext) ||
|
|||
|
!(NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_WINS, TRUE)))
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
// status = STATUS_INVALID_HANDLE;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
pIrp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
|
|||
|
return (status);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((pWins->SendMemoryAllocated < pWins->SendMemoryMax) || MustSend)
|
|||
|
{
|
|||
|
if (pSendAddr->IpAddress != 0)
|
|||
|
{
|
|||
|
DgramLength = pSendAddr->LengthOfBuffer;
|
|||
|
pDgram = WinsAllocMem (pWins, DgramLength, FALSE);
|
|||
|
|
|||
|
if (pDgram)
|
|||
|
{
|
|||
|
CTEMemCopy(pDgram, (PVOID)((PUCHAR)pSendAddr+sizeof(tREM_ADDRESS)), DgramLength);
|
|||
|
|
|||
|
//
|
|||
|
// get a buffer for tracking Dgram Sends
|
|||
|
//
|
|||
|
status = GetTracker(&pTracker, NBT_TRACKER_SEND_WINS_DGRAM);
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
pTracker->SendBuffer.pBuffer = NULL;
|
|||
|
pTracker->SendBuffer.Length = 0;
|
|||
|
pTracker->SendBuffer.pDgramHdr = pDgram;
|
|||
|
pTracker->SendBuffer.HdrLength = DgramLength;
|
|||
|
pTracker->pClientIrp = NULL;
|
|||
|
pTracker->pDeviceContext = pDeviceContext;
|
|||
|
pTracker->pNameAddr = NULL;
|
|||
|
pTracker->pDestName = NULL;
|
|||
|
pTracker->UnicodeDestName = NULL;
|
|||
|
pTracker->pClientEle = NULL;
|
|||
|
pTracker->AllocatedLength = DgramLength;
|
|||
|
pTracker->ClientContext = IntToPtr(pWins->WinsSignature);
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
// send the Datagram...
|
|||
|
status = UdpSendDatagram (pTracker,
|
|||
|
ntohl(pSendAddr->IpAddress),
|
|||
|
WinsDgramCompletion,
|
|||
|
pTracker, // context for completion
|
|||
|
(USHORT)ntohs(pSendAddr->Port),
|
|||
|
NBT_NAME_SERVICE);
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Doing Wins Send, status=%X\n",status));
|
|||
|
|
|||
|
// sending the datagram could return status pending,
|
|||
|
// but since we have buffered the dgram, return status
|
|||
|
// success to the client
|
|||
|
//
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
//
|
|||
|
// Fill in the sent size
|
|||
|
//
|
|||
|
pIrp->IoStatus.Information = DgramLength;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
WinsFreeMem (pWins, (PVOID)pDgram,DgramLength,FALSE);
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
pIrp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Holding onto Buffering Wins Send, status=%X\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Hold onto the datagram till memory frees up
|
|||
|
//
|
|||
|
InsertTailList(&pWins->SendList,&pIrp->Tail.Overlay.ListEntry);
|
|||
|
|
|||
|
status = NTCheckSetCancelRoutine(pIrp,NbtCancelWinsSendIrp,NULL);
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
NTIoComplete(pIrp,status,0);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
status = STATUS_PENDING;
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (fIsWinsDevice)
|
|||
|
{
|
|||
|
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_WINS, FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
pIrp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
CheckIfLocalNameActive(
|
|||
|
IN tREM_ADDRESS *pSendAddr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description
|
|||
|
|
|||
|
This routine checks if this is a name query response and if the
|
|||
|
name is still active on the local node.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pMdl = ptr to WINS Mdl
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
VOID
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
tNAMEHDR UNALIGNED *pNameHdr;
|
|||
|
tNAMEADDR *pResp;
|
|||
|
UCHAR pName[NETBIOS_NAME_SIZE];
|
|||
|
PUCHAR pScope;
|
|||
|
ULONG lNameSize;
|
|||
|
CTELockHandle OldIrq;
|
|||
|
|
|||
|
pNameHdr = (tNAMEHDR UNALIGNED *)((PUCHAR)pSendAddr + sizeof(tREM_ADDRESS));
|
|||
|
//
|
|||
|
// Be sure it is a name query PDU that we are checking
|
|||
|
//
|
|||
|
if (((pNameHdr->OpCodeFlags & NM_FLAGS_MASK) == OP_QUERY) ||
|
|||
|
((pNameHdr->OpCodeFlags & NM_FLAGS_MASK) == OP_RELEASE))
|
|||
|
{
|
|||
|
status = ConvertToAscii ((PCHAR)&pNameHdr->NameRR.NameLength,
|
|||
|
pSendAddr->LengthOfBuffer,
|
|||
|
pName,
|
|||
|
&pScope,
|
|||
|
&lNameSize);
|
|||
|
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
//
|
|||
|
// see if the name is still active in the local hash table
|
|||
|
//
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
status = FindInHashTable(NbtConfig.pLocalHashTbl, pName, pScope, &pResp);
|
|||
|
|
|||
|
if ((pNameHdr->OpCodeFlags & NM_FLAGS_MASK) == OP_QUERY)
|
|||
|
{
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
//
|
|||
|
// if not resolved then set to negative name query resp.
|
|||
|
//
|
|||
|
if (!(pResp->NameTypeState & STATE_RESOLVED))
|
|||
|
{
|
|||
|
pNameHdr->OpCodeFlags |= htons(NAME_ERROR);
|
|||
|
}
|
|||
|
}
|
|||
|
//
|
|||
|
// We can have a scenario where the local machine was a DC
|
|||
|
// at one time, so it set the UNIX to tell Wins when registering
|
|||
|
// the local name.A However, once that machine is downgraded,
|
|||
|
// Wins will still have the UNIX flag set for that record if
|
|||
|
// there were other DC's also present.
|
|||
|
// Thus, we can have the following scenario where the machine
|
|||
|
// is currently not a DC, but the UNIX flag is set in the response
|
|||
|
// so we should not mark the name in Error. This would not
|
|||
|
// be a problem if the client is configured with other Wins
|
|||
|
// server addresses, but otherwise it could cause problems!
|
|||
|
// Bug # 54659
|
|||
|
//
|
|||
|
else if (pName[NETBIOS_NAME_SIZE-1] != SPECIAL_GROUP_SUFFIX)
|
|||
|
{
|
|||
|
pNameHdr->OpCodeFlags |= htons(NAME_ERROR);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// check if it is a release response - if so we must have
|
|||
|
// received a name release request, so mark the name in
|
|||
|
// conflict and return a positive release response.
|
|||
|
//
|
|||
|
// Note: The case we are looking at here is if another Wins
|
|||
|
// sent a NameRelease demand for some name to the local machine.
|
|||
|
// Since we pass all name releases up to Wins, NetBT will
|
|||
|
// not get a chance to determine if it is a local name when
|
|||
|
// the release first came in.
|
|||
|
// Typically, Wins should make the call properly as to whether
|
|||
|
// NetBT should mark the local name in conflict or not, but
|
|||
|
// it has been observed that Wins displayed inconsistent behavior
|
|||
|
// setting the UNIX flag only if the local machine was the last
|
|||
|
// to register/refresh the name (Bug # 431042).
|
|||
|
// For now, we will remove this functionality for Group names.
|
|||
|
//
|
|||
|
if (pNameHdr->OpCodeFlags & OP_RESPONSE)
|
|||
|
{
|
|||
|
//
|
|||
|
// Bug # 206192: If we are sending the response to
|
|||
|
// ourselves, don't put the name into conflict
|
|||
|
// (could be due to NbtStat -RR!)
|
|||
|
//
|
|||
|
if (NT_SUCCESS(status) &&
|
|||
|
(pResp->NameTypeState & STATE_RESOLVED) &&
|
|||
|
(pResp->NameTypeState & NAMETYPE_UNIQUE) &&
|
|||
|
!(pNameHdr->OpCodeFlags & FL_RCODE) && // Only for positive name release response
|
|||
|
!(SrcIsUs(ntohl(pSendAddr->IpAddress))))
|
|||
|
{
|
|||
|
NbtLogEvent (EVENT_NBT_NAME_RELEASE, pSendAddr->IpAddress, 0x122);
|
|||
|
|
|||
|
pResp->NameTypeState &= ~NAME_STATE_MASK;
|
|||
|
pResp->NameTypeState |= STATE_CONFLICT;
|
|||
|
pResp->ConflictMask |= pResp->AdapterMask;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// the name is not in the local table so fail the datagram send attempt
|
|||
|
//
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
WinsDgramCompletion(
|
|||
|
IN tDGRAM_SEND_TRACKING *pTracker,
|
|||
|
IN NTSTATUS status,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description
|
|||
|
|
|||
|
This routine cleans up after a data gram send.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pTracker
|
|||
|
status
|
|||
|
Length
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
VOID
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
CTELockHandle OldIrq;
|
|||
|
LIST_ENTRY *pEntry;
|
|||
|
PIRP pIrp;
|
|||
|
BOOLEAN MustSend;
|
|||
|
#ifdef _PNP_POWER_
|
|||
|
tDEVICECONTEXT *pDeviceContext;
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// free the buffer used for sending the data and the tracker - note
|
|||
|
// that the datagram header and the send buffer are allocated as one
|
|||
|
// chunk.
|
|||
|
//
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
if ((pWinsInfo) &&
|
|||
|
(pTracker->ClientContext == IntToPtr(pWinsInfo->WinsSignature)))
|
|||
|
{
|
|||
|
WinsFreeMem(pWinsInfo,
|
|||
|
(PVOID)pTracker->SendBuffer.pDgramHdr,
|
|||
|
pTracker->AllocatedLength,
|
|||
|
FALSE);
|
|||
|
|
|||
|
if (!IsListEmpty(&pWinsInfo->SendList))
|
|||
|
{
|
|||
|
#ifdef _PNP_POWER_
|
|||
|
//
|
|||
|
// If there are no devices available to send this request on,
|
|||
|
// complete all pending requests gracefully
|
|||
|
//
|
|||
|
if (!(pDeviceContext = pWinsInfo->pDeviceContext) ||
|
|||
|
!(NBT_REFERENCE_DEVICE (pDeviceContext, REF_DEV_WINS, TRUE)))
|
|||
|
{
|
|||
|
status = STATUS_PLUGPLAY_NO_DEVICE;
|
|||
|
|
|||
|
while (!IsListEmpty(&pWinsInfo->SendList))
|
|||
|
{
|
|||
|
pEntry = RemoveHeadList(&pWinsInfo->SendList);
|
|||
|
pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
|
|||
|
NbtCancelCancelRoutine (pIrp);
|
|||
|
pIrp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
|
|||
|
|
|||
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
FreeTracker (pTracker, RELINK_TRACKER);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
#endif // _PNP_POWER_
|
|||
|
|
|||
|
IF_DBG(NBT_DEBUG_WINS)
|
|||
|
KdPrint(("Nbt:Sending another Wins Dgram that is Queued to go\n"));
|
|||
|
|
|||
|
pEntry = RemoveHeadList(&pWinsInfo->SendList);
|
|||
|
pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
|
|||
|
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
NbtCancelCancelRoutine (pIrp);
|
|||
|
|
|||
|
//
|
|||
|
// Send this next datagram
|
|||
|
//
|
|||
|
status = WinsSendDatagram(pDeviceContext,
|
|||
|
pIrp,
|
|||
|
MustSend = TRUE);
|
|||
|
|
|||
|
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_WINS, FALSE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// just free the memory since WINS has closed its address handle.
|
|||
|
//
|
|||
|
CTEMemFree((PVOID)pTracker->SendBuffer.pDgramHdr);
|
|||
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|||
|
}
|
|||
|
|
|||
|
FreeTracker (pTracker, RELINK_TRACKER);
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
PVOID
|
|||
|
WinsAllocMem(
|
|||
|
IN tWINS_INFO *pWinsContext,
|
|||
|
IN ULONG Size,
|
|||
|
IN BOOLEAN Rcv
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This Routine handles allocating memory and keeping track of how
|
|||
|
much has been allocated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Size - number of bytes to allocate
|
|||
|
Rcv - boolean that indicates if it is rcv or send buffering
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ptr to the memory allocated
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (Rcv)
|
|||
|
{
|
|||
|
if (pWinsContext->RcvMemoryAllocated > pWinsContext->RcvMemoryMax)
|
|||
|
{
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pWinsContext->RcvMemoryAllocated += Size;
|
|||
|
return (NbtAllocMem(Size,NBT_TAG('v')));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (pWinsContext->SendMemoryAllocated > pWinsContext->SendMemoryMax)
|
|||
|
{
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pWinsContext->SendMemoryAllocated += Size;
|
|||
|
return(NbtAllocMem(Size,NBT_TAG('v')));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
VOID
|
|||
|
WinsFreeMem(
|
|||
|
IN tWINS_INFO *pWinsContext,
|
|||
|
IN PVOID pBuffer,
|
|||
|
IN ULONG Size,
|
|||
|
IN BOOLEAN Rcv
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This Routine handles freeing memory and keeping track of how
|
|||
|
much has been allocated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pBuffer - buffer to free
|
|||
|
Size - number of bytes to allocate
|
|||
|
Rcv - boolean that indicates if it is rcv or send buffering
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (pWinsContext)
|
|||
|
{
|
|||
|
if (Rcv)
|
|||
|
{
|
|||
|
pWinsContext->RcvMemoryAllocated -= Size;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pWinsContext->SendMemoryAllocated -= Size;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CTEMemFree(pBuffer);
|
|||
|
}
|