Leaked source code of windows server 2003
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.

2021 lines
62 KiB

  1. //depot/Lab03_N/Net/rras/ndis/raspptp/common/call.c#7 - edit change 19457 (text)
  2. /*****************************************************************************
  3. *
  4. * Copyright (c) 1998-1999 Microsoft Corporation
  5. *
  6. * CALL.C - PPTP Call layer functionality
  7. *
  8. * Author: Stan Adermann (stana)
  9. *
  10. * Created: 7/28/1998
  11. *
  12. *****************************************************************************/
  13. #include "raspptp.h"
  14. #include "call.tmh"
  15. //ULONG ProcCountTx[2] = {0, 0};
  16. //ULONG ProcCountRx[2] = {0, 0};
  17. ULONG CallStateToLineCallStateMap[NUM_CALL_STATES] = {
  18. LINECALLSTATE_UNKNOWN, // STATE_CALL_INVALID
  19. LINECALLSTATE_UNKNOWN, // STATE_CALL_CLOSED
  20. LINECALLSTATE_IDLE, // STATE_CALL_IDLE
  21. LINECALLSTATE_IDLE, // STATE_CALL_OFFHOOK
  22. LINECALLSTATE_OFFERING, // STATE_CALL_OFFERING
  23. LINECALLSTATE_OFFERING, // STATE_CALL_PAC_OFFERING
  24. LINECALLSTATE_OFFERING, // STATE_CALL_PAC_WAIT
  25. LINECALLSTATE_DIALING, // STATE_CALL_DIALING
  26. LINECALLSTATE_PROCEEDING, // STATE_CALL_PROCEEDING
  27. LINECALLSTATE_CONNECTED, // STATE_CALL_ESTABLISHED
  28. LINECALLSTATE_CONNECTED, // STATE_CALL_WAIT_DISCONNECT
  29. LINECALLSTATE_DISCONNECTED, // STATE_CALL_CLEANUP
  30. };
  31. ULONG g_CallSerialNumber = 0;
  32. #define RNG_KEY_SIZE 256
  33. #define RNG_THRESHOLD (1024 * 8)
  34. VOID
  35. CallpRekey(
  36. IN PPPTP_WORK_ITEM pWorkItem
  37. )
  38. {
  39. UCHAR pBuf[RNG_KEY_SIZE];
  40. if(pgAdapter->FipsFunctionTable.FIPSGenRandom(pBuf, RNG_KEY_SIZE))
  41. {
  42. NdisAcquireSpinLock(&pgAdapter->Lock);
  43. // Generate the key control structure.
  44. rc4_key(&pgAdapter->Rc4KeyData, RNG_KEY_SIZE, pBuf);
  45. pgAdapter->lRandomCount = 0;
  46. }
  47. else
  48. {
  49. WPLOG(LL_A, LM_Res, ("Failed to call FIPSGenRandom"));
  50. NdisAcquireSpinLock(&pgAdapter->Lock);
  51. }
  52. pgAdapter->bRekeying = FALSE;
  53. NdisReleaseSpinLock(&pgAdapter->Lock);
  54. }
  55. // Assume pAdapter->Lock is held
  56. __inline ULONG CallGetRandomId()
  57. {
  58. ULONG ulRandomNumber;
  59. rc4(&pgAdapter->Rc4KeyData, 4, (PUCHAR)&ulRandomNumber);
  60. ++pgAdapter->lRandomCount;
  61. if(pgAdapter->lRandomCount > RNG_THRESHOLD && !pgAdapter->bRekeying)
  62. {
  63. if(ScheduleWorkItem(CallpRekey, NULL, NULL, 0)==NDIS_STATUS_SUCCESS)
  64. {
  65. pgAdapter->bRekeying = TRUE;
  66. }
  67. }
  68. return (ulRandomNumber % PptpWanEndpoints);
  69. }
  70. // Assume pAdapter->Lock is held
  71. __inline ULONG CallGetRandomWithRange(ULONG ulRange)
  72. {
  73. ULONG ulRandomNumber;
  74. rc4(&pgAdapter->Rc4KeyData, 4, (PUCHAR)&ulRandomNumber);
  75. ++pgAdapter->lRandomCount;
  76. if(pgAdapter->lRandomCount > RNG_THRESHOLD && !pgAdapter->bRekeying)
  77. {
  78. if(ScheduleWorkItem(CallpRekey, NULL, NULL, 0)==NDIS_STATUS_SUCCESS)
  79. {
  80. pgAdapter->bRekeying = TRUE;
  81. }
  82. }
  83. return (ulRandomNumber % ulRange);
  84. }
  85. // Assume pAdapter->Lock is held
  86. __inline VOID CallSetFullCallId(PCALL_SESSION pCall)
  87. {
  88. if(PptpCallIdMask)
  89. {
  90. pCall->FullDeviceId = (CallGetRandomWithRange(MAX_CALL_ID_RANGE) & ~PptpCallIdMask) + pCall->DeviceId;
  91. }
  92. else
  93. {
  94. pCall->FullDeviceId = PptpBaseCallId + pCall->DeviceId;
  95. }
  96. }
  97. static PCHAR aszCallStateType[NUM_CALL_STATES+1] =
  98. {
  99. "INVALID",
  100. "CLOSED",
  101. "IDLE",
  102. "OFFHOOK",
  103. "OFFERING",
  104. "PAC_OFFERING",
  105. "PAC_WAIT",
  106. "DIALING",
  107. "PROCEEDING",
  108. "ESTABLISHED",
  109. "WAIT_DISCONNECT",
  110. "CLEANUP",
  111. "UNKNOWN"
  112. };
  113. __inline PCHAR szCallState(IN CALL_STATE state)
  114. {
  115. if (state >= 0 && state < NUM_CALL_STATES)
  116. {
  117. return aszCallStateType[state];
  118. }
  119. else
  120. {
  121. return aszCallStateType[NUM_CALL_STATES];
  122. }
  123. }
  124. VOID
  125. CallpAckTimeout(
  126. IN PVOID SystemSpecific1,
  127. IN PVOID Context,
  128. IN PVOID SystemSpecific2,
  129. IN PVOID SystemSpecific3
  130. );
  131. VOID
  132. CallpCloseTimeout(
  133. IN PVOID SystemSpecific1,
  134. IN PVOID Context,
  135. IN PVOID SystemSpecific2,
  136. IN PVOID SystemSpecific3
  137. );
  138. VOID
  139. CallpDialTimeout(
  140. IN PVOID SystemSpecific1,
  141. IN PVOID Context,
  142. IN PVOID SystemSpecific2,
  143. IN PVOID SystemSpecific3
  144. );
  145. VOID
  146. CallpFinalDeref(IN PCALL_SESSION pCall);
  147. /*++
  148. Routine Description:
  149. Init FIPS and get the first random RC4 key
  150. Arguments:
  151. Called at PASSIVE level.
  152. Return Value:
  153. NDIS_STATUS_SUCCESS/NDIS_STATUS_FAILURE
  154. --*/
  155. NTSTATUS
  156. RngInit()
  157. {
  158. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  159. UNICODE_STRING DeviceName = { 0 };
  160. KEVENT kEvent = { 0 };
  161. PIRP pIrp = NULL;
  162. IO_STATUS_BLOCK IoStatusBlock = { 0 };
  163. UCHAR pBuf[RNG_KEY_SIZE];
  164. RtlInitUnicodeString(&DeviceName, FIPS_DEVICE_NAME);
  165. do
  166. {
  167. if(!pgAdapter)
  168. {
  169. break;
  170. }
  171. //
  172. // Get pointers to the file and device objects for FIPS.
  173. //
  174. ntStatus = IoGetDeviceObjectPointer(
  175. &DeviceName,
  176. FILE_ALL_ACCESS,
  177. &pgAdapter->pFipsFileObject,
  178. &pgAdapter->pFipsDeviceObject
  179. );
  180. if(!NT_SUCCESS(ntStatus))
  181. {
  182. break;
  183. }
  184. //
  185. // Build the request to send to FIPS to get the library table.
  186. //
  187. KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
  188. pIrp = IoBuildDeviceIoControlRequest(
  189. IOCTL_FIPS_GET_FUNCTION_TABLE,
  190. pgAdapter->pFipsDeviceObject,
  191. NULL,
  192. 0,
  193. &pgAdapter->FipsFunctionTable,
  194. sizeof(FIPS_FUNCTION_TABLE),
  195. FALSE,
  196. &kEvent,
  197. &IoStatusBlock
  198. );
  199. if (!pIrp) {
  200. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  201. break;
  202. }
  203. //
  204. // IoBuildDeviceIoControlRequest queues the IRP it creates in the IRP queue
  205. // of the current thread. When the thread terminates, it deallocates the
  206. // IRP's memory.
  207. //
  208. ntStatus = IoCallDriver(pgAdapter->pFipsDeviceObject, pIrp);
  209. if (ntStatus == STATUS_PENDING) {
  210. ntStatus = KeWaitForSingleObject(
  211. &kEvent,
  212. Executive,
  213. KernelMode,
  214. FALSE,
  215. NULL
  216. );
  217. if (ntStatus == STATUS_SUCCESS) {
  218. ntStatus = IoStatusBlock.Status;
  219. }
  220. }
  221. if(!NT_SUCCESS(ntStatus))
  222. {
  223. break;
  224. }
  225. if(pgAdapter->FipsFunctionTable.FIPSGenRandom(pBuf, RNG_KEY_SIZE) == FALSE)
  226. {
  227. ntStatus = STATUS_UNSUCCESSFUL;
  228. break;
  229. }
  230. //
  231. // Generate the key control structure.
  232. //
  233. rc4_key(&pgAdapter->Rc4KeyData, RNG_KEY_SIZE, pBuf);
  234. } while(FALSE);
  235. if(!NT_SUCCESS(ntStatus))
  236. {
  237. if(pgAdapter->pFipsFileObject)
  238. {
  239. ObDereferenceObject(pgAdapter->pFipsFileObject);
  240. pgAdapter->pFipsFileObject = NULL;
  241. }
  242. }
  243. return (ntStatus);
  244. }
  245. VOID InitCallLayer()
  246. {
  247. if(!PptpClientSide && !PptpBaseCallId)
  248. {
  249. // Get the call id mask
  250. PptpCallIdMask = 1;
  251. while(PptpCallIdMask < PptpWanEndpoints)
  252. {
  253. PptpCallIdMask = PptpCallIdMask << 1;
  254. }
  255. --PptpCallIdMask;
  256. PptpMaxCallId = MAX_CALL_ID_RANGE;
  257. }
  258. else
  259. {
  260. PptpMaxCallId = PptpBaseCallId + PptpWanEndpoints;
  261. }
  262. }
  263. VOID
  264. CallAssignSerialNumber(
  265. PCALL_SESSION pCall
  266. )
  267. {
  268. ASSERT(IS_CALL(pCall));
  269. ASSERT_LOCK_HELD(&pCall->Lock);
  270. pCall->SerialNumber = (USHORT)NdisInterlockedIncrement(&g_CallSerialNumber);
  271. }
  272. PCALL_SESSION
  273. CallAlloc(PPPTP_ADAPTER pAdapter)
  274. {
  275. PCALL_SESSION pCall;
  276. DEBUGMSG(DBG_FUNC, (DTEXT("+CallAlloc\n")));
  277. pCall = MyMemAlloc(sizeof(CALL_SESSION), TAG_PPTP_CALL);
  278. if (!pCall)
  279. {
  280. WPLOG(LL_A, LM_Res, ("Failed to alloc CALL"));
  281. return NULL;
  282. }
  283. NdisZeroMemory(pCall, sizeof(CALL_SESSION));
  284. pCall->Signature = TAG_PPTP_CALL;
  285. pCall->pAdapter = pAdapter;
  286. pCall->Close.Checklist = CALL_CLOSE_COMPLETE;
  287. NdisAllocateSpinLock(&pCall->Lock);
  288. NdisInitializeListHead(&pCall->RxPacketList);
  289. NdisInitializeListHead(&pCall->TxPacketList);
  290. NdisInitializeListHead(&pCall->TxActivePacketList);
  291. NdisMInitializeTimer(&pCall->Close.Timer,
  292. pAdapter->hMiniportAdapter,
  293. CallpCloseTimeout,
  294. pCall);
  295. NdisMInitializeTimer(&pCall->Ack.Timer,
  296. pAdapter->hMiniportAdapter,
  297. CallpAckTimeout,
  298. pCall);
  299. NdisMInitializeTimer(&pCall->DialTimer,
  300. pAdapter->hMiniportAdapter,
  301. CallpDialTimeout,
  302. pCall);
  303. #if 0
  304. PptpInitializeDpc(&pCall->ReceiveDpc,
  305. pAdapter->hMiniportAdapter,
  306. CallProcessRxPackets,
  307. pCall);
  308. #endif
  309. NdisInitializeWorkItem(&pCall->SendWorkItem, CallProcessPackets, pCall);
  310. NdisInitializeWorkItem(&pCall->RecvWorkItem, CallProcessRxPackets, pCall);
  311. pCall->Ack.Packet.StartBuffer = pCall->Ack.PacketBuffer;
  312. pCall->Ack.Packet.EndBuffer = pCall->Ack.PacketBuffer + sizeof(pCall->Ack.PacketBuffer);
  313. pCall->Ack.Packet.CurrentBuffer = pCall->Ack.Packet.EndBuffer;
  314. pCall->Ack.Packet.CurrentLength = 0;
  315. INIT_REFERENCE_OBJECT(pCall, CallpFinalDeref);
  316. //
  317. // Instead of calling:
  318. // CallSetState(pCall, STATE_CALL_CLOSED, 0, UNLOCKED);
  319. //
  320. // it is better to set the state manually since the former creates an exception to our locking
  321. // scheme (First lock call, then lock adapter) exposing a potential deadlock in CallFindAndLock():
  322. //
  323. // - CallFindAndLock takes the Call lock then the Adapter lock.
  324. // - CallFindAndLock takes the adapter lock then calls CallAlloc which calls
  325. // setcallstate which takes the Call lock.
  326. //
  327. // Although this is a hypothetical scenario since the deadlock will never occur as the new
  328. // call context is not in the adapter's call array yet, but let's be consistent.
  329. //
  330. pCall->State = STATE_CALL_CLOSED;
  331. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("-CallAlloc %08x\n"), pCall));
  332. return pCall;
  333. }
  334. VOID
  335. CallpCleanup(
  336. IN PPPTP_WORK_ITEM pWorkItem
  337. )
  338. {
  339. PCALL_SESSION pCall = pWorkItem->Context;
  340. BOOLEAN SignalLineDown = FALSE;
  341. BOOLEAN Cancelled;
  342. BOOLEAN FreeNow = FALSE;
  343. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallpCleanup %08x\n"), pCall));
  344. ASSERT(IS_CALL(pCall));
  345. NdisAcquireSpinLock(&pCall->Lock);
  346. // Signal CLEANUP state
  347. if (!(pCall->Close.Checklist&CALL_CLOSE_CLEANUP_STATE))
  348. {
  349. if (pCall->State!=STATE_CALL_CLEANUP)
  350. {
  351. CallSetState(pCall, STATE_CALL_CLEANUP, 0, LOCKED);
  352. }
  353. pCall->Close.Checklist |= CALL_CLOSE_CLEANUP_STATE;
  354. }
  355. if (REFERENCE_COUNT(pCall)>2)
  356. {
  357. DEBUGMSG(DBG_CALL, (DTEXT("CallpCleanup: too many references (%d)\n"), REFERENCE_COUNT(pCall)));
  358. goto ccDone;
  359. }
  360. if (pCall->Close.Expedited)
  361. {
  362. if ((pCall->Close.Checklist&CALL_CLOSE_DROP) &&
  363. !(pCall->Close.Checklist&CALL_CLOSE_DROP_COMPLETE))
  364. {
  365. pCall->Close.Checklist |= CALL_CLOSE_DROP_COMPLETE;
  366. DEBUGMSG(DBG_CALL, (DTEXT("TapiDrop Completed\n")));
  367. NdisReleaseSpinLock(&pCall->Lock);
  368. NdisMSetInformationComplete(pCall->pAdapter->hMiniportAdapter, NDIS_STATUS_SUCCESS);
  369. NdisAcquireSpinLock(&pCall->Lock);
  370. }
  371. if (!(pCall->Close.Checklist&CALL_CLOSE_DISCONNECT))
  372. {
  373. pCall->Close.Checklist |= CALL_CLOSE_DISCONNECT;
  374. if (pCall->pCtl)
  375. {
  376. NdisReleaseSpinLock(&pCall->Lock);
  377. CtlDisconnectCall(pCall);
  378. NdisAcquireSpinLock(&pCall->Lock);
  379. }
  380. }
  381. if (!(pCall->Close.Checklist&CALL_CLOSE_LINE_DOWN) &&
  382. (pCall->Close.Checklist&CALL_CLOSE_DROP_COMPLETE))
  383. {
  384. SignalLineDown = TRUE;
  385. pCall->Close.Checklist |= CALL_CLOSE_LINE_DOWN;
  386. NdisReleaseSpinLock(&pCall->Lock);
  387. TapiLineDown(pCall);
  388. NdisAcquireSpinLock(&pCall->Lock);
  389. }
  390. }
  391. else // !Expedited
  392. {
  393. if (!(pCall->Close.Checklist&CALL_CLOSE_DISCONNECT))
  394. {
  395. pCall->Close.Checklist |= CALL_CLOSE_DISCONNECT;
  396. if (pCall->pCtl)
  397. {
  398. NdisReleaseSpinLock(&pCall->Lock);
  399. CtlDisconnectCall(pCall);
  400. NdisAcquireSpinLock(&pCall->Lock);
  401. }
  402. }
  403. if (!(pCall->Close.Checklist&CALL_CLOSE_DROP))
  404. {
  405. goto ccDone;
  406. }
  407. if (!(pCall->Close.Checklist&CALL_CLOSE_DROP_COMPLETE))
  408. {
  409. pCall->Close.Checklist |= CALL_CLOSE_DROP_COMPLETE;
  410. DEBUGMSG(DBG_CALL, (DTEXT("TapiDrop Completed 2\n")));
  411. NdisReleaseSpinLock(&pCall->Lock);
  412. NdisMSetInformationComplete(pCall->pAdapter->hMiniportAdapter, NDIS_STATUS_SUCCESS);
  413. NdisAcquireSpinLock(&pCall->Lock);
  414. }
  415. if (!(pCall->Close.Checklist&CALL_CLOSE_LINE_DOWN) &&
  416. (pCall->Close.Checklist&CALL_CLOSE_DROP_COMPLETE))
  417. {
  418. DEBUGMSG(DBG_CALL, (DTEXT("Signalling Line Down 2\n")));
  419. pCall->Close.Checklist |= CALL_CLOSE_LINE_DOWN;
  420. NdisReleaseSpinLock(&pCall->Lock);
  421. TapiLineDown(pCall);
  422. NdisAcquireSpinLock(&pCall->Lock);
  423. }
  424. }
  425. if ((pCall->Close.Checklist&CALL_CLOSE_COMPLETE)!=CALL_CLOSE_COMPLETE)
  426. {
  427. goto ccDone;
  428. }
  429. NdisReleaseSpinLock(&pCall->Lock);
  430. NdisMCancelTimer(&pCall->DialTimer, &Cancelled);
  431. NdisMCancelTimer(&pCall->Close.Timer, &Cancelled);
  432. NdisMCancelTimer(&pCall->Ack.Timer, &Cancelled);
  433. NdisAcquireSpinLock(&pCall->Lock);
  434. if (Cancelled)
  435. {
  436. pCall->Ack.PacketQueued = FALSE;
  437. }
  438. pCall->Close.Expedited = FALSE;
  439. NdisZeroMemory(pCall->CallerId, sizeof(pCall->CallerId));
  440. NdisZeroMemory(&pCall->Remote, sizeof(pCall->Remote));
  441. pCall->Packet.SequenceNumber = pCall->Packet.AckNumber = 0;
  442. CallSetState(pCall, STATE_CALL_IDLE, 0, LOCKED);
  443. pCall->PendingUse = FALSE;
  444. DEBUGMSG(DBG_CALL, (DTEXT("Call:%08x Cleanup complete, state==%d\n"),
  445. pCall, pCall->State));
  446. WPLOG(LL_M, LM_CALL, ("Cid %d Cleanup complete", (ULONG)pCall->DeviceId));
  447. #if 0 // Keep these structures and reuse the memory. They will be cleaned up in AdapterFree()
  448. if (REFERENCE_COUNT(pCall)==1)
  449. {
  450. CallDetachFromAdapter(pCall);
  451. DEREFERENCE_OBJECT(pCall); // For the initial reference.
  452. FreeNow = TRUE;
  453. }
  454. #endif
  455. ccDone:
  456. pCall->Close.Scheduled = FALSE;
  457. NdisReleaseSpinLock(&pCall->Lock);
  458. DEBUGMSG(DBG_FUNC, (DTEXT("-CallpCleanup Checklist:%08x\n"), pCall->Close.Checklist));
  459. if (FreeNow)
  460. {
  461. CallFree(pCall);
  462. }
  463. }
  464. VOID
  465. CallCleanup(
  466. PCALL_SESSION pCall,
  467. BOOLEAN Locked
  468. )
  469. {
  470. DEBUGMSG(DBG_FUNC, (DTEXT("+CallCleanup\n")));
  471. DBGTRACE('U');
  472. WPLOG(LL_I, LM_CALL, ("Cid %d", (ULONG)pCall->DeviceId));
  473. if (!Locked)
  474. {
  475. NdisAcquireSpinLock(&pCall->Lock);
  476. }
  477. ASSERT_LOCK_HELD(&pCall->Lock);
  478. if (!(pCall->Close.Scheduled))
  479. {
  480. if(ScheduleWorkItem(CallpCleanup, pCall, NULL, 0)==NDIS_STATUS_SUCCESS)
  481. {
  482. pCall->Close.Scheduled = TRUE;
  483. }
  484. else
  485. {
  486. DBGTRACE('w');
  487. WPLOG(LL_A, LM_CALL, ("Failed to schedule work item pCall %p, Cid %d", pCall, (ULONG)pCall->DeviceId));
  488. gCounters.ulCleanupWorkItemFail++;
  489. }
  490. }
  491. if (!Locked)
  492. {
  493. NdisReleaseSpinLock(&pCall->Lock);
  494. }
  495. DEBUGMSG(DBG_FUNC, (DTEXT("-CallCleanup\n")));
  496. }
  497. // Call lock must be held when calling this.
  498. VOID
  499. CallDetachFromAdapter(PCALL_SESSION pCall)
  500. {
  501. DEBUGMSG(DBG_FUNC, (DTEXT("+CallDetachFromAdapter %08x\n"), pCall));
  502. NdisAcquireSpinLock(&pCall->pAdapter->Lock);
  503. pCall->pAdapter->pCallArray[pCall->DeviceId] = NULL;
  504. NdisReleaseSpinLock(&pCall->pAdapter->Lock);
  505. pCall->Open = FALSE;
  506. DEBUGMSG(DBG_FUNC, (DTEXT("-CallDetachFromAdapter\n")));
  507. }
  508. VOID
  509. CallFree(PCALL_SESSION pCall)
  510. {
  511. BOOLEAN NotUsed;
  512. if (!pCall)
  513. {
  514. return;
  515. }
  516. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallFree %p\n"), pCall));
  517. ASSERT(IS_CALL(pCall));
  518. // This duplicates some of the cleanup code, but attempting to stop
  519. // the driver without first stopping tapi can result in an ungraceful
  520. // shutdown.
  521. NdisMCancelTimer(&pCall->DialTimer, &NotUsed);
  522. NdisMCancelTimer(&pCall->Close.Timer, &NotUsed);
  523. NdisMCancelTimer(&pCall->Ack.Timer, &NotUsed);
  524. ASSERT(pCall->Signature==TAG_PPTP_CALL);
  525. ASSERT(IsListEmpty(&pCall->RxPacketList));
  526. ASSERT(IsListEmpty(&pCall->TxPacketList));
  527. NdisFreeSpinLock(&pCall->Lock);
  528. MyMemFree(pCall, sizeof(CALL_SESSION));
  529. DEBUGMSG(DBG_FUNC, (DTEXT("-CallFree\n")));
  530. }
  531. PCALL_SESSION FASTCALL
  532. CallGetCall(
  533. IN PPPTP_ADAPTER pAdapter,
  534. IN ULONG_PTR ulDeviceId
  535. )
  536. {
  537. PCALL_SESSION pCall = NULL;
  538. DEBUGMSG(DBG_FUNC, (DTEXT("+CallGetCall %d\n"), ulDeviceId));
  539. NdisAcquireSpinLock(&pAdapter->Lock);
  540. if (ulDeviceId >= PptpBaseCallId && ulDeviceId < PptpMaxCallId)
  541. {
  542. if(PptpCallIdMask)
  543. {
  544. if((ulDeviceId & PptpCallIdMask) < PptpWanEndpoints)
  545. {
  546. pCall = pAdapter->pCallArray[ulDeviceId & PptpCallIdMask];
  547. if(pCall && pCall->FullDeviceId != ulDeviceId)
  548. {
  549. pCall = NULL;
  550. }
  551. }
  552. }
  553. else
  554. {
  555. pCall = pAdapter->pCallArray[ulDeviceId - PptpBaseCallId];
  556. }
  557. }
  558. NdisReleaseSpinLock(&pAdapter->Lock);
  559. DEBUGMSG(DBG_FUNC, (DTEXT("-CallGetCall %08x\n"), pCall));
  560. return pCall;
  561. }
  562. PCALL_SESSION
  563. CallFindAndLock(
  564. IN PPPTP_ADAPTER pAdapter,
  565. IN CALL_STATE State,
  566. IN ULONG Flags
  567. )
  568. {
  569. PCALL_SESSION pCall = NULL;
  570. ULONG ulDeviceId;
  571. LONG i, loopcount;
  572. DEBUGMSG(DBG_FUNC, (DTEXT("+CallFindAndLock %d\n"), State));
  573. // Find a call that matches our state or create a call
  574. NdisAcquireSpinLock(&pAdapter->Lock);
  575. if(PptpClientSide)
  576. {
  577. // Skip the random search, just go upward starting from 0
  578. loopcount = 1;
  579. ulDeviceId = -1; // the first index is 0 as ++(-1)
  580. }
  581. else
  582. {
  583. // Try to find a call randomly first if it's a server
  584. loopcount = 0;
  585. i = 0;
  586. do
  587. {
  588. ulDeviceId = CallGetRandomId();
  589. if (!pAdapter->pCallArray[ulDeviceId])
  590. {
  591. if (State==STATE_CALL_IDLE)
  592. {
  593. pCall = CallAlloc(pAdapter);
  594. if (pCall)
  595. {
  596. pAdapter->pCallArray[ulDeviceId] = pCall;
  597. pCall->DeviceId = ulDeviceId;
  598. CallSetFullCallId(pCall);
  599. pCall->State = State;
  600. pCall->PendingUse = TRUE;
  601. break;
  602. }
  603. }
  604. }
  605. else if (pAdapter->pCallArray[ulDeviceId]->State == State &&
  606. !pAdapter->pCallArray[ulDeviceId]->PendingUse)
  607. {
  608. pCall = pAdapter->pCallArray[ulDeviceId];
  609. pCall->PendingUse = TRUE;
  610. CallSetFullCallId(pCall);
  611. if(pCall->hTapiCall)
  612. {
  613. gCounters.ulFindCallWithTapiHandle++;
  614. }
  615. DBGTRACE_INIT(pCall);
  616. break;
  617. }
  618. } while(++i < (LONG) PptpWanEndpoints / 2);
  619. }
  620. // Do sequential search for clint, and server if necessary
  621. // For client, just go upward
  622. // For server, starting with the current random id, go downward then upward
  623. while(!pCall && (loopcount < 2))
  624. {
  625. i = (LONG) ulDeviceId;
  626. while((loopcount == 0) ? (--i>=0) : (++i<(LONG)PptpWanEndpoints))
  627. {
  628. if(!pAdapter->pCallArray[i])
  629. {
  630. if(State==STATE_CALL_IDLE)
  631. {
  632. pCall = CallAlloc(pAdapter);
  633. if (pCall)
  634. {
  635. pAdapter->pCallArray[i] = pCall;
  636. pCall->DeviceId = (ULONG)i;
  637. CallSetFullCallId(pCall);
  638. pCall->State = State;
  639. pCall->PendingUse = TRUE;
  640. break;
  641. }
  642. }
  643. }
  644. else if(pAdapter->pCallArray[i]->State == State &&
  645. !pAdapter->pCallArray[i]->PendingUse)
  646. {
  647. pCall = pAdapter->pCallArray[i];
  648. pCall->PendingUse = TRUE;
  649. CallSetFullCallId(pCall);
  650. if(pCall->hTapiCall)
  651. {
  652. gCounters.ulFindCallWithTapiHandle++;
  653. }
  654. DBGTRACE_INIT(pCall);
  655. break;
  656. }
  657. }
  658. loopcount++;
  659. }
  660. NdisReleaseSpinLock(&pAdapter->Lock);
  661. if (pCall)
  662. {
  663. NdisAcquireSpinLock( &pCall->Lock );
  664. }
  665. DEBUGMSG(DBG_FUNC, (DTEXT("-CallFindAndLock %08x\n"), pCall));
  666. return pCall;
  667. }
  668. NDIS_STATUS
  669. CallEventCallClearRequest(
  670. PCALL_SESSION pCall,
  671. UNALIGNED PPTP_CALL_CLEAR_REQUEST_PACKET *pPacket,
  672. PCONTROL_TUNNEL pCtl
  673. )
  674. {
  675. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  676. PPPTP_CALL_DISCONNECT_NOTIFY_PACKET pReply;
  677. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallEventCallClearRequest\n")));
  678. pReply = CtlAllocPacket(pCall->pCtl, CALL_DISCONNECT_NOTIFY);
  679. // We don't really care if we fail this allocation because PPTP can clean up
  680. // along other avenues, and the cleanup just won't be as pretty.
  681. if (pReply)
  682. {
  683. pReply->CallId = htons(pCall->Packet.CallId);
  684. WPLOG(LL_M, LM_TUNNEL, ("SEND CALL_DISCONNECT_NOTIFY -> %!IPADDR!, pCall %p, Cid %d, Pkt-Cid %d",
  685. pCtl->Remote.Address.Address[0].Address[0].in_addr,
  686. pCall, (ULONG)pCall->DeviceId, pCall->Packet.CallId));
  687. Status = CtlSend(pCtl, pReply);
  688. }
  689. CallCleanup(pCall, UNLOCKED);
  690. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CallEventCallClearRequest %08x\n"), Status));
  691. return Status;
  692. }
  693. NDIS_STATUS
  694. CallEventCallDisconnectNotify(
  695. PCALL_SESSION pCall,
  696. UNALIGNED PPTP_CALL_DISCONNECT_NOTIFY_PACKET *pPacket
  697. )
  698. {
  699. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  700. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallEventCallDisconnectNotify\n")));
  701. if (IS_CALL(pCall))
  702. {
  703. CallCleanup(pCall, UNLOCKED);
  704. }
  705. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CallEventCallDisconnectNotify %08x\n"), Status));
  706. return Status;
  707. }
  708. NDIS_STATUS
  709. CallEventCallInConnect(
  710. IN PCALL_SESSION pCall,
  711. IN UNALIGNED PPTP_CALL_IN_CONNECT_PACKET *pPacket
  712. )
  713. {
  714. DEBUGMSG(DBG_FUNC, (DTEXT("+CallEventCallInConnect\n")));
  715. ASSERT(IS_CALL(pCall));
  716. NdisAcquireSpinLock(&pCall->Lock);
  717. if (pCall->State==STATE_CALL_PAC_WAIT)
  718. {
  719. pCall->Speed = htonl(pPacket->ConnectSpeed);
  720. CallSetState(pCall, STATE_CALL_ESTABLISHED, htonl(pPacket->ConnectSpeed), LOCKED);
  721. }
  722. NdisReleaseSpinLock(&pCall->Lock);
  723. DEBUGMSG(DBG_FUNC, (DTEXT("-CallEventCallInConnect\n")));
  724. return NDIS_STATUS_SUCCESS;
  725. }
  726. NDIS_STATUS
  727. CallEventCallInRequest(
  728. IN PPPTP_ADAPTER pAdapter,
  729. IN PCONTROL_TUNNEL pCtl,
  730. IN UNALIGNED PPTP_CALL_IN_REQUEST_PACKET *pPacket
  731. )
  732. {
  733. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  734. PCALL_SESSION pCall;
  735. DEBUGMSG(DBG_FUNC, (DTEXT("+CallEventCallInRequest\n")));
  736. pCall = CallFindAndLock(pAdapter, STATE_CALL_IDLE, FIND_INCOMING);
  737. if (pCall)
  738. {
  739. NDIS_TAPI_EVENT TapiEvent;
  740. // We have a call in idle state, spinlock acquired
  741. pCall->Inbound = TRUE;
  742. pCall->Remote.CallId = htons(pPacket->CallId);
  743. pCall->Remote.Address = pCtl->Remote.Address;
  744. pCall->Remote.Address.Address[0].Address[0].sin_port = htons(PptpProtocolNumber);
  745. pCall->SerialNumber = htons(pPacket->SerialNumber);
  746. pCall->Close.Checklist &= ~(CALL_CLOSE_DISCONNECT | CALL_CLOSE_CLOSE_CALL);
  747. CallConnectToCtl(pCall, pCtl, TRUE);
  748. NdisReleaseSpinLock(&pCall->Lock);
  749. pPacket->DialingNumber[MAX_PHONE_NUMBER_LENGTH-1] = '\0';
  750. strcpy(pCall->CallerId, pPacket->DialingNumber);
  751. TapiEvent.htLine = pAdapter->Tapi.hTapiLine;
  752. TapiEvent.htCall = 0;
  753. TapiEvent.ulMsg = LINE_NEWCALL;
  754. TapiEvent.ulParam1 = pCall->FullDeviceId;
  755. TapiEvent.ulParam2 = 0;
  756. TapiEvent.ulParam3 = 0;
  757. NdisMIndicateStatus(pCall->pAdapter->hMiniportAdapter,
  758. NDIS_STATUS_TAPI_INDICATION,
  759. &TapiEvent,
  760. sizeof(TapiEvent));
  761. NdisAcquireSpinLock(&pCall->Lock);
  762. if(TapiEvent.ulParam2)
  763. {
  764. pCall->hTapiCall = TapiEvent.ulParam2;
  765. DEBUGMSG(DBG_CALL, (DTEXT("NEWCALL: Addr:%08x pCall %p Cid %d pCtl %p htCall %x\n"),
  766. pCall->Remote.Address.Address[0].Address[0].in_addr,
  767. pCall, pCall->DeviceId, pCtl, TapiEvent.ulParam2));
  768. WPLOG(LL_M, LM_CALL, ("NEWCALL: %!IPADDR! pCall %p Cid %d pCtl %p htCall %Ix",
  769. pCall->Remote.Address.Address[0].Address[0].in_addr,
  770. pCall, (ULONG)pCall->DeviceId, pCtl, TapiEvent.ulParam2));
  771. CallSetState(pCall, STATE_CALL_PAC_OFFERING, 0, LOCKED);
  772. ASSERT(pCall->PendingUse);
  773. pCall->PendingUse = FALSE;
  774. }
  775. else
  776. {
  777. gCounters.ulNewCallNullTapiHandle++;
  778. pCall->Close.Checklist |= CALL_CLOSE_CLOSE_CALL;
  779. WPLOG(LL_A, LM_CALL, ("NEWCALL: %!IPADDR! pCall %p TapiEvent.ulParam2 == 0!",
  780. pCall->Remote.Address.Address[0].Address[0].in_addr, pCall));
  781. CallCleanup(pCall, LOCKED);
  782. }
  783. NdisReleaseSpinLock(&pCall->Lock);
  784. }
  785. else
  786. {
  787. PPTP_CALL_OUT_REPLY_PACKET *pReply = CtlAllocPacket(pCtl, CALL_IN_REPLY);
  788. if (pReply)
  789. {
  790. pReply->PeerCallId = pPacket->CallId;
  791. pReply->ResultCode = RESULT_CALL_IN_ERROR;
  792. pReply->ErrorCode = PPTP_STATUS_INSUFFICIENT_RESOURCES;
  793. WPLOG(LL_M, LM_TUNNEL, ("SEND CALL_OUT_REPLY (INSUFFICIENT_RESOURCES) -> %!IPADDR! pCtl %p",
  794. pCtl->Remote.Address.Address[0].Address[0].in_addr, pCtl));
  795. // No call was available. Send a rejection.
  796. Status = CtlSend(pCtl, pReply);
  797. }
  798. }
  799. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CallEventCallInRequest %08x\n"), Status));
  800. return Status;
  801. }
  802. NDIS_STATUS
  803. CallEventCallOutRequest(
  804. IN PPPTP_ADAPTER pAdapter,
  805. IN PCONTROL_TUNNEL pCtl,
  806. IN UNALIGNED PPTP_CALL_OUT_REQUEST_PACKET *pPacket
  807. )
  808. {
  809. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  810. PCALL_SESSION pCall;
  811. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallEventCallOutRequest\n")));
  812. pCall = CallFindAndLock(pAdapter, STATE_CALL_IDLE, FIND_INCOMING);
  813. if (pCall)
  814. {
  815. NDIS_TAPI_EVENT TapiEvent;
  816. // We have a call in idle state, spinlock acquired
  817. pCall->Inbound = TRUE;
  818. pCall->Remote.CallId = htons(pPacket->CallId);
  819. pCall->Remote.Address = pCtl->Remote.Address;
  820. pCall->Remote.Address.Address[0].Address[0].sin_port = htons(PptpProtocolNumber);
  821. pCall->SerialNumber = htons(pPacket->SerialNumber);
  822. IpAddressToString(htonl(pCtl->Remote.Address.Address[0].Address[0].in_addr), pCall->CallerId);
  823. pCall->Close.Checklist &= ~(CALL_CLOSE_DISCONNECT | CALL_CLOSE_CLOSE_CALL);
  824. CallConnectToCtl(pCall, pCtl, TRUE);
  825. NdisReleaseSpinLock(&pCall->Lock);
  826. TapiEvent.htLine = pAdapter->Tapi.hTapiLine;
  827. TapiEvent.htCall = 0;
  828. TapiEvent.ulMsg = LINE_NEWCALL;
  829. TapiEvent.ulParam1 = pCall->FullDeviceId;
  830. TapiEvent.ulParam2 = 0;
  831. TapiEvent.ulParam3 = 0;
  832. NdisMIndicateStatus(pCall->pAdapter->hMiniportAdapter,
  833. NDIS_STATUS_TAPI_INDICATION,
  834. &TapiEvent,
  835. sizeof(TapiEvent));
  836. NdisAcquireSpinLock(&pCall->Lock);
  837. if(TapiEvent.ulParam2)
  838. {
  839. pCall->hTapiCall = TapiEvent.ulParam2;
  840. DEBUGMSG(DBG_CALL, (DTEXT("NEWCALL: Addr:%08x pCall %p Cid %d pCtl %p htCall %x\n"),
  841. pCall->Remote.Address.Address[0].Address[0].in_addr,
  842. pCall, pCall->DeviceId, pCtl, TapiEvent.ulParam2));
  843. WPLOG(LL_M, LM_CALL, ("NEWCALL: %!IPADDR! pCall %p Cid %d pCtl %p hdCall %d htCall %Ix",
  844. pCall->Remote.Address.Address[0].Address[0].in_addr,
  845. pCall, (ULONG)pCall->DeviceId, pCtl, (ULONG)TapiEvent.ulParam1, TapiEvent.ulParam2));
  846. CallSetState(pCall, STATE_CALL_OFFERING, 0, LOCKED);
  847. ASSERT(pCall->PendingUse);
  848. pCall->PendingUse = FALSE;
  849. }
  850. else
  851. {
  852. gCounters.ulNewCallNullTapiHandle++;
  853. pCall->Close.Checklist |= CALL_CLOSE_CLOSE_CALL;
  854. WPLOG(LL_A, LM_CALL, ("NEWCALL: %!IPADDR! pCall %p TapiEvent.ulParam2 == 0!",
  855. pCall->Remote.Address.Address[0].Address[0].in_addr, pCall));
  856. CallCleanup(pCall, LOCKED);
  857. }
  858. NdisReleaseSpinLock(&pCall->Lock);
  859. }
  860. else
  861. {
  862. PPTP_CALL_OUT_REPLY_PACKET *pReply = CtlAllocPacket(pCtl, CALL_OUT_REPLY);
  863. if (pReply)
  864. {
  865. pReply->PeerCallId = pPacket->CallId;
  866. pReply->ResultCode = RESULT_CALL_OUT_ERROR;
  867. pReply->ErrorCode = PPTP_STATUS_INSUFFICIENT_RESOURCES;
  868. WPLOG(LL_M, LM_TUNNEL, ("SEND CALL_OUT_REPLY (INSUFFICIENT_RESOURCES) -> %!IPADDR! pCtl %p",
  869. pCtl->Remote.Address.Address[0].Address[0].in_addr, pCtl));
  870. // No call was available. Send a rejection.
  871. Status = CtlSend(pCtl, pReply);
  872. }
  873. }
  874. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CallEventCallOutRequest %08x\n"), Status));
  875. return Status;
  876. }
  877. NDIS_STATUS
  878. CallEventCallOutReply(
  879. IN PCALL_SESSION pCall,
  880. IN UNALIGNED PPTP_CALL_OUT_REPLY_PACKET *pPacket
  881. )
  882. {
  883. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  884. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallEventCallOutReply\n")));
  885. ASSERT(IS_CALL(pCall));
  886. NdisAcquireSpinLock(&pCall->Lock);
  887. if (pPacket->ResultCode != RESULT_CALL_OUT_CONNECTED ||
  888. pCall->State != STATE_CALL_PROCEEDING ||
  889. pCall->Packet.CallId != htons(pPacket->PeerCallId))
  890. {
  891. // The call fails for some reason.
  892. Status = NDIS_STATUS_FAILURE;
  893. WPLOG(LL_A, LM_CALL, ("pCall %p Cid %d not CONNECTED. Clean up the call",
  894. pCall, (ULONG)pCall->DeviceId));
  895. CallCleanup(pCall, LOCKED);
  896. }
  897. else
  898. {
  899. pCall->Remote.CallId = htons(pPacket->CallId);
  900. pCall->Speed = pCall->pCtl->Speed;
  901. CallSetState(pCall, STATE_CALL_ESTABLISHED, htonl(pPacket->ConnectSpeed), LOCKED);
  902. WPLOG(LL_M, LM_CALL, ("%!IPADDR! pCall %p Cid %d Peer's Cid %d UP",
  903. pCall->Remote.Address.Address[0].Address[0].in_addr,
  904. pCall, (ULONG)pCall->DeviceId, pCall->Remote.CallId));
  905. }
  906. NdisReleaseSpinLock(&pCall->Lock);
  907. DEBUGMSG(DBG_FUNC, (DTEXT("-CallEventCallOutReply\n")));
  908. return Status;
  909. }
  910. NDIS_STATUS
  911. CallEventDisconnect(
  912. PCALL_SESSION pCall
  913. )
  914. {
  915. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  916. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallEventDisconnect %08x\n"), pCall));
  917. ASSERT(IS_CALL(pCall));
  918. CallCleanup(pCall, UNLOCKED);
  919. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CallEventDisconnect %08x\n"), Status));
  920. return Status;
  921. }
  922. NDIS_STATUS
  923. CallEventConnectFailure(
  924. PCALL_SESSION pCall,
  925. NDIS_STATUS FailureReason
  926. )
  927. {
  928. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  929. ULONG DisconnectMode;
  930. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallEventConnectFailure %08x\n"), FailureReason));
  931. ASSERT(IS_CALL(pCall));
  932. switch (FailureReason)
  933. {
  934. case STATUS_CONNECTION_REFUSED:
  935. case STATUS_IO_TIMEOUT:
  936. DisconnectMode = LINEDISCONNECTMODE_NOANSWER;
  937. break;
  938. case STATUS_BAD_NETWORK_PATH:
  939. case STATUS_NETWORK_UNREACHABLE:
  940. case STATUS_HOST_UNREACHABLE:
  941. DisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  942. break;
  943. case STATUS_CONNECTION_ABORTED:
  944. DisconnectMode = LINEDISCONNECTMODE_REJECT;
  945. break;
  946. case STATUS_REMOTE_NOT_LISTENING:
  947. DisconnectMode = LINEDISCONNECTMODE_BADADDRESS;
  948. break;
  949. default:
  950. DisconnectMode = LINEDISCONNECTMODE_UNKNOWN;
  951. break;
  952. }
  953. CallSetState(pCall, STATE_CALL_CLEANUP, DisconnectMode, UNLOCKED);
  954. CallCleanup(pCall, UNLOCKED);
  955. DEBUGMSG(DBG_FUNC, (DTEXT("-CallEventConnectFailure\n")));
  956. return Status;
  957. }
  958. NDIS_STATUS
  959. CallEventOutboundTunnelEstablished(
  960. IN PCALL_SESSION pCall,
  961. IN NDIS_STATUS EventStatus
  962. )
  963. {
  964. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  965. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallEventOutboundTunnelEstablished %08x\n"), EventStatus));
  966. ASSERT(IS_CALL(pCall));
  967. DEBUGMSG(DBG_CALL, (DTEXT("Tunnel UP Inbound:%d\n"), pCall->Inbound));
  968. WPLOG(LL_M, LM_TUNNEL, ("%!IPADDR! Tunnel UP Inbound:%d",
  969. pCall->Remote.Address.Address[0].Address[0].in_addr, pCall->Inbound));
  970. if (!pCall->Inbound && pCall->State==STATE_CALL_DIALING)
  971. {
  972. PPTP_CALL_OUT_REQUEST_PACKET *pPacket = CtlAllocPacket(pCall->pCtl, CALL_OUT_REQUEST);
  973. if (!pPacket)
  974. {
  975. // Fatal for this call.
  976. Status = NDIS_STATUS_RESOURCES;
  977. DEBUGMSG(DBG_WARN, (DTEXT("CallEventOutboundTunnelEstablished: Failed to alloc CALL_OUT_REQUEST Cid %d\n"), pCall->DeviceId));
  978. WPLOG(LL_A, LM_TAPI, ("Failed to alloc CALL_OUT_REQUEST Cid %d", (ULONG)pCall->DeviceId));
  979. CallCleanup(pCall, UNLOCKED);
  980. }
  981. else
  982. {
  983. BOOLEAN Cancelled;
  984. USHORT NewCallId;
  985. NdisAcquireSpinLock(&pCall->Lock);
  986. CallSetState(pCall, STATE_CALL_PROCEEDING, 0, LOCKED);
  987. NdisMCancelTimer(&pCall->DialTimer, &Cancelled);
  988. CallAssignSerialNumber(pCall);
  989. if(PptpClientSide)
  990. {
  991. NewCallId = (USHORT)((pCall->SerialNumber << CALL_ID_INDEX_BITS) + pCall->DeviceId);
  992. if (pCall->Packet.CallId == NewCallId)
  993. {
  994. // Don't allow a line to have the same CallId twice in a row.
  995. NewCallId += (1<<CALL_ID_INDEX_BITS);
  996. }
  997. }
  998. else
  999. {
  1000. NewCallId = (USHORT)pCall->FullDeviceId;
  1001. }
  1002. pCall->Packet.CallId = NewCallId;
  1003. // Our call ID is a function of the serial number (initially random)
  1004. // and the DeviceId. This is so we can (CallId&0xfff) on incoming packets
  1005. // and instantly have the proper id.
  1006. pPacket->CallId = htons(pCall->Packet.CallId);
  1007. pPacket->SerialNumber = htons(pCall->SerialNumber);
  1008. pPacket->MinimumBPS = htonl(300);
  1009. pPacket->MaximumBPS = htonl(100000000);
  1010. pPacket->BearerType = htonl(BEARER_ANALOG|BEARER_DIGITAL); // Either
  1011. pPacket->FramingType = htonl(FRAMING_ASYNC|FRAMING_SYNC); // Either
  1012. pPacket->RecvWindowSize = htons(PPTP_RECV_WINDOW); // ToDo: make configurable
  1013. pPacket->ProcessingDelay = 0;
  1014. pPacket->PhoneNumberLength = htons((USHORT)strlen(pCall->CallerId));
  1015. strcpy(pPacket->PhoneNumber, pCall->CallerId);
  1016. // ToDo: subaddress
  1017. NdisReleaseSpinLock(&pCall->Lock);
  1018. WPLOG(LL_M, LM_TUNNEL, ("SEND CALL_OUT_REQUEST -> %!IPADDR! Cid %d, Pkt-Cid %d",
  1019. pCall->Remote.Address.Address[0].Address[0].in_addr, (ULONG)pCall->DeviceId, pCall->Packet.CallId));
  1020. Status = CtlSend(pCall->pCtl, pPacket);
  1021. if(Status != NDIS_STATUS_PENDING && Status != NDIS_STATUS_SUCCESS)
  1022. {
  1023. CallCleanup(pCall, UNLOCKED);
  1024. }
  1025. }
  1026. }
  1027. DEBUGMSG(DBG_FUNC, (DTEXT("-CallEventOutboundTunnelEstablished\n")));
  1028. return Status;
  1029. }
  1030. NDIS_STATUS
  1031. CallReceiveDatagramCallback(
  1032. IN PVOID pContext,
  1033. IN PTRANSPORT_ADDRESS pAddress,
  1034. IN PUCHAR pBuffer,
  1035. IN ULONG ulLength
  1036. )
  1037. {
  1038. PPPTP_ADAPTER pAdapter = (PPPTP_ADAPTER)pContext;
  1039. PTA_IP_ADDRESS pIpAddress = (PTA_IP_ADDRESS)pAddress;
  1040. PCALL_SESSION pCall = NULL;
  1041. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1042. PIP4_HEADER pIp = (PIP4_HEADER)pBuffer;
  1043. PGRE_HEADER pGre = (PGRE_HEADER)(pIp + 1);
  1044. PVOID pPayload;
  1045. LONG GreLength, PayloadLength;
  1046. BOOLEAN ReturnBufferNow = TRUE;
  1047. PDGRAM_CONTEXT pDgContext = ALIGN_UP_POINTER(pBuffer+ulLength, ULONG_PTR);
  1048. DEBUGMSG(DBG_FUNC, (DTEXT("+CallReceiveDatagramCallback\n")));
  1049. ASSERT(sizeof(IP4_HEADER)==20);
  1050. DEBUGMEM(DBG_PACKET, pBuffer, ulLength, 1);
  1051. NdisInterlockedIncrement(&gCounters.PacketsReceived);
  1052. // First line of defense against bad packets.
  1053. if (pIp->iph_verlen != IP_VERSION + (sizeof(IP4_HEADER) >> 2) ||
  1054. pIp->iph_protocol!=PptpProtocolNumber ||
  1055. ulLength<sizeof(IP4_HEADER)+sizeof(GRE_HEADER)+sizeof(ULONG) ||
  1056. pIpAddress->TAAddressCount!=1 ||
  1057. pIpAddress->Address[0].AddressLength!=TDI_ADDRESS_LENGTH_IP ||
  1058. pIpAddress->Address[0].AddressType!=TDI_ADDRESS_TYPE_IP)
  1059. {
  1060. DEBUGMSG(DBG_PACKET|DBG_RX, (DTEXT("Rx: IP header invalid\n")));
  1061. Status = NDIS_STATUS_FAILURE;
  1062. goto crdcDone;
  1063. }
  1064. GreLength = sizeof(GRE_HEADER) +
  1065. (pGre->SequenceNumberPresent ? sizeof(ULONG) : 0) +
  1066. (pGre->AckSequenceNumberPresent ? sizeof(ULONG) : 0);
  1067. pPayload = (PUCHAR)pGre + GreLength;
  1068. PayloadLength = (signed)ulLength - sizeof(IP4_HEADER) - GreLength;
  1069. if (ulLength < sizeof(IP4_HEADER) + GreLength ||
  1070. htons(pGre->KeyLength)>PayloadLength ||
  1071. pGre->StrictSourceRoutePresent ||
  1072. pGre->RecursionControl ||
  1073. !pGre->KeyPresent ||
  1074. pGre->RoutingPresent ||
  1075. pGre->ChecksumPresent ||
  1076. pGre->Version!=1 ||
  1077. pGre->Flags ||
  1078. pGre->ProtocolType!=GRE_PROTOCOL_TYPE_NS)
  1079. {
  1080. DEBUGMSG(DBG_PACKET|DBG_RX, (DTEXT("Rx: GRE header invalid\n")));
  1081. DEBUGMEM(DBG_PACKET, pGre, GreLength, 1);
  1082. Status = NDIS_STATUS_FAILURE;
  1083. goto crdcDone;
  1084. }
  1085. else
  1086. {
  1087. // Just in case the datagram is longer than necessary, take only what
  1088. // the GRE header indicates.
  1089. PayloadLength = htons(pGre->KeyLength);
  1090. }
  1091. // Demultiplex the packet
  1092. pCall = CallGetCall(pAdapter, CallIdToDeviceId(htons(pGre->KeyCallId)));
  1093. if (!IS_CALL(pCall))
  1094. {
  1095. Status = NDIS_STATUS_FAILURE;
  1096. goto crdcDone;
  1097. }
  1098. if(!PptpValidateAddress || pIpAddress->Address[0].Address[0].in_addr == pCall->Remote.Address.Address[0].Address[0].in_addr)
  1099. {
  1100. pDgContext->pBuffer = pBuffer;
  1101. pDgContext->pGreHeader = pGre;
  1102. pDgContext->hCtdi = pAdapter->hCtdiDg;
  1103. if (CallQueueReceivePacket(pCall, pDgContext)==NDIS_STATUS_SUCCESS)
  1104. {
  1105. REFERENCE_OBJECT(pCall);
  1106. ReturnBufferNow = FALSE;
  1107. }
  1108. }
  1109. else
  1110. {
  1111. Status = NDIS_STATUS_FAILURE;
  1112. }
  1113. crdcDone:
  1114. if (ReturnBufferNow)
  1115. {
  1116. (void)
  1117. CtdiReceiveComplete(pAdapter->hCtdiDg, pBuffer);
  1118. }
  1119. if (Status!=NDIS_STATUS_SUCCESS)
  1120. {
  1121. NdisInterlockedIncrement(&gCounters.PacketsRejected);
  1122. }
  1123. #if 0
  1124. else
  1125. {
  1126. CallProcessRxPackets(pCall);
  1127. }
  1128. #endif
  1129. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CallReceiveDatagramCallback %08x\n"), Status));
  1130. return Status;
  1131. }
  1132. BOOLEAN
  1133. CallConnectToCtl(
  1134. IN PCALL_SESSION pCall,
  1135. IN PCONTROL_TUNNEL pCtl,
  1136. IN BOOLEAN CallLocked
  1137. )
  1138. {
  1139. BOOLEAN Connected = FALSE;
  1140. DEBUGMSG(DBG_FUNC, (DTEXT("+CallConnectCtl\n")));
  1141. if (!CallLocked)
  1142. {
  1143. NdisAcquireSpinLock(&pCall->Lock);
  1144. }
  1145. ASSERT_LOCK_HELD(&pCall->Lock);
  1146. NdisAcquireSpinLock(&pCall->pAdapter->Lock);
  1147. if (!pCall->pCtl)
  1148. {
  1149. pCall->pCtl = pCtl;
  1150. InsertTailList(&pCtl->CallList, &pCall->ListEntry);
  1151. Connected = TRUE;
  1152. REFERENCE_OBJECT_EX(pCtl, CTL_REF_CALLCONNECT); // Pair in CallDisconnectFromCtl
  1153. }
  1154. NdisReleaseSpinLock(&pCall->pAdapter->Lock);
  1155. if (!CallLocked)
  1156. {
  1157. NdisReleaseSpinLock(&pCall->Lock);
  1158. }
  1159. DEBUGMSG(DBG_FUNC, (DTEXT("-CallConnectCtl %d\n"), Connected));
  1160. return Connected;
  1161. }
  1162. VOID
  1163. CallDisconnectFromCtl(
  1164. IN PCALL_SESSION pCall,
  1165. IN PCONTROL_TUNNEL pCtl
  1166. )
  1167. {
  1168. BOOLEAN Deref = FALSE;
  1169. DEBUGMSG(DBG_FUNC, (DTEXT("+CallDisconnectFromCtl\n")));
  1170. NdisAcquireSpinLock(&pCall->Lock);
  1171. NdisAcquireSpinLock(&pCall->pAdapter->Lock);
  1172. ASSERT(pCall->pCtl==pCtl);
  1173. if (pCall->pCtl==pCtl)
  1174. {
  1175. pCall->pCtl = NULL;
  1176. RemoveEntryList(&pCall->ListEntry);
  1177. Deref = TRUE;
  1178. }
  1179. NdisReleaseSpinLock(&pCall->pAdapter->Lock);
  1180. NdisReleaseSpinLock(&pCall->Lock);
  1181. if (Deref)
  1182. {
  1183. DEREFERENCE_OBJECT_EX(pCtl, CTL_REF_CALLCONNECT);
  1184. }
  1185. DEBUGMSG(DBG_FUNC, (DTEXT("-CallDisconnectFromCtl\n")));
  1186. }
  1187. NDIS_STATUS
  1188. CallSetLinkInfo(
  1189. PPPTP_ADAPTER pAdapter,
  1190. IN PNDIS_WAN_SET_LINK_INFO pRequest
  1191. )
  1192. {
  1193. PCALL_SESSION pCall;
  1194. PCONTROL_TUNNEL pCtl;
  1195. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1196. PPPTP_SET_LINK_INFO_PACKET pPacket;
  1197. DEBUGMSG(DBG_FUNC, (DTEXT("+CallSetLinkInfo\n")));
  1198. // Verify the ID
  1199. pCall = CallGetCall(pAdapter, LinkHandleToId(pRequest->NdisLinkHandle));
  1200. if (!pCall)
  1201. {
  1202. Status = NDIS_STATUS_FAILURE;
  1203. goto csliDone;
  1204. }
  1205. ASSERT(IS_CALL(pCall));
  1206. NdisAcquireSpinLock(&pCall->Lock);
  1207. pCall->WanLinkInfo = *pRequest;
  1208. #if 0
  1209. DBG_X(DBG_NDIS, pCall->WanLinkInfo.MaxSendFrameSize);
  1210. DBG_X(DBG_NDIS, pCall->WanLinkInfo.MaxRecvFrameSize);
  1211. DBG_X(DBG_NDIS, pCall->WanLinkInfo.HeaderPadding);
  1212. DBG_X(DBG_NDIS, pCall->WanLinkInfo.TailPadding);
  1213. DBG_X(DBG_NDIS, pCall->WanLinkInfo.SendACCM);
  1214. DBG_X(DBG_NDIS, pCall->WanLinkInfo.RecvACCM);
  1215. #endif
  1216. pCtl = pCall->pCtl;
  1217. NdisReleaseSpinLock(&pCall->Lock);
  1218. // Report the new ACCMs to the peer.
  1219. pPacket = CtlAllocPacket(pCtl, SET_LINK_INFO);
  1220. if (!pPacket)
  1221. {
  1222. Status = NDIS_STATUS_RESOURCES;
  1223. }
  1224. else
  1225. {
  1226. pPacket->PeerCallId = ntohs(pCall->Remote.CallId);
  1227. pPacket->SendAccm = ntohl(pCall->WanLinkInfo.SendACCM);
  1228. pPacket->RecvAccm = ntohl(pCall->WanLinkInfo.RecvACCM);
  1229. WPLOG(LL_M, LM_TUNNEL, ("SEND SET_LINK_INFO -> %!IPADDR!",
  1230. pCtl->Remote.Address.Address[0].Address[0].in_addr));
  1231. Status = CtlSend(pCtl, pPacket);
  1232. }
  1233. csliDone:
  1234. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CallSetLinkInfo %08x\n"), Status));
  1235. return Status;
  1236. }
  1237. VOID
  1238. CallSetState(
  1239. IN PCALL_SESSION pCall,
  1240. IN CALL_STATE State,
  1241. IN ULONG_PTR StateParam,
  1242. IN BOOLEAN Locked
  1243. )
  1244. {
  1245. ULONG OldLineCallState = CallGetLineCallState(pCall->State);
  1246. ULONG NewLineCallState = CallGetLineCallState(State);
  1247. DEBUGMSG(DBG_FUNC, (DTEXT("+CallSetState %d\n"), State));
  1248. if (State!=pCall->State)
  1249. {
  1250. DBGTRACE(State);
  1251. WPLOG(LL_M, LM_CALL, ("Cid %d State %s --> %s",
  1252. (ULONG)pCall->DeviceId, szCallState(pCall->State), szCallState(State)));
  1253. }
  1254. ASSERT(IS_CALL(pCall));
  1255. if (!Locked)
  1256. {
  1257. NdisAcquireSpinLock(&pCall->Lock);
  1258. }
  1259. ASSERT_LOCK_HELD(&pCall->Lock);
  1260. pCall->State = State;
  1261. if (!Locked)
  1262. {
  1263. NdisReleaseSpinLock(&pCall->Lock);
  1264. }
  1265. if (OldLineCallState!=NewLineCallState &&
  1266. pCall->hTapiCall)
  1267. {
  1268. NDIS_TAPI_EVENT TapiEvent;
  1269. DEBUGMSG(DBG_TAPI|DBG_NDIS, (DTEXT("PPTP: Indicating new LINE_CALLSTATE %x\n"), NewLineCallState));
  1270. TapiEvent.htLine = pCall->pAdapter->Tapi.hTapiLine;
  1271. TapiEvent.htCall = pCall->hTapiCall;
  1272. TapiEvent.ulMsg = LINE_CALLSTATE;
  1273. TapiEvent.ulParam1 = NewLineCallState;
  1274. TapiEvent.ulParam2 = StateParam;
  1275. TapiEvent.ulParam3 = LINEMEDIAMODE_DIGITALDATA; // ToDo: is this required?
  1276. if (Locked)
  1277. {
  1278. NdisReleaseSpinLock(&pCall->Lock);
  1279. }
  1280. NdisMIndicateStatus(pCall->pAdapter->hMiniportAdapter,
  1281. NDIS_STATUS_TAPI_INDICATION,
  1282. &TapiEvent,
  1283. sizeof(TapiEvent));
  1284. if (Locked)
  1285. {
  1286. NdisAcquireSpinLock(&pCall->Lock);
  1287. }
  1288. }
  1289. DEBUGMSG(DBG_FUNC, (DTEXT("-CallSetState\n")));
  1290. }
  1291. GRE_HEADER DefaultGreHeader = {
  1292. 0, // Recursion control
  1293. 0, // Strict source route present
  1294. 0, // Sequence Number present
  1295. 1, // Key present
  1296. 0, // Routing present
  1297. 0, // Checksum present
  1298. 1, // Version
  1299. 0, // Flags
  1300. 0, // Ack present
  1301. GRE_PROTOCOL_TYPE_NS
  1302. };
  1303. VOID
  1304. CallpSendCompleteDeferred(
  1305. IN PPPTP_WORK_ITEM pWorkItem
  1306. )
  1307. {
  1308. PCALL_SESSION pCall = pWorkItem->Context;
  1309. PNDIS_WAN_PACKET pPacket = pWorkItem->pBuffer;
  1310. NDIS_STATUS Result = pWorkItem->Length;
  1311. DEBUGMSG(DBG_FUNC, (DTEXT("+CallpSendCompleteDeferred\n")));
  1312. NdisMWanSendComplete(pCall->pAdapter->hMiniportAdapter,
  1313. pPacket,
  1314. Result);
  1315. DEREFERENCE_OBJECT(pCall);
  1316. NdisInterlockedIncrement(&gCounters.PacketsSentComplete);
  1317. DEBUGMSG(DBG_FUNC, (DTEXT("-CallpSendCompleteDeferred\n")));
  1318. }
  1319. VOID
  1320. CallpSendComplete(
  1321. IN PVOID pContext,
  1322. IN PVOID pDatagramContext,
  1323. IN PUCHAR pBuffer,
  1324. IN NDIS_STATUS Result
  1325. )
  1326. {
  1327. PCALL_SESSION pCall = pContext;
  1328. PNDIS_WAN_PACKET pPacket = pDatagramContext;
  1329. DEBUGMSG(DBG_FUNC|DBG_TX, (DTEXT("+CallpSendComplete pCall=%x, pPacket=%x, Result=%x\n"), pCall, pPacket, Result));
  1330. ASSERT(IS_CALL(pCall));
  1331. if (Result!=NDIS_STATUS_SUCCESS)
  1332. {
  1333. DEBUGMSG(DBG_ERROR, (DTEXT("Failed to send datagram %08x\n"), Result));
  1334. WPLOG(LL_A, LM_CALL, ("Failed to send datagram %08x", Result));
  1335. NdisInterlockedIncrement(&gCounters.PacketsSentError);
  1336. }
  1337. if (pPacket==&pCall->Ack.Packet)
  1338. {
  1339. NdisAcquireSpinLock(&pCall->Lock);
  1340. pCall->Ack.PacketQueued = FALSE;
  1341. NdisReleaseSpinLock(&pCall->Lock);
  1342. NdisInterlockedIncrement(&gCounters.PacketsSentComplete);
  1343. }
  1344. else
  1345. {
  1346. // When we complet packets immediately, we can get into trouble if a
  1347. // packet has recursed. We need a way to short-circuit a recursing
  1348. // completion so we don't blow the stack.
  1349. // We store a count of times we've completed a packet in the same
  1350. // context and defer to a thread after a certain number of trips through.
  1351. if ((NdisInterlockedIncrement(&pCall->SendCompleteRecursion)<PptpSendRecursionLimit) ||
  1352. ScheduleWorkItem(CallpSendCompleteDeferred, pCall, pPacket, Result)!=NDIS_STATUS_SUCCESS)
  1353. {
  1354. NdisMWanSendComplete(pCall->pAdapter->hMiniportAdapter,
  1355. pPacket,
  1356. Result);
  1357. DEREFERENCE_OBJECT(pCall);
  1358. NdisInterlockedIncrement(&gCounters.PacketsSentComplete);
  1359. }
  1360. NdisInterlockedDecrement(&pCall->SendCompleteRecursion);
  1361. }
  1362. DEBUGMSG(DBG_FUNC, (DTEXT("-CallpSendComplete\n")));
  1363. }
  1364. #define TRANSMIT_SEND_SEQ 1
  1365. #define TRANSMIT_SEND_ACK 2
  1366. #define TRANSMIT_MASK 0x3
  1367. ULONG GreSize[4] = {
  1368. sizeof(GRE_HEADER),
  1369. sizeof(GRE_HEADER) + sizeof(ULONG),
  1370. sizeof(GRE_HEADER) + sizeof(ULONG),
  1371. sizeof(GRE_HEADER) + sizeof(ULONG) * 2
  1372. };
  1373. NDIS_STATUS
  1374. CallTransmitPacket(
  1375. PCALL_SESSION pCall,
  1376. PNDIS_WAN_PACKET pPacket,
  1377. ULONG Flags,
  1378. ULONG SequenceNumber,
  1379. ULONG Ack
  1380. )
  1381. {
  1382. NDIS_STATUS Status = NDIS_STATUS_FAILURE;
  1383. ULONG Length;
  1384. PULONG pSequence, pAck;
  1385. PGRE_HEADER pGreHeader;
  1386. PIP4_HEADER pIp;
  1387. DEBUGMSG(DBG_FUNC, (DTEXT("+CallTransmitPacket\n")));
  1388. if (!IS_CALL(pCall) || pCall->State!=STATE_CALL_ESTABLISHED)
  1389. {
  1390. goto ctpDone;
  1391. }
  1392. Length = GreSize[Flags&TRANSMIT_MASK];
  1393. pGreHeader = (PGRE_HEADER) (pPacket->CurrentBuffer - Length);
  1394. pSequence = pAck = (PULONG)(pGreHeader + 1);
  1395. *pGreHeader = DefaultGreHeader;
  1396. if (Flags&TRANSMIT_SEND_SEQ)
  1397. {
  1398. pGreHeader->SequenceNumberPresent = 1;
  1399. *pSequence = htonl(SequenceNumber);
  1400. pAck++;
  1401. }
  1402. pGreHeader->KeyLength = htons((USHORT)pPacket->CurrentLength);
  1403. pGreHeader->KeyCallId = htons(pCall->Remote.CallId);
  1404. if (Flags&TRANSMIT_SEND_ACK)
  1405. {
  1406. pGreHeader->AckSequenceNumberPresent = 1;
  1407. *pAck = htonl(Ack);
  1408. }
  1409. pIp = (IP4_HEADER *) ((PUCHAR)pGreHeader - sizeof(IP4_HEADER));
  1410. Length += sizeof(IP4_HEADER);
  1411. pIp->iph_verlen = IP_VERSION + (sizeof(IP4_HEADER) >> 2);
  1412. pIp->iph_tos=0;
  1413. pIp->iph_length=htons((USHORT)(pPacket->CurrentLength + Length));
  1414. pIp->iph_id=0; // filled by TCPIP
  1415. pIp->iph_offset=0;
  1416. pIp->iph_ttl=128;
  1417. pIp->iph_protocol=47;
  1418. pIp->iph_xsum = 0; // filled by TCPIP
  1419. pIp->iph_src = pCall->pCtl->LocalAddress;
  1420. pIp->iph_dest = pCall->Remote.Address.Address[0].Address[0].in_addr;
  1421. NdisInterlockedIncrement(&gCounters.PacketsSent);
  1422. Status = CtdiSendDatagram(pCall->pAdapter->hCtdiDg,
  1423. CallpSendComplete,
  1424. pCall,
  1425. pPacket,
  1426. (PTRANSPORT_ADDRESS)&pCall->Remote.Address,
  1427. (PVOID)pIp,
  1428. pPacket->CurrentLength + Length);
  1429. ctpDone:
  1430. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CallTransmitPacket %08x\n"), Status));
  1431. return Status;
  1432. }
  1433. VOID
  1434. CallProcessRxPackets(
  1435. PNDIS_WORK_ITEM pNdisWorkItem,
  1436. PCALL_SESSION pCall
  1437. )
  1438. {
  1439. #if 0
  1440. VOID
  1441. CallProcessRxPackets(
  1442. IN PVOID SystemSpecific1,
  1443. IN PVOID Context,
  1444. IN PVOID SystemSpecific2,
  1445. IN PVOID SystemSpecific3
  1446. )
  1447. {
  1448. PCALL_SESSION pCall = Context;
  1449. #endif
  1450. ULONG_PTR ReceiveMax = 50;
  1451. NDIS_STATUS Status;
  1452. DEBUGMSG(DBG_FUNC, (DTEXT("+CallProcessRxPackets\n")));
  1453. ASSERT(IS_CALL(pCall));
  1454. //++ProcCountRx[KeGetCurrentProcessorNumber()];
  1455. NdisAcquireSpinLock(&pCall->Lock);
  1456. // First send up any received packets.
  1457. while (ReceiveMax-- && !IsListEmpty(&pCall->RxPacketList))
  1458. {
  1459. PDGRAM_CONTEXT pDgram;
  1460. PLIST_ENTRY pListEntry = RemoveHeadList(&pCall->RxPacketList);
  1461. pCall->RxPacketsPending--;
  1462. pDgram = CONTAINING_RECORD(pListEntry,
  1463. DGRAM_CONTEXT,
  1464. ListEntry);
  1465. if (pCall->State==STATE_CALL_ESTABLISHED &&
  1466. htons(pDgram->pGreHeader->KeyCallId)==pCall->Packet.CallId &&
  1467. IS_LINE_UP(pCall))
  1468. {
  1469. LONG GreLength, PayloadLength;
  1470. PVOID pPayload;
  1471. BOOLEAN SetAckTimer = FALSE;
  1472. ULONG Sequence;
  1473. NdisReleaseSpinLock(&pCall->Lock);
  1474. if (pDgram->pGreHeader->SequenceNumberPresent)
  1475. {
  1476. // Call is still in good state, indicate the packet.
  1477. Sequence = htonl(GreSequence(pDgram->pGreHeader));
  1478. pCall->Remote.SequenceNumber = Sequence + 1;
  1479. NdisAcquireSpinLock(&pCall->Lock);
  1480. if (IsListEmpty(&pCall->TxPacketList) && !pCall->Ack.PacketQueued && pDgram->pGreHeader->KeyLength)
  1481. {
  1482. // We only ack if there aren't already other transmits sent, and this
  1483. // isn't an ack-only packet.
  1484. SetAckTimer = pCall->Ack.PacketQueued = TRUE;
  1485. }
  1486. NdisReleaseSpinLock(&pCall->Lock);
  1487. }
  1488. if (!PptpEchoAlways)
  1489. {
  1490. pCall->pCtl->Echo.Needed = FALSE;
  1491. }
  1492. if (SetAckTimer)
  1493. {
  1494. NdisMSetTimer(&pCall->Ack.Timer, 100);
  1495. }
  1496. GreLength = sizeof(GRE_HEADER) +
  1497. (pDgram->pGreHeader->SequenceNumberPresent ? sizeof(ULONG) : 0) +
  1498. (pDgram->pGreHeader->AckSequenceNumberPresent ? sizeof(ULONG) : 0);
  1499. pPayload = (PUCHAR)pDgram->pGreHeader + GreLength;
  1500. PayloadLength = htons(pDgram->pGreHeader->KeyLength);
  1501. if (PayloadLength && pDgram->pGreHeader->SequenceNumberPresent)
  1502. {
  1503. NdisMWanIndicateReceive(&Status,
  1504. pCall->pAdapter->hMiniportAdapter,
  1505. pCall->NdisLinkContext,
  1506. pPayload,
  1507. PayloadLength);
  1508. if (Status==NDIS_STATUS_SUCCESS)
  1509. {
  1510. NdisMWanIndicateReceiveComplete(pCall->pAdapter->hMiniportAdapter,
  1511. pCall->NdisLinkContext);
  1512. }
  1513. }
  1514. }
  1515. else if (pCall->State!=STATE_CALL_ESTABLISHED || !IS_LINE_UP(pCall))
  1516. {
  1517. NdisReleaseSpinLock(&pCall->Lock);
  1518. // If this call is being torn down, we want to put priority on
  1519. // clearing out any packets left over. It should go fast since
  1520. // we're not indicating them up.
  1521. ReceiveMax = 100;
  1522. }
  1523. DEREFERENCE_OBJECT(pCall);
  1524. (void)CtdiReceiveComplete(pDgram->hCtdi, pDgram->pBuffer);
  1525. NdisAcquireSpinLock(&pCall->Lock);
  1526. }
  1527. if (IsListEmpty(&pCall->RxPacketList))
  1528. {
  1529. pCall->Receiving = FALSE;
  1530. NdisReleaseSpinLock(&pCall->Lock);
  1531. DEREFERENCE_OBJECT(pCall); // work item
  1532. }
  1533. else
  1534. {
  1535. NdisScheduleWorkItem(&pCall->RecvWorkItem);
  1536. // PptpQueueDpc(&pCall->ReceiveDpc);
  1537. NdisReleaseSpinLock(&pCall->Lock);
  1538. }
  1539. DEBUGMSG(DBG_FUNC, (DTEXT("-CallProcessRxPackets\n")));
  1540. }
  1541. VOID
  1542. CallProcessPackets(
  1543. PNDIS_WORK_ITEM pNdisWorkItem,
  1544. PCALL_SESSION pCall
  1545. )
  1546. {
  1547. BOOLEAN MorePacketsToTransfer = FALSE;
  1548. ULONG TransmitFlags = 0;
  1549. NDIS_STATUS Status;
  1550. ULONG Ack = 0, Seq = 0;
  1551. ULONG TransferMax = 50;
  1552. PLIST_ENTRY pListEntry;
  1553. PNDIS_WAN_PACKET pPacket;
  1554. DEBUGMSG(DBG_FUNC, (DTEXT("+CallProcessPackets\n")));
  1555. ASSERT(sizeof(GRE_HEADER)==8);
  1556. ASSERT(IS_CALL(pCall));
  1557. //++ProcCountTx[KeGetCurrentProcessorNumber()];
  1558. NdisAcquireSpinLock(&pCall->Lock);
  1559. while (TransferMax-- && !IsListEmpty(&pCall->TxPacketList))
  1560. {
  1561. pListEntry = RemoveHeadList(&pCall->TxPacketList);
  1562. pPacket = CONTAINING_RECORD(pListEntry,
  1563. NDIS_WAN_PACKET,
  1564. WanPacketQueue);
  1565. if(pCall->Packet.AckNumber != pCall->Remote.SequenceNumber)
  1566. {
  1567. TransmitFlags |= TRANSMIT_SEND_ACK;
  1568. pCall->Packet.AckNumber = pCall->Remote.SequenceNumber;
  1569. // Ack tracks the Remote.SequenceNumber, which is actually the
  1570. // sequence of the NEXT packet, so we need to translate when
  1571. // we prepare to send an ack.
  1572. Ack = pCall->Remote.SequenceNumber - 1;
  1573. }
  1574. NdisReleaseSpinLock(&pCall->Lock);
  1575. if (pPacket!=&pCall->Ack.Packet || TransmitFlags&TRANSMIT_SEND_ACK)
  1576. {
  1577. if (pPacket != &pCall->Ack.Packet)
  1578. {
  1579. TransmitFlags |= TRANSMIT_SEND_SEQ;
  1580. Seq = pCall->Packet.SequenceNumber++;
  1581. }
  1582. Status = CallTransmitPacket(pCall, pPacket, TransmitFlags, Seq, Ack);
  1583. if (Status!=NDIS_STATUS_PENDING)
  1584. {
  1585. if (pPacket == &pCall->Ack.Packet)
  1586. {
  1587. NdisAcquireSpinLock(&pCall->Lock);
  1588. pCall->Ack.PacketQueued = FALSE;
  1589. NdisReleaseSpinLock(&pCall->Lock);
  1590. }
  1591. else
  1592. {
  1593. // We didn't send the packet, so tell NDIS we're done with it.
  1594. NdisMWanSendComplete(pCall->pAdapter->hMiniportAdapter,
  1595. pPacket,
  1596. NDIS_STATUS_SUCCESS); // so I lied. Sue me.
  1597. DEREFERENCE_OBJECT(pCall);
  1598. }
  1599. }
  1600. }
  1601. else
  1602. {
  1603. // it was the ack-only packet, and we already sent an ack.
  1604. NdisAcquireSpinLock(&pCall->Lock);
  1605. pCall->Ack.PacketQueued = FALSE;
  1606. NdisReleaseSpinLock(&pCall->Lock);
  1607. }
  1608. TransmitFlags = 0;
  1609. NdisAcquireSpinLock(&pCall->Lock);
  1610. }
  1611. if(IsListEmpty(&pCall->TxPacketList))
  1612. {
  1613. pCall->Transferring = FALSE;
  1614. NdisReleaseSpinLock(&pCall->Lock);
  1615. DEREFERENCE_OBJECT(pCall); // work item
  1616. }
  1617. else
  1618. {
  1619. NdisScheduleWorkItem(&pCall->SendWorkItem);
  1620. NdisReleaseSpinLock(&pCall->Lock);
  1621. }
  1622. DEBUGMSG(DBG_FUNC, (DTEXT("-CallProcessPackets %d\n"), MorePacketsToTransfer));
  1623. return;
  1624. }
  1625. VOID
  1626. CallpAckTimeout(
  1627. IN PVOID SystemSpecific1,
  1628. IN PVOID Context,
  1629. IN PVOID SystemSpecific2,
  1630. IN PVOID SystemSpecific3
  1631. )
  1632. {
  1633. PCALL_SESSION pCall = Context;
  1634. DEBUGMSG(DBG_FUNC, (DTEXT("+CallpAckTimeout\n")));
  1635. if (IS_CALL(pCall))
  1636. {
  1637. if (pCall->State!=STATE_CALL_ESTABLISHED ||
  1638. CallQueueTransmitPacket(pCall, &pCall->Ack.Packet)!=NDIS_STATUS_PENDING)
  1639. {
  1640. NdisAcquireSpinLock(&pCall->Lock);
  1641. pCall->Ack.PacketQueued = FALSE;
  1642. NdisReleaseSpinLock(&pCall->Lock);
  1643. }
  1644. }
  1645. DEBUGMSG(DBG_FUNC, (DTEXT("-CallpAckTimeout\n")));
  1646. }
  1647. VOID
  1648. CallpDialTimeout(
  1649. IN PVOID SystemSpecific1,
  1650. IN PVOID Context,
  1651. IN PVOID SystemSpecific2,
  1652. IN PVOID SystemSpecific3
  1653. )
  1654. {
  1655. PCALL_SESSION pCall = Context;
  1656. DEBUGMSG(DBG_FUNC, (DTEXT("+CallpDialTimeout\n")));
  1657. WPLOG(LL_M, LM_CALL, ("pCall %p Cid %d timed out in dialing state",
  1658. pCall, (ULONG)pCall->DeviceId));
  1659. ASSERT(IS_CALL(pCall));
  1660. if (pCall->State==STATE_CALL_DIALING)
  1661. {
  1662. CallCleanup(pCall, UNLOCKED);
  1663. }
  1664. DEBUGMSG(DBG_FUNC, (DTEXT("-CallpDialTimeout\n")));
  1665. }
  1666. VOID
  1667. CallpCloseTimeout(
  1668. IN PVOID SystemSpecific1,
  1669. IN PVOID Context,
  1670. IN PVOID SystemSpecific2,
  1671. IN PVOID SystemSpecific3
  1672. )
  1673. {
  1674. PCALL_SESSION pCall = Context;
  1675. DEBUGMSG(DBG_FUNC, (DTEXT("+CallpCloseTimeout\n")));
  1676. ASSERT(IS_CALL(pCall));
  1677. pCall->Close.Expedited = TRUE;
  1678. CallCleanup(pCall, UNLOCKED);
  1679. // ToDo: check for failure.
  1680. DEBUGMSG(DBG_FUNC, (DTEXT("-CallpCloseTimeout\n")));
  1681. }
  1682. VOID CallpFinalDeref(PCALL_SESSION pCall)
  1683. {
  1684. DEBUGMSG(DBG_FUNC|DBG_CALL, (DTEXT("+CallpFinalDeref\n")));
  1685. }
  1686. VOID CallpCleanupLooseEnds(PPPTP_ADAPTER pAdapter)
  1687. {
  1688. ULONG i;
  1689. DEBUGMSG(DBG_FUNC, (DTEXT("+CallpCleanupLooseEnds\n")));
  1690. for (i=0; i<pAdapter->Info.Endpoints; i++)
  1691. {
  1692. PCALL_SESSION pCall = pAdapter->pCallArray[i];
  1693. if (IS_CALL(pCall))
  1694. {
  1695. NdisAcquireSpinLock(&pCall->Lock);
  1696. if (pCall->State==STATE_CALL_CLEANUP)
  1697. {
  1698. CallCleanup(pCall, LOCKED);
  1699. }
  1700. NdisReleaseSpinLock(&pCall->Lock);
  1701. }
  1702. }
  1703. DEBUGMSG(DBG_FUNC, (DTEXT("-CallpCleanupLooseEnds\n")));
  1704. }