Source code of Windows XP (NT5)
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.

1159 lines
39 KiB

  1. /*******************************************************************
  2. *
  3. * Copyright (c) 1998-1999 Microsoft Corporation
  4. *
  5. * DESCRIPTION: THREAD.C - Thread handling routines, for NT
  6. * Also implements work items.
  7. *
  8. * AUTHOR: Stan Adermann (StanA)
  9. *
  10. * DATE:10/20/1998
  11. *
  12. *******************************************************************/
  13. #include "raspptp.h"
  14. #include <stdarg.h>
  15. #include <stdio.h>
  16. extern struct PPTP_ADAPTER * pgAdapter;
  17. #define TX_ON_THREAD BIT(0)
  18. #define TX_DEFAULT BIT(31)
  19. ULONG TransmitPath = TX_ON_THREAD;
  20. BOOLEAN TransmitRealtime = FALSE;
  21. ULONG BuildEnv = VER_PRODUCTVERSION_DW;
  22. #define AFFINITY_MASK(n) ((ULONG_PTR)1 << (n))
  23. // from NTHAL.H
  24. extern KAFFINITY
  25. KeSetAffinityThread (
  26. IN PKTHREAD Thread,
  27. IN KAFFINITY Affinity
  28. );
  29. HANDLE hPassiveThread = NULL;
  30. KEVENT EventPassiveThread;
  31. KEVENT EventKillThread;
  32. LIST_ENTRY WorkItemList;
  33. NDIS_SPIN_LOCK GlobalThreadLock;
  34. typedef struct {
  35. LIST_ENTRY TransmitList;
  36. // List of calls with packets to transmit.
  37. KEVENT WorkEvent;
  38. // Signal to process packets.
  39. KEVENT KillEvent;
  40. // Signal to die
  41. NDIS_SPIN_LOCK Lock;
  42. // Lock for this structure
  43. HANDLE hThread;
  44. // Thread with affinity to this processor.
  45. UINT Number;
  46. // 0 based index of this processor
  47. } PROCESSOR, *PPROCESSOR;
  48. PPROCESSOR Processor = NULL;
  49. BOOLEAN ThreadingInitialized = FALSE;
  50. NDIS_STATUS
  51. ScheduleWorkItem(
  52. WORK_PROC Callback,
  53. PVOID Context,
  54. PVOID InfoBuf,
  55. ULONG InfoBufLen)
  56. {
  57. PPPTP_WORK_ITEM pWorkItem;
  58. NDIS_STATUS Status = NDIS_STATUS_FAILURE;
  59. DEBUGMSG(DBG_FUNC, (DTEXT("+ScheduleWorkItem\n")));
  60. ASSERT(ThreadingInitialized);
  61. pWorkItem = MyMemAlloc(sizeof(PPTP_WORK_ITEM), TAG_WORK_ITEM);
  62. if (pWorkItem != NULL)
  63. {
  64. pWorkItem->Context = Context;
  65. pWorkItem->pBuffer = InfoBuf;
  66. pWorkItem->Length = InfoBufLen;
  67. /*
  68. ** This interface was designed to use NdisScheduleWorkItem(), which
  69. ** would be good except that we're really only supposed to use that
  70. ** interface during startup and shutdown, due to the limited pool of
  71. ** threads available to service NdisScheduleWorkItem(). Therefore,
  72. ** instead of scheduling real work items, we simulate them, and use
  73. ** our own thread to process the calls. This also makes it easy to
  74. ** expand the size of our own thread pool, if we wish.
  75. **
  76. ** Our version is slightly different from actual NDIS_WORK_ITEMs,
  77. ** because that is an NDIS 5.0 structure, and we want people to
  78. ** (at least temporarily) build this with NDIS 4.0 headers.
  79. */
  80. pWorkItem->Callback = Callback;
  81. /*
  82. ** Our worker thread checks this list for new jobs, whenever its event
  83. ** is signalled.
  84. */
  85. MyInterlockedInsertTailList(&WorkItemList,
  86. &pWorkItem->ListEntry,
  87. &GlobalThreadLock);
  88. // Wake up our thread.
  89. KeSetEvent(&EventPassiveThread, 0, FALSE);
  90. Status = NDIS_STATUS_SUCCESS;
  91. }
  92. return Status;
  93. }
  94. VOID
  95. FreeWorkItem(
  96. PPPTP_WORK_ITEM pItem
  97. )
  98. {
  99. MyMemFree((PVOID)pItem, sizeof(PPTP_WORK_ITEM));
  100. }
  101. STATIC VOID
  102. MainPassiveLevelThread(
  103. IN OUT PVOID Context
  104. )
  105. {
  106. NDIS_STATUS Status;
  107. NTSTATUS NtStatus;
  108. PLIST_ENTRY pListEntry;
  109. PKEVENT EventList[2];
  110. DEBUGMSG(DBG_FUNC, (DTEXT("+MainPassiveLevelThread\n")));
  111. //KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
  112. EventList[0] = &EventPassiveThread;
  113. EventList[1] = &EventKillThread;
  114. for (;;)
  115. {
  116. //
  117. // The EventPassiveThread is an auto-clearing event, so
  118. // we don't need to reset the event.
  119. //
  120. NtStatus = KeWaitForMultipleObjects(2,
  121. EventList,
  122. WaitAny,
  123. Executive,
  124. KernelMode,
  125. FALSE,
  126. NULL,
  127. NULL);
  128. if (NtStatus==0) // The first event, for a work item, was signalled
  129. {
  130. while (pListEntry = MyInterlockedRemoveHeadList(&WorkItemList,
  131. &GlobalThreadLock))
  132. {
  133. PPPTP_WORK_ITEM pWorkItem = CONTAINING_RECORD(pListEntry,
  134. PPTP_WORK_ITEM,
  135. ListEntry);
  136. ASSERT(KeGetCurrentIrql()<DISPATCH_LEVEL);
  137. pWorkItem->Callback(pWorkItem);
  138. ASSERT(KeGetCurrentIrql()<DISPATCH_LEVEL);
  139. FreeWorkItem(pWorkItem);
  140. }
  141. }
  142. else
  143. {
  144. // A kill event was received.
  145. DEBUGMSG(DBG_THREAD, (DTEXT("Thread: HALT %08x\n"), NtStatus));
  146. // Free any pending requests
  147. while (pListEntry = MyInterlockedRemoveHeadList(&WorkItemList,
  148. &GlobalThreadLock))
  149. {
  150. PPPTP_WORK_ITEM pWorkItem = CONTAINING_RECORD(pListEntry,
  151. PPTP_WORK_ITEM,
  152. ListEntry);
  153. DEBUGMSG(DBG_WARN, (DTEXT("Releasing work item %08x\n"), pWorkItem));
  154. FreeWorkItem(pWorkItem);
  155. }
  156. hPassiveThread = NULL;
  157. DEBUGMSG(DBG_FUNC, (DTEXT("PsTerminateSystemThread MainPassiveLevelThread\n")));
  158. PsTerminateSystemThread(STATUS_SUCCESS);
  159. break;
  160. }
  161. }
  162. DEBUGMSG(DBG_FUNC, (DTEXT("-MainPassiveLevelThread\n")));
  163. }
  164. #if 0
  165. extern NDIS_STATUS
  166. CallTransmitPacket(
  167. PCALL_SESSION pCall,
  168. PNDIS_WAN_PACKET pPacket,
  169. BOOLEAN SendAck,
  170. ULONG Ack
  171. );
  172. NDIS_STATUS
  173. TransmitPacketNow(
  174. PCALL_SESSION pCall,
  175. PNDIS_WAN_PACKET pWanPacket
  176. )
  177. {
  178. BOOLEAN NeedToSendAck;
  179. ULONG Ack = 0;
  180. NDIS_STATUS Status;
  181. DEBUGMSG(DBG_FUNC, (DTEXT("+TransmitPacketNow\n")));
  182. if (!IS_CALL(pCall) || pCall->State!=STATE_CALL_ESTABLISHED)
  183. {
  184. // Drop the packet.
  185. Status = NDIS_STATUS_SUCCESS;
  186. goto cqtpDone;
  187. }
  188. NdisAcquireSpinLock(&pCall->Lock);
  189. if (NeedToSendAck = (pCall->Packet.AckNumber!=pCall->Remote.SequenceNumber))
  190. {
  191. pCall->Packet.AckNumber = pCall->Remote.SequenceNumber;
  192. Ack = pCall->Packet.AckNumber - 1;
  193. }
  194. NdisReleaseSpinLock(&pCall->Lock);
  195. Status = CallTransmitPacket(pCall, pWanPacket, NeedToSendAck, Ack);
  196. // We can get a failure here, but since we're in the direct path from
  197. // MiniportWanSend, it's ok. Just pass the status back and we're done.
  198. cqtpDone:
  199. DEBUGMSG(DBG_FUNC, (DTEXT("-TransmitPacketNow\n")));
  200. return Status;
  201. }
  202. #endif
  203. NDIS_STATUS
  204. TransmitPacketOnThread(
  205. PCALL_SESSION pCall,
  206. PNDIS_WAN_PACKET pWanPacket
  207. )
  208. {
  209. BOOLEAN StartTransferring = FALSE;
  210. ULONG_PTR ProcNum = 0;
  211. NDIS_STATUS Status = NDIS_STATUS_PENDING;
  212. DEBUGMSG(DBG_FUNC, (DTEXT("+TransmitPacketOnThread\n")));
  213. if (!IS_CALL(pCall) || pCall->State!=STATE_CALL_ESTABLISHED)
  214. {
  215. // Drop the packet.
  216. Status = NDIS_STATUS_SUCCESS;
  217. goto cqtpDone;
  218. }
  219. NdisAcquireSpinLock(&pCall->Lock);
  220. InsertTailList(&pCall->TxPacketList, &pWanPacket->WanPacketQueue);
  221. if (!pCall->Transferring)
  222. {
  223. StartTransferring = pCall->Transferring = TRUE;
  224. ProcNum = pCall->DeviceId % KeNumberProcessors;
  225. REFERENCE_OBJECT(pCall);
  226. MyInterlockedInsertTailList(&Processor[ProcNum].TransmitList,
  227. &pCall->TxListEntry,
  228. &Processor[ProcNum].Lock);
  229. KeSetEvent(&Processor[ProcNum].WorkEvent, 0, FALSE);
  230. }
  231. NdisReleaseSpinLock(&pCall->Lock);
  232. cqtpDone:
  233. DEBUGMSG(DBG_FUNC, (DTEXT("-TransmitPacketOnThread\n")));
  234. return Status;
  235. }
  236. NDIS_STATUS
  237. CallQueueTransmitPacket(
  238. PCALL_SESSION pCall,
  239. PNDIS_WAN_PACKET pWanPacket
  240. )
  241. {
  242. NDIS_STATUS Status;
  243. DEBUGMSG(DBG_FUNC, (DTEXT("+CallQueueTransmitPacket\n")));
  244. if (TransmitPath&TX_ON_THREAD)
  245. {
  246. Status = TransmitPacketOnThread(pCall, pWanPacket);
  247. }
  248. else
  249. {
  250. Status = NDIS_STATUS_FAILURE;
  251. ASSERT(0);
  252. }
  253. DEBUGMSG(DBG_FUNC, (DTEXT("-CallQueueTransmitPacket\n")));
  254. return Status;
  255. }
  256. NDIS_STATUS
  257. CallQueueReceivePacket(
  258. PCALL_SESSION pCall,
  259. PDGRAM_CONTEXT pDgContext
  260. )
  261. {
  262. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  263. PGRE_HEADER pGre = pDgContext->pGreHeader;
  264. ULONG_PTR ProcNum = 0;
  265. DEBUGMSG(DBG_FUNC, (DTEXT("+CallQueueReceivePacket\n")));
  266. if(!pGre->SequenceNumberPresent)
  267. {
  268. return NDIS_STATUS_FAILURE;
  269. }
  270. NdisAcquireSpinLock(&pCall->Lock);
  271. if (pCall->RxPacketsPending > 256 ||
  272. htons(pGre->KeyCallId)!=pCall->Packet.CallId ||
  273. pCall->State!=STATE_CALL_ESTABLISHED ||
  274. !IS_LINE_UP(pCall))
  275. {
  276. DEBUGMSG(DBG_PACKET|DBG_RX, (DTEXT("Rx: GRE CallId invalid or call in wrong state\n")));
  277. Status = NDIS_STATUS_FAILURE;
  278. goto cqrpDone;
  279. }
  280. // The packet has passed all of our tests.
  281. if (IsListEmpty(&pCall->RxPacketList))
  282. {
  283. PULONG pSequence = (PULONG)(pGre + 1);
  284. ULONG Sequence = htonl(*pSequence);
  285. if (Sequence==1)
  286. {
  287. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"Receiving GRE data:%d\n"),
  288. LOGHDR(29, pCall->Remote.Address.Address[0].Address[0].in_addr),
  289. pCall->DeviceId));
  290. }
  291. // We don't check the sequence # anymore, just put it on the queue
  292. InsertTailList(&pCall->RxPacketList, &pDgContext->ListEntry);
  293. pCall->RxPacketsPending++;
  294. }
  295. else
  296. {
  297. // There are packets already queued. Put this one in order.
  298. PULONG pSequence = (PULONG)(pGre + 1);
  299. ULONG Sequence = htonl(*pSequence);
  300. if (Sequence==1)
  301. {
  302. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"Receiving GRE data:%d\n"),
  303. LOGHDR(29, pCall->Remote.Address.Address[0].Address[0].in_addr),
  304. pCall->DeviceId));
  305. }
  306. // We don't check the sequence # anymore, just put it on the queue in order
  307. {
  308. PLIST_ENTRY pListEntry;
  309. BOOLEAN OnList = FALSE;
  310. for (pListEntry = pCall->RxPacketList.Flink;
  311. pListEntry != &pCall->RxPacketList;
  312. pListEntry = pListEntry->Flink)
  313. {
  314. PDGRAM_CONTEXT pListDg = CONTAINING_RECORD(pListEntry,
  315. DGRAM_CONTEXT,
  316. ListEntry);
  317. if ((signed)htonl(GreSequence(pListDg->pGreHeader)) - (signed)Sequence > 0)
  318. {
  319. // The one on the list is newer! Put this one before it.
  320. InsertTailList(&pListDg->ListEntry, &pDgContext->ListEntry);
  321. pCall->RxPacketsPending++;
  322. OnList = TRUE;
  323. break;
  324. }
  325. }
  326. if (!OnList)
  327. {
  328. // There were no packets on this list with a greater sequence.
  329. // Put this at the end.
  330. InsertTailList(&pCall->RxPacketList, &pDgContext->ListEntry);
  331. pCall->RxPacketsPending++;
  332. }
  333. }
  334. // We don't really care about the ACK from the peer, so save some cycles here
  335. /*
  336. pSequence++; // point to the ack
  337. if (pGre->AckSequenceNumberPresent)
  338. {
  339. ULONG Ack = ntohl(*pSequence);
  340. if ((signed)Ack - (signed)pCall->Remote.AckNumber >= 0 &&
  341. (signed)pCall->Packet.SequenceNumber - (signed)Ack >= 0)
  342. {
  343. pCall->Remote.AckNumber = Ack;
  344. }
  345. else
  346. {
  347. DEBUGMSG(DBG_WARN, (DTEXT("Ack out of range, Ack:%x LastAck:%x, NextSeq:%x\n"),
  348. Ack, pCall->Remote.AckNumber, pCall->Packet.SequenceNumber));
  349. }
  350. }
  351. */
  352. }
  353. if (Status==NDIS_STATUS_SUCCESS && !pCall->Receiving)
  354. {
  355. pCall->Receiving = TRUE;
  356. REFERENCE_OBJECT(pCall);
  357. #if 0
  358. ProcNum = pCall->DeviceId % KeNumberProcessors;
  359. MyInterlockedInsertTailList(&Processor[ProcNum].TransmitList,
  360. &pCall->TxListEntry,
  361. &Processor[ProcNum].Lock);
  362. KeSetEvent(&Processor[ProcNum].WorkEvent, 0, FALSE);
  363. #else
  364. PptpQueueDpc(&pCall->ReceiveDpc);
  365. #endif
  366. }
  367. cqrpDone:
  368. NdisReleaseSpinLock(&pCall->Lock);
  369. DEBUGMSG(DBG_FUNC, (DTEXT("-CallQueueReceivePacket\n")));
  370. return Status;
  371. }
  372. STATIC VOID
  373. PacketWorkingThread(
  374. IN OUT PVOID Context
  375. )
  376. {
  377. NDIS_STATUS Status;
  378. NTSTATUS NtStatus;
  379. PLIST_ENTRY pListEntry;
  380. PKEVENT EventList[2];
  381. PPROCESSOR pProcessor = Context;
  382. DEBUGMSG(DBG_FUNC, (DTEXT("+PacketWorkingThread\n")));
  383. if (TransmitRealtime)
  384. {
  385. KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
  386. }
  387. KeSetAffinityThread(KeGetCurrentThread(), AFFINITY_MASK(pProcessor->Number));
  388. EventList[0] = &pProcessor->WorkEvent;
  389. EventList[1] = &pProcessor->KillEvent;
  390. for (;;)
  391. {
  392. //
  393. // The events are auto-clearing, so
  394. // we don't need to reset the event.
  395. //
  396. NtStatus = KeWaitForMultipleObjects(2,
  397. EventList,
  398. WaitAny,
  399. Executive,
  400. KernelMode,
  401. FALSE,
  402. NULL,
  403. NULL);
  404. if (NtStatus==0) // The first event, for packet processing, was signalled
  405. {
  406. while (pListEntry = MyInterlockedRemoveHeadList(&pProcessor->TransmitList,
  407. &pProcessor->Lock))
  408. {
  409. PCALL_SESSION pCall = CONTAINING_RECORD(pListEntry,
  410. CALL_SESSION,
  411. TxListEntry);
  412. ULONG PacketsToTransmit;
  413. if (IsListEmpty(&pProcessor->TransmitList))
  414. {
  415. PacketsToTransmit = 0xffffffff;
  416. }
  417. else
  418. {
  419. PacketsToTransmit = 10;
  420. }
  421. if (CallProcessPackets(pCall, PacketsToTransmit))
  422. {
  423. MyInterlockedInsertTailList(&pProcessor->TransmitList,
  424. &pCall->TxListEntry,
  425. &pProcessor->Lock);
  426. }
  427. else
  428. {
  429. DEREFERENCE_OBJECT(pCall); // Matches TransmitPacketOnThread
  430. }
  431. }
  432. }
  433. else
  434. {
  435. // A kill event was received.
  436. DEBUGMSG(DBG_THREAD, (DTEXT("Thread: HALT %08x\n"), NtStatus));
  437. // Free any pending requests
  438. // ToDo: write code here
  439. pProcessor->hThread = NULL;
  440. DEBUGMSG(DBG_FUNC, (DTEXT("PsTerminateSystemThread PacketWorkingThread\n")));
  441. PsTerminateSystemThread(STATUS_SUCCESS);
  442. break;
  443. }
  444. }
  445. DEBUGMSG(DBG_FUNC, (DTEXT("-PacketWorkingThread\n")));
  446. }
  447. NDIS_STATUS
  448. InitThreading(
  449. NDIS_HANDLE hMiniportAdapter
  450. )
  451. {
  452. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  453. NTSTATUS NtStatus;
  454. UNREFERENCED_PARAMETER(hMiniportAdapter);
  455. DEBUGMSG(DBG_FUNC, (DTEXT("+InitializeThreading\n")));
  456. if (ThreadingInitialized)
  457. {
  458. ASSERT(!"Threading initialized twice");
  459. goto itDone;
  460. }
  461. ThreadingInitialized = TRUE;
  462. NdisInitializeListHead(&WorkItemList);
  463. NdisAllocateSpinLock(&GlobalThreadLock);
  464. KeInitializeEvent(
  465. &EventPassiveThread,
  466. SynchronizationEvent, // auto-clearing event
  467. FALSE // event initially non-signalled
  468. );
  469. KeInitializeEvent(
  470. &EventKillThread,
  471. SynchronizationEvent, // auto-clearing event
  472. FALSE // event initially non-signalled
  473. );
  474. NtStatus = PsCreateSystemThread(&hPassiveThread,
  475. (ACCESS_MASK) 0L,
  476. NULL,
  477. NULL,
  478. NULL,
  479. MainPassiveLevelThread,
  480. NULL);
  481. if (NtStatus!=STATUS_SUCCESS)
  482. {
  483. DEBUGMSG(DBG_ERROR, (DTEXT("PsCreateSystemThread failed. %08x\n"), Status));
  484. Status = NDIS_STATUS_FAILURE;
  485. goto itDone;
  486. }
  487. DBG_D(DBG_THREAD, KeNumberProcessors);
  488. #if 0
  489. if (KeNumberProcessors==1 && (TransmitPath&TX_DEFAULT))
  490. {
  491. // We've got one processor and the user hasn't requested a specific type
  492. // of transmission, so we'll opt to transmit immediately.
  493. TransmitPath &= ~TX_ON_THREAD;
  494. }
  495. #endif
  496. if (TransmitPath&TX_ON_THREAD)
  497. {
  498. Processor = MyMemAlloc(sizeof(PROCESSOR)*KeNumberProcessors, TAG_THREAD);
  499. if (!Processor)
  500. {
  501. Status = NDIS_STATUS_RESOURCES;
  502. }
  503. else
  504. {
  505. ULONG i;
  506. NdisZeroMemory(Processor, sizeof(PROCESSOR)*KeNumberProcessors);
  507. for (i=0; i<(ULONG)KeNumberProcessors; i++)
  508. {
  509. NdisInitializeListHead(&Processor[i].TransmitList);
  510. NdisAllocateSpinLock(&Processor[i].Lock);
  511. KeInitializeEvent(
  512. &Processor[i].WorkEvent,
  513. SynchronizationEvent, // auto-clearing event
  514. FALSE // event initially non-signalled
  515. );
  516. KeInitializeEvent(
  517. &Processor[i].KillEvent,
  518. SynchronizationEvent, // auto-clearing event
  519. FALSE // event initially non-signalled
  520. );
  521. Processor[i].Number = i;
  522. // ToDo: we should create the thread when we really need it.
  523. NtStatus = PsCreateSystemThread(&Processor[i].hThread,
  524. (ACCESS_MASK) 0L,
  525. NULL,
  526. NULL,
  527. NULL,
  528. PacketWorkingThread,
  529. &Processor[i]);
  530. if (NtStatus!=STATUS_SUCCESS)
  531. {
  532. DEBUGMSG(DBG_ERROR, (DTEXT("PsCreateSystemThread failed. %08x\n"), Status));
  533. Status = NDIS_STATUS_FAILURE;
  534. break;
  535. }
  536. }
  537. }
  538. }
  539. itDone:
  540. DEBUGMSG(DBG_FUNC, (DTEXT("-InitializeThreading %08x\n"), Status));
  541. return Status;
  542. }
  543. VOID STATIC WaitForThreadToDieAndCloseIt(HANDLE hThread, PRKEVENT pKillEvent)
  544. {
  545. PVOID pThread = NULL;
  546. NTSTATUS Status;
  547. DEBUGMSG(DBG_FUNC, (DTEXT("+WaitForThreadToDie\n")));
  548. if ( hThread != NULL && pKillEvent != NULL )
  549. {
  550. Status = ObReferenceObjectByHandle(hThread, 0, NULL, KernelMode, &pThread, NULL);
  551. if (Status==STATUS_SUCCESS)
  552. {
  553. KeSetEvent(pKillEvent, 0, FALSE);
  554. KeWaitForSingleObject(pThread, Executive, KernelMode, FALSE, NULL);
  555. ObDereferenceObject(pThread);
  556. }
  557. ZwClose(hThread);
  558. }
  559. DEBUGMSG(DBG_FUNC, (DTEXT("-WaitForThreadToDie\n")));
  560. }
  561. VOID
  562. DeinitThreading()
  563. {
  564. DEBUGMSG(DBG_FUNC, (DTEXT("+DeinitThreading\n")));
  565. ThreadingInitialized = FALSE;
  566. if ((TransmitPath&TX_ON_THREAD) && Processor!=NULL)
  567. {
  568. LONG i;
  569. for (i=0; i<KeNumberProcessors; i++)
  570. {
  571. WaitForThreadToDieAndCloseIt( Processor[i].hThread,
  572. &Processor[i].KillEvent );
  573. }
  574. MyMemFree(Processor, sizeof(PROCESSOR)*KeNumberProcessors);
  575. Processor = NULL;
  576. }
  577. WaitForThreadToDieAndCloseIt( hPassiveThread,
  578. &EventKillThread );
  579. DEBUGMSG(DBG_FUNC, (DTEXT("-DeinitThreading\n")));
  580. }
  581. UCHAR TapiLineNameBuffer[64] = TAPI_LINE_NAME_STRING;
  582. ANSI_STRING TapiLineName = {
  583. sizeof(TAPI_LINE_NAME_STRING),
  584. sizeof(TapiLineNameBuffer),
  585. TapiLineNameBuffer
  586. };
  587. typedef UCHAR TAPI_CHAR_TYPE;
  588. ANSI_STRING TapiLineAddrList = { 0, 0, NULL };
  589. #define READ_NDIS_REG_ULONG(hConfig, Var, Value) \
  590. { \
  591. PNDIS_CONFIGURATION_PARAMETER RegValue; \
  592. NDIS_STATUS Status; \
  593. NDIS_STRING String = NDIS_STRING_CONST(Value); \
  594. \
  595. NdisReadConfiguration(&Status, \
  596. &RegValue, \
  597. hConfig, \
  598. &String, \
  599. NdisParameterInteger); \
  600. if (Status==NDIS_STATUS_SUCCESS) \
  601. { \
  602. (Var) = RegValue->ParameterData.IntegerData; \
  603. DEBUGMSG(DBG_INIT, (DTEXT(#Var"==%d\n"), (Var))); \
  604. } \
  605. else \
  606. { \
  607. DEBUGMSG(DBG_INIT, (DTEXT(Value", default==%d\n"), (Var)));\
  608. } \
  609. }
  610. #define READ_NDIS_REG_USHORT(hConfig, Var, Value) \
  611. { \
  612. PNDIS_CONFIGURATION_PARAMETER RegValue; \
  613. NDIS_STATUS Status; \
  614. NDIS_STRING String = NDIS_STRING_CONST(Value); \
  615. \
  616. NdisReadConfiguration(&Status, \
  617. &RegValue, \
  618. hConfig, \
  619. &String, \
  620. NdisParameterInteger); \
  621. if (Status==NDIS_STATUS_SUCCESS) \
  622. { \
  623. (Var) = (USHORT)(RegValue->ParameterData.IntegerData&0xffff); \
  624. DEBUGMSG(DBG_INIT, (DTEXT(#Var"==%d\n"), (Var))); \
  625. } \
  626. else \
  627. { \
  628. DEBUGMSG(DBG_INIT, (DTEXT(Value", default==%d\n"), (Var)));\
  629. } \
  630. }
  631. #define READ_NDIS_REG_BOOL(hConfig, Var, Value) \
  632. { \
  633. PNDIS_CONFIGURATION_PARAMETER RegValue; \
  634. NDIS_STATUS Status; \
  635. NDIS_STRING String = NDIS_STRING_CONST(Value); \
  636. \
  637. NdisReadConfiguration(&Status, \
  638. &RegValue, \
  639. hConfig, \
  640. &String, \
  641. NdisParameterInteger); \
  642. if (Status==NDIS_STATUS_SUCCESS) \
  643. { \
  644. (Var) = RegValue->ParameterData.IntegerData ? TRUE : FALSE; \
  645. DEBUGMSG(DBG_INIT, (DTEXT(#Var"==%d\n"), (Var))); \
  646. } \
  647. else \
  648. { \
  649. DEBUGMSG(DBG_INIT, (DTEXT(Value", default==%d\n"), (Var)));\
  650. } \
  651. }
  652. VOID
  653. OsReadConfig(
  654. NDIS_HANDLE hConfig
  655. )
  656. {
  657. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  658. PNDIS_CONFIGURATION_PARAMETER Value;
  659. #if 0
  660. NDIS_STRING TransmitPathString = NDIS_STRING_CONST("TransmitPath");
  661. #endif
  662. NDIS_STRING TapiLineNameString = NDIS_STRING_CONST("TapiLineName");
  663. #if VER_PRODUCTVERSION_W < 0x0500
  664. NDIS_STRING TapiLineAddrString = NDIS_STRING_CONST("AddressList");
  665. #endif
  666. NDIS_STRING PeerClientIpAddressString = NDIS_STRING_CONST("ClientIpAddresses");
  667. NDIS_STRING PeerClientIpMaskString = NDIS_STRING_CONST("ClientIpMasks");
  668. DEBUGMSG(DBG_FUNC, (DTEXT("+OsReadConfig\n")));
  669. #if 0
  670. READ_NDIS_REG_ULONG(hConfig, "TransmitPath", TransmitPath);
  671. #endif
  672. READ_NDIS_REG_USHORT(hConfig, PptpControlPort, "TcpPortNumber");
  673. READ_NDIS_REG_USHORT(hConfig, PptpUdpPort, "UdpPortNumber");
  674. READ_NDIS_REG_ULONG (hConfig, PptpWanEndpoints, "MaxWanEndpoints");
  675. READ_NDIS_REG_ULONG (hConfig, PptpMaxTransmit, "MaxTransmit");
  676. READ_NDIS_REG_ULONG (hConfig, PptpEchoTimeout, "InactivityIdleSeconds");
  677. READ_NDIS_REG_BOOL (hConfig, PptpEchoAlways, "AlwaysEcho");
  678. READ_NDIS_REG_ULONG (hConfig, PptpTunnelConfig, "TunnelConfig");
  679. READ_NDIS_REG_ULONG (hConfig, CtdiTcpDisconnectTimeout, "TcpDisconnectTimeout");
  680. READ_NDIS_REG_ULONG (hConfig, CtdiTcpConnectTimeout, "TcpConnectTimeout");
  681. READ_NDIS_REG_ULONG (hConfig, FileLogLevel, "Logging");
  682. READ_NDIS_REG_BOOL (hConfig, TransmitRealtime, "TransmitRealtime");
  683. READ_NDIS_REG_BOOL (hConfig, PptpAuthenticateIncomingCalls, "AuthenticateIncomingCalls");
  684. READ_NDIS_REG_ULONG (hConfig, PptpValidateAddress, "ValidateAddress");
  685. OS_RANGE_CHECK_ENDPOINTS(PptpWanEndpoints);
  686. OS_RANGE_CHECK_MAX_TRANSMIT(PptpMaxTransmit);
  687. if (PptpAuthenticateIncomingCalls)
  688. {
  689. NdisReadConfiguration(&Status, // Not required value
  690. &Value,
  691. hConfig,
  692. &PeerClientIpAddressString,
  693. NdisParameterMultiString);
  694. if (Status==NDIS_STATUS_SUCCESS)
  695. {
  696. ULONG i, NumAddresses = 0;
  697. BOOLEAN InEntry = 0, ValidAddress;
  698. PWCHAR AddressList = Value->ParameterData.StringData.Buffer;
  699. TA_IP_ADDRESS Address;
  700. // Loop and count the addresses, so we can allocate proper size to hold them.
  701. for (i=0, InEntry=FALSE; i<(Value->ParameterData.StringData.Length/sizeof(WCHAR))-1; i++)
  702. {
  703. if (!InEntry)
  704. {
  705. if (AddressList[i]!=L'\0')
  706. {
  707. InEntry = TRUE;
  708. StringToIpAddressW(&AddressList[i],
  709. &Address,
  710. &ValidAddress);
  711. if (ValidAddress)
  712. {
  713. NumAddresses++;
  714. }
  715. }
  716. }
  717. else
  718. {
  719. if (AddressList[i]==L'\0')
  720. {
  721. InEntry = FALSE;
  722. }
  723. }
  724. }
  725. NumClientAddresses = NumAddresses;
  726. if (NumClientAddresses)
  727. {
  728. ClientList = MyMemAlloc(sizeof(CLIENT_ADDRESS)*NumClientAddresses, TAG_PPTP_ADDR_LIST);
  729. if (ClientList)
  730. {
  731. NumAddresses = 0;
  732. for (i=0, InEntry=FALSE; i<(Value->ParameterData.StringData.Length/sizeof(WCHAR))-1; i++)
  733. {
  734. if (!InEntry)
  735. {
  736. if (AddressList[i]!=L'\0')
  737. {
  738. InEntry = TRUE;
  739. if (NumAddresses<NumClientAddresses)
  740. {
  741. StringToIpAddressW(&AddressList[i],
  742. &Address,
  743. &ValidAddress);
  744. if (ValidAddress)
  745. {
  746. ClientList[NumAddresses].Address = Address.Address[0].Address[0].in_addr;
  747. ClientList[NumAddresses].Mask = 0xFFFFFFFF;
  748. NumAddresses++;
  749. }
  750. }
  751. }
  752. }
  753. else
  754. {
  755. if (AddressList[i]==L'\0')
  756. {
  757. InEntry = FALSE;
  758. }
  759. }
  760. }
  761. NdisReadConfiguration(&Status, // Not required value
  762. &Value,
  763. hConfig,
  764. &PeerClientIpMaskString,
  765. NdisParameterMultiString);
  766. if (Status==NDIS_STATUS_SUCCESS)
  767. {
  768. AddressList = Value->ParameterData.StringData.Buffer;
  769. NumAddresses = 0;
  770. for (i=0, InEntry=FALSE;
  771. i<(Value->ParameterData.StringData.Length/sizeof(WCHAR))-1 && NumAddresses<=NumClientAddresses;
  772. i++)
  773. {
  774. if (!InEntry)
  775. {
  776. if (AddressList[i]!=L'\0')
  777. {
  778. InEntry = TRUE;
  779. if (NumAddresses<NumClientAddresses)
  780. {
  781. StringToIpAddressW(&AddressList[i],
  782. &Address,
  783. &ValidAddress);
  784. if (ValidAddress)
  785. {
  786. ClientList[NumAddresses].Mask = Address.Address[0].Address[0].in_addr;
  787. NumAddresses++;
  788. }
  789. }
  790. }
  791. }
  792. else
  793. {
  794. if (AddressList[i]==L'\0')
  795. {
  796. InEntry = FALSE;
  797. }
  798. }
  799. }
  800. }
  801. for (i=0; i<NumClientAddresses; i++)
  802. {
  803. DEBUGMSG(DBG_INIT, (DTEXT("Client Address:%d.%d.%d.%d Mask:%d.%d.%d.%d\n"),
  804. IPADDR(ClientList[i].Address), IPADDR(ClientList[i].Mask)));
  805. }
  806. }
  807. else
  808. PptpAuthenticateIncomingCalls = FALSE;
  809. }
  810. else
  811. PptpAuthenticateIncomingCalls = FALSE;
  812. }
  813. }
  814. NdisReadConfiguration(&Status, // Not required value
  815. &Value,
  816. hConfig,
  817. &TapiLineNameString,
  818. NdisParameterString);
  819. if (Status==NDIS_STATUS_SUCCESS)
  820. {
  821. RtlUnicodeStringToAnsiString(&TapiLineName, &Value->ParameterData.StringData, FALSE);
  822. *(TAPI_CHAR_TYPE*)(TapiLineName.Buffer+TapiLineName.MaximumLength-sizeof(TAPI_CHAR_TYPE)) = (TAPI_CHAR_TYPE)0;
  823. }
  824. #if VER_PRODUCTVERSION_W < 0x0500
  825. NdisReadConfiguration(&Status, // Not required value
  826. &Value,
  827. hConfig,
  828. &TapiLineAddrString,
  829. NdisParameterMultiString);
  830. if (Status==NDIS_STATUS_SUCCESS)
  831. {
  832. RtlInitAnsiString( &TapiLineAddrList, NULL );
  833. if (RtlUnicodeStringToAnsiString(&TapiLineAddrList, &Value->ParameterData.StringData, TRUE)==NDIS_STATUS_SUCCESS)
  834. {
  835. // NT4 doesn't have the same registry value to tell us how many lines to publish.
  836. // We work around that by counting the number of address strings here
  837. PUCHAR p = TapiLineAddrList.Buffer;
  838. DEBUGMEM(DBG_TAPI, TapiLineAddrList.Buffer, TapiLineAddrList.Length, 1);
  839. PptpWanEndpoints = 0;
  840. if (p)
  841. {
  842. // Count the valid MULTI_SZ entries.
  843. while (*p++)
  844. {
  845. PptpWanEndpoints++;
  846. while (*p++); // This also skips the first NULL
  847. }
  848. }
  849. DBG_D(DBG_INIT, PptpWanEndpoints);
  850. }
  851. }
  852. #endif
  853. DEBUGMSG(DBG_FUNC, (DTEXT("-OsReadConfig\n")));
  854. }
  855. VOID
  856. OsGetTapiLineAddress(ULONG Index, PUCHAR s, ULONG Length)
  857. {
  858. #if VER_PRODUCTVERSION_W < 0x0500
  859. PUCHAR pAddr = TapiLineAddrList.Buffer;
  860. *s = 0;
  861. if (pAddr)
  862. {
  863. UINT i;
  864. for (i=0; i<Index; i++)
  865. {
  866. if (!*pAddr)
  867. {
  868. // No string at index
  869. return;
  870. }
  871. while (*pAddr) pAddr++;
  872. pAddr++;
  873. }
  874. strncpy(s, pAddr, Length);
  875. s[Length-1] = 0;
  876. }
  877. #else // VER_PRODUCTVERSION_W >= 0x0500
  878. strncpy(s, TAPI_LINE_ADDR_STRING, Length);
  879. s[Length-1] = 0;
  880. #endif
  881. }
  882. NDIS_STATUS
  883. OsSpecificTapiGetDevCaps(
  884. ULONG_PTR ulDeviceId,
  885. IN OUT PNDIS_TAPI_GET_DEV_CAPS pRequest
  886. )
  887. {
  888. PUCHAR pTmp, pTmp2;
  889. ULONG_PTR Index;
  890. DEBUGMSG(DBG_FUNC, (DTEXT("+OsSpecificTapiGetDevCaps\n")));
  891. // Convert to our internal index
  892. ulDeviceId -= pgAdapter->Tapi.DeviceIdBase;
  893. pRequest->LineDevCaps.ulStringFormat = STRINGFORMAT_ASCII;
  894. // The *6 at the end adds enough space for " 9999"
  895. pRequest->LineDevCaps.ulNeededSize = sizeof(pRequest->LineDevCaps) +
  896. sizeof(TAPI_PROVIDER_STRING) +
  897. TapiLineName.Length +
  898. sizeof(TAPI_CHAR_TYPE) * 6;
  899. if (pRequest->LineDevCaps.ulTotalSize<pRequest->LineDevCaps.ulNeededSize)
  900. {
  901. DEBUGMSG(DBG_FUNC|DBG_WARN, (DTEXT("-TapiGetDevCaps NDIS_STATUS_SUCCESS without PROVIDER or LINE_NAME strings\n")));
  902. return NDIS_STATUS_SUCCESS;
  903. }
  904. // Tack the provider string to the end of the LineDevCaps structure.
  905. pRequest->LineDevCaps.ulProviderInfoSize = sizeof(TAPI_PROVIDER_STRING);
  906. pRequest->LineDevCaps.ulProviderInfoOffset = sizeof(pRequest->LineDevCaps);
  907. pTmp = ((PUCHAR)&pRequest->LineDevCaps) + sizeof(pRequest->LineDevCaps);
  908. NdisMoveMemory(pTmp, TAPI_PROVIDER_STRING, sizeof(TAPI_PROVIDER_STRING));
  909. pTmp += sizeof(TAPI_PROVIDER_STRING);
  910. // Tack on the LineName after the provider string.
  911. pRequest->LineDevCaps.ulLineNameSize = TapiLineName.Length + sizeof(TAPI_CHAR_TYPE);
  912. pRequest->LineDevCaps.ulLineNameOffset = pRequest->LineDevCaps.ulProviderInfoOffset +
  913. pRequest->LineDevCaps.ulProviderInfoSize;
  914. NdisMoveMemory(pTmp, TapiLineName.Buffer, TapiLineName.Length+sizeof(TAPI_CHAR_TYPE));
  915. while (*pTmp) pTmp++; // Find the NULL
  916. *pTmp++ = ' ';
  917. pRequest->LineDevCaps.ulLineNameSize++;
  918. // Put a number at the end of the string.
  919. if (ulDeviceId==0)
  920. {
  921. *pTmp++ = '0';
  922. *pTmp++ = '\0';
  923. pRequest->LineDevCaps.ulLineNameSize += 2;
  924. }
  925. else
  926. {
  927. Index = ulDeviceId;
  928. ASSERT(Index<100000);
  929. pTmp2 = pTmp;
  930. while (Index)
  931. {
  932. *pTmp2++ = (UCHAR)((Index%10) + '0');
  933. Index /= 10;
  934. pRequest->LineDevCaps.ulLineNameSize++;
  935. }
  936. *pTmp2-- = '\0'; // Null terminate and point to the last digit.
  937. pRequest->LineDevCaps.ulLineNameSize++;
  938. // We put the number in backwards, now reverse it.
  939. while (pTmp<pTmp2)
  940. {
  941. UCHAR t = *pTmp;
  942. *pTmp++ = *pTmp2;
  943. *pTmp2-- = t;
  944. }
  945. }
  946. pRequest->LineDevCaps.ulUsedSize = pRequest->LineDevCaps.ulNeededSize;
  947. DEBUGMSG(DBG_FUNC, (DTEXT("-OsSpecificTapiGetDevCaps\n")));
  948. return NDIS_STATUS_SUCCESS;
  949. }
  950. NDIS_HANDLE LogHandle = 0;
  951. VOID __cdecl OsFileLogInit()
  952. {
  953. NDIS_STATUS Status =
  954. NdisMCreateLog(pgAdapter->hMiniportAdapter,
  955. 16384,
  956. &LogHandle);
  957. }
  958. VOID __cdecl OsFileLogOpen()
  959. {
  960. }
  961. VOID __cdecl OsLogPrintf(char *pszFmt, ... )
  962. {
  963. va_list ArgList;
  964. CHAR Buf[512];
  965. ULONG Len;
  966. if (LogHandle)
  967. {
  968. va_start(ArgList, pszFmt);
  969. Len = vsprintf(Buf, pszFmt, ArgList);
  970. va_end(ArgList);
  971. NdisMWriteLogData(LogHandle, Buf, Len);
  972. }
  973. }
  974. VOID __cdecl OsFileLogClose(void)
  975. {
  976. }
  977. VOID __cdecl OsFileLogShutdown(void)
  978. {
  979. if (LogHandle)
  980. {
  981. NdisMCloseLog(LogHandle);
  982. LogHandle = 0;
  983. }
  984. }
  985. VOID __cdecl OsFileLogFlush(void)
  986. {
  987. }