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.

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