windows-nt/Source/XPSP1/NT/net/rras/ipx/ipxwan/ipxwan.c
2020-09-26 16:20:57 +08:00

406 lines
7.8 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
ipxwan.c
Abstract:
ipxwan control
Author:
Stefan Solomon 02/06/1996
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
ULONG EnableUnnumberedWanLinks;
HANDLE WorkerThreadHandle;
// IPXCP Entry Points
DWORD
(WINAPI *IpxcpGetWanNetNumber)(IN OUT PUCHAR Network,
IN OUT PULONG AllocatedNetworkIndexp,
IN ULONG InterfaceType);
VOID
(WINAPI *IpxcpReleaseWanNetNumber)(ULONG AllocatedNetworkIndex);
DWORD
(WINAPI *IpxcpConfigDone)(ULONG ConnectionId,
PUCHAR Network,
PUCHAR LocalNode,
PUCHAR RemoteNode,
BOOL Success);
VOID
(WINAPI *IpxcpGetInternalNetNumber)(PUCHAR Network);
ULONG
(WINAPI *IpxcpGetInterfaceType)(ULONG ConnectionId);
DWORD
(WINAPI *IpxcpGetRemoteNode)(ULONG ConnectionId,
PUCHAR RemoteNode);
BOOL
(WINAPI *IpxcpIsRoute)(PUCHAR Network);
// worker thread waitable objects
HANDLE hWaitableObject[MAX_WAITABLE_OBJECTS];
VOID
ProcessWorkItem(VOID);
VOID
WorkerThread(VOID);
VOID
ProcessDequeuedIoPacket(DWORD ErrorCode,
DWORD BytesTransferred,
LPOVERLAPPED Overlappedp);
CRITICAL_SECTION DbaseCritSec;
CRITICAL_SECTION QueuesCritSec;
LIST_ENTRY WorkersQueue;
// worker thread object handlers
typedef VOID (*WOBJECT_HANDLER)(VOID);
WOBJECT_HANDLER WaitableObjectHandler[MAX_WAITABLE_OBJECTS] = {
AdapterNotification, // ADAPTER_NOTIFICATION_EVENT
ProcessWorkItem, // WORKERS_QUEUE_EVENT
ProcessTimerQueue // TIMER_HANDLE
};
BOOLEAN Active;
TCHAR ModuleName[MAX_PATH+1];
BOOL WINAPI
IpxWanDllEntry(HINSTANCE hInstDll,
DWORD fdwReason,
LPVOID pReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
GetModuleFileName (hInstDll, ModuleName,
sizeof (ModuleName)/sizeof (ModuleName[0]));
// Create the adapters hash table lock
InitializeCriticalSection(&DbaseCritSec);
// Create the queues lock
InitializeCriticalSection(&QueuesCritSec);
StartTracing();
break;
case DLL_PROCESS_DETACH:
StopTracing ();
// delete the database lock
DeleteCriticalSection(&DbaseCritSec);
// delete the queues lock
DeleteCriticalSection(&QueuesCritSec);
break;
default:
break;
}
return TRUE;
}
/*++
Function: IpxwanBind
Descr: called by IPXCP to initialize the IPXWAN module
--*/
DWORD
IPXWAN_BIND_ENTRY_POINT(PIPXWAN_INTERFACE IpxwanIfp)
{
DWORD threadid, i;
HANDLE ThreadHandle;
Trace(INIT_TRACE, "IpxwanBind: Entered\n");
EnableUnnumberedWanLinks = IpxwanIfp->EnableUnnumberedWanLinks;
IpxcpGetWanNetNumber = IpxwanIfp->IpxcpGetWanNetNumber;
IpxcpReleaseWanNetNumber = IpxwanIfp->IpxcpReleaseWanNetNumber;
IpxcpConfigDone = IpxwanIfp->IpxcpConfigDone;
IpxcpGetInternalNetNumber = IpxwanIfp->IpxcpGetInternalNetNumber;
IpxcpGetInterfaceType = IpxwanIfp->IpxcpGetInterfaceType;
IpxcpGetRemoteNode = IpxwanIfp->IpxcpGetRemoteNode;
IpxcpIsRoute = IpxwanIfp->IpxcpIsRoute;
// create the worker thread's waitable objects array
// for the ipxwan worker thread
for(i=0; i<MAX_EVENTS; i++) {
if((hWaitableObject[i] = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
return ERROR_CAN_NOT_COMPLETE;
}
}
if((hWaitableObject[TIMER_HANDLE] = CreateWaitableTimer(NULL, FALSE, NULL)) == NULL) {
return ERROR_CAN_NOT_COMPLETE;
}
//
// init all the queues
//
InitializeListHead(&WorkersQueue);
InitializeListHead(&TimerQueue);
// create the workers work items heap
if(CreateWorkItemsManager() != NO_ERROR) {
goto ErrorExit;
}
// open the IpxWan socket for I/O
if(OpenIpxWanSocket() != NO_ERROR) {
Trace(INIT_TRACE, "Cannot open IPXWAN socket\n");
goto ErrorExit;
}
if(! BindIoCompletionCallback(IpxWanSocketHandle,
ProcessDequeuedIoPacket, 0)) {
Trace(INIT_TRACE, "Cannot associate IO CompletionPort\n");
goto ErrorExit;
}
if(StartAdapterManager() != NO_ERROR) {
Trace(INIT_TRACE, "Cannot create adapter config port\n");
goto ErrorExit;
}
// create the Worker thread
if ((WorkerThreadHandle = CreateThread(
(LPSECURITY_ATTRIBUTES) NULL,
0,
(LPTHREAD_START_ROUTINE) WorkerThread,
NULL,
0,
&threadid)) == NULL) {
// !!! log error cannot create the worker thread !!!
goto ErrorExit;
}
Active = TRUE;
return NO_ERROR;
ErrorExit:
return ERROR_CAN_NOT_COMPLETE;
}
VOID
IPXWAN_UNBIND_ENTRY_POINT (VOID) {
Active = FALSE;
SetEvent (hWaitableObject[WORKERS_QUEUE_EVENT]);
Trace(INIT_TRACE, "IpxwanUnBind: Finished\n");
}
VOID
WorkerThread(VOID)
{
INT i;
DWORD rc;
DWORD signaled_object;
HINSTANCE hModule = LoadLibrary (ModuleName);
Trace(INIT_TRACE, "IpxwanWorker: Started\n");
StartReceiver();
while(TRUE)
{
rc = WaitForMultipleObjectsEx(
MAX_WAITABLE_OBJECTS,
hWaitableObject,
FALSE, // wait any
INFINITE, // timeout
TRUE // wait alertable, so we can run APCs
);
if (Active) {
ASSERT (((int)rc>=WAIT_OBJECT_0) && (rc<WAIT_OBJECT_0+MAX_WAITABLE_OBJECTS));
signaled_object = rc - WAIT_OBJECT_0;
if(signaled_object < MAX_WAITABLE_OBJECTS) {
// invoke the event handler
(*WaitableObjectHandler[signaled_object])();
}
else
SleepEx (3000, TRUE);
}
else
break;
}
StopAdapterManager ();
CloseIpxWanSocket ();
DestroyWorkItemsManager ();
for(i=0; i<MAX_WAITABLE_OBJECTS; i++) {
CloseHandle (hWaitableObject[i]);
}
Trace(INIT_TRACE, "IpxwanWorker: Finished\n");
FreeLibraryAndExitThread (hModule, 0);
}
VOID
ProcessDequeuedIoPacket(DWORD ErrorCode,
DWORD BytesTransferred,
LPOVERLAPPED Overlappedp)
{
PWORK_ITEM wip;
DWORD nBytes;
wip = CONTAINING_RECORD(Overlappedp, WORK_ITEM, Overlapped);
IpxAdjustIoCompletionParams (Overlappedp, &nBytes, &wip->IoCompletionStatus);
switch(wip->Type) {
case RECEIVE_PACKET_TYPE:
ReceiveComplete(wip);
break;
default:
SendComplete(wip);
break;
}
}
VOID
ProcessWorkItem(VOID)
{
PLIST_ENTRY lep;
PWORK_ITEM wip;
PACB acbp;
ACQUIRE_QUEUES_LOCK;
while(!IsListEmpty(&WorkersQueue)) {
lep = RemoveHeadList(&WorkersQueue);
wip = CONTAINING_RECORD(lep, WORK_ITEM, Linkage);
RELEASE_QUEUES_LOCK;
switch(wip->Type) {
case RECEIVE_PACKET_TYPE:
ACQUIRE_DATABASE_LOCK;
if((acbp = GetAdapterByIndex(wip->AdapterIndex)) != NULL) {
ACQUIRE_ADAPTER_LOCK(acbp);
RELEASE_DATABASE_LOCK;
ProcessReceivedPacket(acbp, wip);
RELEASE_ADAPTER_LOCK(acbp);
}
else
{
RELEASE_DATABASE_LOCK;
}
RepostRcvPacket(wip);
break;
default:
// these are ReXmit packets referencing the adapter via ACB ptr
acbp = wip->acbp;
ACQUIRE_ADAPTER_LOCK(acbp);
acbp->RefCount--;
switch(wip->Type) {
case SEND_PACKET_TYPE:
ProcessReXmitPacket(wip);
break;
case WITIMER_TYPE:
ProcessTimeout(wip);
break;
default:
SS_ASSERT(FALSE);
break;
}
if(acbp->Discarded && (acbp->RefCount == 0)) {
ACQUIRE_DATABASE_LOCK;
// remove the adapter from the discarded list
RemoveEntryList(&acbp->Linkage);
RELEASE_DATABASE_LOCK;
Trace(ADAPTER_TRACE, "ProcessWorkItem: adpt# %d not referenced and discarded. Free CB",
acbp->AdapterIndex);
DeleteCriticalSection(&acbp->AdapterLock);
GlobalFree(acbp);
}
else
{
RELEASE_ADAPTER_LOCK(acbp);
}
}
ACQUIRE_QUEUES_LOCK;
}
RELEASE_QUEUES_LOCK;
}