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.
402 lines
9.0 KiB
402 lines
9.0 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
netbcom.c
|
|
|
|
Abstract:
|
|
|
|
NetBios transport common code between server and client.
|
|
|
|
Author:
|
|
|
|
Steven Zeck (stevez) 2/12/92
|
|
|
|
Danny Glasser (dannygl) 3/1/93
|
|
|
|
--*/
|
|
|
|
#include "NetBCom.h"
|
|
|
|
// The maximum value of a lana number
|
|
#define MAX_LANA_NUMBER UCHAR_MAX
|
|
|
|
// This the netbios name of this (self) machine.
|
|
// NOTE: We assume one-byte characters here
|
|
|
|
unsigned char MachineName[NCBNAMSZ];
|
|
size_t MachineNameLengthUnpadded;
|
|
|
|
CRITICAL_SECTION NetBiosMutex;
|
|
|
|
PROTOCOL_MAP ProtoToLana[MAX_LANA];
|
|
|
|
|
|
|
|
#define MAX_MAP_ENTRIES 20
|
|
|
|
void RPC_ENTRY
|
|
InitNBMutex (
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the critical section object used to serialize
|
|
access to the global data structures. It is called by both the client
|
|
and server DLLs (once by each), both of which use this critical section
|
|
object.
|
|
|
|
Note: There is a small potential race condition in which the client and
|
|
server could both call this function at the same time. Given the design
|
|
of the RPC runtime, however, this is highly unlikely if not impossible.
|
|
Even if it were to occur, it would probably not be harmful.
|
|
--*/
|
|
{
|
|
#ifdef WIN32RPC
|
|
static char AlreadyDone = 0;
|
|
|
|
if (! AlreadyDone)
|
|
{
|
|
AlreadyDone = 1;
|
|
|
|
InitializeCriticalSection(&NetBiosMutex);
|
|
}
|
|
#endif // WIN32RPC
|
|
}
|
|
|
|
RPC_STATUS
|
|
MapProtocol(
|
|
IN RPC_CHAR *ProtoSeq,
|
|
IN int DriverNumber,
|
|
OUT PPROTOCOL_MAP *ProtocolEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function maps a protocol string into a protocol map entry.
|
|
|
|
In the non-NT versions, it looks up the information dynamically
|
|
in the registry. In the NT version, the registry information is
|
|
pre-loaded
|
|
|
|
Arguments:
|
|
|
|
ProtoSeq - the protocol sequence that we want to map
|
|
|
|
DriverNumber - the logical driver number for the protocol.
|
|
|
|
ProtocolEntry - pointer to place to return the results.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK, RPC_S_OUT_OF_RESOURCES, RPC_S_INVALID_ENDPOINT_FORMAT
|
|
|
|
The output pointer is set to the corresponding entry when found.
|
|
|
|
--*/
|
|
{
|
|
long status;
|
|
int i;
|
|
HKEY RegHandle;
|
|
char Protocol[40];
|
|
char LanaString[10];
|
|
DWORD dtype;
|
|
long BufferLength = sizeof(LanaString);
|
|
|
|
// Copy the possible unicode protocol string to ascii.
|
|
|
|
for (i = 0; (Protocol[i] = (char) ProtoSeq[i]) && i < sizeof(Protocol); i++) ;
|
|
|
|
// Add the logical driver number to the protocol string. This
|
|
// allows multiple drivers (net cards) to be attached to the same
|
|
// logical protocol.
|
|
|
|
Protocol[i] = (char) ('0' + DriverNumber);
|
|
Protocol[i+1] = 0;
|
|
|
|
// First look in the proto sequences that we have already mapped.
|
|
|
|
for (i = 0; ProtocolTable[i].ProtoSeq && i < MAX_LANA; i++)
|
|
{
|
|
// If found, set the output pointer.
|
|
|
|
if (strcmp(ProtocolTable[i].ProtoSeq, Protocol) == 0)
|
|
{
|
|
*ProtocolEntry = &ProtocolTable[i];
|
|
return(RPC_S_OK);
|
|
}
|
|
}
|
|
|
|
if (i >= MAX_LANA)
|
|
return(RPC_S_PROTSEQ_NOT_FOUND);
|
|
|
|
status = RegOpenKeyEx(RPC_REG_ROOT, REG_NETBIOS, 0, KEY_READ, &RegHandle);
|
|
|
|
if (status)
|
|
return(RPC_S_PROTSEQ_NOT_FOUND);
|
|
|
|
status = RegQueryValueExA(RegHandle, Protocol, 0, &dtype, LanaString, &BufferLength);
|
|
|
|
RegCloseKey(RegHandle);
|
|
|
|
if (status || ! (*LanaString >= '0' && *LanaString <= '9'))
|
|
return(RPC_S_PROTSEQ_NOT_FOUND);
|
|
|
|
// Now we have a Lana number for the protocol sequence. Put this
|
|
// info in the protocol to lana mapping structure.
|
|
|
|
if (! (ProtocolTable[i].ProtoSeq
|
|
= (char *) I_RpcAllocate(strlen(Protocol)+1)) )
|
|
{
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
strcpy(ProtocolTable[i].ProtoSeq, Protocol);
|
|
ProtocolTable[i].Lana = (unsigned char) (*LanaString - '0');
|
|
|
|
*ProtocolEntry = &ProtocolTable[i];
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
MapErrorCode (
|
|
IN ERROR_TABLE * MapTable,
|
|
IN RPC_OS_ERROR Status,
|
|
IN RPC_STATUS DefaultStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function maps a OS specific error code into a generic RPC
|
|
status code. The ERROR_TABLE is an unordered list of pairs, with
|
|
a value of 0 terminating the table. So don't try to translate a
|
|
0 OS_ERROR.
|
|
|
|
You will see this routine called , with the return value ignored.
|
|
This is done when we don't need the translated error code, but
|
|
want to check for unexpected failures.
|
|
|
|
Arguments:
|
|
|
|
MapTable - The table to OS codes to RPC_STATUS codes.
|
|
|
|
Status - The OS specific error that we wish to map.
|
|
|
|
DefaultStatus - The status to return if none of the codes match.
|
|
We will ASSERT in the debug version if we have to take this action.
|
|
|
|
Return Value:
|
|
|
|
The translated error code if there is match, else the value
|
|
of DefaultStatus.
|
|
|
|
--*/
|
|
{
|
|
int TableIndex;
|
|
|
|
ASSERT(MapTable);
|
|
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPC NetBIOS Map Status %x(%d)\n", Status, DefaultStatus);
|
|
#endif
|
|
|
|
for (TableIndex = 0; MapTable[TableIndex].OScode != 0; TableIndex++)
|
|
if (MapTable[TableIndex].OScode == Status)
|
|
return (MapTable[TableIndex].RpcStatus);
|
|
|
|
return (DefaultStatus);
|
|
}
|
|
|
|
|
|
int
|
|
SetupNetBios (
|
|
IN RPC_CHAR * RpcProtocolSequence
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loadable transport initialization function. Get the machine name
|
|
of this workstation into MachineName and perform other OS specific
|
|
initiailization.
|
|
|
|
Arguments:
|
|
|
|
RpcProtocolSequence - the protocol string that mapped to this library.
|
|
|
|
Returns:
|
|
|
|
TRUE if the initialization was OK.
|
|
|
|
--*/
|
|
|
|
{
|
|
int i;
|
|
BOOLEAN BooleanStatus;
|
|
DWORD Status;
|
|
DWORD ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
unsigned char ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
|
|
Status = GetComputerNameA(ComputerName, &ComputerNameLength);
|
|
|
|
ASSERT(Status == TRUE);
|
|
|
|
_strupr(ComputerName);
|
|
|
|
// Store padded machine name (and save unpadded length)
|
|
|
|
MachineNameLengthUnpadded = strlen(ComputerName);
|
|
memcpy(MachineName, ComputerName, MachineNameLengthUnpadded);
|
|
memset(MachineName + MachineNameLengthUnpadded,
|
|
NETBIOS_NAME_PAD_BYTE,
|
|
sizeof(MachineName) - MachineNameLengthUnpadded);
|
|
|
|
ASSERT(MachineNameLengthUnpadded < sizeof(MachineName));
|
|
|
|
PUNUSED(RpcProtocolSequence);
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
UCHAR RPC_ENTRY
|
|
AdapterReset (
|
|
IN PPROTOCOL_MAP ProtocolEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used by both the client and server NetBIOS transports
|
|
to submit the RESET NCB for a process, as is required by NetBIOS on NT.
|
|
|
|
We need to perform this in a single place to allow a process to act
|
|
as both an RPC client and server over NetBIOS. Otherwise, both the
|
|
client and server transports would submit RESETs and the second one
|
|
would destroy the state of the first.
|
|
|
|
Arguments:
|
|
|
|
ProtocolEntry - This is the entry in the protocol map for the adapter
|
|
to be reset.
|
|
|
|
Returns:
|
|
|
|
The return code of the RESET NCB, if it's submitted.
|
|
|
|
0 if the RESET has already occurred.
|
|
--*/
|
|
{
|
|
unsigned char status = 0;
|
|
|
|
// Make sure that no other threads are accessing this function
|
|
CRITICAL_ENTER();
|
|
|
|
// Perform the reset, if necessary
|
|
if (! ProtocolEntry->ResetDone)
|
|
{
|
|
NCB theNCB;
|
|
|
|
memset(&theNCB, 0 , sizeof(theNCB));
|
|
theNCB.ncb_lana_num = ProtocolEntry->Lana;
|
|
|
|
// The values are needed for the server
|
|
theNCB.ncb_callname[0] = 254; // max sessions
|
|
theNCB.ncb_callname[1] = 64; // max commands
|
|
theNCB.ncb_callname[2] = 32; // max names
|
|
|
|
status = execNCB(NCBRESET, &theNCB);
|
|
|
|
// If the NCB was successfully invoked, get the status from the
|
|
// completed NCB itself.
|
|
if (status == 0)
|
|
{
|
|
status = theNCB.ncb_retcode;
|
|
}
|
|
|
|
// Set the flag so the reset is performed only once (per process).
|
|
if (status == 0)
|
|
{
|
|
ProtocolEntry->ResetDone = 1;
|
|
}
|
|
}
|
|
|
|
// Allow other threads to run again
|
|
CRITICAL_LEAVE();
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
unsigned char RPC_ENTRY
|
|
execNCB(
|
|
IN unsigned char command,
|
|
IN OUT NCB *pNCB
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pass an NCB to the NetBios software to execute. This function hides
|
|
the differences of the OS from the other parts of the driver.
|
|
|
|
Arguments:
|
|
|
|
command - command to execute
|
|
|
|
pNCB - NCB to act on
|
|
|
|
Returns:
|
|
|
|
The result of ncb_retcode field from the NCB executed.
|
|
|
|
--*/
|
|
{
|
|
unsigned char result;
|
|
|
|
pNCB->ncb_command = command;
|
|
|
|
#if defined(WIN32RPC)
|
|
result = Netbios(pNCB);
|
|
|
|
#elif defined(WIN)
|
|
// If the command is an async one, call the transport helper
|
|
// functions to corrdinate the waiting.
|
|
|
|
_asm
|
|
{
|
|
les bx,pNCB
|
|
call NetBiosCall
|
|
|
|
mov al,es:[bx+1]
|
|
mov result,al
|
|
}
|
|
|
|
if (result == NRC_PENDING)
|
|
result = 0;
|
|
|
|
#else // DOS
|
|
_asm {
|
|
les bx, pNCB
|
|
int 05ch ; call NetBios Directly
|
|
mov result,al
|
|
};
|
|
|
|
if (result == NRC_PENDING)
|
|
result = 0;
|
|
|
|
#endif
|
|
|
|
return(result);
|
|
}
|