1160 lines
39 KiB
C
1160 lines
39 KiB
C
/*******************************************************************
|
|
*
|
|
* Copyright (c) 1998-1999 Microsoft Corporation
|
|
*
|
|
* DESCRIPTION: THREAD.C - Thread handling routines, for NT
|
|
* Also implements work items.
|
|
*
|
|
* AUTHOR: Stan Adermann (StanA)
|
|
*
|
|
* DATE:10/20/1998
|
|
*
|
|
*******************************************************************/
|
|
|
|
#include "raspptp.h"
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
|
|
extern struct PPTP_ADAPTER * pgAdapter;
|
|
|
|
#define TX_ON_THREAD BIT(0)
|
|
#define TX_DEFAULT BIT(31)
|
|
|
|
ULONG TransmitPath = TX_ON_THREAD;
|
|
BOOLEAN TransmitRealtime = FALSE;
|
|
|
|
ULONG BuildEnv = VER_PRODUCTVERSION_DW;
|
|
|
|
#define AFFINITY_MASK(n) ((ULONG_PTR)1 << (n))
|
|
|
|
// from NTHAL.H
|
|
extern KAFFINITY
|
|
KeSetAffinityThread (
|
|
IN PKTHREAD Thread,
|
|
IN KAFFINITY Affinity
|
|
);
|
|
|
|
HANDLE hPassiveThread = NULL;
|
|
KEVENT EventPassiveThread;
|
|
KEVENT EventKillThread;
|
|
LIST_ENTRY WorkItemList;
|
|
NDIS_SPIN_LOCK GlobalThreadLock;
|
|
|
|
typedef struct {
|
|
LIST_ENTRY TransmitList;
|
|
// List of calls with packets to transmit.
|
|
|
|
KEVENT WorkEvent;
|
|
// Signal to process packets.
|
|
|
|
KEVENT KillEvent;
|
|
// Signal to die
|
|
|
|
NDIS_SPIN_LOCK Lock;
|
|
// Lock for this structure
|
|
|
|
HANDLE hThread;
|
|
// Thread with affinity to this processor.
|
|
|
|
UINT Number;
|
|
// 0 based index of this processor
|
|
} PROCESSOR, *PPROCESSOR;
|
|
|
|
PPROCESSOR Processor = NULL;
|
|
|
|
BOOLEAN ThreadingInitialized = FALSE;
|
|
|
|
NDIS_STATUS
|
|
ScheduleWorkItem(
|
|
WORK_PROC Callback,
|
|
PVOID Context,
|
|
PVOID InfoBuf,
|
|
ULONG InfoBufLen)
|
|
{
|
|
PPPTP_WORK_ITEM pWorkItem;
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+ScheduleWorkItem\n")));
|
|
|
|
ASSERT(ThreadingInitialized);
|
|
pWorkItem = MyMemAlloc(sizeof(PPTP_WORK_ITEM), TAG_WORK_ITEM);
|
|
|
|
if (pWorkItem != NULL)
|
|
{
|
|
pWorkItem->Context = Context;
|
|
pWorkItem->pBuffer = InfoBuf;
|
|
pWorkItem->Length = InfoBufLen;
|
|
|
|
/*
|
|
** This interface was designed to use NdisScheduleWorkItem(), which
|
|
** would be good except that we're really only supposed to use that
|
|
** interface during startup and shutdown, due to the limited pool of
|
|
** threads available to service NdisScheduleWorkItem(). Therefore,
|
|
** instead of scheduling real work items, we simulate them, and use
|
|
** our own thread to process the calls. This also makes it easy to
|
|
** expand the size of our own thread pool, if we wish.
|
|
**
|
|
** Our version is slightly different from actual NDIS_WORK_ITEMs,
|
|
** because that is an NDIS 5.0 structure, and we want people to
|
|
** (at least temporarily) build this with NDIS 4.0 headers.
|
|
*/
|
|
|
|
pWorkItem->Callback = Callback;
|
|
|
|
/*
|
|
** Our worker thread checks this list for new jobs, whenever its event
|
|
** is signalled.
|
|
*/
|
|
|
|
MyInterlockedInsertTailList(&WorkItemList,
|
|
&pWorkItem->ListEntry,
|
|
&GlobalThreadLock);
|
|
|
|
// Wake up our thread.
|
|
|
|
KeSetEvent(&EventPassiveThread, 0, FALSE);
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
FreeWorkItem(
|
|
PPPTP_WORK_ITEM pItem
|
|
)
|
|
{
|
|
MyMemFree((PVOID)pItem, sizeof(PPTP_WORK_ITEM));
|
|
}
|
|
|
|
|
|
STATIC VOID
|
|
MainPassiveLevelThread(
|
|
IN OUT PVOID Context
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
NTSTATUS NtStatus;
|
|
PLIST_ENTRY pListEntry;
|
|
PKEVENT EventList[2];
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+MainPassiveLevelThread\n")));
|
|
|
|
//KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
|
|
|
|
EventList[0] = &EventPassiveThread;
|
|
EventList[1] = &EventKillThread;
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// The EventPassiveThread is an auto-clearing event, so
|
|
// we don't need to reset the event.
|
|
//
|
|
|
|
NtStatus = KeWaitForMultipleObjects(2,
|
|
EventList,
|
|
WaitAny,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (NtStatus==0) // The first event, for a work item, was signalled
|
|
{
|
|
while (pListEntry = MyInterlockedRemoveHeadList(&WorkItemList,
|
|
&GlobalThreadLock))
|
|
{
|
|
PPPTP_WORK_ITEM pWorkItem = CONTAINING_RECORD(pListEntry,
|
|
PPTP_WORK_ITEM,
|
|
ListEntry);
|
|
|
|
ASSERT(KeGetCurrentIrql()<DISPATCH_LEVEL);
|
|
pWorkItem->Callback(pWorkItem);
|
|
ASSERT(KeGetCurrentIrql()<DISPATCH_LEVEL);
|
|
FreeWorkItem(pWorkItem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// A kill event was received.
|
|
|
|
DEBUGMSG(DBG_THREAD, (DTEXT("Thread: HALT %08x\n"), NtStatus));
|
|
|
|
// Free any pending requests
|
|
|
|
while (pListEntry = MyInterlockedRemoveHeadList(&WorkItemList,
|
|
&GlobalThreadLock))
|
|
{
|
|
PPPTP_WORK_ITEM pWorkItem = CONTAINING_RECORD(pListEntry,
|
|
PPTP_WORK_ITEM,
|
|
ListEntry);
|
|
|
|
DEBUGMSG(DBG_WARN, (DTEXT("Releasing work item %08x\n"), pWorkItem));
|
|
FreeWorkItem(pWorkItem);
|
|
}
|
|
|
|
hPassiveThread = NULL;
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("PsTerminateSystemThread MainPassiveLevelThread\n")));
|
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-MainPassiveLevelThread\n")));
|
|
}
|
|
|
|
#if 0
|
|
extern NDIS_STATUS
|
|
CallTransmitPacket(
|
|
PCALL_SESSION pCall,
|
|
PNDIS_WAN_PACKET pPacket,
|
|
BOOLEAN SendAck,
|
|
ULONG Ack
|
|
);
|
|
|
|
|
|
NDIS_STATUS
|
|
TransmitPacketNow(
|
|
PCALL_SESSION pCall,
|
|
PNDIS_WAN_PACKET pWanPacket
|
|
)
|
|
{
|
|
BOOLEAN NeedToSendAck;
|
|
ULONG Ack = 0;
|
|
NDIS_STATUS Status;
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+TransmitPacketNow\n")));
|
|
|
|
if (!IS_CALL(pCall) || pCall->State!=STATE_CALL_ESTABLISHED)
|
|
{
|
|
// Drop the packet.
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
goto cqtpDone;
|
|
}
|
|
NdisAcquireSpinLock(&pCall->Lock);
|
|
if (NeedToSendAck = (pCall->Packet.AckNumber!=pCall->Remote.SequenceNumber))
|
|
{
|
|
pCall->Packet.AckNumber = pCall->Remote.SequenceNumber;
|
|
Ack = pCall->Packet.AckNumber - 1;
|
|
}
|
|
NdisReleaseSpinLock(&pCall->Lock);
|
|
|
|
Status = CallTransmitPacket(pCall, pWanPacket, NeedToSendAck, Ack);
|
|
// We can get a failure here, but since we're in the direct path from
|
|
// MiniportWanSend, it's ok. Just pass the status back and we're done.
|
|
|
|
|
|
cqtpDone:
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-TransmitPacketNow\n")));
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
NDIS_STATUS
|
|
TransmitPacketOnThread(
|
|
PCALL_SESSION pCall,
|
|
PNDIS_WAN_PACKET pWanPacket
|
|
)
|
|
{
|
|
BOOLEAN StartTransferring = FALSE;
|
|
ULONG_PTR ProcNum = 0;
|
|
NDIS_STATUS Status = NDIS_STATUS_PENDING;
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+TransmitPacketOnThread\n")));
|
|
|
|
if (!IS_CALL(pCall) || pCall->State!=STATE_CALL_ESTABLISHED)
|
|
{
|
|
// Drop the packet.
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
goto cqtpDone;
|
|
}
|
|
|
|
NdisAcquireSpinLock(&pCall->Lock);
|
|
|
|
InsertTailList(&pCall->TxPacketList, &pWanPacket->WanPacketQueue);
|
|
|
|
if (!pCall->Transferring)
|
|
{
|
|
StartTransferring = pCall->Transferring = TRUE;
|
|
ProcNum = pCall->DeviceId % KeNumberProcessors;
|
|
REFERENCE_OBJECT(pCall);
|
|
MyInterlockedInsertTailList(&Processor[ProcNum].TransmitList,
|
|
&pCall->TxListEntry,
|
|
&Processor[ProcNum].Lock);
|
|
KeSetEvent(&Processor[ProcNum].WorkEvent, 0, FALSE);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&pCall->Lock);
|
|
|
|
cqtpDone:
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-TransmitPacketOnThread\n")));
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
CallQueueTransmitPacket(
|
|
PCALL_SESSION pCall,
|
|
PNDIS_WAN_PACKET pWanPacket
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+CallQueueTransmitPacket\n")));
|
|
if (TransmitPath&TX_ON_THREAD)
|
|
{
|
|
Status = TransmitPacketOnThread(pCall, pWanPacket);
|
|
}
|
|
else
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
ASSERT(0);
|
|
}
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-CallQueueTransmitPacket\n")));
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
CallQueueReceivePacket(
|
|
PCALL_SESSION pCall,
|
|
PDGRAM_CONTEXT pDgContext
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PGRE_HEADER pGre = pDgContext->pGreHeader;
|
|
ULONG_PTR ProcNum = 0;
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+CallQueueReceivePacket\n")));
|
|
|
|
if(!pGre->SequenceNumberPresent)
|
|
{
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
NdisAcquireSpinLock(&pCall->Lock);
|
|
if (pCall->RxPacketsPending > 256 ||
|
|
htons(pGre->KeyCallId)!=pCall->Packet.CallId ||
|
|
pCall->State!=STATE_CALL_ESTABLISHED ||
|
|
!IS_LINE_UP(pCall))
|
|
{
|
|
DEBUGMSG(DBG_PACKET|DBG_RX, (DTEXT("Rx: GRE CallId invalid or call in wrong state\n")));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
goto cqrpDone;
|
|
}
|
|
|
|
// The packet has passed all of our tests.
|
|
|
|
if (IsListEmpty(&pCall->RxPacketList))
|
|
{
|
|
PULONG pSequence = (PULONG)(pGre + 1);
|
|
ULONG Sequence = htonl(*pSequence);
|
|
|
|
if (Sequence==1)
|
|
{
|
|
LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"Receiving GRE data:%d\n"),
|
|
LOGHDR(29, pCall->Remote.Address.Address[0].Address[0].in_addr),
|
|
pCall->DeviceId));
|
|
}
|
|
|
|
// We don't check the sequence # anymore, just put it on the queue
|
|
InsertTailList(&pCall->RxPacketList, &pDgContext->ListEntry);
|
|
pCall->RxPacketsPending++;
|
|
}
|
|
else
|
|
{
|
|
// There are packets already queued. Put this one in order.
|
|
|
|
PULONG pSequence = (PULONG)(pGre + 1);
|
|
ULONG Sequence = htonl(*pSequence);
|
|
|
|
if (Sequence==1)
|
|
{
|
|
LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"Receiving GRE data:%d\n"),
|
|
LOGHDR(29, pCall->Remote.Address.Address[0].Address[0].in_addr),
|
|
pCall->DeviceId));
|
|
}
|
|
|
|
// We don't check the sequence # anymore, just put it on the queue in order
|
|
{
|
|
PLIST_ENTRY pListEntry;
|
|
BOOLEAN OnList = FALSE;
|
|
|
|
for (pListEntry = pCall->RxPacketList.Flink;
|
|
pListEntry != &pCall->RxPacketList;
|
|
pListEntry = pListEntry->Flink)
|
|
{
|
|
PDGRAM_CONTEXT pListDg = CONTAINING_RECORD(pListEntry,
|
|
DGRAM_CONTEXT,
|
|
ListEntry);
|
|
|
|
if ((signed)htonl(GreSequence(pListDg->pGreHeader)) - (signed)Sequence > 0)
|
|
{
|
|
// The one on the list is newer! Put this one before it.
|
|
InsertTailList(&pListDg->ListEntry, &pDgContext->ListEntry);
|
|
pCall->RxPacketsPending++;
|
|
OnList = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!OnList)
|
|
{
|
|
// There were no packets on this list with a greater sequence.
|
|
// Put this at the end.
|
|
InsertTailList(&pCall->RxPacketList, &pDgContext->ListEntry);
|
|
pCall->RxPacketsPending++;
|
|
}
|
|
}
|
|
|
|
// We don't really care about the ACK from the peer, so save some cycles here
|
|
/*
|
|
pSequence++; // point to the ack
|
|
if (pGre->AckSequenceNumberPresent)
|
|
{
|
|
ULONG Ack = ntohl(*pSequence);
|
|
if ((signed)Ack - (signed)pCall->Remote.AckNumber >= 0 &&
|
|
(signed)pCall->Packet.SequenceNumber - (signed)Ack >= 0)
|
|
{
|
|
pCall->Remote.AckNumber = Ack;
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(DBG_WARN, (DTEXT("Ack out of range, Ack:%x LastAck:%x, NextSeq:%x\n"),
|
|
Ack, pCall->Remote.AckNumber, pCall->Packet.SequenceNumber));
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
if (Status==NDIS_STATUS_SUCCESS && !pCall->Receiving)
|
|
{
|
|
pCall->Receiving = TRUE;
|
|
REFERENCE_OBJECT(pCall);
|
|
#if 0
|
|
ProcNum = pCall->DeviceId % KeNumberProcessors;
|
|
MyInterlockedInsertTailList(&Processor[ProcNum].TransmitList,
|
|
&pCall->TxListEntry,
|
|
&Processor[ProcNum].Lock);
|
|
KeSetEvent(&Processor[ProcNum].WorkEvent, 0, FALSE);
|
|
#else
|
|
PptpQueueDpc(&pCall->ReceiveDpc);
|
|
#endif
|
|
}
|
|
|
|
cqrpDone:
|
|
NdisReleaseSpinLock(&pCall->Lock);
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-CallQueueReceivePacket\n")));
|
|
return Status;
|
|
}
|
|
|
|
STATIC VOID
|
|
PacketWorkingThread(
|
|
IN OUT PVOID Context
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
NTSTATUS NtStatus;
|
|
PLIST_ENTRY pListEntry;
|
|
PKEVENT EventList[2];
|
|
PPROCESSOR pProcessor = Context;
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+PacketWorkingThread\n")));
|
|
|
|
if (TransmitRealtime)
|
|
{
|
|
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
|
|
}
|
|
|
|
KeSetAffinityThread(KeGetCurrentThread(), AFFINITY_MASK(pProcessor->Number));
|
|
|
|
EventList[0] = &pProcessor->WorkEvent;
|
|
EventList[1] = &pProcessor->KillEvent;
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// The events are auto-clearing, so
|
|
// we don't need to reset the event.
|
|
//
|
|
|
|
NtStatus = KeWaitForMultipleObjects(2,
|
|
EventList,
|
|
WaitAny,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (NtStatus==0) // The first event, for packet processing, was signalled
|
|
{
|
|
while (pListEntry = MyInterlockedRemoveHeadList(&pProcessor->TransmitList,
|
|
&pProcessor->Lock))
|
|
{
|
|
PCALL_SESSION pCall = CONTAINING_RECORD(pListEntry,
|
|
CALL_SESSION,
|
|
TxListEntry);
|
|
ULONG PacketsToTransmit;
|
|
|
|
if (IsListEmpty(&pProcessor->TransmitList))
|
|
{
|
|
PacketsToTransmit = 0xffffffff;
|
|
}
|
|
else
|
|
{
|
|
PacketsToTransmit = 10;
|
|
}
|
|
if (CallProcessPackets(pCall, PacketsToTransmit))
|
|
{
|
|
MyInterlockedInsertTailList(&pProcessor->TransmitList,
|
|
&pCall->TxListEntry,
|
|
&pProcessor->Lock);
|
|
}
|
|
else
|
|
{
|
|
DEREFERENCE_OBJECT(pCall); // Matches TransmitPacketOnThread
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// A kill event was received.
|
|
|
|
DEBUGMSG(DBG_THREAD, (DTEXT("Thread: HALT %08x\n"), NtStatus));
|
|
|
|
// Free any pending requests
|
|
|
|
// ToDo: write code here
|
|
pProcessor->hThread = NULL;
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("PsTerminateSystemThread PacketWorkingThread\n")));
|
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-PacketWorkingThread\n")));
|
|
}
|
|
|
|
NDIS_STATUS
|
|
InitThreading(
|
|
NDIS_HANDLE hMiniportAdapter
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
NTSTATUS NtStatus;
|
|
|
|
UNREFERENCED_PARAMETER(hMiniportAdapter);
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+InitializeThreading\n")));
|
|
|
|
if (ThreadingInitialized)
|
|
{
|
|
ASSERT(!"Threading initialized twice");
|
|
goto itDone;
|
|
}
|
|
ThreadingInitialized = TRUE;
|
|
|
|
NdisInitializeListHead(&WorkItemList);
|
|
NdisAllocateSpinLock(&GlobalThreadLock);
|
|
|
|
KeInitializeEvent(
|
|
&EventPassiveThread,
|
|
SynchronizationEvent, // auto-clearing event
|
|
FALSE // event initially non-signalled
|
|
);
|
|
|
|
KeInitializeEvent(
|
|
&EventKillThread,
|
|
SynchronizationEvent, // auto-clearing event
|
|
FALSE // event initially non-signalled
|
|
);
|
|
|
|
NtStatus = PsCreateSystemThread(&hPassiveThread,
|
|
(ACCESS_MASK) 0L,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
MainPassiveLevelThread,
|
|
NULL);
|
|
if (NtStatus!=STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (DTEXT("PsCreateSystemThread failed. %08x\n"), Status));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
goto itDone;
|
|
}
|
|
|
|
DBG_D(DBG_THREAD, KeNumberProcessors);
|
|
|
|
#if 0
|
|
if (KeNumberProcessors==1 && (TransmitPath&TX_DEFAULT))
|
|
{
|
|
// We've got one processor and the user hasn't requested a specific type
|
|
// of transmission, so we'll opt to transmit immediately.
|
|
TransmitPath &= ~TX_ON_THREAD;
|
|
}
|
|
#endif
|
|
|
|
if (TransmitPath&TX_ON_THREAD)
|
|
{
|
|
Processor = MyMemAlloc(sizeof(PROCESSOR)*KeNumberProcessors, TAG_THREAD);
|
|
if (!Processor)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
ULONG i;
|
|
NdisZeroMemory(Processor, sizeof(PROCESSOR)*KeNumberProcessors);
|
|
|
|
for (i=0; i<(ULONG)KeNumberProcessors; i++)
|
|
{
|
|
NdisInitializeListHead(&Processor[i].TransmitList);
|
|
NdisAllocateSpinLock(&Processor[i].Lock);
|
|
|
|
KeInitializeEvent(
|
|
&Processor[i].WorkEvent,
|
|
SynchronizationEvent, // auto-clearing event
|
|
FALSE // event initially non-signalled
|
|
);
|
|
|
|
KeInitializeEvent(
|
|
&Processor[i].KillEvent,
|
|
SynchronizationEvent, // auto-clearing event
|
|
FALSE // event initially non-signalled
|
|
);
|
|
|
|
Processor[i].Number = i;
|
|
|
|
// ToDo: we should create the thread when we really need it.
|
|
NtStatus = PsCreateSystemThread(&Processor[i].hThread,
|
|
(ACCESS_MASK) 0L,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
PacketWorkingThread,
|
|
&Processor[i]);
|
|
if (NtStatus!=STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (DTEXT("PsCreateSystemThread failed. %08x\n"), Status));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
itDone:
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-InitializeThreading %08x\n"), Status));
|
|
return Status;
|
|
}
|
|
|
|
VOID STATIC WaitForThreadToDieAndCloseIt(HANDLE hThread, PRKEVENT pKillEvent)
|
|
{
|
|
PVOID pThread = NULL;
|
|
NTSTATUS Status;
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+WaitForThreadToDie\n")));
|
|
|
|
if ( hThread != NULL && pKillEvent != NULL )
|
|
{
|
|
|
|
Status = ObReferenceObjectByHandle(hThread, 0, NULL, KernelMode, &pThread, NULL);
|
|
if (Status==STATUS_SUCCESS)
|
|
{
|
|
KeSetEvent(pKillEvent, 0, FALSE);
|
|
|
|
KeWaitForSingleObject(pThread, Executive, KernelMode, FALSE, NULL);
|
|
ObDereferenceObject(pThread);
|
|
}
|
|
ZwClose(hThread);
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-WaitForThreadToDie\n")));
|
|
}
|
|
|
|
VOID
|
|
DeinitThreading()
|
|
{
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+DeinitThreading\n")));
|
|
|
|
ThreadingInitialized = FALSE;
|
|
if ((TransmitPath&TX_ON_THREAD) && Processor!=NULL)
|
|
{
|
|
LONG i;
|
|
|
|
for (i=0; i<KeNumberProcessors; i++)
|
|
{
|
|
WaitForThreadToDieAndCloseIt( Processor[i].hThread,
|
|
&Processor[i].KillEvent );
|
|
}
|
|
MyMemFree(Processor, sizeof(PROCESSOR)*KeNumberProcessors);
|
|
Processor = NULL;
|
|
}
|
|
|
|
WaitForThreadToDieAndCloseIt( hPassiveThread,
|
|
&EventKillThread );
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-DeinitThreading\n")));
|
|
}
|
|
|
|
UCHAR TapiLineNameBuffer[64] = TAPI_LINE_NAME_STRING;
|
|
ANSI_STRING TapiLineName = {
|
|
sizeof(TAPI_LINE_NAME_STRING),
|
|
sizeof(TapiLineNameBuffer),
|
|
TapiLineNameBuffer
|
|
};
|
|
typedef UCHAR TAPI_CHAR_TYPE;
|
|
|
|
ANSI_STRING TapiLineAddrList = { 0, 0, NULL };
|
|
|
|
#define READ_NDIS_REG_ULONG(hConfig, Var, Value) \
|
|
{ \
|
|
PNDIS_CONFIGURATION_PARAMETER RegValue; \
|
|
NDIS_STATUS Status; \
|
|
NDIS_STRING String = NDIS_STRING_CONST(Value); \
|
|
\
|
|
NdisReadConfiguration(&Status, \
|
|
&RegValue, \
|
|
hConfig, \
|
|
&String, \
|
|
NdisParameterInteger); \
|
|
if (Status==NDIS_STATUS_SUCCESS) \
|
|
{ \
|
|
(Var) = RegValue->ParameterData.IntegerData; \
|
|
DEBUGMSG(DBG_INIT, (DTEXT(#Var"==%d\n"), (Var))); \
|
|
} \
|
|
else \
|
|
{ \
|
|
DEBUGMSG(DBG_INIT, (DTEXT(Value", default==%d\n"), (Var)));\
|
|
} \
|
|
}
|
|
|
|
#define READ_NDIS_REG_USHORT(hConfig, Var, Value) \
|
|
{ \
|
|
PNDIS_CONFIGURATION_PARAMETER RegValue; \
|
|
NDIS_STATUS Status; \
|
|
NDIS_STRING String = NDIS_STRING_CONST(Value); \
|
|
\
|
|
NdisReadConfiguration(&Status, \
|
|
&RegValue, \
|
|
hConfig, \
|
|
&String, \
|
|
NdisParameterInteger); \
|
|
if (Status==NDIS_STATUS_SUCCESS) \
|
|
{ \
|
|
(Var) = (USHORT)(RegValue->ParameterData.IntegerData&0xffff); \
|
|
DEBUGMSG(DBG_INIT, (DTEXT(#Var"==%d\n"), (Var))); \
|
|
} \
|
|
else \
|
|
{ \
|
|
DEBUGMSG(DBG_INIT, (DTEXT(Value", default==%d\n"), (Var)));\
|
|
} \
|
|
}
|
|
|
|
#define READ_NDIS_REG_BOOL(hConfig, Var, Value) \
|
|
{ \
|
|
PNDIS_CONFIGURATION_PARAMETER RegValue; \
|
|
NDIS_STATUS Status; \
|
|
NDIS_STRING String = NDIS_STRING_CONST(Value); \
|
|
\
|
|
NdisReadConfiguration(&Status, \
|
|
&RegValue, \
|
|
hConfig, \
|
|
&String, \
|
|
NdisParameterInteger); \
|
|
if (Status==NDIS_STATUS_SUCCESS) \
|
|
{ \
|
|
(Var) = RegValue->ParameterData.IntegerData ? TRUE : FALSE; \
|
|
DEBUGMSG(DBG_INIT, (DTEXT(#Var"==%d\n"), (Var))); \
|
|
} \
|
|
else \
|
|
{ \
|
|
DEBUGMSG(DBG_INIT, (DTEXT(Value", default==%d\n"), (Var)));\
|
|
} \
|
|
}
|
|
|
|
VOID
|
|
OsReadConfig(
|
|
NDIS_HANDLE hConfig
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PNDIS_CONFIGURATION_PARAMETER Value;
|
|
#if 0
|
|
NDIS_STRING TransmitPathString = NDIS_STRING_CONST("TransmitPath");
|
|
#endif
|
|
NDIS_STRING TapiLineNameString = NDIS_STRING_CONST("TapiLineName");
|
|
#if VER_PRODUCTVERSION_W < 0x0500
|
|
NDIS_STRING TapiLineAddrString = NDIS_STRING_CONST("AddressList");
|
|
#endif
|
|
NDIS_STRING PeerClientIpAddressString = NDIS_STRING_CONST("ClientIpAddresses");
|
|
NDIS_STRING PeerClientIpMaskString = NDIS_STRING_CONST("ClientIpMasks");
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+OsReadConfig\n")));
|
|
|
|
#if 0
|
|
READ_NDIS_REG_ULONG(hConfig, "TransmitPath", TransmitPath);
|
|
#endif
|
|
READ_NDIS_REG_USHORT(hConfig, PptpControlPort, "TcpPortNumber");
|
|
READ_NDIS_REG_USHORT(hConfig, PptpUdpPort, "UdpPortNumber");
|
|
READ_NDIS_REG_ULONG (hConfig, PptpWanEndpoints, "MaxWanEndpoints");
|
|
READ_NDIS_REG_ULONG (hConfig, PptpMaxTransmit, "MaxTransmit");
|
|
READ_NDIS_REG_ULONG (hConfig, PptpEchoTimeout, "InactivityIdleSeconds");
|
|
READ_NDIS_REG_BOOL (hConfig, PptpEchoAlways, "AlwaysEcho");
|
|
READ_NDIS_REG_ULONG (hConfig, PptpTunnelConfig, "TunnelConfig");
|
|
READ_NDIS_REG_ULONG (hConfig, CtdiTcpDisconnectTimeout, "TcpDisconnectTimeout");
|
|
READ_NDIS_REG_ULONG (hConfig, CtdiTcpConnectTimeout, "TcpConnectTimeout");
|
|
READ_NDIS_REG_ULONG (hConfig, FileLogLevel, "Logging");
|
|
READ_NDIS_REG_BOOL (hConfig, TransmitRealtime, "TransmitRealtime");
|
|
READ_NDIS_REG_BOOL (hConfig, PptpAuthenticateIncomingCalls, "AuthenticateIncomingCalls");
|
|
READ_NDIS_REG_ULONG (hConfig, PptpValidateAddress, "ValidateAddress");
|
|
|
|
OS_RANGE_CHECK_ENDPOINTS(PptpWanEndpoints);
|
|
OS_RANGE_CHECK_MAX_TRANSMIT(PptpMaxTransmit);
|
|
|
|
if (PptpAuthenticateIncomingCalls)
|
|
{
|
|
NdisReadConfiguration(&Status, // Not required value
|
|
&Value,
|
|
hConfig,
|
|
&PeerClientIpAddressString,
|
|
NdisParameterMultiString);
|
|
if (Status==NDIS_STATUS_SUCCESS)
|
|
{
|
|
ULONG i, NumAddresses = 0;
|
|
BOOLEAN InEntry = 0, ValidAddress;
|
|
PWCHAR AddressList = Value->ParameterData.StringData.Buffer;
|
|
TA_IP_ADDRESS Address;
|
|
|
|
// Loop and count the addresses, so we can allocate proper size to hold them.
|
|
for (i=0, InEntry=FALSE; i<(Value->ParameterData.StringData.Length/sizeof(WCHAR))-1; i++)
|
|
{
|
|
if (!InEntry)
|
|
{
|
|
if (AddressList[i]!=L'\0')
|
|
{
|
|
InEntry = TRUE;
|
|
StringToIpAddressW(&AddressList[i],
|
|
&Address,
|
|
&ValidAddress);
|
|
if (ValidAddress)
|
|
{
|
|
NumAddresses++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (AddressList[i]==L'\0')
|
|
{
|
|
InEntry = FALSE;
|
|
}
|
|
}
|
|
}
|
|
NumClientAddresses = NumAddresses;
|
|
if (NumClientAddresses)
|
|
{
|
|
ClientList = MyMemAlloc(sizeof(CLIENT_ADDRESS)*NumClientAddresses, TAG_PPTP_ADDR_LIST);
|
|
if (ClientList)
|
|
{
|
|
NumAddresses = 0;
|
|
for (i=0, InEntry=FALSE; i<(Value->ParameterData.StringData.Length/sizeof(WCHAR))-1; i++)
|
|
{
|
|
if (!InEntry)
|
|
{
|
|
if (AddressList[i]!=L'\0')
|
|
{
|
|
InEntry = TRUE;
|
|
if (NumAddresses<NumClientAddresses)
|
|
{
|
|
StringToIpAddressW(&AddressList[i],
|
|
&Address,
|
|
&ValidAddress);
|
|
if (ValidAddress)
|
|
{
|
|
ClientList[NumAddresses].Address = Address.Address[0].Address[0].in_addr;
|
|
ClientList[NumAddresses].Mask = 0xFFFFFFFF;
|
|
NumAddresses++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (AddressList[i]==L'\0')
|
|
{
|
|
InEntry = FALSE;
|
|
}
|
|
}
|
|
}
|
|
NdisReadConfiguration(&Status, // Not required value
|
|
&Value,
|
|
hConfig,
|
|
&PeerClientIpMaskString,
|
|
NdisParameterMultiString);
|
|
if (Status==NDIS_STATUS_SUCCESS)
|
|
{
|
|
AddressList = Value->ParameterData.StringData.Buffer;
|
|
NumAddresses = 0;
|
|
for (i=0, InEntry=FALSE;
|
|
i<(Value->ParameterData.StringData.Length/sizeof(WCHAR))-1 && NumAddresses<=NumClientAddresses;
|
|
i++)
|
|
{
|
|
if (!InEntry)
|
|
{
|
|
if (AddressList[i]!=L'\0')
|
|
{
|
|
InEntry = TRUE;
|
|
if (NumAddresses<NumClientAddresses)
|
|
{
|
|
StringToIpAddressW(&AddressList[i],
|
|
&Address,
|
|
&ValidAddress);
|
|
if (ValidAddress)
|
|
{
|
|
ClientList[NumAddresses].Mask = Address.Address[0].Address[0].in_addr;
|
|
NumAddresses++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (AddressList[i]==L'\0')
|
|
{
|
|
InEntry = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (i=0; i<NumClientAddresses; i++)
|
|
{
|
|
DEBUGMSG(DBG_INIT, (DTEXT("Client Address:%d.%d.%d.%d Mask:%d.%d.%d.%d\n"),
|
|
IPADDR(ClientList[i].Address), IPADDR(ClientList[i].Mask)));
|
|
}
|
|
}
|
|
else
|
|
PptpAuthenticateIncomingCalls = FALSE;
|
|
}
|
|
else
|
|
PptpAuthenticateIncomingCalls = FALSE;
|
|
}
|
|
}
|
|
|
|
NdisReadConfiguration(&Status, // Not required value
|
|
&Value,
|
|
hConfig,
|
|
&TapiLineNameString,
|
|
NdisParameterString);
|
|
if (Status==NDIS_STATUS_SUCCESS)
|
|
{
|
|
RtlUnicodeStringToAnsiString(&TapiLineName, &Value->ParameterData.StringData, FALSE);
|
|
*(TAPI_CHAR_TYPE*)(TapiLineName.Buffer+TapiLineName.MaximumLength-sizeof(TAPI_CHAR_TYPE)) = (TAPI_CHAR_TYPE)0;
|
|
}
|
|
|
|
#if VER_PRODUCTVERSION_W < 0x0500
|
|
NdisReadConfiguration(&Status, // Not required value
|
|
&Value,
|
|
hConfig,
|
|
&TapiLineAddrString,
|
|
NdisParameterMultiString);
|
|
if (Status==NDIS_STATUS_SUCCESS)
|
|
{
|
|
RtlInitAnsiString( &TapiLineAddrList, NULL );
|
|
if (RtlUnicodeStringToAnsiString(&TapiLineAddrList, &Value->ParameterData.StringData, TRUE)==NDIS_STATUS_SUCCESS)
|
|
{
|
|
// NT4 doesn't have the same registry value to tell us how many lines to publish.
|
|
// We work around that by counting the number of address strings here
|
|
|
|
PUCHAR p = TapiLineAddrList.Buffer;
|
|
|
|
DEBUGMEM(DBG_TAPI, TapiLineAddrList.Buffer, TapiLineAddrList.Length, 1);
|
|
PptpWanEndpoints = 0;
|
|
if (p)
|
|
{
|
|
// Count the valid MULTI_SZ entries.
|
|
while (*p++)
|
|
{
|
|
PptpWanEndpoints++;
|
|
while (*p++); // This also skips the first NULL
|
|
}
|
|
}
|
|
DBG_D(DBG_INIT, PptpWanEndpoints);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-OsReadConfig\n")));
|
|
}
|
|
|
|
VOID
|
|
OsGetTapiLineAddress(ULONG Index, PUCHAR s, ULONG Length)
|
|
{
|
|
#if VER_PRODUCTVERSION_W < 0x0500
|
|
PUCHAR pAddr = TapiLineAddrList.Buffer;
|
|
|
|
*s = 0;
|
|
|
|
if (pAddr)
|
|
{
|
|
UINT i;
|
|
|
|
for (i=0; i<Index; i++)
|
|
{
|
|
if (!*pAddr)
|
|
{
|
|
// No string at index
|
|
return;
|
|
}
|
|
while (*pAddr) pAddr++;
|
|
pAddr++;
|
|
}
|
|
strncpy(s, pAddr, Length);
|
|
s[Length-1] = 0;
|
|
}
|
|
#else // VER_PRODUCTVERSION_W >= 0x0500
|
|
|
|
strncpy(s, TAPI_LINE_ADDR_STRING, Length);
|
|
s[Length-1] = 0;
|
|
#endif
|
|
}
|
|
|
|
NDIS_STATUS
|
|
OsSpecificTapiGetDevCaps(
|
|
ULONG_PTR ulDeviceId,
|
|
IN OUT PNDIS_TAPI_GET_DEV_CAPS pRequest
|
|
)
|
|
{
|
|
PUCHAR pTmp, pTmp2;
|
|
ULONG_PTR Index;
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("+OsSpecificTapiGetDevCaps\n")));
|
|
|
|
// Convert to our internal index
|
|
ulDeviceId -= pgAdapter->Tapi.DeviceIdBase;
|
|
|
|
pRequest->LineDevCaps.ulStringFormat = STRINGFORMAT_ASCII;
|
|
|
|
|
|
// The *6 at the end adds enough space for " 9999"
|
|
pRequest->LineDevCaps.ulNeededSize = sizeof(pRequest->LineDevCaps) +
|
|
sizeof(TAPI_PROVIDER_STRING) +
|
|
TapiLineName.Length +
|
|
sizeof(TAPI_CHAR_TYPE) * 6;
|
|
|
|
if (pRequest->LineDevCaps.ulTotalSize<pRequest->LineDevCaps.ulNeededSize)
|
|
{
|
|
DEBUGMSG(DBG_FUNC|DBG_WARN, (DTEXT("-TapiGetDevCaps NDIS_STATUS_SUCCESS without PROVIDER or LINE_NAME strings\n")));
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
// Tack the provider string to the end of the LineDevCaps structure.
|
|
|
|
pRequest->LineDevCaps.ulProviderInfoSize = sizeof(TAPI_PROVIDER_STRING);
|
|
pRequest->LineDevCaps.ulProviderInfoOffset = sizeof(pRequest->LineDevCaps);
|
|
|
|
pTmp = ((PUCHAR)&pRequest->LineDevCaps) + sizeof(pRequest->LineDevCaps);
|
|
NdisMoveMemory(pTmp, TAPI_PROVIDER_STRING, sizeof(TAPI_PROVIDER_STRING));
|
|
|
|
pTmp += sizeof(TAPI_PROVIDER_STRING);
|
|
|
|
// Tack on the LineName after the provider string.
|
|
|
|
pRequest->LineDevCaps.ulLineNameSize = TapiLineName.Length + sizeof(TAPI_CHAR_TYPE);
|
|
pRequest->LineDevCaps.ulLineNameOffset = pRequest->LineDevCaps.ulProviderInfoOffset +
|
|
pRequest->LineDevCaps.ulProviderInfoSize;
|
|
NdisMoveMemory(pTmp, TapiLineName.Buffer, TapiLineName.Length+sizeof(TAPI_CHAR_TYPE));
|
|
|
|
while (*pTmp) pTmp++; // Find the NULL
|
|
|
|
*pTmp++ = ' ';
|
|
pRequest->LineDevCaps.ulLineNameSize++;
|
|
|
|
// Put a number at the end of the string.
|
|
|
|
if (ulDeviceId==0)
|
|
{
|
|
*pTmp++ = '0';
|
|
*pTmp++ = '\0';
|
|
pRequest->LineDevCaps.ulLineNameSize += 2;
|
|
}
|
|
else
|
|
{
|
|
Index = ulDeviceId;
|
|
ASSERT(Index<100000);
|
|
pTmp2 = pTmp;
|
|
while (Index)
|
|
{
|
|
*pTmp2++ = (UCHAR)((Index%10) + '0');
|
|
Index /= 10;
|
|
pRequest->LineDevCaps.ulLineNameSize++;
|
|
}
|
|
*pTmp2-- = '\0'; // Null terminate and point to the last digit.
|
|
pRequest->LineDevCaps.ulLineNameSize++;
|
|
// We put the number in backwards, now reverse it.
|
|
while (pTmp<pTmp2)
|
|
{
|
|
UCHAR t = *pTmp;
|
|
*pTmp++ = *pTmp2;
|
|
*pTmp2-- = t;
|
|
}
|
|
}
|
|
|
|
pRequest->LineDevCaps.ulUsedSize = pRequest->LineDevCaps.ulNeededSize;
|
|
|
|
DEBUGMSG(DBG_FUNC, (DTEXT("-OsSpecificTapiGetDevCaps\n")));
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_HANDLE LogHandle = 0;
|
|
|
|
VOID __cdecl OsFileLogInit()
|
|
{
|
|
NDIS_STATUS Status =
|
|
NdisMCreateLog(pgAdapter->hMiniportAdapter,
|
|
16384,
|
|
&LogHandle);
|
|
|
|
}
|
|
|
|
VOID __cdecl OsFileLogOpen()
|
|
{
|
|
}
|
|
|
|
VOID __cdecl OsLogPrintf(char *pszFmt, ... )
|
|
{
|
|
va_list ArgList;
|
|
CHAR Buf[512];
|
|
ULONG Len;
|
|
|
|
if (LogHandle)
|
|
{
|
|
va_start(ArgList, pszFmt);
|
|
Len = vsprintf(Buf, pszFmt, ArgList);
|
|
va_end(ArgList);
|
|
NdisMWriteLogData(LogHandle, Buf, Len);
|
|
}
|
|
}
|
|
|
|
VOID __cdecl OsFileLogClose(void)
|
|
{
|
|
}
|
|
|
|
VOID __cdecl OsFileLogShutdown(void)
|
|
{
|
|
if (LogHandle)
|
|
{
|
|
NdisMCloseLog(LogHandle);
|
|
LogHandle = 0;
|
|
}
|
|
}
|
|
|
|
VOID __cdecl OsFileLogFlush(void)
|
|
{
|
|
|
|
}
|
|
|