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.

2131 lines
72 KiB

  1. /*****************************************************************************
  2. *
  3. * Copyright (c) 1998-1999 Microsoft Corporation
  4. *
  5. * CONTROL.C - PPTP Control Layer functionality
  6. *
  7. * Author: Stan Adermann (stana)
  8. *
  9. * Created: 7/28/1998
  10. *
  11. *****************************************************************************/
  12. #include "raspptp.h"
  13. typedef struct {
  14. LIST_ENTRY ListEntry;
  15. ULONG Length;
  16. } MESSAGE_HEADER, *PMESSAGE_HEADER;
  17. USHORT PptpControlPort = PPTP_TCP_PORT;
  18. USHORT PptpProtocolNumber = PPTP_IP_GRE_PROTOCOL;
  19. USHORT PptpUdpPort = PPTP_IP_GRE_PROTOCOL;
  20. ULONG PptpWanEndpoints = OS_DEFAULT_WAN_ENDPOINTS;
  21. ULONG PptpTunnelConfig = 0;
  22. ULONG PptpListensPending = OS_LISTENS_PENDING;
  23. BOOLEAN PptpEchoAlways = TRUE;
  24. ULONG PptpEchoTimeout = PPTP_ECHO_TIMEOUT_DEFAULT;
  25. ULONG PptpMessageTimeout = PPTP_MESSAGE_TIMEOUT_DEFAULT;
  26. ULONG PptpMaxTransmit = PPTP_MAX_TRANSMIT;
  27. BOOLEAN PptpAuthenticateIncomingCalls = FALSE;
  28. PCLIENT_ADDRESS ClientList = NULL;
  29. ULONG NumClientAddresses = 0;
  30. BOOLEAN PptpInitialized = FALSE;
  31. LONG PptpSendRecursionLimit = PPTP_SEND_RECURSION_LIMIT_DEFAULT;
  32. ULONG PptpValidateAddress = TRUE;
  33. static ULONG PptpMessageLength_v1[NUM_MESSAGE_TYPES] =
  34. {
  35. 0, // invalid
  36. sizeof(PPTP_CONTROL_START_PACKET), // Request
  37. sizeof(PPTP_CONTROL_START_PACKET), // Reply
  38. sizeof(PPTP_CONTROL_STOP_PACKET), // Request
  39. sizeof(PPTP_CONTROL_STOP_PACKET), // Reply
  40. sizeof(PPTP_CONTROL_ECHO_REQUEST_PACKET),
  41. sizeof(PPTP_CONTROL_ECHO_REPLY_PACKET),
  42. sizeof(PPTP_CALL_OUT_REQUEST_PACKET),
  43. sizeof(PPTP_CALL_OUT_REPLY_PACKET),
  44. sizeof(PPTP_CALL_IN_REQUEST_PACKET),
  45. sizeof(PPTP_CALL_IN_REPLY_PACKET),
  46. sizeof(PPTP_CALL_IN_CONNECT_PACKET),
  47. sizeof(PPTP_CALL_CLEAR_REQUEST_PACKET),
  48. sizeof(PPTP_CALL_DISCONNECT_NOTIFY_PACKET),
  49. sizeof(PPTP_WAN_ERROR_NOTIFY_PACKET),
  50. sizeof(PPTP_SET_LINK_INFO_PACKET)
  51. };
  52. VOID
  53. CtlCleanup(
  54. PCONTROL_TUNNEL pCtl,
  55. BOOLEAN Locked
  56. );
  57. VOID
  58. CtlpEchoTimeout(
  59. IN PVOID SystemSpecific1,
  60. IN PVOID pContext,
  61. IN PVOID SystemSpecific2,
  62. IN PVOID SystemSpecific3
  63. );
  64. VOID
  65. CtlpDeathTimeout(
  66. IN PVOID SystemSpecific1,
  67. IN PVOID pContext,
  68. IN PVOID SystemSpecific2,
  69. IN PVOID SystemSpecific3
  70. );
  71. CONTROL_STATE
  72. CtlSetState(
  73. IN PCONTROL_TUNNEL pCtl,
  74. IN CONTROL_STATE State,
  75. IN ULONG_PTR StateParam,
  76. IN BOOLEAN Locked
  77. );
  78. CHAR *
  79. ControlMsgToString(
  80. ULONG Message
  81. );
  82. PCONTROL_TUNNEL
  83. CtlAlloc(
  84. PPPTP_ADAPTER pAdapter
  85. )
  86. {
  87. PCONTROL_TUNNEL pCtl;
  88. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlAlloc\n")));
  89. pCtl = MyMemAlloc(sizeof(CONTROL_TUNNEL), TAG_PPTP_TUNNEL);
  90. if (pCtl)
  91. {
  92. NdisZeroMemory(pCtl, sizeof(CONTROL_TUNNEL));
  93. pCtl->Signature = TAG_PPTP_TUNNEL;
  94. pCtl->pAdapter = pAdapter;
  95. pCtl->PptpMessageLength = PptpMessageLength_v1;
  96. NdisAllocateSpinLock(&pCtl->Lock);
  97. NdisInitializeListHead(&pCtl->CallList);
  98. NdisInitializeListHead(&pCtl->MessageList);
  99. NdisMInitializeTimer(&pCtl->Echo.Timer,
  100. pAdapter->hMiniportAdapter,
  101. CtlpEchoTimeout,
  102. pCtl);
  103. NdisMInitializeTimer(&pCtl->WaitTimeout,
  104. pAdapter->hMiniportAdapter,
  105. CtlpDeathTimeout,
  106. pCtl);
  107. NdisMInitializeTimer(&pCtl->StopTimeout,
  108. pAdapter->hMiniportAdapter,
  109. CtlpDeathTimeout,
  110. pCtl);
  111. INIT_REFERENCE_OBJECT(pCtl, CtlFree);
  112. MyInterlockedInsertTailList(&pAdapter->ControlTunnelList,
  113. &pCtl->ListEntry,
  114. &pAdapter->Lock);
  115. // If doing file logging open the log session here
  116. OsFileLogOpen();
  117. }
  118. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlAlloc %08x\n"), pCtl));
  119. return pCtl;
  120. }
  121. VOID
  122. CtlFree(PCONTROL_TUNNEL pCtl)
  123. {
  124. BOOLEAN NotUsed;
  125. if (!IS_CTL(pCtl))
  126. {
  127. return;
  128. }
  129. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlFree %08x\n"), pCtl));
  130. pCtl->Signature = 0;
  131. ASSERT(IsListEmpty(&pCtl->CallList));
  132. ASSERT(IsListEmpty(&pCtl->MessageList));
  133. NdisAcquireSpinLock(&pCtl->pAdapter->Lock);
  134. RemoveEntryList(&pCtl->ListEntry);
  135. NdisReleaseSpinLock(&pCtl->pAdapter->Lock);
  136. // This duplicates some of the cleanup code, but attempting to stop
  137. // the driver without first stopping tapi can result in an ungraceful
  138. // shutdown.
  139. NdisMCancelTimer(&pCtl->Echo.Timer, &NotUsed);
  140. NdisMCancelTimer(&pCtl->WaitTimeout, &NotUsed);
  141. NdisMCancelTimer(&pCtl->StopTimeout, &NotUsed);
  142. if (pCtl->hCtdi)
  143. {
  144. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"TCP disconnecting\n"),
  145. LOGHDR(21, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  146. CtdiDisconnect(pCtl->hCtdi, FALSE);
  147. CtdiClose(pCtl->hCtdi);
  148. pCtl->hCtdi = NULL;
  149. }
  150. if (pCtl->hCtdiEndpoint)
  151. {
  152. CtdiClose(pCtl->hCtdiEndpoint);
  153. pCtl->hCtdiEndpoint = NULL;
  154. }
  155. NdisFreeSpinLock(&pCtl->Lock);
  156. MyMemFree(pCtl, sizeof(CONTROL_TUNNEL));
  157. OsFileLogClose(); // Close the logging session opened with the creation of the Ctl channel
  158. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlFree\n")));
  159. }
  160. PVOID
  161. CtlpAllocPacketLocked(
  162. PCONTROL_TUNNEL pCtl,
  163. PPTP_MESSAGE_TYPE Message
  164. )
  165. {
  166. PMESSAGE_HEADER pMsg;
  167. ULONG PacketLength;
  168. DEBUGMSG(DBG_TUNNEL, (DTEXT("+CtlpAllocPacketLocked %d\n"), Message));
  169. ASSERT(IS_CTL(pCtl));
  170. ASSERT(Message>=CONTROL_START_REQUEST && Message<NUM_MESSAGE_TYPES);
  171. if (pCtl->State!=STATE_CTL_CLEANUP)
  172. {
  173. PacketLength = pCtl->PptpMessageLength[Message];
  174. pMsg = MyMemAlloc(sizeof(MESSAGE_HEADER)+PacketLength, TAG_CTL_PACKET);
  175. if (!pMsg)
  176. {
  177. DEBUGMSG(DBG_ERROR, (DTEXT("Failed to alloc control packet\n")));
  178. }
  179. else
  180. {
  181. PPTP_HEADER *pHeader = (PVOID)&pMsg[1];
  182. NdisZeroMemory(pMsg, sizeof(MESSAGE_HEADER)+PacketLength);
  183. pMsg->Length = sizeof(MESSAGE_HEADER)+PacketLength;
  184. pHeader->Length = htons((USHORT)PacketLength);
  185. pHeader->PacketType = htons(PPTP_CONTROL_MESSAGE);
  186. pHeader->Cookie = htonl(PPTP_MAGIC_COOKIE);
  187. pHeader->MessageType = htons(Message);
  188. InsertTailList(&pCtl->MessageList, &pMsg->ListEntry);
  189. REFERENCE_OBJECT(pCtl); // pair in CtlFreePacket
  190. }
  191. }
  192. else
  193. {
  194. pMsg = NULL;
  195. }
  196. DEBUGMSG(DBG_TUNNEL, (DTEXT("-CtlpAllocPacketLocked %08x\n"), (pMsg ? &pMsg[1] : NULL)));
  197. return (pMsg ? &pMsg[1] : NULL);
  198. }
  199. PVOID
  200. CtlAllocPacket(
  201. PCONTROL_TUNNEL pCtl,
  202. PPTP_MESSAGE_TYPE Message
  203. )
  204. {
  205. PVOID pPacket = NULL;
  206. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlAllocPacket\n")));
  207. if (IS_CTL(pCtl))
  208. {
  209. NdisAcquireSpinLock(&pCtl->Lock);
  210. pPacket = CtlpAllocPacketLocked(pCtl, Message);
  211. NdisReleaseSpinLock(&pCtl->Lock);
  212. }
  213. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlAllocPacket\n")));
  214. return pPacket;
  215. }
  216. VOID
  217. CtlFreePacket(
  218. PCONTROL_TUNNEL pCtl,
  219. PVOID pPacket
  220. )
  221. {
  222. PMESSAGE_HEADER pMsg = ((PMESSAGE_HEADER)pPacket) - 1;
  223. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlFreePacket %08x\n"), pPacket));
  224. ASSERT(IS_CTL(pCtl));
  225. NdisAcquireSpinLock(&pCtl->Lock);
  226. RemoveEntryList(&pMsg->ListEntry);
  227. if (pCtl->State==STATE_CTL_CLEANUP && IsListEmpty(&pCtl->MessageList))
  228. {
  229. CtlCleanup(pCtl, LOCKED);
  230. }
  231. NdisReleaseSpinLock(&pCtl->Lock);
  232. MyMemFree(pMsg, pMsg->Length);
  233. DEREFERENCE_OBJECT(pCtl); // pair in CtlpAllocPacket
  234. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlFreePacket\n")));
  235. }
  236. STATIC VOID
  237. CtlpCleanup(
  238. IN PPPTP_WORK_ITEM pWorkItem
  239. )
  240. {
  241. PCONTROL_TUNNEL pCtl = pWorkItem->Context;
  242. BOOLEAN CleanupComplete = FALSE;
  243. BOOLEAN TimeoutStopped;
  244. DEBUGMSG(DBG_FUNC|DBG_TUNNEL, (DTEXT("+CtlpCleanup %08x\n"), pCtl));
  245. ASSERT(IS_CTL(pCtl));
  246. NdisAcquireSpinLock(&pCtl->Lock);
  247. if (!IsListEmpty(&pCtl->CallList))
  248. {
  249. ENUM_CONTEXT Enum;
  250. PCALL_SESSION pCall;
  251. PLIST_ENTRY pListEntry;
  252. REFERENCE_OBJECT(pCtl);
  253. NdisReleaseSpinLock(&pCtl->Lock);
  254. InitEnumContext(&Enum);
  255. while (pListEntry = EnumListEntry(&pCtl->CallList, &Enum, &pCtl->pAdapter->Lock))
  256. {
  257. pCall = CONTAINING_RECORD(pListEntry,
  258. CALL_SESSION,
  259. ListEntry);
  260. if (IS_CALL(pCall))
  261. {
  262. CallEventDisconnect(pCall);
  263. }
  264. }
  265. EnumComplete(&Enum, &pCtl->pAdapter->Lock);
  266. DEREFERENCE_OBJECT(pCtl); // pair above
  267. NdisAcquireSpinLock(&pCtl->Lock);
  268. goto ccDone;
  269. }
  270. if (!IsListEmpty(&pCtl->MessageList))
  271. {
  272. goto ccDone;
  273. }
  274. NdisMCancelTimer(&pCtl->Echo.Timer, &TimeoutStopped);
  275. if (pCtl->Reference.Count!=2)
  276. {
  277. DEBUGMSG(DBG_TUNNEL, (DTEXT("CtlpCleanup %d references held, not cleaning up.\n"),
  278. pCtl->Reference.Count));
  279. goto ccDone;
  280. }
  281. NdisMCancelTimer(&pCtl->WaitTimeout, &TimeoutStopped);
  282. NdisMCancelTimer(&pCtl->StopTimeout, &TimeoutStopped);
  283. if (pCtl->hCtdi)
  284. {
  285. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"TCP disconnecting\n"),
  286. LOGHDR(21, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  287. CtdiDisconnect(pCtl->hCtdi, FALSE);
  288. CtdiClose(pCtl->hCtdi);
  289. pCtl->hCtdi = NULL;
  290. }
  291. if (pCtl->hCtdiEndpoint)
  292. {
  293. CtdiClose(pCtl->hCtdiEndpoint);
  294. pCtl->hCtdiEndpoint = NULL;
  295. }
  296. CleanupComplete = TRUE;
  297. ccDone:
  298. if (!CleanupComplete)
  299. {
  300. pCtl->Cleanup = FALSE;
  301. }
  302. NdisReleaseSpinLock(&pCtl->Lock);
  303. DEREFERENCE_OBJECT(pCtl); // For this work item.
  304. if (CleanupComplete)
  305. {
  306. //CtdiDeleteHostRoute(&pCtl->Remote.Address);
  307. DEREFERENCE_OBJECT(pCtl); // Should be last one
  308. }
  309. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlpCleanup\n")));
  310. }
  311. VOID
  312. CtlCleanup(
  313. PCONTROL_TUNNEL pCtl,
  314. BOOLEAN Locked
  315. )
  316. {
  317. DEBUGMSG(DBG_FUNC|DBG_TUNNEL, (DTEXT("+CtlCleanup %08x\n"), pCtl));
  318. if (!Locked)
  319. {
  320. NdisAcquireSpinLock(&pCtl->Lock);
  321. }
  322. if (IS_CTL(pCtl) && !pCtl->Cleanup)
  323. {
  324. REFERENCE_OBJECT(pCtl);
  325. pCtl->Cleanup = TRUE;
  326. if (ScheduleWorkItem(CtlpCleanup, pCtl, NULL, 0)!=NDIS_STATUS_SUCCESS)
  327. {
  328. DEREFERENCE_OBJECT(pCtl);
  329. }
  330. }
  331. if (!Locked)
  332. {
  333. NdisReleaseSpinLock(&pCtl->Lock);
  334. }
  335. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlCleanup\n")));
  336. }
  337. VOID
  338. CtlpQueryConnInfoCallback(
  339. IN PVOID pContext,
  340. IN PVOID pData,
  341. IN NDIS_STATUS Result
  342. )
  343. {
  344. PCONTROL_TUNNEL pCtl = pContext;
  345. PTDI_CONNECTION_INFO pInfo = pData;
  346. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlpQueryConnInfoCallback Result=%x\n"), Result));
  347. ASSERT(IS_CTL(pCtl));
  348. if (Result==NDIS_STATUS_SUCCESS && IS_CTL(pCtl) && pCtl->State!=STATE_CTL_CLEANUP)
  349. {
  350. pCtl->Speed = (pInfo->Throughput.QuadPart==-1) ? 0 : pInfo->Throughput.LowPart;
  351. DBG_D(DBG_INIT, pCtl->Speed);
  352. }
  353. MyMemFree(pInfo, sizeof(*pInfo));
  354. DEREFERENCE_OBJECT(pCtl);
  355. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlpQueryConnInfoCallback\n")));
  356. }
  357. STATIC VOID
  358. CtlpEngine(
  359. IN PCONTROL_TUNNEL pCtl,
  360. IN PUCHAR pNewData,
  361. IN ULONG Length
  362. )
  363. {
  364. UNALIGNED PPTP_HEADER *pHeader;
  365. ULONG NeededLength;
  366. ULONG MessageType;
  367. BOOLEAN TimerStopped;
  368. BOOLEAN PacketValid = FALSE;
  369. BOOLEAN Shutdown = FALSE;
  370. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlpEngine\n")));
  371. // Check to see if we have a full packet yet.
  372. ASSERT(IS_CTL(pCtl));
  373. while (Length)
  374. {
  375. if (pCtl->BytesInPartialBuffer)
  376. {
  377. while (Length && pCtl->BytesInPartialBuffer < sizeof(PPTP_HEADER))
  378. {
  379. pCtl->PartialPacketBuffer[pCtl->BytesInPartialBuffer++] = *pNewData++;
  380. Length--;
  381. }
  382. if (pCtl->BytesInPartialBuffer < sizeof(PPTP_HEADER))
  383. {
  384. return;
  385. }
  386. pHeader = (UNALIGNED PPTP_HEADER*)pCtl->PartialPacketBuffer;
  387. }
  388. else if (Length >= sizeof(PPTP_HEADER))
  389. {
  390. pHeader = (UNALIGNED PPTP_HEADER*)pNewData;
  391. }
  392. else
  393. {
  394. // Too little data. Copy and exit.
  395. memcpy(pCtl->PartialPacketBuffer, pNewData, Length);
  396. pCtl->BytesInPartialBuffer = Length;
  397. return;
  398. }
  399. // We have the header. Validate it.
  400. NeededLength = htons(pHeader->Length);
  401. MessageType = htons(pHeader->MessageType);
  402. if (NeededLength <= MAX_CONTROL_PACKET_LENGTH &&
  403. pHeader->Cookie == htonl(PPTP_MAGIC_COOKIE) &&
  404. pHeader->PacketType == htons(PPTP_CONTROL_MESSAGE) &&
  405. MessageType >= CONTROL_START_REQUEST &&
  406. MessageType < NUM_MESSAGE_TYPES)
  407. {
  408. // ToDo: will probably need some v2 code here for the first packet
  409. if (NeededLength == pCtl->PptpMessageLength[MessageType])
  410. {
  411. PacketValid = TRUE;
  412. }
  413. }
  414. if (PacketValid)
  415. {
  416. if (pCtl->BytesInPartialBuffer+Length < NeededLength)
  417. {
  418. // We don't have the whole packet yet. Copy and exit.
  419. memcpy(&pCtl->PartialPacketBuffer[pCtl->BytesInPartialBuffer],
  420. pNewData,
  421. Length);
  422. pCtl->BytesInPartialBuffer += Length;
  423. return;
  424. }
  425. if (pCtl->BytesInPartialBuffer)
  426. {
  427. // Make cetain the entire packet is in our PartialPacketBuffer and process it there.
  428. NeededLength -= pCtl->BytesInPartialBuffer;
  429. memcpy(&pCtl->PartialPacketBuffer[pCtl->BytesInPartialBuffer],
  430. pNewData,
  431. NeededLength);
  432. // We now have one complete packet in the PartialPacketBuffer
  433. pNewData += NeededLength;
  434. Length -= NeededLength;
  435. pHeader = (UNALIGNED PPTP_HEADER *)pCtl->PartialPacketBuffer;
  436. // We've got the whole packet, and we're about to consume it
  437. // Clear the var so next time through we start from the buffer
  438. // beginning
  439. pCtl->BytesInPartialBuffer = 0;
  440. }
  441. else
  442. {
  443. // The whole packet is in the new buffer. Process it there.
  444. pHeader = (UNALIGNED PPTP_HEADER *)pNewData;
  445. pNewData += NeededLength;
  446. Length -= NeededLength;
  447. }
  448. switch (htons(pHeader->MessageType))
  449. {
  450. case CONTROL_START_REQUEST:
  451. {
  452. UNALIGNED PPTP_CONTROL_START_PACKET *pPacket =
  453. (UNALIGNED PPTP_CONTROL_START_PACKET*)pHeader;
  454. UNALIGNED PPTP_CONTROL_START_PACKET *pReply;
  455. NDIS_STATUS Status;
  456. DEBUGMSG(DBG_TUNNEL, (DTEXT("CONTROL_START_REQUEST RECEIVED\n")));
  457. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CONTROL_START_REQUEST RECEIVED\n"),
  458. LOGHDR(2, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  459. switch (pCtl->State)
  460. {
  461. case STATE_CTL_WAIT_REQUEST:
  462. {
  463. pReply = CtlAllocPacket(pCtl, CONTROL_START_REPLY);
  464. if (pReply)
  465. {
  466. PTDI_CONNECTION_INFO pInfo;
  467. NdisMCancelTimer(&pCtl->WaitTimeout, &TimerStopped);
  468. // Take the pertinent data.
  469. pCtl->Remote.Version = htons(pPacket->Version);
  470. pCtl->Remote.Framing = htonl(pPacket->FramingCapabilities);
  471. pCtl->Remote.Bearer = htonl(pPacket->BearerCapabilities);
  472. memcpy(pCtl->Remote.HostName, pPacket->HostName, MAX_HOSTNAME_LENGTH);
  473. pCtl->Remote.HostName[MAX_HOSTNAME_LENGTH-1] = '\0';
  474. memcpy(pCtl->Remote.Vendor, pPacket->Vendor, MAX_VENDOR_LENGTH);
  475. pCtl->Remote.Vendor[MAX_VENDOR_LENGTH-1] = '\0';
  476. DBG_X(DBG_PACKET, pCtl->Remote.Version);
  477. DBG_X(DBG_PACKET, pCtl->Remote.Framing);
  478. DBG_X(DBG_PACKET, pCtl->Remote.Bearer);
  479. DBG_S(DBG_PACKET, pCtl->Remote.HostName);
  480. DBG_S(DBG_PACKET, pCtl->Remote.Vendor);
  481. if (pCtl->Remote.Version==PPTP_PROTOCOL_VERSION_1_00)
  482. {
  483. pReply->Version = ntohs(PPTP_PROTOCOL_VERSION_1_00);
  484. pReply->ResultCode = RESULT_CONTROL_START_SUCCESS;
  485. pReply->FramingCapabilities = htonl(FRAMING_SYNC);
  486. pReply->BearerCapabilities = htonl(BEARER_ANALOG|BEARER_DIGITAL);
  487. pReply->MaxChannels = 0;
  488. pReply->FirmwareRevision = htons(PPTP_FIRMWARE_REVISION);
  489. strcpy(pReply->Vendor, PPTP_VENDOR);
  490. }
  491. else
  492. {
  493. // ToDo: implement new version
  494. ASSERT(0);
  495. }
  496. CtlSetState(pCtl, STATE_CTL_ESTABLISHED, 0, UNLOCKED);
  497. CtlSend(pCtl, pReply); // ToDo: return value?
  498. pInfo = MyMemAlloc(sizeof(*pInfo), TAG_CTL_CONNINFO);
  499. if (pInfo)
  500. {
  501. REFERENCE_OBJECT(pCtl);
  502. Status = CtdiQueryInformation(pCtl->hCtdi,
  503. TDI_QUERY_CONNECTION_INFO,
  504. pInfo,
  505. sizeof(*pInfo),
  506. CtlpQueryConnInfoCallback,
  507. pCtl);
  508. ASSERT(NT_SUCCESS(Status));
  509. Status = NDIS_STATUS_SUCCESS;
  510. }
  511. }
  512. else
  513. {
  514. // Alloc failed. Do nothing, and timeout will cause cleanup.
  515. }
  516. break;
  517. }
  518. case STATE_CTL_CLEANUP:
  519. DEBUGMSG(DBG_WARN, (DTEXT("Shutting down tunnel, ignore packet\n")));
  520. break;
  521. default:
  522. DEBUGMSG(DBG_WARN, (DTEXT("Bad state, shutdown tunnel\n")));
  523. Shutdown = TRUE;
  524. break;
  525. }
  526. break;
  527. }
  528. case CONTROL_START_REPLY:
  529. {
  530. UNALIGNED PPTP_CONTROL_START_PACKET *pPacket =
  531. (UNALIGNED PPTP_CONTROL_START_PACKET*)pHeader;
  532. DEBUGMSG(DBG_TUNNEL, (DTEXT("CONTROL_START_REPLY RECEIVED\n")));
  533. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CTL CONTROL_START_REPLY RECEIVED\n"),
  534. LOGHDR(3, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  535. switch (pCtl->State)
  536. {
  537. case STATE_CTL_WAIT_REPLY:
  538. {
  539. ENUM_CONTEXT Enum;
  540. PCALL_SESSION pCall;
  541. PLIST_ENTRY pListEntry;
  542. NdisMCancelTimer(&pCtl->WaitTimeout, &TimerStopped);
  543. // Take the pertinent data.
  544. pCtl->Remote.Version = htons(pPacket->Version);
  545. pCtl->Remote.Framing = htonl(pPacket->FramingCapabilities);
  546. pCtl->Remote.Bearer = htonl(pPacket->BearerCapabilities);
  547. memcpy(pCtl->Remote.HostName, pPacket->HostName, MAX_HOSTNAME_LENGTH);
  548. pCtl->Remote.HostName[MAX_HOSTNAME_LENGTH-1] = '\0';
  549. memcpy(pCtl->Remote.Vendor, pPacket->Vendor, MAX_VENDOR_LENGTH);
  550. pCtl->Remote.Vendor[MAX_VENDOR_LENGTH-1] = '\0';
  551. DBG_X(DBG_PACKET, pCtl->Remote.Version);
  552. DBG_X(DBG_PACKET, pCtl->Remote.Framing);
  553. DBG_X(DBG_PACKET, pCtl->Remote.Bearer);
  554. DBG_S(DBG_PACKET, pCtl->Remote.HostName);
  555. DBG_S(DBG_PACKET, pCtl->Remote.Vendor);
  556. CtlSetState(pCtl, STATE_CTL_ESTABLISHED, 0, UNLOCKED);
  557. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"Control Channel Successfully Established\n"),
  558. LOGHDR(4, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  559. // Notify all calls on this session.
  560. REFERENCE_OBJECT(pCtl);
  561. InitEnumContext(&Enum);
  562. while (pListEntry = EnumListEntry(&pCtl->CallList, &Enum, &pCtl->pAdapter->Lock))
  563. {
  564. pCall = CONTAINING_RECORD(pListEntry,
  565. CALL_SESSION,
  566. ListEntry);
  567. if (IS_CALL(pCall))
  568. {
  569. CallEventOutboundTunnelEstablished(pCall,
  570. NDIS_STATUS_SUCCESS);
  571. }
  572. }
  573. EnumComplete(&Enum, &pCtl->pAdapter->Lock);
  574. DEREFERENCE_OBJECT(pCtl); // pair above
  575. break;
  576. }
  577. default:
  578. break;
  579. }
  580. break;
  581. }
  582. case CONTROL_ECHO_REQUEST:
  583. {
  584. UNALIGNED PPTP_CONTROL_ECHO_REQUEST_PACKET *pPacket =
  585. (UNALIGNED PPTP_CONTROL_ECHO_REQUEST_PACKET*)pHeader;
  586. UNALIGNED PPTP_CONTROL_ECHO_REPLY_PACKET *pReply;
  587. DEBUGMSG(DBG_TUNNEL, (DTEXT("ECHO_REQUEST RECEIVED\n")));
  588. DBG_X(DBG_PACKET, pPacket->Identifier);
  589. pCtl->Echo.Needed = FALSE;
  590. pReply = CtlAllocPacket(pCtl, CONTROL_ECHO_REPLY);
  591. if (pReply)
  592. {
  593. if (pCtl->Remote.Version==PPTP_PROTOCOL_VERSION_1_00)
  594. {
  595. pReply->Identifier = pPacket->Identifier;
  596. pReply->ResultCode = RESULT_CONTROL_ECHO_SUCCESS;
  597. // ToDo: why would we send a ResultCode==failure?
  598. CtlSend(pCtl, pReply); // ToDo: return value?
  599. }
  600. else
  601. {
  602. // ToDo: implement new version
  603. DEBUGMSG(DBG_WARN, (DTEXT("Echo request received when version unknown or wrong. Ignoring.\n")));
  604. }
  605. }
  606. break;
  607. }
  608. case CALL_OUT_REQUEST:
  609. {
  610. UNALIGNED PPTP_CALL_OUT_REQUEST_PACKET *pPacket =
  611. (UNALIGNED PPTP_CALL_OUT_REQUEST_PACKET*)pHeader;
  612. DEBUGMSG(DBG_TUNNEL, (DTEXT("CALL_OUT_REQUEST RECEIVED\n")));
  613. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CTL CALL_OUT_REQUEST RECEIVED\n"),
  614. LOGHDR(5, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  615. switch (pCtl->State)
  616. {
  617. case STATE_CTL_ESTABLISHED:
  618. {
  619. DBG_X(DBG_TUNNEL, htons(pPacket->CallId));
  620. DBG_X(DBG_TUNNEL, htons(pPacket->SerialNumber));
  621. DBG_D(DBG_TUNNEL, htonl(pPacket->MinimumBPS));
  622. DBG_D(DBG_TUNNEL, htonl(pPacket->MaximumBPS));
  623. DBG_X(DBG_TUNNEL, htonl(pPacket->BearerType));
  624. DBG_X(DBG_TUNNEL, htonl(pPacket->FramingType));
  625. DBG_X(DBG_TUNNEL, htons(pPacket->RecvWindowSize));
  626. DBG_X(DBG_TUNNEL, htons(pPacket->ProcessingDelay));
  627. DBG_X(DBG_TUNNEL, htons(pPacket->PhoneNumberLength));
  628. DBG_S(DBG_TUNNEL, pPacket->PhoneNumber);
  629. DBG_S(DBG_TUNNEL, pPacket->Subaddress);
  630. // It's possible we had just closed our last call & were
  631. // waiting for a CONTROL_STOP_REQUEST from the other side.
  632. NdisMCancelTimer(&pCtl->StopTimeout, &TimerStopped);
  633. CallEventCallOutRequest(pCtl->pAdapter,
  634. pCtl,
  635. pPacket);
  636. break;
  637. }
  638. default:
  639. // Bogus, but not enough to kill us. Ignore it.
  640. break;
  641. }
  642. break;
  643. }
  644. case CALL_OUT_REPLY:
  645. {
  646. UNALIGNED PPTP_CALL_OUT_REPLY_PACKET *pPacket =
  647. (UNALIGNED PPTP_CALL_OUT_REPLY_PACKET*)pHeader;
  648. DEBUGMSG(DBG_TUNNEL, (DTEXT("CALL_OUT_REPLY RECEIVED\n")));
  649. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CALL_OUT_REPLY RECEIVED\n"),
  650. LOGHDR(6, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  651. if (pCtl->State==STATE_CTL_ESTABLISHED)
  652. {
  653. ULONG CallId = htons(pPacket->PeerCallId);
  654. PCALL_SESSION pCall = CallGetCall(pCtl->pAdapter, CallIdToDeviceId(CallId));
  655. if (pCall)
  656. {
  657. DBG_X(DBG_TUNNEL, htons(pPacket->PeerCallId));
  658. DBG_X(DBG_TUNNEL, pPacket->ResultCode);
  659. DBG_X(DBG_TUNNEL, pPacket->ErrorCode);
  660. DBG_X(DBG_TUNNEL, htons(pPacket->CauseCode));
  661. DBG_D(DBG_TUNNEL, htonl(pPacket->ConnectSpeed));
  662. DBG_D(DBG_TUNNEL, htons(pPacket->RecvWindowSize));
  663. DBG_X(DBG_TUNNEL, htonl(pPacket->PhysicalChannelId));
  664. CallEventCallOutReply(pCall, pPacket);
  665. }
  666. else
  667. {
  668. DEBUGMSG(DBG_WARN, (DTEXT("Bogus PeerCallId\n")));
  669. }
  670. }
  671. else
  672. {
  673. // Bogus, but not enough to kill us. Ignore it.
  674. }
  675. break;
  676. }
  677. case CALL_CLEAR_REQUEST:
  678. {
  679. UNALIGNED PPTP_CALL_CLEAR_REQUEST_PACKET *pPacket =
  680. (UNALIGNED PPTP_CALL_CLEAR_REQUEST_PACKET*)pHeader;
  681. DEBUGMSG(DBG_TUNNEL, (DTEXT("CALL_CLEAR_REQUEST RECEIVED\n")));
  682. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CALL_CLEAR_REQUEST RECEIVED\n"),
  683. LOGHDR(7, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  684. if (pCtl->State==STATE_CTL_ESTABLISHED)
  685. {
  686. ULONG CallId = htons(pPacket->CallId);
  687. ENUM_CONTEXT Enum;
  688. PCALL_SESSION pCall;
  689. PLIST_ENTRY pListEntry;
  690. // The peer has given us his own call ID, which does little
  691. // good for fast lookup of the call. Find the associated call.
  692. REFERENCE_OBJECT(pCtl);
  693. InitEnumContext(&Enum);
  694. do
  695. {
  696. NdisAcquireSpinLock(&pCtl->pAdapter->Lock);
  697. pListEntry = EnumListEntry(&pCtl->CallList, &Enum, NULL);
  698. if(pListEntry != NULL)
  699. {
  700. pCall = CONTAINING_RECORD(pListEntry,
  701. CALL_SESSION,
  702. ListEntry);
  703. if (IS_CALL(pCall) && pCall->pCtl==pCtl && pCall->Remote.CallId==CallId)
  704. {
  705. REFERENCE_OBJECT(pCall);
  706. NdisReleaseSpinLock(&pCtl->pAdapter->Lock);
  707. CallEventCallClearRequest(pCall, pPacket, pCtl);
  708. DEREFERENCE_OBJECT(pCall);
  709. break;
  710. }
  711. }
  712. NdisReleaseSpinLock(&pCtl->pAdapter->Lock);
  713. } while(pListEntry != NULL);
  714. #if 0
  715. while (pListEntry = EnumListEntry(&pCtl->CallList, &Enum, &pCtl->pAdapter->Lock))
  716. {
  717. pCall = CONTAINING_RECORD(pListEntry,
  718. CALL_SESSION,
  719. ListEntry);
  720. if (IS_CALL(pCall) && pCall->pCtl==pCtl && pCall->Remote.CallId==CallId)
  721. {
  722. CallEventCallClearRequest(pCall, pPacket);
  723. break;
  724. }
  725. }
  726. #endif
  727. EnumComplete(&Enum, &pCtl->pAdapter->Lock);
  728. DEREFERENCE_OBJECT(pCtl); // pair above
  729. }
  730. break;
  731. }
  732. case CALL_DISCONNECT_NOTIFY:
  733. {
  734. UNALIGNED PPTP_CALL_DISCONNECT_NOTIFY_PACKET *pPacket =
  735. (UNALIGNED PPTP_CALL_DISCONNECT_NOTIFY_PACKET*)pHeader;
  736. DEBUGMSG(DBG_TUNNEL, (DTEXT("CALL_DISCONNECT_NOTIFY RECEIVED\n")));
  737. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CALL_DISCONNECT_NOTIFY RECEIVED\n"),
  738. LOGHDR(8, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  739. if (pCtl->State==STATE_CTL_ESTABLISHED)
  740. {
  741. ULONG CallId = htons(pPacket->CallId);
  742. ENUM_CONTEXT Enum;
  743. PCALL_SESSION pCall;
  744. PLIST_ENTRY pListEntry;
  745. // The peer has given us his own call ID, which does little
  746. // good for fast lookup of the call. Find the associated call.
  747. REFERENCE_OBJECT(pCtl);
  748. InitEnumContext(&Enum);
  749. while (pListEntry = EnumListEntry(&pCtl->CallList, &Enum, &pCtl->pAdapter->Lock))
  750. {
  751. pCall = CONTAINING_RECORD(pListEntry,
  752. CALL_SESSION,
  753. ListEntry);
  754. if (IS_CALL(pCall) && pCall->pCtl==pCtl && pCall->Remote.CallId==CallId)
  755. {
  756. DBG_X(DBG_TUNNEL, htons(pPacket->CallId));
  757. DBG_X(DBG_TUNNEL, pPacket->ResultCode);
  758. DBG_X(DBG_TUNNEL, pPacket->ErrorCode);
  759. DBG_X(DBG_TUNNEL, htons(pPacket->CauseCode));
  760. CallEventCallDisconnectNotify(pCall, pPacket);
  761. break;
  762. }
  763. }
  764. EnumComplete(&Enum, &pCtl->pAdapter->Lock);
  765. DEREFERENCE_OBJECT(pCtl); // pair above
  766. }
  767. break;
  768. }
  769. case CONTROL_STOP_REQUEST:
  770. {
  771. DEBUGMSG(DBG_TUNNEL, (DTEXT("CONTROL_STOP_REQUEST RECEIVED\n")));
  772. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CONTROL_STOP_REQUEST RECEIVED\n"),
  773. LOGHDR(9, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  774. switch (pCtl->State)
  775. {
  776. case STATE_CTL_WAIT_STOP:
  777. {
  778. NdisMCancelTimer(&pCtl->StopTimeout, &TimerStopped);
  779. // No break
  780. }
  781. case STATE_CTL_WAIT_REPLY:
  782. case STATE_CTL_ESTABLISHED:
  783. {
  784. UNALIGNED PPTP_CONTROL_STOP_PACKET *pReply;
  785. pReply = CtlAllocPacket(pCtl, CONTROL_STOP_REPLY);
  786. if (pReply)
  787. {
  788. pReply->ResultCode = RESULT_CONTROL_STOP_SUCCESS;
  789. CtlSend(pCtl, pReply);
  790. }
  791. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, UNLOCKED);
  792. CtlCleanup(pCtl, UNLOCKED);
  793. break;
  794. }
  795. default:
  796. break;
  797. }
  798. break;
  799. }
  800. case CONTROL_STOP_REPLY:
  801. {
  802. DEBUGMSG(DBG_TUNNEL, (DTEXT("CONTROL_STOP_REPLY RECEIVED\n")));
  803. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CONTROL_STOP_REPLY RECEIVED\n"),
  804. LOGHDR(10, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  805. if (pCtl->State==STATE_CTL_WAIT_STOP)
  806. {
  807. NdisMCancelTimer(&pCtl->StopTimeout, &TimerStopped);
  808. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, UNLOCKED);
  809. CtlCleanup(pCtl, UNLOCKED);
  810. }
  811. break;
  812. }
  813. case SET_LINK_INFO:
  814. {
  815. DEBUGMSG(DBG_TUNNEL, (DTEXT("SET_LINK_INFO RECEIVED\n")));
  816. break;
  817. }
  818. case CALL_IN_REQUEST:
  819. {
  820. UNALIGNED PPTP_CALL_IN_REQUEST_PACKET *pPacket =
  821. (UNALIGNED PPTP_CALL_IN_REQUEST_PACKET*)pHeader;
  822. DEBUGMSG(DBG_TUNNEL, (DTEXT("CALL_IN_REQUEST RECEIVED\n")));
  823. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CALL_IN_REQUEST RECEIVED\n"),
  824. LOGHDR(11, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  825. if (pCtl->State==STATE_CTL_ESTABLISHED)
  826. {
  827. DBG_X(DBG_TUNNEL, htons(pPacket->CallId));
  828. DBG_X(DBG_TUNNEL, htons(pPacket->SerialNumber));
  829. DBG_X(DBG_TUNNEL, htonl(pPacket->BearerType));
  830. DBG_X(DBG_TUNNEL, htonl(pPacket->PhysicalChannelId));
  831. DBG_X(DBG_TUNNEL, htons(pPacket->DialedNumberLength));
  832. DBG_X(DBG_TUNNEL, htons(pPacket->DialingNumberLength));
  833. DBG_S(DBG_TUNNEL, pPacket->DialedNumber);
  834. DBG_S(DBG_TUNNEL, pPacket->DialingNumber);
  835. DBG_S(DBG_TUNNEL, pPacket->Subaddress);
  836. // It's possible we had just closed our last call & were
  837. // waiting for a CONTROL_STOP_REQUEST from the other side.
  838. NdisMCancelTimer(&pCtl->StopTimeout, &TimerStopped);
  839. CallEventCallInRequest(pCtl->pAdapter,
  840. pCtl,
  841. pPacket);
  842. }
  843. break;
  844. }
  845. case CALL_IN_REPLY:
  846. DEBUGMSG(DBG_TUNNEL, (DTEXT("CALL_IN_REPLY RECEIVED\n")));
  847. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CALL_IN_REPLY RECEIVED\n"),
  848. LOGHDR(12, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  849. // We should never get one of these.
  850. break;
  851. case CALL_IN_CONNECTED:
  852. {
  853. UNALIGNED PPTP_CALL_IN_CONNECT_PACKET *pPacket =
  854. (UNALIGNED PPTP_CALL_IN_CONNECT_PACKET*)pHeader;
  855. DEBUGMSG(DBG_TUNNEL, (DTEXT("CALL_IN_CONNECTED RECEIVED\n")));
  856. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"CALL_IN_CONNECTED RECEIVED\n"),
  857. LOGHDR(13, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  858. if (pCtl->State==STATE_CTL_ESTABLISHED)
  859. {
  860. ULONG CallId = htons(pPacket->PeerCallId);
  861. PCALL_SESSION pCall;
  862. DBG_X(DBG_TUNNEL, htons(pPacket->PeerCallId));
  863. DBG_X(DBG_TUNNEL, htonl(pPacket->ConnectSpeed));
  864. DBG_X(DBG_TUNNEL, htons(pPacket->RecvWindowSize));
  865. DBG_X(DBG_TUNNEL, htons(pPacket->ProcessingDelay));
  866. DBG_X(DBG_TUNNEL, htonl(pPacket->FramingType));
  867. pCall = CallGetCall(pCtl->pAdapter, CallIdToDeviceId(CallId));
  868. if (pCall)
  869. {
  870. CallEventCallInConnect(pCall, pPacket);
  871. }
  872. }
  873. break;
  874. }
  875. case CONTROL_ECHO_REPLY:
  876. DEBUGMSG(DBG_TUNNEL, (DTEXT("CONTROL_ECHO_REPLY RECEIVED\n")));
  877. break;
  878. case WAN_ERROR_NOTIFY:
  879. DEBUGMSG(DBG_TUNNEL, (DTEXT("WAN_ERROR_NOTIFY RECEIVED\n")));
  880. break;
  881. default:
  882. DEBUGMSG(DBG_TUNNEL|DBG_WARN, (DTEXT("UNKNOWN RECEIVED\n")));
  883. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"Unknown control packet received\n"),
  884. LOGHDR(23, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  885. break;
  886. }
  887. }
  888. else // !PacketValid
  889. {
  890. Shutdown = TRUE;
  891. }
  892. if (Shutdown)
  893. {
  894. DEBUGMSG(DBG_TUNNEL|DBG_ERROR, (DTEXT("Tunnel problem, shutting it down.\n")));
  895. break;
  896. }
  897. }
  898. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlpEngine\n")));
  899. }
  900. NDIS_STATUS
  901. CtlConnectQueryCallback(
  902. IN PVOID pContext,
  903. IN PTRANSPORT_ADDRESS pAddress,
  904. IN HANDLE hNewCtdi,
  905. OUT PVOID *pNewContext
  906. )
  907. {
  908. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  909. PPPTP_ADAPTER pAdapter = pContext;
  910. PTA_IP_ADDRESS pIp = (PTA_IP_ADDRESS)pAddress;
  911. PCONTROL_TUNNEL pCtl;
  912. BOOLEAN Accepting = TRUE;
  913. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlConnectQueryCallback\n")));
  914. DEBUGMSG(DBG_TUNNEL, (DTEXT("Request to connect from %d.%d.%d.%d\n"),
  915. IPADDR(pIp->Address[0].Address[0].in_addr)));
  916. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"TCP connection request\n"),
  917. LOGHDR(1, pIp->Address[0].Address[0].in_addr)));
  918. if (PptpAuthenticateIncomingCalls)
  919. {
  920. ULONG i;
  921. BOOLEAN Match = FALSE;
  922. for (i=0; i<NumClientAddresses; i++)
  923. {
  924. if ((pIp->Address[0].Address[0].in_addr&ClientList[i].Mask)==
  925. (ClientList[i].Address&ClientList[i].Mask))
  926. {
  927. Match = TRUE;
  928. break;
  929. }
  930. }
  931. if (!Match)
  932. {
  933. DEBUGMSG(DBG_TUNNEL|DBG_WARN, (DTEXT("No match found for IP %d.%d.%d.%d. Refused.\n"),
  934. IPADDR(pIp->Address[0].Address[0].in_addr)));
  935. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"IP not authenticated\n"),
  936. LOGHDR(24, pIp->Address[0].Address[0].in_addr)));
  937. Accepting = FALSE;
  938. Status = NDIS_STATUS_FAILURE;
  939. }
  940. }
  941. if (Accepting)
  942. {
  943. pCtl = CtlAlloc(pAdapter);
  944. if (!pCtl)
  945. {
  946. Status = NDIS_STATUS_RESOURCES;
  947. }
  948. else
  949. {
  950. NdisAcquireSpinLock(&pAdapter->Lock);
  951. CtlSetState(pCtl, STATE_CTL_WAIT_REQUEST, 0, LOCKED);
  952. pCtl->Inbound = TRUE;
  953. NdisReleaseSpinLock(&pAdapter->Lock);
  954. NdisAcquireSpinLock(&pCtl->Lock);
  955. pCtl->hCtdi = hNewCtdi;
  956. pCtl->Remote.Address = *pIp;
  957. NdisMSetTimer(&pCtl->WaitTimeout, PptpMessageTimeout*1000);
  958. if (PptpEchoTimeout)
  959. {
  960. NdisMSetPeriodicTimer(&pCtl->Echo.Timer, PptpEchoTimeout*1000);
  961. pCtl->Echo.Needed = TRUE;
  962. }
  963. NdisReleaseSpinLock(&pCtl->Lock);
  964. *pNewContext = pCtl;
  965. }
  966. }
  967. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtlConnectQueryCallback %08x\n"), Status));
  968. return Status;
  969. }
  970. NDIS_STATUS
  971. CtlConnectCompleteCallback(
  972. IN PVOID pContext,
  973. IN HANDLE hNewCtdi,
  974. IN NDIS_STATUS ConnectStatus
  975. )
  976. {
  977. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  978. PCONTROL_TUNNEL pCtl = pContext;
  979. PPTP_CONTROL_START_PACKET *pPacket = NULL;
  980. PTDI_CONNECTION_INFO pInfo;
  981. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlConnectCompleteCallback\n")));
  982. if (IS_CTL(pCtl))
  983. {
  984. if (pCtl->State!=STATE_CTL_DIALING)
  985. {
  986. DEBUGMSG(DBG_TUNNEL|DBG_ERR(Status), (DTEXT("Ctl in wrong state after connect %d\n"), pCtl->State));
  987. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, UNLOCKED);
  988. CtlCleanup(pCtl, UNLOCKED);
  989. Status = NDIS_STATUS_FAILURE;
  990. }
  991. else if (ConnectStatus==NDIS_STATUS_SUCCESS)
  992. {
  993. pPacket = CtlAllocPacket(pCtl, CONTROL_START_REQUEST);
  994. CtlSetState(pCtl, STATE_CTL_WAIT_REPLY, 0, UNLOCKED);
  995. NdisAcquireSpinLock(&pCtl->Lock);
  996. pCtl->hCtdi = hNewCtdi;
  997. NdisMSetTimer(&pCtl->WaitTimeout, PptpMessageTimeout*1000);
  998. if (PptpEchoTimeout)
  999. {
  1000. NdisMSetPeriodicTimer(&pCtl->Echo.Timer, PptpEchoTimeout*1000);
  1001. pCtl->Echo.Needed = TRUE;
  1002. }
  1003. NdisReleaseSpinLock(&pCtl->Lock);
  1004. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"Control channel TCP/IP port successfully connected\n"),
  1005. LOGHDR(14, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  1006. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"Starting PPTP control channel setup\n"),
  1007. LOGHDR(15, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  1008. OsFileLogFlush();
  1009. if (pPacket)
  1010. {
  1011. pPacket->Version = ntohs(PPTP_PROTOCOL_VERSION_1_00); // ToDo: do v2
  1012. pPacket->FramingCapabilities = ntohl(FRAMING_ASYNC);
  1013. pPacket->BearerCapabilities = ntohl(BEARER_ANALOG);
  1014. pPacket->MaxChannels = 0;
  1015. pPacket->FirmwareRevision = htons(PPTP_FIRMWARE_REVISION);
  1016. strcpy(pPacket->Vendor, PPTP_VENDOR);
  1017. CtlSend(pCtl, pPacket); // ToDo: return value?
  1018. }
  1019. else
  1020. {
  1021. // Allocation failure will be covered by timeout
  1022. }
  1023. pInfo = MyMemAlloc(sizeof(*pInfo), TAG_CTL_CONNINFO);
  1024. if (pInfo)
  1025. {
  1026. REFERENCE_OBJECT(pCtl);
  1027. Status = CtdiQueryInformation(pCtl->hCtdi,
  1028. TDI_QUERY_CONNECTION_INFO,
  1029. pInfo,
  1030. sizeof(*pInfo),
  1031. CtlpQueryConnInfoCallback,
  1032. pCtl);
  1033. ASSERT(NT_SUCCESS(Status));
  1034. Status = NDIS_STATUS_SUCCESS;
  1035. }
  1036. }
  1037. else
  1038. {
  1039. ENUM_CONTEXT Enum;
  1040. PCALL_SESSION pCall;
  1041. PLIST_ENTRY pListEntry;
  1042. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"Connection failed: NDIS Error 0x%x\n"),
  1043. LOGHDR(16, pCtl->Remote.Address.Address[0].Address[0].in_addr),
  1044. ConnectStatus));
  1045. REFERENCE_OBJECT(pCtl);
  1046. InitEnumContext(&Enum);
  1047. while (pListEntry = EnumListEntry(&pCtl->CallList, &Enum, &pCtl->pAdapter->Lock))
  1048. {
  1049. pCall = CONTAINING_RECORD(pListEntry,
  1050. CALL_SESSION,
  1051. ListEntry);
  1052. if (IS_CALL(pCall))
  1053. {
  1054. CallEventConnectFailure(pCall, ConnectStatus);
  1055. }
  1056. }
  1057. EnumComplete(&Enum, &pCtl->pAdapter->Lock);
  1058. DEREFERENCE_OBJECT(pCtl); // pair above
  1059. Status = NDIS_STATUS_FAILURE;
  1060. }
  1061. DEREFERENCE_OBJECT(pCtl); // pair at call to CtdiConnect
  1062. }
  1063. else
  1064. {
  1065. Status = NDIS_STATUS_FAILURE;
  1066. }
  1067. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtlConnectCompleteCallback %08x\n"), Status));
  1068. return Status;
  1069. }
  1070. NDIS_STATUS
  1071. CtlDisconnectCallback(
  1072. IN PVOID pContext,
  1073. IN BOOLEAN Abortive
  1074. )
  1075. {
  1076. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1077. PCONTROL_TUNNEL pCtl = pContext;
  1078. BOOLEAN Cleanup = TRUE;
  1079. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlDisconnectCallback\n")));
  1080. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"TCP disconnected\n"),
  1081. LOGHDR(20, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  1082. NdisAcquireSpinLock(&pCtl->pAdapter->Lock);
  1083. if (pCtl->State!=STATE_CTL_CLEANUP)
  1084. {
  1085. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, LOCKED);
  1086. Cleanup = TRUE;
  1087. }
  1088. NdisReleaseSpinLock(&pCtl->pAdapter->Lock);
  1089. if (Cleanup)
  1090. {
  1091. CtlCleanup(pCtl, UNLOCKED);
  1092. }
  1093. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtlDisconnectCallback %08x\n"), Status));
  1094. return Status;
  1095. }
  1096. NDIS_STATUS
  1097. CtlReceiveCallback(
  1098. IN PVOID pContext,
  1099. IN PUCHAR pBuffer,
  1100. IN ULONG ulLength
  1101. )
  1102. {
  1103. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1104. PCONTROL_TUNNEL pCtl = pContext;
  1105. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlReceiveCallback\n")));
  1106. // We must copy or consume the data before leaving this function.
  1107. ASSERT(IS_CTL(pCtl));
  1108. CtlpEngine(pCtl, pBuffer, ulLength);
  1109. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtlReceiveCallback %08x\n"), Status));
  1110. return Status;
  1111. }
  1112. NDIS_STATUS
  1113. CtlConnectCall(
  1114. IN PPPTP_ADAPTER pAdapter,
  1115. IN PCALL_SESSION pCall,
  1116. IN PTA_IP_ADDRESS pTargetAddress
  1117. )
  1118. {
  1119. TA_IP_ADDRESS Local;
  1120. PCONTROL_TUNNEL pCtl = NULL;
  1121. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1122. ENUM_CONTEXT Enum;
  1123. PLIST_ENTRY pListEntry;
  1124. BOOLEAN SignalEstablished = FALSE;
  1125. BOOLEAN Connected = FALSE;
  1126. BOOLEAN InvalidAddress = (pTargetAddress->TAAddressCount == 0xffffffff); // Magic cookie passed set by
  1127. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlConnectCall\n")));
  1128. DEBUGMSG(DBG_CALL, (DTEXT("New Dial request: Call:%08x Ctl:%08x Addr:%08x\n"),
  1129. pCall, pCtl, pTargetAddress->Address[0].Address[0].in_addr));
  1130. if( !InvalidAddress ){
  1131. InitEnumContext(&Enum);
  1132. NdisAcquireSpinLock(&pAdapter->Lock);
  1133. while (!Connected && (pListEntry = EnumListEntry(&pAdapter->ControlTunnelList, &Enum, NULL)))
  1134. {
  1135. pCtl = CONTAINING_RECORD(pListEntry, CONTROL_TUNNEL, ListEntry);
  1136. if (IS_CTL(pCtl) &&
  1137. (pCtl->State>=STATE_CTL_DIALING && pCtl->State<=STATE_CTL_ESTABLISHED) &&
  1138. pTargetAddress->Address[0].Address[0].in_addr==pCtl->Remote.Address.Address[0].Address[0].in_addr)
  1139. {
  1140. DEBUGMSG(DBG_CALL, (DTEXT("Existing tunnel found for call %08x\n"), pCall));
  1141. REFERENCE_OBJECT(pCtl);
  1142. NdisReleaseSpinLock(&pAdapter->Lock);
  1143. Connected = CallConnectToCtl(pCall, pCtl, FALSE);
  1144. if (Connected)
  1145. {
  1146. // keep the reference for now
  1147. }
  1148. else
  1149. {
  1150. DEREFERENCE_OBJECT(pCtl);
  1151. }
  1152. NdisAcquireSpinLock(&pAdapter->Lock);
  1153. if (Connected && pCtl->State==STATE_CTL_ESTABLISHED)
  1154. {
  1155. SignalEstablished = TRUE;
  1156. }
  1157. }
  1158. }
  1159. EnumComplete(&Enum, NULL);
  1160. NdisReleaseSpinLock(&pAdapter->Lock);
  1161. }
  1162. if (Connected)
  1163. {
  1164. if (SignalEstablished)
  1165. {
  1166. CallEventOutboundTunnelEstablished(pCall,
  1167. NDIS_STATUS_SUCCESS);
  1168. }
  1169. // We found an existing tunnel, for which we have a reference. Drop it.
  1170. DEREFERENCE_OBJECT(pCtl);
  1171. }
  1172. else
  1173. {
  1174. HANDLE hCtdiEndpoint;
  1175. pCtl = CtlAlloc(pAdapter);
  1176. if (!pCtl)
  1177. {
  1178. Status = NDIS_STATUS_RESOURCES;
  1179. goto cmcDone;
  1180. }
  1181. NdisAcquireSpinLock(&pAdapter->Lock);
  1182. CtlSetState(pCtl, STATE_CTL_DIALING, 0, LOCKED);
  1183. pCtl->Inbound = pCall->Inbound;
  1184. NdisReleaseSpinLock(&pAdapter->Lock);
  1185. Connected = CallConnectToCtl(pCall, pCtl, FALSE);
  1186. if (!Connected)
  1187. {
  1188. Status = NDIS_STATUS_FAILURE;
  1189. }
  1190. else
  1191. {
  1192. NdisZeroMemory(&Local, sizeof(Local));
  1193. if( InvalidAddress ){
  1194. DEBUGMSG(DBG_ERROR, (DTEXT("Disconnecting due to error passed down from gethostbyname\n")));
  1195. CallSetState(pCall, STATE_CALL_CLEANUP, LINEDISCONNECTMODE_UNREACHABLE, UNLOCKED);
  1196. goto cmcDone;
  1197. }
  1198. Local.TAAddressCount = 1;
  1199. Local.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  1200. Local.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1201. Local.Address[0].Address[0].sin_port = 0;
  1202. Local.Address[0].Address[0].in_addr = 0;
  1203. Status = CtdiCreateEndpoint(&hCtdiEndpoint,
  1204. AF_INET,
  1205. SOCK_STREAM,
  1206. (PTRANSPORT_ADDRESS)&Local,
  1207. 0);
  1208. if (Status!=NDIS_STATUS_SUCCESS)
  1209. {
  1210. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiCreateEndpoint failed %08x\n"), Status));
  1211. goto cmcDone;
  1212. }
  1213. NdisAcquireSpinLock(&pCtl->Lock);
  1214. pCtl->hCtdiEndpoint = hCtdiEndpoint;
  1215. pCtl->Remote.Address = *pTargetAddress;
  1216. REFERENCE_OBJECT(pCtl); // Pair in CtlConnectCompleteCallback
  1217. NdisReleaseSpinLock(&pCtl->Lock);
  1218. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"Attempting to connect to remote computer via TCP/IP\n"),
  1219. LOGHDR(17, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  1220. Status = CtdiConnect(pCtl->hCtdiEndpoint,
  1221. (PTRANSPORT_ADDRESS)pTargetAddress,
  1222. CtlConnectCompleteCallback,
  1223. CtlReceiveCallback,
  1224. CtlDisconnectCallback,
  1225. pCtl);
  1226. }
  1227. }
  1228. cmcDone:
  1229. if ( (Status!=NDIS_STATUS_SUCCESS && Status!=NDIS_STATUS_PENDING) || InvalidAddress)
  1230. {
  1231. if (IS_CTL(pCtl))
  1232. {
  1233. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"Connection failed immediately NDIS Error 0x%x\n"),
  1234. LOGHDR(18, pCtl->Remote.Address.Address[0].Address[0].in_addr),Status));
  1235. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, UNLOCKED);
  1236. CtlCleanup(pCtl, UNLOCKED);
  1237. }
  1238. }
  1239. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtlConnectCall %08x\n"), Status));
  1240. return Status;
  1241. }
  1242. NDIS_STATUS
  1243. CtlDisconnectCall(
  1244. IN PCALL_SESSION pCall
  1245. )
  1246. {
  1247. PPPTP_ADAPTER pAdapter = pCall->pAdapter;
  1248. PCONTROL_TUNNEL pCtl = pCall->pCtl;
  1249. BOOLEAN Inbound = pCall->Inbound;
  1250. BOOLEAN CloseTunnelNow = FALSE;
  1251. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1252. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlDisconnectCall\n")));
  1253. ASSERT(IS_CTL(pCtl));
  1254. DEBUGMSG(DBG_CALL, (DTEXT("Call:%08x disconnected\n"), pCall));
  1255. REFERENCE_OBJECT(pCtl);
  1256. CallDisconnectFromCtl(pCall, pCtl);
  1257. NdisAcquireSpinLock(&pAdapter->Lock);
  1258. if (IsListEmpty(&pCtl->CallList))
  1259. {
  1260. if (pCtl->State==STATE_CTL_ESTABLISHED)
  1261. {
  1262. if (!pCtl->Inbound)
  1263. {
  1264. CtlSetState(pCtl, STATE_CTL_WAIT_STOP, 0, LOCKED);
  1265. CloseTunnelNow = TRUE;
  1266. }
  1267. else
  1268. {
  1269. NdisMSetTimer(&pCtl->StopTimeout, PptpMessageTimeout*1000);
  1270. }
  1271. }
  1272. else
  1273. {
  1274. // Tunnel is already gone.
  1275. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, LOCKED);
  1276. NdisReleaseSpinLock(&pAdapter->Lock);
  1277. CtlCleanup(pCtl, UNLOCKED);
  1278. NdisAcquireSpinLock(&pAdapter->Lock);
  1279. }
  1280. }
  1281. NdisReleaseSpinLock(&pAdapter->Lock);
  1282. if (CloseTunnelNow)
  1283. {
  1284. PPPTP_CONTROL_STOP_PACKET pPacket;
  1285. pPacket = CtlAllocPacket(pCtl, CONTROL_STOP_REQUEST);
  1286. if (!pPacket)
  1287. {
  1288. Status = NDIS_STATUS_RESOURCES;
  1289. // Don't attempt to shutdown gracefully. Just close everything.
  1290. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, UNLOCKED);
  1291. CtlCleanup(pCtl, UNLOCKED);
  1292. }
  1293. else
  1294. {
  1295. pPacket->Reason = CONTROL_STOP_GENERAL;
  1296. CtlSend(pCtl, pPacket);
  1297. NdisAcquireSpinLock(&pCtl->Lock);
  1298. NdisMSetTimer(&pCtl->StopTimeout, PptpMessageTimeout*1000);
  1299. NdisReleaseSpinLock(&pCtl->Lock);
  1300. }
  1301. }
  1302. DEREFERENCE_OBJECT(pCtl); // Pair above
  1303. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtlDisconnectCall, %08x\n"), Status));
  1304. return Status;
  1305. }
  1306. NDIS_STATUS
  1307. CtlListen(
  1308. IN PPPTP_ADAPTER pAdapter
  1309. )
  1310. {
  1311. NDIS_STATUS Status;
  1312. TA_IP_ADDRESS Ip;
  1313. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlListen\n")));
  1314. if (pAdapter->hCtdiListen)
  1315. {
  1316. // Already listening. Bail with success.
  1317. Status = NDIS_STATUS_SUCCESS;
  1318. goto clDone;
  1319. }
  1320. NdisZeroMemory(&Ip, sizeof(Ip));
  1321. Ip.TAAddressCount = 1;
  1322. Ip.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  1323. Ip.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1324. Ip.Address[0].Address[0].sin_port = htons(PptpControlPort);
  1325. Ip.Address[0].Address[0].in_addr = 0;
  1326. Status = CtdiCreateEndpoint(&pAdapter->hCtdiListen,
  1327. AF_INET,
  1328. SOCK_STREAM,
  1329. (PTRANSPORT_ADDRESS)&Ip,
  1330. 0);
  1331. if (Status!=NDIS_STATUS_SUCCESS)
  1332. {
  1333. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiCreateEndpoint failed %08x\n"), Status));
  1334. goto clDone;
  1335. }
  1336. Status = CtdiListen(pAdapter->hCtdiListen,
  1337. PptpListensPending,
  1338. CtlConnectQueryCallback,
  1339. CtlReceiveCallback,
  1340. CtlDisconnectCallback,
  1341. pAdapter);
  1342. if (Status!=NDIS_STATUS_SUCCESS)
  1343. {
  1344. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiListen failed %08x\n"), Status));
  1345. goto clDone;
  1346. }
  1347. clDone:
  1348. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtlListen %08x\n"), Status));
  1349. return Status;
  1350. }
  1351. STATIC VOID
  1352. CtlpSendMessageComplete(
  1353. IN PVOID pContext,
  1354. IN PVOID pDatagramContext,
  1355. IN PUCHAR pBuffer,
  1356. IN NDIS_STATUS Result
  1357. )
  1358. {
  1359. PCONTROL_TUNNEL pCtl = pContext;
  1360. UNREFERENCED_PARAMETER(pDatagramContext);
  1361. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlpSendMessageComplete\n")));
  1362. ASSERT(IS_CTL(pCtl));
  1363. if (Result!=NDIS_STATUS_SUCCESS)
  1364. {
  1365. DEBUGMSG(DBG_ERROR, (DTEXT("Failed to send control message %08x\n"), Result));
  1366. // ToDo: code for this failure
  1367. }
  1368. CtlFreePacket(pCtl, pBuffer);
  1369. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlpSendMessageComplete\n")));
  1370. }
  1371. NDIS_STATUS
  1372. CtlSend(
  1373. IN PCONTROL_TUNNEL pCtl,
  1374. IN PVOID pPacketBuffer
  1375. )
  1376. {
  1377. ULONG PacketLength = htons(((UNALIGNED PPTP_HEADER *)pPacketBuffer)->Length);
  1378. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1379. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlSend %08x\n"), pPacketBuffer));
  1380. ASSERT(IS_CTL(pCtl));
  1381. DEBUGMSG(DBG_TUNNEL, (DTEXT("SENDING %s\n"),
  1382. ControlMsgToString( htons(((UNALIGNED PPTP_HEADER *)pPacketBuffer)->MessageType))));
  1383. // Log only if logging is on and not and ECHO message. Do a quick skip for the
  1384. // common case of no logging
  1385. if( (FileLogLevel>=FLL_DETAILED) &&
  1386. (((UNALIGNED PPTP_HEADER *)pPacketBuffer)->MessageType != htons(CONTROL_ECHO_REQUEST)) &&
  1387. (((UNALIGNED PPTP_HEADER *)pPacketBuffer)->MessageType != htons(CONTROL_ECHO_REPLY)))
  1388. {
  1389. LOGMSG(FLL_DETAILED, (DTEXT(LOGHDRS"Sending %s\n"),
  1390. LOGHDR(19, pCtl->Remote.Address.Address[0].Address[0].in_addr),
  1391. ControlMsgToString( htons(((UNALIGNED PPTP_HEADER *)pPacketBuffer)->MessageType))));
  1392. }
  1393. Status = CtdiSend(pCtl->hCtdi,
  1394. CtlpSendMessageComplete,
  1395. pCtl,
  1396. pPacketBuffer,
  1397. PacketLength);
  1398. if (Status==NDIS_STATUS_PENDING)
  1399. {
  1400. Status = NDIS_STATUS_SUCCESS;
  1401. }
  1402. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtlSend %08x\n"), Status));
  1403. return Status;
  1404. }
  1405. CONTROL_STATE
  1406. CtlSetState(
  1407. IN PCONTROL_TUNNEL pCtl,
  1408. IN CONTROL_STATE State,
  1409. IN ULONG_PTR StateParam,
  1410. IN BOOLEAN Locked
  1411. )
  1412. {
  1413. CONTROL_STATE PreviousState;
  1414. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlSetState %08x %d %x\n"), pCtl, State, StateParam));
  1415. ASSERT(IS_CTL(pCtl));
  1416. if (!Locked)
  1417. {
  1418. NdisAcquireSpinLock(&pCtl->pAdapter->Lock);
  1419. }
  1420. PreviousState = pCtl->State;
  1421. pCtl->State = State;
  1422. if (!Locked)
  1423. {
  1424. NdisReleaseSpinLock(&pCtl->pAdapter->Lock);
  1425. }
  1426. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlSetState\n")));
  1427. return PreviousState;
  1428. }
  1429. // StanA: lift some functions from L2TP to convert an IP address to text
  1430. VOID
  1431. ReversePsz(
  1432. IN OUT CHAR* psz )
  1433. // Reverse the order of the characters in 'psz' in place.
  1434. //
  1435. {
  1436. CHAR* pchLeft;
  1437. CHAR* pchRight;
  1438. pchLeft = psz;
  1439. pchRight = psz + strlen( psz ) - 1;
  1440. while (pchLeft < pchRight)
  1441. {
  1442. CHAR ch;
  1443. ch = *pchLeft;
  1444. *pchLeft++ = *pchRight;
  1445. *pchRight-- = ch;
  1446. }
  1447. }
  1448. VOID
  1449. ultoa(
  1450. IN ULONG ul,
  1451. OUT CHAR* pszBuf )
  1452. // Convert 'ul' to null-terminated string form in caller's 'pszBuf'. It's
  1453. // caller job to make sure 'pszBuf' is long enough to hold the returned
  1454. // string.
  1455. //
  1456. {
  1457. CHAR* pch;
  1458. pch = pszBuf;
  1459. do
  1460. {
  1461. *pch++ = (CHAR )((ul % 10) + '0');
  1462. ul /= 10;
  1463. }
  1464. while (ul);
  1465. *pch = '\0';
  1466. ReversePsz( pszBuf );
  1467. }
  1468. PWCHAR
  1469. StringToIpAddressW(
  1470. IN PWCHAR pszIpAddress,
  1471. IN OUT PTA_IP_ADDRESS pAddress,
  1472. OUT PBOOLEAN pValidAddress
  1473. )
  1474. // Convert an address of the form #.#.#.#[:#][ \0] to a binary ip address
  1475. // [ and optional port ]
  1476. // Return a pointer to the end of the address. If the string is determined
  1477. // to not contain an IP address, return the passed-in pszIpAddress unchanged
  1478. // ToDo: IPv6
  1479. {
  1480. PWCHAR pStartString = pszIpAddress;
  1481. ULONG Octet;
  1482. ULONG NumOctets;
  1483. ULONG IpAddress = INADDR_NONE;
  1484. ULONG Port = PptpControlPort;
  1485. *pValidAddress = FALSE;
  1486. // Find the first digit.
  1487. while (*pszIpAddress && (*pszIpAddress<L'0' || *pszIpAddress>L'9'))
  1488. {
  1489. pszIpAddress++;
  1490. }
  1491. if (!*pszIpAddress)
  1492. {
  1493. return pStartString;
  1494. }
  1495. for (NumOctets = 0; NumOctets<4 && *pszIpAddress; NumOctets++)
  1496. {
  1497. Octet = 0;
  1498. while (*pszIpAddress && *pszIpAddress>=L'0' && *pszIpAddress<=L'9')
  1499. {
  1500. Octet = Octet * 10 + *pszIpAddress - L'0';
  1501. if (Octet>0xff)
  1502. {
  1503. return pStartString;
  1504. }
  1505. pszIpAddress++;
  1506. }
  1507. if (NumOctets < 3)
  1508. {
  1509. if (*pszIpAddress!='.' || *(++pszIpAddress) < L'0' || *pszIpAddress > L'9')
  1510. {
  1511. return pStartString;
  1512. }
  1513. }
  1514. IpAddress = (IpAddress << 8) + Octet;
  1515. }
  1516. if (*pszIpAddress==':')
  1517. {
  1518. // They've also specified the port. Parse it.
  1519. while (*pszIpAddress && *pszIpAddress>=L'0' && *pszIpAddress<=L'9')
  1520. {
  1521. Port = Port * 10 + *pszIpAddress - L'0';
  1522. if (Port>0xffff)
  1523. {
  1524. return pStartString;
  1525. }
  1526. pszIpAddress++;
  1527. }
  1528. }
  1529. pAddress->TAAddressCount = 1;
  1530. pAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  1531. pAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1532. pAddress->Address[0].Address[0].sin_port = htons((USHORT)Port);
  1533. pAddress->Address[0].Address[0].in_addr = htonl(IpAddress);
  1534. *pValidAddress = TRUE;
  1535. return pszIpAddress;
  1536. }
  1537. PUCHAR
  1538. StringToIpAddress(
  1539. IN PUCHAR pszIpAddress,
  1540. IN OUT PTA_IP_ADDRESS pAddress,
  1541. OUT PBOOLEAN pValidAddress
  1542. )
  1543. // Convert an address of the form #.#.#.#[:#][ \0] to a binary ip address
  1544. // [ and optional port ]
  1545. // Return a pointer to the end of the address. If the string is determined
  1546. // to not contain an IP address, return the passed-in pszIpAddress unchanged
  1547. // ToDo: IPv6
  1548. {
  1549. PUCHAR pStartString = pszIpAddress;
  1550. ULONG Octet;
  1551. ULONG NumOctets;
  1552. ULONG IpAddress = INADDR_NONE;
  1553. ULONG Port = PptpControlPort;
  1554. *pValidAddress = FALSE;
  1555. // Find the first digit.
  1556. while (*pszIpAddress && (*pszIpAddress<'0' || *pszIpAddress>'9'))
  1557. {
  1558. pszIpAddress++;
  1559. }
  1560. if (!*pszIpAddress)
  1561. {
  1562. return pStartString;
  1563. }
  1564. for (NumOctets = 0; NumOctets<4 && *pszIpAddress; NumOctets++)
  1565. {
  1566. Octet = 0;
  1567. while (*pszIpAddress && *pszIpAddress>='0' && *pszIpAddress<='9')
  1568. {
  1569. Octet = Octet * 10 + *pszIpAddress - '0';
  1570. if (Octet>0xff)
  1571. {
  1572. return pStartString;
  1573. }
  1574. pszIpAddress++;
  1575. }
  1576. if (NumOctets < 3)
  1577. {
  1578. if (*pszIpAddress!='.' || *(++pszIpAddress) < '0' || *pszIpAddress > '9')
  1579. {
  1580. return pStartString;
  1581. }
  1582. }
  1583. IpAddress = (IpAddress << 8) + Octet;
  1584. }
  1585. if (*pszIpAddress==':')
  1586. {
  1587. // They've also specified the port. Parse it.
  1588. while (*pszIpAddress && *pszIpAddress>='0' && *pszIpAddress<='9')
  1589. {
  1590. Port = Port * 10 + *pszIpAddress - '0';
  1591. if (Port>0xffff)
  1592. {
  1593. return pStartString;
  1594. }
  1595. pszIpAddress++;
  1596. }
  1597. }
  1598. pAddress->TAAddressCount = 1;
  1599. pAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  1600. pAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1601. pAddress->Address[0].Address[0].sin_port = htons((USHORT)Port);
  1602. pAddress->Address[0].Address[0].in_addr = htonl(IpAddress);
  1603. *pValidAddress = TRUE;
  1604. return pszIpAddress;
  1605. }
  1606. VOID
  1607. IpAddressToString(
  1608. IN ULONG ulIpAddress,
  1609. OUT CHAR* pszIpAddress )
  1610. // Converts network byte-ordered IP addresss 'ulIpAddress' to a string in
  1611. // the a.b.c.d form and returns same in caller's 'pszIpAddress' buffer.
  1612. // The buffer should be at least 16 characters long.
  1613. //
  1614. // ToDo: IPv6
  1615. {
  1616. CHAR szBuf[ 3 + 1 ];
  1617. ULONG ulA = (ulIpAddress & 0xFF000000) >> 24;
  1618. ULONG ulB = (ulIpAddress & 0x00FF0000) >> 16;
  1619. ULONG ulC = (ulIpAddress & 0x0000FF00) >> 8;
  1620. ULONG ulD = (ulIpAddress & 0x000000FF);
  1621. ultoa( ulA, szBuf );
  1622. strcpy( pszIpAddress, szBuf );
  1623. strcat( pszIpAddress, "." );
  1624. ultoa( ulB, szBuf );
  1625. strcat( pszIpAddress, szBuf );
  1626. strcat( pszIpAddress, "." );
  1627. ultoa( ulC, szBuf );
  1628. strcat( pszIpAddress, szBuf );
  1629. strcat( pszIpAddress, "." );
  1630. ultoa( ulD, szBuf );
  1631. strcat( pszIpAddress, szBuf );
  1632. }
  1633. VOID
  1634. CtlpEchoTimeout(
  1635. IN PVOID SystemSpecific1,
  1636. IN PVOID pContext,
  1637. IN PVOID SystemSpecific2,
  1638. IN PVOID SystemSpecific3
  1639. )
  1640. {
  1641. PCONTROL_TUNNEL pCtl = pContext;
  1642. PPTP_CONTROL_ECHO_REQUEST_PACKET *pPacket;
  1643. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlpEchoTimeout\n")));
  1644. NdisAcquireSpinLock(&pCtl->Lock);
  1645. // Don't take the adapter lock because we're only reading the State
  1646. if (pCtl->State!=STATE_CTL_CLEANUP)
  1647. {
  1648. BOOLEAN DoEcho = pCtl->Echo.Needed;
  1649. LONG Identifier = ++(pCtl->Echo.Identifier);
  1650. pCtl->Echo.Needed = TRUE;
  1651. NdisReleaseSpinLock(&pCtl->Lock);
  1652. if (DoEcho)
  1653. {
  1654. pPacket = CtlAllocPacket(pCtl, CONTROL_ECHO_REQUEST);
  1655. if (pPacket)
  1656. {
  1657. pPacket->Identifier = Identifier;
  1658. // ToDo: deal with V2 stuff
  1659. CtlSend(pCtl, pPacket);
  1660. }
  1661. }
  1662. }
  1663. else
  1664. {
  1665. NdisReleaseSpinLock(&pCtl->Lock);
  1666. }
  1667. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlpEchoTimeout\n")));
  1668. }
  1669. VOID
  1670. CtlpDeathTimeout(
  1671. IN PVOID SystemSpecific1,
  1672. IN PVOID pContext,
  1673. IN PVOID SystemSpecific2,
  1674. IN PVOID SystemSpecific3
  1675. )
  1676. {
  1677. PCONTROL_TUNNEL pCtl = pContext;
  1678. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlpDeathTimeout\n")));
  1679. LOGMSG(FLL_USER, (DTEXT(LOGHDRS"Fatal timeout\n"),
  1680. LOGHDR(22, pCtl->Remote.Address.Address[0].Address[0].in_addr)));
  1681. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, UNLOCKED);
  1682. CtlCleanup(pCtl, UNLOCKED);
  1683. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlpDeathTimeout\n")));
  1684. }
  1685. VOID
  1686. CtlpCleanupLooseEnds(
  1687. PPPTP_ADAPTER pAdapter
  1688. )
  1689. {
  1690. ENUM_CONTEXT Enum;
  1691. PLIST_ENTRY pListEntry;
  1692. PCONTROL_TUNNEL pCtl;
  1693. DEBUGMSG(DBG_FUNC, (DTEXT("+CtlpCleanupLooseEnds\n")));
  1694. NdisAcquireSpinLock(&pAdapter->Lock);
  1695. InitEnumContext(&Enum);
  1696. while (pListEntry = EnumListEntry(&pAdapter->ControlTunnelList, &Enum, NULL))
  1697. {
  1698. pCtl = CONTAINING_RECORD(pListEntry, CONTROL_TUNNEL, ListEntry);
  1699. if (pCtl->State==STATE_CTL_CLEANUP)
  1700. {
  1701. // REFERENCE the Ctl so it doesn't go away before we call CtlCleanup
  1702. REFERENCE_OBJECT(pCtl);
  1703. NdisReleaseSpinLock(&pAdapter->Lock);
  1704. CtlCleanup(pCtl, UNLOCKED);
  1705. DEREFERENCE_OBJECT(pCtl); // Pair above
  1706. NdisAcquireSpinLock(&pAdapter->Lock);
  1707. }
  1708. }
  1709. EnumComplete(&Enum, NULL);
  1710. NdisReleaseSpinLock(&pAdapter->Lock);
  1711. DEBUGMSG(DBG_FUNC, (DTEXT("-CtlpCleanupLooseEnds\n")));
  1712. }
  1713. NDIS_STATUS
  1714. PptpInitialize(
  1715. PPPTP_ADAPTER pAdapter
  1716. )
  1717. {
  1718. NDIS_STATUS Status;
  1719. TA_IP_ADDRESS Local;
  1720. HANDLE hCtdi;
  1721. DEBUGMSG(DBG_FUNC, (DTEXT("+PptpInitialize\n")));
  1722. Status = CtdiInitialize(CTDI_FLAG_ENABLE_ROUTING|CTDI_FLAG_NETWORK_HEADER);
  1723. if (Status!=STATUS_SUCCESS)
  1724. {
  1725. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiInitialize failed %08x\n"), Status));
  1726. goto piDone;
  1727. }
  1728. if (!pAdapter->hCtdiDg && !(PptpTunnelConfig&CONFIG_DONT_ACCEPT_GRE))
  1729. {
  1730. NdisZeroMemory(&Local, sizeof(Local));
  1731. Local.TAAddressCount = 1;
  1732. Local.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  1733. Local.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1734. Local.Address[0].Address[0].sin_port = PptpProtocolNumber;
  1735. Local.Address[0].Address[0].in_addr = 0;
  1736. Status = CtdiCreateEndpoint(&hCtdi,
  1737. AF_INET,
  1738. SOCK_RAW, //ToDo: RAWIP?
  1739. (PTRANSPORT_ADDRESS)&Local,
  1740. sizeof(DGRAM_CONTEXT));
  1741. if (Status!=NDIS_STATUS_SUCCESS)
  1742. {
  1743. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiCreateEndpoint failed %08x\n"), Status));
  1744. goto piDone;
  1745. }
  1746. NdisAcquireSpinLock(&pAdapter->Lock);
  1747. pAdapter->hCtdiDg = hCtdi;
  1748. NdisReleaseSpinLock(&pAdapter->Lock);
  1749. Status = CtdiSetEventHandler(pAdapter->hCtdiDg,
  1750. TDI_EVENT_RECEIVE_DATAGRAM,
  1751. CallReceiveDatagramCallback,
  1752. pAdapter);
  1753. if (Status!=NDIS_STATUS_SUCCESS)
  1754. {
  1755. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiSetEventHandler failed %08x\n"), Status));
  1756. goto piDone;
  1757. }
  1758. }
  1759. if (!pAdapter->hCtdiUdp && (PptpTunnelConfig&(CONFIG_ACCEPT_UDP|CONFIG_INITIATE_UDP)))
  1760. {
  1761. NdisZeroMemory(&Local, sizeof(Local));
  1762. Local.TAAddressCount = 1;
  1763. Local.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  1764. Local.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1765. Local.Address[0].Address[0].sin_port = htons(PptpProtocolNumber);
  1766. Local.Address[0].Address[0].in_addr = 0;
  1767. Status = CtdiCreateEndpoint(&hCtdi,
  1768. AF_INET,
  1769. SOCK_DGRAM,
  1770. (PTRANSPORT_ADDRESS)&Local,
  1771. sizeof(DGRAM_CONTEXT));
  1772. if (Status!=NDIS_STATUS_SUCCESS)
  1773. {
  1774. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiCreateEndpoint (UDP) failed %08x\n"), Status));
  1775. goto piDone;
  1776. }
  1777. NdisAcquireSpinLock(&pAdapter->Lock);
  1778. pAdapter->hCtdiUdp = hCtdi;
  1779. NdisReleaseSpinLock(&pAdapter->Lock);
  1780. Status = CtdiSetEventHandler(pAdapter->hCtdiUdp,
  1781. TDI_EVENT_RECEIVE_DATAGRAM,
  1782. CallReceiveUdpCallback,
  1783. pAdapter);
  1784. if (Status!=NDIS_STATUS_SUCCESS)
  1785. {
  1786. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiSetEventHandler failed %08x\n"), Status));
  1787. goto piDone;
  1788. }
  1789. }
  1790. piDone:
  1791. if (Status==STATUS_SUCCESS)
  1792. {
  1793. PptpInitialized = TRUE;
  1794. }
  1795. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-PptpInitialize %08x\n"), Status));
  1796. return Status;
  1797. }
  1798. CHAR *pControlMessageStrings[] =
  1799. {
  1800. "INVALID CONTROL MESSAGE NUMBER", // 0
  1801. "CONTROL_START_REQUEST", // 1
  1802. "CONTROL_START_REPLY", // 2
  1803. "CONTROL_STOP_REQUEST", // 3
  1804. "CONTROL_STOP_REPLY", // 4
  1805. "CONTROL_ECHO_REQUEST", // 5
  1806. "CONTROL_ECHO_REPLY", // 6
  1807. "CALL_OUT_REQUEST", // 7
  1808. "CALL_OUT_REPLY", // 8
  1809. "CALL_IN_REQUEST", // 9
  1810. "CALL_IN_REPLY", // 10
  1811. "CALL_IN_CONNECTED", // 11
  1812. "CALL_CLEAR_REQUEST", // 12
  1813. "CALL_DISCONNECT_NOTIFY", // 13
  1814. "WAN_ERROR_NOTIFY", // 14
  1815. "SET_LINK_INFO", // 15
  1816. };
  1817. CHAR *ControlMsgToString( ULONG Message )
  1818. {
  1819. if( Message >= NUM_MESSAGE_TYPES ){
  1820. return pControlMessageStrings[0];
  1821. }else{
  1822. return pControlMessageStrings[Message];
  1823. }
  1824. }
  1825. VOID
  1826. CtlpCleanupCtls(
  1827. PPPTP_ADAPTER pAdapter
  1828. )
  1829. {
  1830. ENUM_CONTEXT Enum;
  1831. PLIST_ENTRY pListEntry;
  1832. PCONTROL_TUNNEL pCtl;
  1833. NdisAcquireSpinLock(&pAdapter->Lock);
  1834. InitEnumContext(&Enum);
  1835. while (pListEntry = EnumListEntry(&pAdapter->ControlTunnelList, &Enum, NULL))
  1836. {
  1837. pCtl = CONTAINING_RECORD(pListEntry, CONTROL_TUNNEL, ListEntry);
  1838. // REFERENCE the Ctl so it doesn't go away before we call CtlCleanup
  1839. REFERENCE_OBJECT(pCtl);
  1840. NdisReleaseSpinLock(&pAdapter->Lock);
  1841. CtlSetState(pCtl, STATE_CTL_CLEANUP, 0, UNLOCKED);
  1842. CtlCleanup(pCtl, UNLOCKED);
  1843. DEREFERENCE_OBJECT(pCtl); // Pair above
  1844. NdisAcquireSpinLock(&pAdapter->Lock);
  1845. }
  1846. EnumComplete(&Enum, NULL);
  1847. NdisReleaseSpinLock(&pAdapter->Lock);
  1848. }