mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
723 lines
16 KiB
723 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
atkutils.c
|
|
|
|
Abstract:
|
|
|
|
This module contains utility routines for windows nt implementation of stack
|
|
|
|
Author:
|
|
|
|
Nikhil Kamkolkar (NikhilK) 28-Jun-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "atalknt.h"
|
|
|
|
|
|
|
|
|
|
UINT
|
|
AtalkWstrLength(
|
|
IN PWSTR Wstr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the length of null-terminated word string
|
|
|
|
Arguments:
|
|
|
|
Wstr - the word-string whose length is to be determined
|
|
|
|
Return Value:
|
|
|
|
Length of the string
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT Length = 0;
|
|
while (*Wstr++) {
|
|
Length += sizeof(WCHAR);
|
|
}
|
|
return Length;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkGetProtocolSocketType(
|
|
PATALK_DEVICE_CONTEXT Context,
|
|
PUNICODE_STRING RemainingFileName,
|
|
PUCHAR ProtocolType,
|
|
PUCHAR SocketType
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG protocolType;
|
|
UNICODE_STRING typeString;
|
|
|
|
*ProtocolType = PROTOCOL_TYPE_UNDEFINED;
|
|
*SocketType = SOCKET_TYPE_UNDEFINED;
|
|
|
|
switch (Context->DeviceType) {
|
|
case ATALK_DEVICE_DDP :
|
|
|
|
if ((UINT)RemainingFileName->Length <= AtalkWstrLength(PROTOCOLTYPE_PREFIX)){
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
}
|
|
|
|
RtlInitUnicodeString(
|
|
&typeString,
|
|
(PWCHAR)((PCHAR)RemainingFileName->Buffer +
|
|
AtalkWstrLength(PROTOCOLTYPE_PREFIX)));
|
|
|
|
status = AtalkUnicodeStringToInteger(
|
|
&typeString,
|
|
DECIMAL_BASE, // Decimal base
|
|
&protocolType);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkGetProtocolType - protocol type is %lx\n", protocolType));
|
|
|
|
if ((protocolType > DDPPROTO_DDP) && (protocolType <= DDPPROTO_MAX)) {
|
|
*ProtocolType = (UCHAR)protocolType;
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case ATALK_DEVICE_ADSP :
|
|
|
|
//
|
|
// Check for the socket type
|
|
//
|
|
|
|
if (RemainingFileName->Length == 0) {
|
|
*SocketType = SOCKET_TYPE_RDM;
|
|
break;
|
|
}
|
|
|
|
if ((UINT)RemainingFileName->Length != AtalkWstrLength(SOCKETSTREAM_SUFFIX)){
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
}
|
|
|
|
RtlInitUnicodeString(
|
|
&typeString,
|
|
SOCKETSTREAM_SUFFIX);
|
|
|
|
//
|
|
// Case insensitive compare
|
|
//
|
|
|
|
if (RtlEqualUnicodeString(&
|
|
typeString,
|
|
RemainingFileName,
|
|
TRUE)) {
|
|
|
|
*SocketType = SOCKET_TYPE_STREAM;
|
|
break;
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
}
|
|
|
|
case ATALK_DEVICE_ATP :
|
|
case ATALK_DEVICE_ASP :
|
|
case ATALK_DEVICE_PAP :
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
}
|
|
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkUnicodeStringToInteger (
|
|
IN PUNICODE_STRING String,
|
|
IN ULONG Base OPTIONAL,
|
|
OUT PULONG Value
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UCHAR ResultBuffer[ 36 ];
|
|
ANSI_STRING AnsiString;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
UnicodeString = *String;
|
|
if (UnicodeString.Length >= (sizeof( ResultBuffer ) * sizeof( WCHAR ))) {
|
|
UnicodeString.Length = ((sizeof( ResultBuffer )-1) * sizeof( WCHAR ));
|
|
}
|
|
|
|
AnsiString.Buffer = ResultBuffer;
|
|
AnsiString.MaximumLength = sizeof( ResultBuffer );
|
|
AnsiString.Length = 0;
|
|
Status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeString, FALSE );
|
|
if (NT_SUCCESS( Status )) {
|
|
AnsiString.Buffer[ AnsiString.Length ] = '\0';
|
|
Status = RtlCharToInteger( AnsiString.Buffer, Base, Value );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GetDuplicateAnsiString(
|
|
PWCHAR SourceString,
|
|
PANSI_STRING AnsiString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Duplicates the string as an AnsiString.
|
|
|
|
Arguments:
|
|
|
|
SourceString - Null terminated word string
|
|
AnsiString - Pointer to the AnsiString structure where the created string
|
|
is to be returned.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - if created ok
|
|
Error status if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeString;
|
|
ULONG ansiSize;
|
|
|
|
NTSTATUS status;
|
|
|
|
RtlInitUnicodeString(&unicodeString, SourceString);
|
|
ansiSize = RtlUnicodeStringToAnsiSize(&unicodeString);
|
|
AnsiString->Buffer = (PCHAR)AtalkAllocNonPagedMemory( ansiSize+1);
|
|
if (AnsiString->Buffer == NULL) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_RESOURCES, DEBUG_LEVEL_ERROR, ("GetDuplicateAnsiString: Allocate Memory failed! %lx\n", ansiSize+1));
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
AnsiString->MaximumLength = (USHORT)ansiSize+2;
|
|
AnsiString->Length = 0;
|
|
|
|
status = RtlUnicodeStringToAnsiString(AnsiString, &unicodeString, (BOOLEAN)FALSE);
|
|
if (status != STATUS_SUCCESS) {
|
|
DBGPRINT(ATALK_DEBUG_SYSTEM, DEBUG_LEVEL_ERROR, ("Unicode to ansi failed %d\n", status));
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
|
|
|
|
INT
|
|
IrpGetEaCreateType(
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks the EA name and returns the appropriate open type.
|
|
|
|
Arguments:
|
|
|
|
Irp - the irp for the create request, the EA value is stored in the
|
|
SystemBuffer
|
|
|
|
Return Value:
|
|
|
|
TDI_TRANSPORT_ADDRESS_FILE: Create irp was for a transport address
|
|
TDI_CONNECTION_FILE: Create irp was for a connection object
|
|
ATALK_FILE_TYPE_CONTROL: Create irp was for a control channel (ea = NULL)
|
|
|
|
--*/
|
|
|
|
{
|
|
PFILE_FULL_EA_INFORMATION openType;
|
|
BOOLEAN found;
|
|
INT returnType;
|
|
USHORT i;
|
|
|
|
openType =
|
|
(PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (openType != NULL) {
|
|
|
|
do {
|
|
|
|
found = TRUE;
|
|
|
|
for (i=0;i<(USHORT)openType->EaNameLength;i++) {
|
|
if (openType->EaName[i] == TdiTransportAddress[i]) {
|
|
continue;
|
|
} else {
|
|
found = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
returnType = TDI_TRANSPORT_ADDRESS_FILE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Is this a connection object?
|
|
//
|
|
|
|
found = TRUE;
|
|
|
|
for (i=0;i<(USHORT)openType->EaNameLength;i++) {
|
|
if (openType->EaName[i] == TdiConnectionContext[i]) {
|
|
continue;
|
|
} else {
|
|
found = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
returnType = TDI_CONNECTION_FILE;
|
|
break;
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
} else {
|
|
|
|
returnType = ATALK_FILE_TYPE_CONTROL;
|
|
}
|
|
|
|
return(returnType);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Tdi Request- Create/Destroy Ref/Deref routines
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
AtalkCreateTdiRequest(
|
|
PATALK_TDI_REQUEST *Request
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates and references a TDI request structure
|
|
|
|
Arguments:
|
|
|
|
Request - pointer to created structure is returned in here
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if created, error status otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PATALK_TDI_REQUEST request;
|
|
USHORT i;
|
|
|
|
request = (PATALK_TDI_REQUEST)AtalkCallocNonPagedMemory(sizeof(ATALK_TDI_REQUEST), sizeof(char));
|
|
if (request == NULL) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_SEVERE, ("SEVERE ERROR: Malloc failed in CreateRequest %lx!\n", sizeof(ATALK_TDI_REQUEST)));
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
request->Type = ATALK_TDI_REQUEST_SIGNATURE;
|
|
request->Size = sizeof(ATALK_TDI_REQUEST);
|
|
|
|
request->Flags = REQUEST_FLAGS_OPEN;
|
|
request->ActionCode = 0;
|
|
|
|
//
|
|
// Initialize list head and spin lock
|
|
//
|
|
|
|
InitializeListHead(&request->Linkage);
|
|
NdisAllocateSpinLock(&request->RequestLock);
|
|
|
|
for (i = 0; i < MAX_REQUESTMDLS; i++) {
|
|
request->MdlChain[i] = NULL;
|
|
}
|
|
|
|
//
|
|
// A reference for creation
|
|
//
|
|
|
|
#if DBG
|
|
request->RefTypes[RQREF_CREATE] = 1;
|
|
#endif
|
|
|
|
request->ReferenceCount = 1;
|
|
|
|
*Request = request;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDestroyTdiRequest(
|
|
PATALK_TDI_REQUEST Request
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when the last reference on the request goes away. The request
|
|
is now destroyed. The associated connection object/address object/
|
|
control channel is dereferenced.
|
|
|
|
Arguments:
|
|
|
|
Request - the request to be destroyed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Request->Flags & REQUEST_FLAGS_DEREFOWNER) {
|
|
|
|
//
|
|
// Remove a reference to the owner of this request
|
|
// We do it here, so we know for sure that the request is nolonger
|
|
// going to reference the fileobject it is associated with/
|
|
//
|
|
|
|
switch ((INT)Request->OwnerType) {
|
|
case TDI_TRANSPORT_ADDRESS_FILE :
|
|
|
|
AtalkDereferenceAddress("TdiReqAddr", ((PADDRESS_FILE)Request->Owner), AREF_REQUEST, SECONDARY_REFSET);
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE :
|
|
|
|
AtalkDereferenceConnection("TdiReqConn", ((PCONNECTION_FILE)Request->Owner), CREF_REQUEST, SECONDARY_REFSET);
|
|
break;
|
|
|
|
case ATALK_FILE_TYPE_CONTROL :
|
|
|
|
AtalkDereferenceControlChannel("TdiReqChan", ((PCONTROLCHANNEL_FILE)Request->Owner), CCREF_REQUEST, SECONDARY_REFSET);
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// BUGBUG:
|
|
// Should never happen; log error
|
|
//
|
|
|
|
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_SEVERE,
|
|
("ERROR: AtalkTdiDestroyRequest - Unknown object type when dereferencing request %ld-%lx\n", (INT)Request->OwnerType, Request));
|
|
|
|
DBGBRK(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_SEVERE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NdisFreeSpinLock(&Request->RequestLock);
|
|
AtalkFreeNonPagedMemory(Request);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkRefTdiRequest(
|
|
IN PATALK_TDI_REQUEST Request
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine increments the reference count on a request structure
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG count;
|
|
|
|
count = NdisInterlockedAddUlong (
|
|
(PULONG)&Request->ReferenceCount,
|
|
(ULONG)1,
|
|
&AtalkGlobalRefLock);
|
|
|
|
ASSERT (count > 0);
|
|
return;
|
|
|
|
} /* AtalkRefTdiRequest */
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDerefTdiRequest(
|
|
IN PATALK_TDI_REQUEST Request
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dereferences a transport Request by decrementing the
|
|
reference count contained in the structure. If, after being
|
|
decremented, the reference count is zero, then this routine calls
|
|
AtalkDestroyRequest to remove it from the system.
|
|
|
|
Arguments:
|
|
|
|
Request - Pointer to a transport Request object.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG count;
|
|
|
|
count = NdisInterlockedAddUlong (
|
|
(PULONG)&Request->ReferenceCount,
|
|
(ULONG)-1,
|
|
&AtalkGlobalRefLock);
|
|
|
|
//
|
|
// If we have deleted all references to this Request, then we can
|
|
// destroy the object. It is okay to have already released the spin
|
|
// lock at this point because there is no possible way that another
|
|
// stream of execution has access to the Request any longer.
|
|
//
|
|
|
|
ASSERT (count >= 1);
|
|
|
|
if (count == 1) {
|
|
|
|
//
|
|
// Free the information buffer and then the atalkRequest buffer
|
|
//
|
|
|
|
DBGPRINT(ATALK_DEBUG_REFCOUNTS, DEBUG_LEVEL_INFOCLASS1,
|
|
("INFO1: AtalkDerefRequest - Destroying TDI request buffer %lx\n", Request));
|
|
|
|
AtalkDestroyTdiRequest(Request);
|
|
}
|
|
|
|
} /* AtalkDerefRequest */
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkCompleteTdiRequest (
|
|
PATALK_TDI_REQUEST Request,
|
|
NTSTATUS status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes the ioRequest irp for the request, and then dereferences the
|
|
tdi request.
|
|
|
|
Arguments:
|
|
|
|
Request - request to complete
|
|
Status - status to use for io completion
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT i;
|
|
|
|
//
|
|
// Free the MDL's if they exist
|
|
//
|
|
|
|
for (i = 0; i < MAX_REQUESTMDLS; i++) {
|
|
if (Request->MdlChain[i] != NULL) {
|
|
FreeAnMdl(Request->MdlChain[i]);
|
|
} else
|
|
break; // Break upon first null mdl
|
|
}
|
|
|
|
//
|
|
// Complete the request and then dereference it
|
|
//
|
|
|
|
Request->IoStatus->Status = status;
|
|
DBGPRINT(ATALK_DEBUG_ALL, DEBUG_LEVEL_INFOCLASS1,
|
|
("INFO1: AtalkCompleteTdiRequest - status %lx info %lx pending %d\n",
|
|
status, Request->IoStatus->Information,
|
|
Request->IoRequestIrp->PendingReturned));
|
|
|
|
IoCompleteRequest(Request->IoRequestIrp, IO_NETWORK_INCREMENT );
|
|
AtalkDereferenceTdiRequest("TdiReqCmpl", Request, RQREF_MAKEREQ);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
DbgPrintPortInfo(
|
|
INT NumberOfPorts,
|
|
PPORT_INFO PortInformation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < NumberOfPorts; i++) {
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("PORT INFORMATION STRUCTURE DUMP: Port %d\n", i));
|
|
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("DesiredPort -> %d\n", PortInformation[i].desiredPort));
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("PortType -> %d\n", PortInformation[i].portType));
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("A(ProtocolInfo)-> %lx\n",&PortInformation[i].protocolInfo));
|
|
|
|
if (PortInformation[i].portName != NULL) {
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("PortName -> %s\n", PortInformation[i].portName));
|
|
} else {
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("PortName -> (NULL)\n"));
|
|
}
|
|
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("AARP Probes -> %d\n", PortInformation[i].aarpProbes));
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("RoutingPort -> %d\n", PortInformation[i].routingPort));
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("SeedRouter -> %d\n", PortInformation[i].seedRouter));
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("networkRange -> %lx-%lx\n", \
|
|
PortInformation[i].networkRange.firstNetworkNumber, \
|
|
PortInformation[i].networkRange.lastNetworkNumber))
|
|
|
|
DbgPrintZoneList(PortInformation[i].zoneList);
|
|
|
|
if (PortInformation[i].defaultZone != NULL) {
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("DefaultZone -> %s\n", PortInformation[i].defaultZone));
|
|
} else {
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("DefaultZone -> NULL\n"));
|
|
}
|
|
|
|
if (PortInformation[i].desiredZone != NULL) {
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("DesiredZone -> %s\n", PortInformation[i].desiredZone));
|
|
} else {
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("DesiredZone -> NULL\n"));
|
|
}
|
|
|
|
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("defaultPort -> %d\n", PortInformation[i].defaultPort));
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("sendDdpChec -> %d\n", PortInformation[i].sendDdpChecksums));
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("startRouter -> %d\n", PortInformation[i].startRouter));
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
DbgPrintZoneList(
|
|
PZONELIST Zlist
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("ZoneList:\n"));
|
|
while (Zlist != NULL) {
|
|
if (Zlist->zone != NULL) {
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("%s\n", Zlist->zone));
|
|
}
|
|
else
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_ERROR, ("Zlist->zone = NULL!!\n"));
|
|
|
|
Zlist = Zlist->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|