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.

3975 lines
129 KiB

  1. //depot/Lab03_N/Net/rras/ndis/raspptp/nt/ctdi.c#10 - edit change 19457 (text)
  2. /*******************************************************************
  3. *
  4. * Copyright (c) 1998-1999 Microsoft Corporation
  5. *
  6. * DESCRIPTION: CTDI.C - Common TDI layer, for NT
  7. *
  8. * AUTHOR: Stan Adermann (StanA)
  9. *
  10. * DATE:9/29/1998
  11. *
  12. *******************************************************************/
  13. /** include files **/
  14. #include "raspptp.h"
  15. #include "bpool.h"
  16. #include "tcpinfo.h"
  17. #include "ctdi.tmh"
  18. #if VER_PRODUCTVERSION_W >= 0x0500
  19. #define IP_ROUTE_REFCOUNT
  20. #endif
  21. /** local definitions **/
  22. typedef enum {
  23. CTDI_REF_CONNECT = 0,
  24. CTDI_REF_ASSOADDR,
  25. CTDI_REF_SETEVENT,
  26. CTDI_REF_ADDRREF,
  27. CTDI_REF_LIST,
  28. CTDI_REF_REPLENISH,
  29. CTDI_REF_DISASSO,
  30. CTDI_REF_DISCONNECT,
  31. CTDI_REF_RECVDG,
  32. CTDI_REF_SEND,
  33. CTDI_REF_SENDDG,
  34. CTDI_REF_QUERY,
  35. CTDI_REF_INLISTEN,
  36. CTDI_REF_INITIAL,
  37. CTDI_REF_UNKNOWN,
  38. CTDI_REF_MAX
  39. } CTDI_REF;
  40. #if DBG
  41. #define CTDI_F_BUILD_ASSOCADDR 0x00000001
  42. #define CTDI_F_ASSOCADDR_CALLBACK 0x00000002
  43. #define CTDI_F_ACCEPT 0x00000004
  44. #define CTDI_F_CONNECTCOMP_CALLBACK 0x00000008
  45. #define CTDI_F_DISCONNECT_CALLBACK 0x00000010
  46. #define CTDI_F_DISCONNECT 0x00000020
  47. #define CTDI_F_BUILD_DISCONNECT_1 0x00000040
  48. #define CTDI_F_BUILD_DISCONNECT_2 0x00000080
  49. #define CTDI_F_DISCONNECTCOMP_CALLBACK 0x00000100
  50. #define CTDI_F_DISCONNECT_CLEANUP 0x00000200
  51. #define CTDI_F_BUILD_DISASSOC 0x00001000
  52. #define CTDI_F_DISASSOC_CALLBACK 0x00002000
  53. #endif
  54. #define CTDI_SIGNATURE 'IDTC'
  55. #define NUM_TCP_LISTEN 5
  56. #define CTDI_UNKNOWN 'NKNU'
  57. #define CTDI_ENDPOINT 'PDNE'
  58. #define CTDI_DATAGRAM 'MRGD'
  59. #define CTDI_LISTEN 'TSIL'
  60. #define CTDI_CONNECTION 'NNOC'
  61. #define PROBE 0
  62. #define IS_CTDI(c) ((c) && (c)->Signature==CTDI_SIGNATURE)
  63. typedef struct CTDI_DATA * PCTDI_DATA;
  64. typedef struct CTDI_DATA {
  65. LIST_ENTRY ListEntry;
  66. ULONG Signature;
  67. ULONG Type;
  68. REFERENCE_COUNT Reference;
  69. HANDLE hFile;
  70. PFILE_OBJECT pFileObject;
  71. NDIS_SPIN_LOCK Lock;
  72. BOOLEAN Closed;
  73. BOOLEAN CloseReqPending;
  74. CTDI_EVENT_CONNECT_QUERY ConnectQueryCallback;
  75. CTDI_EVENT_CONNECT_COMPLETE ConnectCompleteCallback;
  76. CTDI_EVENT_DISCONNECT DisconnectCallback;
  77. CTDI_EVENT_RECEIVE RecvCallback;
  78. PVOID RecvContext;
  79. CTDI_EVENT_RECEIVE_DATAGRAM RecvDatagramCallback;
  80. CTDI_EVENT_SEND_COMPLETE SendCompleteCallback;
  81. CTDI_EVENT_QUERY_COMPLETE QueryCompleteCallback;
  82. CTDI_EVENT_SET_COMPLETE SetCompleteCallback;
  83. union {
  84. struct {
  85. PVOID Context;
  86. LIST_ENTRY ConnectList;
  87. ULONG NumConnection;
  88. } Listen;
  89. struct {
  90. PVOID Context;
  91. PCTDI_DATA LocalEndpoint;
  92. PVOID ConnectInfo;
  93. TA_IP_ADDRESS RemoteAddress;
  94. LIST_ENTRY ListEntry;
  95. ULONG DisconnectCount;
  96. union {
  97. BOOLEAN Disconnect;
  98. ULONG_PTR Padding1;
  99. };
  100. union {
  101. BOOLEAN Abort;
  102. ULONG_PTR Padding2;
  103. };
  104. } Connection;
  105. struct {
  106. BUFFERPOOL RxPool;
  107. } Datagram;
  108. };
  109. LIST_ENTRY TxActiveIrpList;
  110. #if DBG
  111. ULONG arrRef[16];
  112. ULONG DbgFlags;
  113. BOOLEAN bRef;
  114. #endif
  115. } CTDI_DATA, *PCTDI_DATA;
  116. #if DBG
  117. #define SET_DBGFLAG(_p, _f) (_p)->DbgFlags |= (_f)
  118. #else
  119. #define SET_DBGFLAG(_p, _f)
  120. #endif
  121. typedef struct {
  122. PVOID Context;
  123. CTDI_EVENT_SEND_COMPLETE pSendCompleteCallback;
  124. } CTDI_SEND_CONTEXT, *PCTDI_SEND_CONTEXT;
  125. typedef struct {
  126. PVOID Context;
  127. CTDI_EVENT_QUERY_COMPLETE pQueryCompleteCallback;
  128. } CTDI_QUERY_CONTEXT, *PCTDI_QUERY_CONTEXT;
  129. typedef struct {
  130. PVOID Context;
  131. PVOID DatagramContext;
  132. CTDI_EVENT_SEND_COMPLETE pSendCompleteCallback;
  133. TDI_CONNECTION_INFORMATION TdiConnectionInfo;
  134. TA_IP_ADDRESS Ip;
  135. } CTDI_SEND_DATAGRAM_CONTEXT, *PCTDI_SEND_DATAGRAM_CONTEXT;
  136. #define BLOCKS_NEEDED_FOR_SIZE(BlockSize, Size) ((Size)/(BlockSize) + ((((Size)/(BlockSize))*(BlockSize) < (Size)) ? 1 : 0 ))
  137. #define NUM_STACKS_FOR_CONTEXT(ContextSize) \
  138. BLOCKS_NEEDED_FOR_SIZE(sizeof(IO_STACK_LOCATION), (ContextSize))
  139. STATIC PVOID __inline
  140. GetContextArea(
  141. PIRP pIrp,
  142. ULONG ContextSize
  143. )
  144. {
  145. #if 0
  146. ULONG i;
  147. for (i=0; i<BLOCKS_NEEDED_FOR_SIZE(sizeof(IO_STACK_LOCATION), ContextSize); i++)
  148. IoSetNextIrpStackLocation(pIrp);
  149. #else
  150. ULONG NumStacks = BLOCKS_NEEDED_FOR_SIZE(sizeof(IO_STACK_LOCATION), ContextSize);
  151. pIrp->CurrentLocation -= (CHAR)NumStacks;
  152. pIrp->Tail.Overlay.CurrentStackLocation -= NumStacks;
  153. #endif
  154. ASSERT(BLOCKS_NEEDED_FOR_SIZE(sizeof(IO_STACK_LOCATION), ContextSize)<=2);
  155. return IoGetCurrentIrpStackLocation(pIrp);
  156. }
  157. #define GET_CONTEXT(Irp, Context) (Context*)GetContextArea((Irp), sizeof(Context))
  158. STATIC VOID __inline
  159. ReleaseContextArea(
  160. PIRP pIrp,
  161. ULONG ContextSize
  162. )
  163. {
  164. ULONG NumStacks = BLOCKS_NEEDED_FOR_SIZE(sizeof(IO_STACK_LOCATION), ContextSize) - 1;
  165. pIrp->CurrentLocation += (CHAR)NumStacks;
  166. pIrp->Tail.Overlay.CurrentStackLocation += NumStacks;
  167. }
  168. #define RELEASE_CONTEXT(Irp, Context) ReleaseContextArea((Irp), sizeof(Context))
  169. typedef struct {
  170. LIST_ENTRY ListEntry;
  171. REFERENCE_COUNT Reference;
  172. ULONG IpAddress;
  173. BOOLEAN ExternalRoute;
  174. } CTDI_ROUTE, *PCTDI_ROUTE;
  175. typedef struct {
  176. LIST_ENTRY ListEntry;
  177. IPNotifyData Data;
  178. } CTDI_ROUTE_NOTIFY, *PCTDI_ROUTE_NOTIFY;
  179. /* default settings */
  180. /** external functions **/
  181. /** external data **/
  182. /** public data **/
  183. LIST_ENTRY CtdiList;
  184. LIST_ENTRY CtdiFreeList;
  185. LIST_ENTRY CtdiRouteList;
  186. //LIST_ENTRY CtdiRouteNotifyList;
  187. NDIS_SPIN_LOCK CtdiListLock;
  188. HANDLE hTcp = 0;
  189. PFILE_OBJECT pFileTcp = NULL;
  190. HANDLE hIp = 0;
  191. PFILE_OBJECT pFileIp = NULL;
  192. ULONG CtdiTcpDisconnectTimeout = 30; // Seconds
  193. ULONG CtdiTcpConnectTimeout = 30;
  194. /** private data **/
  195. BOOLEAN fCtdiInitialized = FALSE;
  196. CSHORT CtdiMdlFlags = 0;
  197. /** private functions **/
  198. NDIS_STATUS
  199. CtdiAddHostRoute(
  200. IN PTA_IP_ADDRESS pIpAddress
  201. );
  202. NDIS_STATUS
  203. CtdiDeleteHostRoute(
  204. IN PTA_IP_ADDRESS pIpAddress
  205. );
  206. STATIC VOID
  207. CtdipIpRequestRoutingNotification(
  208. IN ULONG IpAddress
  209. );
  210. STATIC VOID
  211. CtdipCloseProtocol(
  212. HANDLE hFile,
  213. PFILE_OBJECT pFileObject
  214. )
  215. {
  216. NTSTATUS NtStatus;
  217. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipCloseProtocol\n")));
  218. ASSERT(KeGetCurrentIrql()<DISPATCH_LEVEL);
  219. if (pFileObject)
  220. {
  221. ObDereferenceObject(pFileObject);
  222. }
  223. NtStatus = ZwClose(hFile);
  224. if (NtStatus!=STATUS_SUCCESS)
  225. {
  226. DEBUGMSG(DBG_ERROR, (DTEXT("ZwClose(hFile) failed %08x\n"), NtStatus));
  227. WPLOG(LL_A, LM_TDI, ("ZwClose(hFile) failed %08x", NtStatus));
  228. }
  229. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipCloseProtocol\n")));
  230. }
  231. STATIC VOID
  232. CtdipDataFreeWorker(
  233. IN PPPTP_WORK_ITEM pWorkItem
  234. )
  235. {
  236. PCTDI_DATA pCtdi;
  237. NTSTATUS NtStatus;
  238. PLIST_ENTRY ListEntry;
  239. BOOLEAN FoundEntry = FALSE;
  240. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipDataFreeWorker\n")));
  241. while (ListEntry = MyInterlockedRemoveHeadList(&CtdiFreeList, &CtdiListLock))
  242. {
  243. pCtdi = CONTAINING_RECORD(ListEntry, CTDI_DATA, ListEntry);
  244. if (pCtdi->Type==CTDI_DATAGRAM)
  245. {
  246. FreeBufferPool(&pCtdi->Datagram.RxPool);
  247. }
  248. if (pCtdi->hFile)
  249. {
  250. CtdipCloseProtocol(pCtdi->hFile, pCtdi->pFileObject);
  251. pCtdi->pFileObject = NULL;
  252. pCtdi->hFile = NULL;
  253. }
  254. NdisFreeSpinLock(&pCtdi->Lock);
  255. pCtdi->Signature = 0;
  256. if(pCtdi->Type == CTDI_LISTEN)
  257. {
  258. if(pCtdi->CloseReqPending)
  259. {
  260. // TapiClose pended this request, complete it now
  261. DEBUGMSG(DBG_TDI, (DTEXT("Complete TapiClose request\n")));
  262. ASSERT(pgAdapter);
  263. NdisMSetInformationComplete(pgAdapter->hMiniportAdapter, NDIS_STATUS_SUCCESS);
  264. }
  265. }
  266. MyMemFree(pCtdi, sizeof(CTDI_DATA));
  267. }
  268. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipDataFreeWorker\n")));
  269. }
  270. STATIC VOID
  271. CtdipDataFree(
  272. PCTDI_DATA pCtdi
  273. )
  274. // This should only be called by DEREFERENCE_OBJECT
  275. {
  276. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipDataFree\n")));
  277. NdisAcquireSpinLock(&CtdiListLock);
  278. RemoveEntryList(&pCtdi->ListEntry);
  279. InsertTailList(&CtdiFreeList, &pCtdi->ListEntry);
  280. pCtdi->Signature = 0;
  281. NdisReleaseSpinLock(&CtdiListLock);
  282. ScheduleWorkItem(CtdipDataFreeWorker, NULL, NULL, 0);
  283. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipDataFree\n")));
  284. }
  285. STATIC PCTDI_DATA
  286. CtdipDataAlloc()
  287. {
  288. PCTDI_DATA pCtdi;
  289. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipDataAlloc\n")));
  290. pCtdi = MyMemAlloc(sizeof(CTDI_DATA), TAG_CTDI_DATA);
  291. if (!pCtdi)
  292. {
  293. WPLOG(LL_A, LM_Res, ("Failed to alloc CTDI"));
  294. return NULL;
  295. }
  296. NdisZeroMemory(pCtdi, sizeof(CTDI_DATA));
  297. pCtdi->Signature = CTDI_SIGNATURE;
  298. pCtdi->Type = CTDI_UNKNOWN;
  299. INIT_REFERENCE_OBJECT(pCtdi, CtdipDataFree); // pair in CtdiClose
  300. NdisInitializeListHead(&pCtdi->TxActiveIrpList);
  301. NdisAllocateSpinLock(&pCtdi->Lock);
  302. MyInterlockedInsertHeadList(&CtdiList, &pCtdi->ListEntry, &CtdiListLock);
  303. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipDataAlloc %08x\n"), pCtdi));
  304. return pCtdi;
  305. }
  306. STATIC NDIS_STATUS
  307. CtdipIpQueryRouteTable(
  308. OUT IPRouteEntry **ppQueryBuffer,
  309. OUT PULONG pQuerySize,
  310. OUT PULONG pNumRoutes
  311. )
  312. {
  313. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  314. ULONG NumRoutes = 20;
  315. ULONG QuerySize = 0;
  316. TCP_REQUEST_QUERY_INFORMATION_EX QueryRoute;
  317. IPRouteEntry *pQueryBuffer = NULL;
  318. PIO_STACK_LOCATION IrpSp;
  319. IO_STATUS_BLOCK IoStatusBlock;
  320. PIRP pIrp;
  321. KEVENT Event;
  322. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipIpQueryRouteTable\n")));
  323. if (!fCtdiInitialized)
  324. {
  325. Status = NDIS_STATUS_FAILURE;
  326. goto ciqrtDone;
  327. }
  328. // Query TCPfor the current routing table
  329. QueryRoute.ID.toi_entity.tei_entity = CL_NL_ENTITY;
  330. QueryRoute.ID.toi_entity.tei_instance = 0;
  331. QueryRoute.ID.toi_class = INFO_CLASS_PROTOCOL;
  332. QueryRoute.ID.toi_type = INFO_TYPE_PROVIDER;
  333. do
  334. {
  335. QuerySize = sizeof(IPRouteEntry) * NumRoutes;
  336. QueryRoute.ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  337. NdisZeroMemory(&QueryRoute.Context, CONTEXT_SIZE);
  338. pQueryBuffer = MyMemAlloc(QuerySize, TAG_CTDI_ROUTE);
  339. if (!pQueryBuffer)
  340. {
  341. // ToDo: free the new pRoute
  342. WPLOG(LL_A, LM_Res, ("Failed to alloc query CTDI_ROUTE size %d", QuerySize));
  343. Status = NDIS_STATUS_RESOURCES;
  344. goto ciqrtDone;
  345. }
  346. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  347. pIrp = IoBuildDeviceIoControlRequest(IOCTL_TCP_QUERY_INFORMATION_EX,
  348. pFileTcp->DeviceObject,
  349. &QueryRoute,
  350. sizeof(QueryRoute),
  351. pQueryBuffer,
  352. QuerySize,
  353. FALSE,
  354. &Event,
  355. &IoStatusBlock);
  356. if (!pIrp)
  357. {
  358. WPLOG(LL_A, LM_Res, ("Failed to build TCP_QUERY_INFORMATION IRP"));
  359. gCounters.ulIoBuildIrpFail++;
  360. Status = NDIS_STATUS_RESOURCES;
  361. goto ciqrtDone;
  362. }
  363. IrpSp = IoGetNextIrpStackLocation(pIrp);
  364. IrpSp->FileObject = pFileTcp;
  365. Status = IoCallDriver(pFileTcp->DeviceObject, pIrp);
  366. if (Status == STATUS_PENDING) {
  367. KeWaitForSingleObject(&Event,
  368. Executive,
  369. KernelMode,
  370. FALSE,
  371. NULL);
  372. Status = IoStatusBlock.Status;
  373. }
  374. if (Status==STATUS_BUFFER_OVERFLOW)
  375. {
  376. // We have no idea of the size of the routing table and no good
  377. // way to find out, so we just loop, increasing our buffer until
  378. // we win or die
  379. MyMemFree(pQueryBuffer, QuerySize);
  380. pQueryBuffer = NULL;
  381. NumRoutes *= 2;
  382. }
  383. else if (Status!=STATUS_SUCCESS)
  384. {
  385. DEBUGMSG(DBG_TDI, (DTEXT("Failed to query complete routing table %08x\n"), Status));
  386. WPLOG(LL_A, LM_TDI, ("Failed to query complete routing table %08x", Status));
  387. goto ciqrtDone;
  388. }
  389. } while ( Status==STATUS_BUFFER_OVERFLOW );
  390. NumRoutes = (ULONG)(IoStatusBlock.Information / sizeof(IPRouteEntry));
  391. ciqrtDone:
  392. if (Status == NDIS_STATUS_SUCCESS)
  393. {
  394. ASSERT(pQueryBuffer);
  395. *ppQueryBuffer = pQueryBuffer;
  396. *pNumRoutes = NumRoutes;
  397. *pQuerySize = QuerySize;
  398. }
  399. else
  400. {
  401. if (pQueryBuffer)
  402. {
  403. MyMemFree(pQueryBuffer, QuerySize);
  404. }
  405. *ppQueryBuffer = NULL;
  406. *pNumRoutes = 0;
  407. *pQuerySize = 0;
  408. }
  409. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipIpQueryRouteTable\n")));
  410. return Status;
  411. }
  412. // Code not used
  413. #if 0
  414. NTSTATUS
  415. CtdipRouteChangeEvent(
  416. IN PDEVICE_OBJECT pDeviceObject,
  417. IN PIRP pIrp,
  418. IN PVOID pContext
  419. )
  420. {
  421. NDIS_STATUS Status;
  422. PCTDI_ROUTE_NOTIFY pNotify = pContext;
  423. ENUM_CONTEXT Enum;
  424. PLIST_ENTRY pListEntry;
  425. PCTDI_DATA pCtdi;
  426. ULONG IpAddress = pNotify->Data.Add;
  427. KIRQL Irql;
  428. IPRouteEntry *pQueryBuffer = NULL;
  429. ULONG NumRoutes = 20;
  430. ULONG QuerySize = 0;
  431. ULONG i;
  432. BOOLEAN RouteWentAway = TRUE;
  433. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipRouteChangeEvent\n")));
  434. DEBUGMSG(DBG_TDI, (DTEXT("Route change irp for %d.%d.%d.%d completed with status %08x\n"),
  435. IPADDR(IpAddress), pIrp->IoStatus.Status));
  436. NdisAcquireSpinLock(&CtdiListLock);
  437. RemoveEntryList(&pNotify->ListEntry);
  438. NdisReleaseSpinLock(&CtdiListLock);
  439. if (!fCtdiInitialized)
  440. {
  441. goto crceDone;
  442. }
  443. if (pIrp->IoStatus.Status==STATUS_SUCCESS)
  444. {
  445. Status = CtdipIpQueryRouteTable(&pQueryBuffer, &QuerySize, &NumRoutes);
  446. if (Status!=NDIS_STATUS_SUCCESS)
  447. {
  448. goto crceDone;
  449. }
  450. for (i=0; i<NumRoutes; i++)
  451. {
  452. if (pQueryBuffer[i].ire_dest == IpAddress &&
  453. pQueryBuffer[i].ire_proto == IRE_PROTO_NETMGMT &&
  454. pQueryBuffer[i].ire_mask == 0xFFFFFFFF)
  455. {
  456. RouteWentAway = FALSE;
  457. break;
  458. }
  459. }
  460. MyMemFree(pQueryBuffer, QuerySize);
  461. if (RouteWentAway)
  462. {
  463. InitEnumContext(&Enum);
  464. while (pListEntry = EnumListEntry(&CtdiList, &Enum, &CtdiListLock))
  465. {
  466. pCtdi = CONTAINING_RECORD(pListEntry,
  467. CTDI_DATA,
  468. ListEntry);
  469. if (IS_CTDI(pCtdi) &&
  470. pCtdi->Type==CTDI_CONNECTION &&
  471. !pCtdi->Closed &&
  472. pCtdi->Connection.RemoteAddress.Address[0].Address[0].in_addr==IpAddress &&
  473. pCtdi->DisconnectCallback)
  474. {
  475. DEBUGMSG(DBG_TDI, (DTEXT("Disconnecting Ctdi:%08x due to route change.\n"),
  476. pCtdi));
  477. pCtdi->DisconnectCallback(pCtdi->Connection.Context, TRUE);
  478. }
  479. }
  480. EnumComplete(&Enum, &CtdiListLock);
  481. }
  482. else
  483. {
  484. CtdipIpRequestRoutingNotification(IpAddress);
  485. }
  486. }
  487. crceDone:
  488. RELEASE_CONTEXT(pIrp, CTDI_ROUTE_NOTIFY);
  489. IoFreeIrp(pIrp);
  490. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipRouteChangeEvent\n")));
  491. return STATUS_MORE_PROCESSING_REQUIRED;
  492. }
  493. STATIC VOID
  494. CtdipIpRequestRoutingNotification(
  495. IN ULONG IpAddress
  496. )
  497. {
  498. PLIST_ENTRY pListEntry;
  499. PIRP pIrp = NULL;
  500. NTSTATUS Status;
  501. IO_STATUS_BLOCK IoStatusBlock;
  502. PIO_STACK_LOCATION IrpSp;
  503. PCTDI_ROUTE_NOTIFY pNotify = NULL;
  504. BOOLEAN NotifyActive = FALSE;
  505. BOOLEAN LockHeld;
  506. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipIpRequestRoutingNotification\n")));
  507. if (!fCtdiInitialized)
  508. {
  509. return;
  510. }
  511. NdisAcquireSpinLock(&CtdiListLock);
  512. LockHeld = TRUE;
  513. for (pListEntry = CtdiRouteNotifyList.Flink;
  514. pListEntry!=&CtdiRouteNotifyList;
  515. pListEntry = pListEntry->Flink)
  516. {
  517. pNotify = CONTAINING_RECORD(pListEntry,
  518. CTDI_ROUTE_NOTIFY,
  519. ListEntry);
  520. if (IpAddress==pNotify->Data.Add)
  521. {
  522. DEBUGMSG(DBG_TDI, (DTEXT("Routing notification already active on %d.%d.%d.%d\n"),
  523. IPADDR(IpAddress)));
  524. NotifyActive = TRUE;
  525. }
  526. }
  527. if (!NotifyActive)
  528. {
  529. DEBUGMSG(DBG_TDI, (DTEXT("Requesting routing notification on %d.%d.%d.%d\n"),
  530. IPADDR(IpAddress)));
  531. pIrp = IoAllocateIrp((CCHAR)(pFileIp->DeviceObject->StackSize +
  532. NUM_STACKS_FOR_CONTEXT(sizeof(CTDI_ROUTE_NOTIFY))),
  533. FALSE);
  534. if (!pIrp)
  535. {
  536. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  537. gCounters.ulIoAllocateIrpFail++;
  538. Status = NDIS_STATUS_RESOURCES;
  539. goto crrnDone;
  540. }
  541. pNotify = GET_CONTEXT(pIrp, CTDI_ROUTE_NOTIFY);
  542. //
  543. // Setup IRP stack location to forward IRP to IP
  544. // Must be METHOD_BUFFERED or we are not setting it up correctly
  545. //
  546. ASSERT ( (IOCTL_IP_RTCHANGE_NOTIFY_REQUEST & 0x03)==METHOD_BUFFERED );
  547. pIrp->AssociatedIrp.SystemBuffer = &pNotify->Data;
  548. IrpSp = IoGetNextIrpStackLocation(pIrp);
  549. IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  550. IrpSp->MinorFunction = 0;
  551. IrpSp->Flags = 0;
  552. IrpSp->Control = 0;
  553. IrpSp->FileObject = pFileIp;
  554. IrpSp->DeviceObject = pFileIp->DeviceObject;
  555. IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(IPNotifyData);
  556. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  557. IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_IP_RTCHANGE_NOTIFY_REQUEST;
  558. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  559. IoSetCompletionRoutine(pIrp, CtdipRouteChangeEvent, pNotify, TRUE, TRUE, TRUE);
  560. pNotify->Data.Version = 0;
  561. pNotify->Data.Add = IpAddress;
  562. InsertTailList(&CtdiRouteNotifyList, &pNotify->ListEntry);
  563. LockHeld = FALSE;
  564. NdisReleaseSpinLock(&CtdiListLock);
  565. (void)IoCallDriver(pFileIp->DeviceObject, pIrp);
  566. pIrp = NULL;
  567. }
  568. crrnDone:
  569. if (LockHeld)
  570. {
  571. NdisReleaseSpinLock(&CtdiListLock);
  572. }
  573. if (pIrp)
  574. {
  575. IoFreeIrp(pIrp);
  576. }
  577. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipIpRequestRoutingNotification\n")));
  578. }
  579. #endif
  580. STATIC VOID
  581. CtdipScheduleAddHostRoute(
  582. PPPTP_WORK_ITEM pWorkItem
  583. )
  584. {
  585. PCTDI_DATA pCtdi = pWorkItem->Context;
  586. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipScheduleAddHostRoute\n")));
  587. CtdiAddHostRoute(&pCtdi->Connection.RemoteAddress);
  588. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipScheduleAddHostRoute\n")));
  589. }
  590. STATIC NTSTATUS
  591. CtdipConnectCompleteCallback(
  592. IN PDEVICE_OBJECT pDeviceObject,
  593. IN PIRP pIrp,
  594. IN PVOID Context
  595. )
  596. {
  597. PCTDI_DATA pCtdi = Context;
  598. NDIS_STATUS NdisStatus;
  599. PTDI_CONNECTION_INFORMATION pRequestInfo = NULL;
  600. PTA_IP_ADDRESS pRequestAddress = NULL;
  601. PTDI_CONNECTION_INFORMATION pReturnInfo = NULL;
  602. PTA_IP_ADDRESS pReturnAddress = NULL;
  603. PBOOLEAN pInboundFlag = NULL;
  604. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipConnectCompleteCallback %08x\n"), pIrp->IoStatus.Status));
  605. SET_DBGFLAG(pCtdi, CTDI_F_CONNECTCOMP_CALLBACK);
  606. pRequestInfo = pCtdi->Connection.ConnectInfo;
  607. pRequestAddress =
  608. (PTA_IP_ADDRESS)((PUCHAR)(pRequestInfo + 1) + sizeof(PVOID));
  609. (ULONG_PTR)pRequestAddress &=
  610. ~((ULONG_PTR)sizeof(PVOID) - 1);
  611. pReturnInfo =
  612. (PTDI_CONNECTION_INFORMATION)
  613. ((PUCHAR)(pRequestAddress + 1) + sizeof(PVOID));
  614. (ULONG_PTR)pReturnInfo &=
  615. ~((ULONG_PTR)sizeof(PVOID) - 1);
  616. pReturnAddress =
  617. (PTA_IP_ADDRESS)((PUCHAR)(pReturnInfo + 1) + sizeof(PVOID));
  618. (ULONG_PTR)pReturnAddress &=
  619. ~((ULONG_PTR)sizeof(PVOID) - 1);
  620. pInboundFlag = (PBOOLEAN)(pReturnAddress + 1);
  621. // Connection complete. Tell the client.
  622. if (pIrp->IoStatus.Status==STATUS_SUCCESS)
  623. {
  624. pCtdi->Connection.RemoteAddress = *pReturnAddress;
  625. ScheduleWorkItem(CtdipScheduleAddHostRoute, pCtdi, NULL, 0);
  626. if (*pInboundFlag)
  627. {
  628. NdisInterlockedIncrement(&gCounters.InboundConnectComplete);
  629. }
  630. else
  631. {
  632. NdisInterlockedIncrement(&gCounters.OutboundConnectComplete);
  633. }
  634. }
  635. MyMemFree(pRequestInfo,
  636. 2*(sizeof(TDI_CONNECTION_INFORMATION)+sizeof(TA_IP_ADDRESS)) +
  637. sizeof(BOOLEAN) + 3*sizeof(PVOID) );
  638. pCtdi->Connection.ConnectInfo = NULL;
  639. if (pCtdi->ConnectCompleteCallback)
  640. {
  641. // Report status and give them the new handle if we succeeded.
  642. NdisStatus = pCtdi->ConnectCompleteCallback(pCtdi->Connection.Context,
  643. (pIrp->IoStatus.Status ? 0 : (HANDLE)pCtdi),
  644. pIrp->IoStatus.Status);
  645. if (NdisStatus!=NDIS_STATUS_SUCCESS || pIrp->IoStatus.Status!=STATUS_SUCCESS)
  646. {
  647. CtdiDisconnect(pCtdi, FALSE);
  648. CtdiClose(pCtdi);
  649. }
  650. }
  651. else
  652. {
  653. // We assume that if there's no ConnectCompleteCallback, that this is
  654. // probably a listen, we've already given the handle for this, and
  655. // we don't want to close it ourselves. Instead, we'll do a disconnect
  656. // indication and allow the upper layer to clean up.
  657. if (pIrp->IoStatus.Status!=STATUS_SUCCESS &&
  658. !pCtdi->Closed &&
  659. pCtdi->DisconnectCallback)
  660. {
  661. WPLOG(LL_A, LM_TDI, ("Refused. pCtdi %p Failed IRP status 0x%0x", pCtdi, pIrp->IoStatus.Status));
  662. pCtdi->DisconnectCallback(pCtdi->Connection.Context, TRUE);
  663. }
  664. }
  665. IoFreeIrp(pIrp);
  666. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_CONNECT); // Pair in CtdiConnect
  667. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipConnectCompleteCallback\n")));
  668. return STATUS_MORE_PROCESSING_REQUIRED;
  669. }
  670. STATIC NTSTATUS
  671. CtdipAssociateAddressCallback(
  672. IN PDEVICE_OBJECT pDeviceObject,
  673. IN PIRP pIrp,
  674. IN PVOID Context
  675. )
  676. {
  677. PCTDI_DATA pConnect = Context;
  678. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipAssociateAddressCallback\n")));
  679. DEBUGMSG(DBG_TDI, (DTEXT("TDI_ASSOCIATE_ADDRESS Sts:%08x\n"), pIrp->IoStatus.Status));
  680. // ToDo: What cleanup do we need to do if this fails?
  681. SET_DBGFLAG(pConnect, CTDI_F_ASSOCADDR_CALLBACK);
  682. //ASSERT(NT_SUCCESS(pIrp->IoStatus.Status));
  683. IoFreeIrp(pIrp);
  684. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_ASSOADDR); // Pair in CtdipAddListenConnection and also in CtdiConnect
  685. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipAssociateAddressCallback\n")));
  686. return STATUS_MORE_PROCESSING_REQUIRED;
  687. }
  688. // This function expects the CtdiListLock to be held.
  689. PCTDI_ROUTE
  690. CtdipFindRoute(
  691. ULONG IpAddress
  692. )
  693. {
  694. PCTDI_ROUTE pRoute = NULL;
  695. PLIST_ENTRY pListEntry;
  696. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipFindRoute\n")));
  697. for (pListEntry = CtdiRouteList.Flink;
  698. pListEntry != &CtdiRouteList;
  699. pListEntry = pListEntry->Flink)
  700. {
  701. pRoute = CONTAINING_RECORD(pListEntry,
  702. CTDI_ROUTE,
  703. ListEntry);
  704. if (pRoute->IpAddress==IpAddress)
  705. {
  706. // Found the route, return it.
  707. goto cfrDone;
  708. }
  709. }
  710. pRoute = NULL;
  711. cfrDone:
  712. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipFindRoute %08x\n"), pRoute));
  713. return pRoute;
  714. }
  715. STATIC NTSTATUS
  716. CtdipSetEventCallback(
  717. IN PDEVICE_OBJECT pDeviceObject,
  718. IN PIRP pIrp,
  719. IN PVOID Context
  720. )
  721. {
  722. PCTDI_DATA pConnect = Context;
  723. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipSetEventCallback\n")));
  724. DEBUGMSG(DBG_TDI, (DTEXT("TDI_SET_EVENT_HANDLER Sts:%08x\n"), pIrp->IoStatus.Status));
  725. // ToDo: What cleanup do we need to do if this fails?
  726. IoFreeIrp(pIrp);
  727. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_SETEVENT); // Pair in CtdipSetEventHandler
  728. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipSetEventCallback\n")));
  729. return STATUS_MORE_PROCESSING_REQUIRED;
  730. }
  731. STATIC NDIS_STATUS
  732. CtdipSetEventHandler(
  733. IN PCTDI_DATA pCtdi,
  734. IN ULONG ulEventType,
  735. IN PVOID pEventHandler
  736. )
  737. {
  738. PIRP pIrp;
  739. NDIS_STATUS ReturnStatus = NDIS_STATUS_SUCCESS;
  740. NTSTATUS NtStatus;
  741. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipSetEventHandler\n")));
  742. if (!IS_CTDI(pCtdi))
  743. {
  744. DEBUGMSG(DBG_ERROR, (DTEXT("Ctdi: Bad handle %p\n"), pCtdi));
  745. WPLOG(LL_A, LM_TDI, ("Ctdi: Bad handle %p", pCtdi));
  746. ReturnStatus = NDIS_STATUS_FAILURE;
  747. goto cpsehDone;
  748. }
  749. // This should be the Address context ToDo: is this always true?
  750. pIrp = IoAllocateIrp(pCtdi->pFileObject->DeviceObject->StackSize, FALSE);
  751. if (!pIrp)
  752. {
  753. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  754. gCounters.ulIoAllocateIrpFail++;
  755. ReturnStatus = NDIS_STATUS_RESOURCES;
  756. goto cpsehDone;
  757. }
  758. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_SETEVENT); // Pair in CtdipSetEventCallback
  759. TdiBuildSetEventHandler(pIrp,
  760. pCtdi->pFileObject->DeviceObject,
  761. pCtdi->pFileObject,
  762. CtdipSetEventCallback,
  763. pCtdi,
  764. ulEventType,
  765. pEventHandler,
  766. pCtdi);
  767. DEBUGMSG(DBG_TDI, (DTEXT("IoCallDriver TDI_SET_EVENT_HANDLER\n")));
  768. // Completion handler always called, don't care on return value.
  769. (void)IoCallDriver(pCtdi->pFileObject->DeviceObject, pIrp);
  770. ReturnStatus = STATUS_SUCCESS;
  771. cpsehDone:
  772. DEBUGMSG(DBG_FUNC|DBG_ERR(ReturnStatus), (DTEXT("-CtdipSetEventHandler\n")));
  773. return ReturnStatus;
  774. }
  775. STATIC NDIS_STATUS
  776. CtdipAddListenConnection(
  777. IN PCTDI_DATA pEndpoint
  778. )
  779. {
  780. NTSTATUS NtStatus;
  781. OBJECT_ATTRIBUTES ObjectAttributes;
  782. IO_STATUS_BLOCK IoStatusBlock;
  783. PIRP pIrp;
  784. UNICODE_STRING DeviceName;
  785. UCHAR EaBuffer[sizeof(FILE_FULL_EA_INFORMATION) +
  786. TDI_CONNECTION_CONTEXT_LENGTH +
  787. sizeof(PVOID)];
  788. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION)EaBuffer;
  789. PVOID UNALIGNED *ppContext;
  790. NDIS_STATUS ReturnStatus = NDIS_STATUS_SUCCESS;
  791. PCTDI_DATA pConnect;
  792. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipAddListenConnection\n")));
  793. pConnect = CtdipDataAlloc();
  794. if (!pConnect)
  795. {
  796. ReturnStatus = NDIS_STATUS_RESOURCES;
  797. goto calcDone;
  798. }
  799. pConnect->Type = CTDI_CONNECTION;
  800. pConnect->Connection.LocalEndpoint = pEndpoint;
  801. pConnect->RecvCallback = pEndpoint->RecvCallback;
  802. pConnect->DisconnectCallback = pEndpoint->DisconnectCallback;
  803. DeviceName.Length = sizeof(DD_TCP_DEVICE_NAME) - sizeof(WCHAR);
  804. DeviceName.Buffer = DD_TCP_DEVICE_NAME;
  805. InitializeObjectAttributes(&ObjectAttributes,
  806. &DeviceName,
  807. OBJ_CASE_INSENSITIVE,
  808. NULL,
  809. NULL);
  810. NdisZeroMemory(pEa, sizeof(EaBuffer));
  811. pEa->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  812. pEa->EaValueLength = sizeof(PVOID);
  813. NdisMoveMemory(pEa->EaName, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH);
  814. ppContext = (PVOID UNALIGNED*)
  815. (pEa->EaName + TDI_CONNECTION_CONTEXT_LENGTH + 1);
  816. *ppContext = pConnect;
  817. NdisZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  818. NtStatus =
  819. ZwCreateFile(&pConnect->hFile, /* FileHandle */
  820. FILE_READ_DATA | FILE_WRITE_DATA, /* Desired Access */
  821. &ObjectAttributes, /* Object Attributes */
  822. &IoStatusBlock, /* IO Status Block */
  823. NULL, /* Allocation Size */
  824. FILE_ATTRIBUTE_NORMAL, /* File Attributes */
  825. 0, /* Share Access */
  826. FILE_OPEN, /* Create Disposition */
  827. 0, /* Create Options */
  828. pEa, /* EaBuffer */
  829. sizeof(EaBuffer) /* EaLength */
  830. );
  831. if (NtStatus!=STATUS_SUCCESS)
  832. {
  833. WPLOG(LL_A, LM_TDI, ("ZwCreateFile failed"));
  834. ReturnStatus = NtStatus;
  835. goto calcDone;
  836. }
  837. // Convert the address file handle to a FILE_OBJECT
  838. NtStatus =
  839. ObReferenceObjectByHandle(pConnect->hFile, /* Handle */
  840. 0, /* DesiredAccess */
  841. NULL, /* ObjectType */
  842. KernelMode, /* AccessMode */
  843. &pConnect->pFileObject, /* Object */
  844. NULL /* HandleInfo */
  845. );
  846. if (NtStatus != STATUS_SUCCESS)
  847. {
  848. WPLOG(LL_A, LM_TDI, ("ObReferenceObjectByHandle failed"));
  849. ReturnStatus = NtStatus;
  850. goto calcDone;
  851. }
  852. // Make an irp to associate the endpoint and connection.
  853. pIrp = IoAllocateIrp(pConnect->pFileObject->DeviceObject->StackSize, FALSE);
  854. if (!pIrp)
  855. {
  856. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  857. gCounters.ulIoAllocateIrpFail++;
  858. ReturnStatus = NDIS_STATUS_RESOURCES;
  859. goto calcDone;
  860. }
  861. REFERENCE_OBJECT_EX(pConnect, CTDI_REF_ASSOADDR); // Pair in CtdipAssociateAddressCallback
  862. TdiBuildAssociateAddress(pIrp,
  863. pConnect->pFileObject->DeviceObject,
  864. pConnect->pFileObject,
  865. CtdipAssociateAddressCallback,
  866. pConnect,
  867. pEndpoint->hFile);
  868. DEBUGMSG(DBG_TDI, (DTEXT("IoCallDriver TDI_ASSOCIATE_ADDRESS\n")));
  869. // Completion handler always called, don't care on return value.
  870. (void)IoCallDriver(pConnect->pFileObject->DeviceObject, pIrp);
  871. // Associate address creates a reference from the connection to the endpoint.
  872. REFERENCE_OBJECT_EX(pEndpoint, CTDI_REF_ADDRREF); // Pair in CtdipDisassociateAddressCallback
  873. SET_DBGFLAG(pConnect, CTDI_F_BUILD_ASSOCADDR);
  874. #if DBG
  875. pConnect->bRef = TRUE;
  876. #endif
  877. // It's ready. Put it on the list.
  878. REFERENCE_OBJECT_EX(pEndpoint, CTDI_REF_LIST); //Pair in CtdipConnectCallback
  879. REFERENCE_OBJECT_EX(pConnect, CTDI_REF_LIST); //Pair in CtdipConnectCallback
  880. MyInterlockedInsertTailList(&pEndpoint->Listen.ConnectList, &pConnect->Connection.ListEntry, &pEndpoint->Lock);
  881. NdisInterlockedIncrement(&pEndpoint->Listen.NumConnection);
  882. // This pConnect should now be an active TCP listen.
  883. calcDone:
  884. if (NT_SUCCESS(ReturnStatus))
  885. {
  886. WPLOG(LL_M, LM_TDI, ("New pCtdi %p added for listen", pConnect));
  887. }
  888. else
  889. {
  890. if (pConnect)
  891. {
  892. // Any failure means no associate address. don't disassociate.
  893. // It also means it's not attached to the listen.
  894. CtdiClose(pConnect);
  895. }
  896. WPLOG(LL_A, LM_TDI, ("Failed to add CTDI for listen"));
  897. }
  898. DEBUGMSG(DBG_FUNC|DBG_ERR(ReturnStatus), (DTEXT("-CtdipAddListenConnection %08x\n"), ReturnStatus));
  899. return ReturnStatus;
  900. }
  901. STATIC VOID
  902. CtdipReplenishListens(
  903. IN PPPTP_WORK_ITEM pWorkItem
  904. )
  905. {
  906. PCTDI_DATA pEndpoint = pWorkItem->Context;
  907. ULONG i;
  908. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipReplenishListens\n")));
  909. for (i=pEndpoint->Listen.NumConnection; i<NUM_TCP_LISTEN; i++)
  910. {
  911. CtdipAddListenConnection(pEndpoint);
  912. }
  913. DEREFERENCE_OBJECT_EX(pEndpoint, CTDI_REF_REPLENISH); // Pair in CtdipConnectCallback
  914. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipReplenishListens\n")));
  915. }
  916. STATIC NTSTATUS
  917. CtdipConnectCallback(
  918. IN PVOID TdiEventContext,
  919. IN LONG RemoteAddressLength,
  920. IN PVOID RemoteAddress,
  921. IN LONG UserDataLength,
  922. IN PVOID UserData,
  923. IN LONG OptionsLength,
  924. IN PVOID Options,
  925. OUT CONNECTION_CONTEXT *ConnectionContext,
  926. OUT PIRP *AcceptIrp
  927. )
  928. {
  929. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  930. NDIS_STATUS NdisStatus;
  931. PTRANSPORT_ADDRESS pAddress = (PTRANSPORT_ADDRESS)RemoteAddress;
  932. PCTDI_DATA pCtdi = (PCTDI_DATA)TdiEventContext;
  933. PCTDI_DATA pConnect = NULL;
  934. UINT i;
  935. PIRP pIrp = NULL;
  936. PTDI_CONNECTION_INFORMATION pRequestInfo = NULL;
  937. PTDI_CONNECTION_INFORMATION pReturnInfo = NULL;
  938. PTA_IP_ADDRESS pRemoteAddress;
  939. PVOID pNewContext;
  940. PLIST_ENTRY pListEntry = NULL;
  941. PBOOLEAN pInboundFlag;
  942. BOOLEAN bTrusted;
  943. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipConnectCallback\n")));
  944. NdisInterlockedIncrement(&gCounters.InboundConnectAttempts);
  945. if (RemoteAddressLength<sizeof(TA_IP_ADDRESS) ||
  946. !RemoteAddress ||
  947. pCtdi->Closed)
  948. {
  949. Status = STATUS_CONNECTION_REFUSED;
  950. WPLOG(LL_A, LM_TDI, ("Refused. Incorrect remote address."));
  951. goto cccDone;
  952. }
  953. ASSERT(UserDataLength==0);
  954. ASSERT(OptionsLength==0);
  955. if(PptpMaxTunnelsPerIpAddress == -1)
  956. {
  957. // By default, we trust all IP addresses.
  958. bTrusted = TRUE;
  959. }
  960. else
  961. {
  962. bTrusted = FALSE;
  963. // Does this come from a trusted IP address?
  964. if (g_ulTrustedClientAddresses)
  965. {
  966. for (i=0; i<g_ulTrustedClientAddresses; i++)
  967. {
  968. if ((((PTA_IP_ADDRESS)pAddress)->Address[0].Address[0].in_addr & g_TrustedClientList[i].Mask) ==
  969. (g_TrustedClientList[i].Address & g_TrustedClientList[i].Mask))
  970. {
  971. bTrusted = TRUE;
  972. WPLOG(LL_A, LM_TDI, ("Trusted IP address %!IPADDR!.",
  973. ((PTA_IP_ADDRESS)pAddress)->Address[0].Address[0].in_addr));
  974. break;
  975. }
  976. }
  977. }
  978. // If it's not from a trusted ip address, we need to check the number of TCP connections.
  979. if(!bTrusted)
  980. {
  981. PCTDI_DATA pCtdiTemp;
  982. ULONG ulFoundTcpConnections = 0;
  983. NdisAcquireSpinLock(&CtdiListLock);
  984. for (pListEntry = CtdiList.Flink;
  985. pListEntry != &CtdiList;
  986. pListEntry = pListEntry->Flink)
  987. {
  988. pCtdiTemp = CONTAINING_RECORD(pListEntry,
  989. CTDI_DATA,
  990. ListEntry);
  991. if (IS_CTDI(pCtdiTemp) &&
  992. pCtdiTemp->Type == CTDI_CONNECTION &&
  993. pCtdiTemp->Connection.RemoteAddress.Address[0].Address[0].in_addr ==
  994. ((PTA_IP_ADDRESS)pAddress)->Address[0].Address[0].in_addr)
  995. {
  996. ulFoundTcpConnections++;
  997. }
  998. }
  999. NdisReleaseSpinLock(&CtdiListLock);
  1000. if(ulFoundTcpConnections >= PptpMaxTunnelsPerIpAddress)
  1001. {
  1002. Status = STATUS_CONNECTION_REFUSED;
  1003. WPLOG(LL_A, LM_TDI, ("Refused. %d connections from %!IPADDR! exceeded the limit.",
  1004. ulFoundTcpConnections, ((PTA_IP_ADDRESS)pAddress)->Address[0].Address[0].in_addr));
  1005. goto cccDone;
  1006. }
  1007. }
  1008. }
  1009. // Do all the allocation we'll need at one shot.
  1010. pIrp = IoAllocateIrp(pCtdi->pFileObject->DeviceObject->StackSize, FALSE);
  1011. if(!pIrp)
  1012. {
  1013. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  1014. gCounters.ulIoAllocateIrpFail++;
  1015. Status = STATUS_INSUFFICIENT_RESOURCES;
  1016. goto cccDone;
  1017. }
  1018. // No sign saying we can't allocate the request info, return info and address buffers
  1019. // in one shot.
  1020. pRequestInfo = MyMemAlloc(2*(sizeof(TDI_CONNECTION_INFORMATION)+
  1021. sizeof(TA_IP_ADDRESS)) +
  1022. 3*sizeof(PVOID) + sizeof(BOOLEAN),
  1023. TAG_CTDI_CONNECT_INFO);
  1024. if (!pRequestInfo)
  1025. {
  1026. Status = STATUS_INSUFFICIENT_RESOURCES;
  1027. WPLOG(LL_A, LM_Res, ("Refused. Insufficient resources."));
  1028. goto cccDone;
  1029. }
  1030. pListEntry = MyInterlockedRemoveHeadList(&pCtdi->Listen.ConnectList,
  1031. &pCtdi->Lock);
  1032. if (!pListEntry)
  1033. {
  1034. DEBUGMSG(DBG_ERROR, (DTEXT("No listen connections available.\n")));
  1035. WPLOG(LL_A, LM_TDI, ("Refused. No listen connections available."));
  1036. Status = STATUS_CONNECTION_REFUSED;
  1037. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_REPLENISH); // pair in CtdipReplenishListens
  1038. if (ScheduleWorkItem(CtdipReplenishListens, pCtdi, NULL, 0)!=NDIS_STATUS_SUCCESS)
  1039. {
  1040. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_REPLENISH); // pair for above if Schedule fails
  1041. }
  1042. goto cccDone;
  1043. }
  1044. NdisInterlockedDecrement(&pCtdi->Listen.NumConnection);
  1045. pConnect = CONTAINING_RECORD(pListEntry,
  1046. CTDI_DATA,
  1047. Connection.ListEntry);
  1048. // We have a double reference when an object is on the list of another object,
  1049. // and we want to release them both when we remove the item from the list,
  1050. // but in this case we also want to take a reference on the connection object,
  1051. // so one of them cancels out.
  1052. //REFERENCE_OBJECT(pConnect); // Pair in CtdiDisconnect
  1053. //DEREFERENCE_OBJECT(pConnect); // Pair in CtdipAddListenConnection
  1054. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_LIST); // Pair in CtdipAddListenConnection
  1055. if (!pCtdi->ConnectQueryCallback || pCtdi->Closed)
  1056. {
  1057. Status = STATUS_CONNECTION_REFUSED;
  1058. WPLOG(LL_A, LM_TDI, ("Refused. pCtdi %p in wrong state.", pCtdi));
  1059. goto cccDone;
  1060. }
  1061. NdisStatus = pCtdi->ConnectQueryCallback(pCtdi->Listen.Context,
  1062. pAddress,
  1063. pConnect,
  1064. &pNewContext);
  1065. if (NdisStatus!=NDIS_STATUS_SUCCESS)
  1066. {
  1067. Status = STATUS_CONNECTION_REFUSED;
  1068. WPLOG(LL_A, LM_TDI, ("Refused. QueryCallback failed NdisStatus %x", NdisStatus));
  1069. goto cccDone;
  1070. }
  1071. // We've got the go-ahead to accept this connection, at the TCP level.
  1072. pConnect->Connection.ConnectInfo = pRequestInfo;
  1073. pConnect->Connection.Context = pNewContext;
  1074. pConnect->Connection.RemoteAddress = *(PTA_IP_ADDRESS)pAddress;
  1075. NdisZeroMemory(pRequestInfo,
  1076. 2*(sizeof(TDI_CONNECTION_INFORMATION)+sizeof(TA_IP_ADDRESS))
  1077. + sizeof(BOOLEAN) + 3*sizeof(PVOID));
  1078. pRequestInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
  1079. pRemoteAddress =
  1080. (PTA_IP_ADDRESS)((PUCHAR)(pRequestInfo + 1) + sizeof(PVOID));
  1081. (ULONG_PTR)pRemoteAddress &=
  1082. ~((ULONG_PTR)sizeof(PVOID) - 1);
  1083. pRequestInfo->RemoteAddress = pRemoteAddress;
  1084. *pRemoteAddress = *(PTA_IP_ADDRESS)pAddress;
  1085. pReturnInfo =
  1086. (PTDI_CONNECTION_INFORMATION)
  1087. ((PUCHAR)(pRemoteAddress + 1) + sizeof(PVOID));
  1088. (ULONG_PTR)pReturnInfo &=
  1089. ~((ULONG_PTR)sizeof(PVOID) - 1);
  1090. pReturnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
  1091. pRemoteAddress =
  1092. (PTA_IP_ADDRESS)((PUCHAR)(pReturnInfo + 1) + sizeof(PVOID));
  1093. (ULONG_PTR)pRemoteAddress &=
  1094. ~((ULONG_PTR)sizeof(PVOID) - 1);
  1095. pReturnInfo->RemoteAddress = pRemoteAddress;
  1096. pInboundFlag = (PBOOLEAN)(pRemoteAddress + 1);
  1097. *pInboundFlag = TRUE;
  1098. // ToDo: the old PPTP driver filled in the ReturnInfo remote address.
  1099. //
  1100. pRemoteAddress->TAAddressCount = 1;
  1101. pRemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  1102. pRemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1103. SET_DBGFLAG(pConnect, CTDI_F_ACCEPT);
  1104. TdiBuildAccept(pIrp,
  1105. pConnect->pFileObject->DeviceObject,
  1106. pConnect->pFileObject,
  1107. CtdipConnectCompleteCallback,
  1108. pConnect, // Context
  1109. pRequestInfo,
  1110. pReturnInfo);
  1111. IoSetNextIrpStackLocation(pIrp);
  1112. *ConnectionContext = pConnect;
  1113. *AcceptIrp = pIrp;
  1114. REFERENCE_OBJECT_EX(pConnect->Connection.LocalEndpoint, CTDI_REF_REPLENISH); // pair in CtdipReplenishListens
  1115. if (ScheduleWorkItem(CtdipReplenishListens, pConnect->Connection.LocalEndpoint, NULL, 0)!=NDIS_STATUS_SUCCESS)
  1116. {
  1117. DEREFERENCE_OBJECT_EX(pConnect->Connection.LocalEndpoint, CTDI_REF_REPLENISH); // pair for above if Schedule fails
  1118. }
  1119. cccDone:
  1120. if (Status!=STATUS_MORE_PROCESSING_REQUIRED)
  1121. {
  1122. // We lose. Clean up.
  1123. if (pConnect)
  1124. {
  1125. // We haven't used this connection, so it is still valid. return it
  1126. // to the list, and reapply the references.
  1127. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_LIST);
  1128. //REFERENCE_OBJECT(pConnect);
  1129. MyInterlockedInsertTailList(&pCtdi->Listen.ConnectList,
  1130. &pConnect->Connection.ListEntry,
  1131. &pCtdi->Lock);
  1132. NdisInterlockedIncrement(&pCtdi->Listen.NumConnection);
  1133. }
  1134. if (pIrp)
  1135. {
  1136. IoFreeIrp(pIrp);
  1137. }
  1138. if (pRequestInfo)
  1139. {
  1140. MyMemFree(pRequestInfo,
  1141. 2*(sizeof(TDI_CONNECTION_INFORMATION)+sizeof(TA_IP_ADDRESS)));
  1142. }
  1143. }
  1144. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtdipConnectCallback %08x\n"), Status));
  1145. return Status;
  1146. }
  1147. STATIC NTSTATUS
  1148. CtdipDisassociateAddressCallback(
  1149. IN PDEVICE_OBJECT pDeviceObject,
  1150. IN PIRP pIrp,
  1151. IN PVOID Context
  1152. )
  1153. {
  1154. PCTDI_DATA pConnect = Context;
  1155. PCTDI_DATA pEndpoint;
  1156. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipDisassociateAddressCallback\n")));
  1157. DEBUGMSG(DBG_TDI, (DTEXT("TDI_DISASSOCIATE_ADDRESS Sts:%08x\n"), pIrp->IoStatus.Status));
  1158. // ToDo: What cleanup do we need to do if this fails?
  1159. SET_DBGFLAG(pConnect, CTDI_F_DISASSOC_CALLBACK);
  1160. IoFreeIrp(pIrp);
  1161. pEndpoint = pConnect->Connection.LocalEndpoint;
  1162. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISASSO); // Pair in CtdipDisconnectCleanup
  1163. DEREFERENCE_OBJECT_EX(pEndpoint, CTDI_REF_ADDRREF); // Pair in CtdipAddListenConnection and CtdiConnect
  1164. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipDisassociateAddressCallback\n")));
  1165. return STATUS_MORE_PROCESSING_REQUIRED;
  1166. }
  1167. STATIC VOID
  1168. CtdipDisconnectCleanup(
  1169. IN PPPTP_WORK_ITEM pWorkItem
  1170. )
  1171. {
  1172. PCTDI_DATA pConnect = pWorkItem->Context;
  1173. PIRP pIrp = NULL;
  1174. NTSTATUS Status;
  1175. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipDisconnectCleanup\n")));
  1176. SET_DBGFLAG(pConnect, CTDI_F_DISCONNECT_CLEANUP);
  1177. pIrp = IoAllocateIrp(pConnect->pFileObject->DeviceObject->StackSize, FALSE);
  1178. if (!pIrp)
  1179. {
  1180. PCTDI_DATA pEndpoint = pConnect->Connection.LocalEndpoint;
  1181. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  1182. gCounters.ulIoAllocateIrpFail++;
  1183. DEREFERENCE_OBJECT_EX(pEndpoint, CTDI_REF_ADDRREF); // Pair in CtdipAddListenConnection and CtdiConnect
  1184. }
  1185. else
  1186. {
  1187. // Normally we would reference pConnect for making an irp, but we already
  1188. // have one for this work item, & we'll just keep it.
  1189. SET_DBGFLAG(pConnect, CTDI_F_BUILD_DISASSOC);
  1190. TdiBuildDisassociateAddress(pIrp,
  1191. pConnect->pFileObject->DeviceObject,
  1192. pConnect->pFileObject,
  1193. CtdipDisassociateAddressCallback,
  1194. pConnect);
  1195. DEBUGMSG(DBG_TDI, (DTEXT("IoCallDriver TDI_DISASSOCIATE_ADDRESS\n")));
  1196. REFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISASSO);
  1197. // Completion handler always called, don't care on return value.
  1198. (void)IoCallDriver(pConnect->pFileObject->DeviceObject, pIrp);
  1199. }
  1200. CtdiDeleteHostRoute(&pConnect->Connection.RemoteAddress);
  1201. if (!pConnect->Closed && pConnect->DisconnectCallback)
  1202. {
  1203. pConnect->DisconnectCallback(pConnect->Connection.Context,
  1204. pConnect->Connection.Abort);
  1205. }
  1206. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISCONNECT); // Pair CtdipDisconnectCallback and CtdiDisconnect
  1207. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipDisconnectCleanup\n")));
  1208. }
  1209. STATIC NTSTATUS
  1210. CtdipDisconnectCompleteCallback(
  1211. PDEVICE_OBJECT pDeviceObject,
  1212. PIRP pIrp,
  1213. PVOID Context
  1214. )
  1215. {
  1216. PCTDI_DATA pConnect = Context;
  1217. PIO_STACK_LOCATION pIrpSp = IoGetNextIrpStackLocation(pIrp);
  1218. PTDI_REQUEST_KERNEL pRequest = (PTDI_REQUEST_KERNEL)&pIrpSp->Parameters;
  1219. BOOLEAN CleanupNow = FALSE;
  1220. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipDisconnectCompleteCallback %08x\n"), pIrp->IoStatus.Status));
  1221. if (pRequest->RequestConnectionInformation)
  1222. {
  1223. // We don't do anything with this info yet
  1224. }
  1225. if (pRequest->ReturnConnectionInformation)
  1226. {
  1227. // We don't do anything with this info yet
  1228. }
  1229. if (pRequest->RequestSpecific)
  1230. {
  1231. // Allocated as part of irp, don't free it.
  1232. }
  1233. if (IS_CTDI(pConnect))
  1234. {
  1235. SET_DBGFLAG(pConnect, CTDI_F_DISCONNECTCOMP_CALLBACK);
  1236. // Possible to do a release AND and abort, so we'll get called here twice.
  1237. // We only want to cleanup once.
  1238. NdisAcquireSpinLock(&pConnect->Lock);
  1239. CleanupNow = ((--pConnect->Connection.DisconnectCount)==0) ? TRUE : FALSE;
  1240. NdisReleaseSpinLock(&pConnect->Lock);
  1241. if (!CleanupNow ||
  1242. ScheduleWorkItem(CtdipDisconnectCleanup, pConnect, NULL, 0)!=NDIS_STATUS_SUCCESS)
  1243. {
  1244. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISCONNECT); // Pair CtdipDisconnectCallback and CtdiDisconnect
  1245. }
  1246. }
  1247. IoFreeIrp(pIrp);
  1248. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipDisconnectCompleteCallback\n")));
  1249. return STATUS_MORE_PROCESSING_REQUIRED;
  1250. }
  1251. STATIC NTSTATUS
  1252. CtdipDisconnectCallback(
  1253. IN PVOID TdiEventContext,
  1254. IN CONNECTION_CONTEXT ConnectionContext,
  1255. IN LONG DisconnectDataLength,
  1256. IN PVOID DisconnectData,
  1257. IN LONG DisconnectInformationLength,
  1258. IN PVOID DisconnectInformation,
  1259. IN ULONG DisconnectFlags
  1260. )
  1261. {
  1262. PCTDI_DATA pConnect = (PCTDI_DATA)ConnectionContext;
  1263. PCTDI_DATA pEndpoint;
  1264. PIRP pIrp = NULL;
  1265. PTIME pTimeout = NULL;
  1266. PTDI_CONNECTION_INFORMATION pConnectInfo = NULL;
  1267. NTSTATUS Status = STATUS_SUCCESS;
  1268. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipDisconnectCallback\n")));
  1269. if (!IS_CTDI(pConnect))
  1270. {
  1271. DEBUGMSG(DBG_ERROR, (DTEXT("pConnect: Bad handle %p\n"), pConnect));
  1272. WPLOG(LL_A, LM_TDI, ("pConnect: Bad handle %p", pConnect));
  1273. Status = NDIS_STATUS_FAILURE;
  1274. goto cdcDone;
  1275. }
  1276. SET_DBGFLAG(pConnect, CTDI_F_DISCONNECT_CALLBACK);
  1277. if (DisconnectFlags==0)
  1278. {
  1279. DisconnectFlags = TDI_DISCONNECT_ABORT;
  1280. }
  1281. ASSERT(DisconnectFlags==TDI_DISCONNECT_RELEASE || DisconnectFlags==TDI_DISCONNECT_ABORT);
  1282. NdisAcquireSpinLock(&pConnect->Lock);
  1283. if (DisconnectFlags==TDI_DISCONNECT_ABORT)
  1284. {
  1285. BOOLEAN CleanupNow;
  1286. WPLOG(LL_M, LM_TDI, ("pCtdi %p, Flags ABORT", pConnect));
  1287. pConnect->Connection.Disconnect = TRUE;
  1288. pConnect->Connection.Abort = TRUE;
  1289. CleanupNow = (pConnect->Connection.DisconnectCount==0) ? TRUE : FALSE;
  1290. REFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISCONNECT); // Pair in CtdipDisconnectCleanup
  1291. NdisReleaseSpinLock(&pConnect->Lock);
  1292. if (CleanupNow)
  1293. {
  1294. if (ScheduleWorkItem(CtdipDisconnectCleanup, pConnect, NULL, 0)!=NDIS_STATUS_SUCCESS)
  1295. {
  1296. // Schedule failed, deref now
  1297. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISCONNECT); // Pair above
  1298. }
  1299. }
  1300. else
  1301. {
  1302. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISCONNECT); // Pair above
  1303. }
  1304. }
  1305. else
  1306. {
  1307. WPLOG(LL_I, LM_TDI, ("pCtdi %p, Flags %d", pConnect, DisconnectFlags));
  1308. if (pConnect->Connection.Disconnect)
  1309. {
  1310. // We've already disconnected. Ignore.
  1311. NdisReleaseSpinLock(&pConnect->Lock);
  1312. }
  1313. else
  1314. {
  1315. pConnect->Connection.Disconnect = TRUE;
  1316. pConnect->Connection.DisconnectCount++;
  1317. REFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISCONNECT); // Pair in CtdipDisconnectCompleteCallback
  1318. NdisReleaseSpinLock(&pConnect->Lock);
  1319. pIrp = IoAllocateIrp((CCHAR)(pConnect->pFileObject->DeviceObject->StackSize +
  1320. NUM_STACKS_FOR_CONTEXT(sizeof(TIME)+sizeof(TDI_CONNECTION_INFORMATION))),
  1321. FALSE);
  1322. if (!pIrp)
  1323. {
  1324. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  1325. gCounters.ulIoAllocateIrpFail++;
  1326. Status = STATUS_INSUFFICIENT_RESOURCES;
  1327. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISCONNECT); // Pair above
  1328. goto cdcDone;
  1329. }
  1330. pTimeout = (PTIME)GetContextArea(pIrp, sizeof(TIME)+sizeof(TDI_CONNECTION_INFORMATION));
  1331. pConnectInfo = (PTDI_CONNECTION_INFORMATION)(pTimeout + 1);
  1332. pTimeout->LowPart = CtdiTcpDisconnectTimeout * -10000000L;
  1333. pTimeout->HighPart = (pTimeout->LowPart) ? -1 : 0;
  1334. // Responding to a controlled disconnect, we don't provide
  1335. // TDI_CONNECTION_INFORMATION, but we request it from the peer.
  1336. SET_DBGFLAG(pConnect, CTDI_F_BUILD_DISCONNECT_1);
  1337. TdiBuildDisconnect(pIrp,
  1338. pConnect->pFileObject->DeviceObject,
  1339. pConnect->pFileObject,
  1340. CtdipDisconnectCompleteCallback,
  1341. pConnect,
  1342. pTimeout,
  1343. TDI_DISCONNECT_RELEASE,
  1344. NULL,
  1345. pConnectInfo);
  1346. // Completion handler always called, don't care on return value.
  1347. (void)IoCallDriver(pConnect->pFileObject->DeviceObject, pIrp);
  1348. }
  1349. }
  1350. cdcDone:
  1351. if (!NT_SUCCESS(Status))
  1352. {
  1353. if (pIrp)
  1354. {
  1355. IoFreeIrp(pIrp);
  1356. }
  1357. }
  1358. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipDisconnectCallback\n")));
  1359. return STATUS_SUCCESS;
  1360. }
  1361. STATIC NTSTATUS
  1362. CtdipOpenProtocol(
  1363. IN PUNICODE_STRING pDeviceName,
  1364. IN PTRANSPORT_ADDRESS pAddress,
  1365. OUT PHANDLE phFile,
  1366. OUT PFILE_OBJECT *ppFileObject
  1367. )
  1368. {
  1369. NTSTATUS NtStatus = STATUS_SUCCESS;
  1370. UCHAR EaBuffer[sizeof(FILE_FULL_EA_INFORMATION) +
  1371. TDI_TRANSPORT_ADDRESS_LENGTH +
  1372. sizeof(TA_IP_ADDRESS)];
  1373. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION)EaBuffer;
  1374. TA_IP_ADDRESS UNALIGNED *pEaTaIp;
  1375. IO_STATUS_BLOCK IoStatusBlock;
  1376. OBJECT_ATTRIBUTES ObjectAttributes;
  1377. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipOpenProtocol %wZ\n"), pDeviceName));
  1378. *phFile = 0;
  1379. *ppFileObject = NULL;
  1380. InitializeObjectAttributes(&ObjectAttributes,
  1381. pDeviceName,
  1382. OBJ_CASE_INSENSITIVE,
  1383. NULL,
  1384. NULL);
  1385. NdisZeroMemory(pEa, sizeof(EaBuffer));
  1386. pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  1387. pEa->EaValueLength = sizeof(TA_IP_ADDRESS);
  1388. NdisMoveMemory(pEa->EaName, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH);
  1389. pEaTaIp = (TA_IP_ADDRESS UNALIGNED*)
  1390. (pEa->EaName + TDI_TRANSPORT_ADDRESS_LENGTH + 1);
  1391. *pEaTaIp = *(PTA_IP_ADDRESS)pAddress;
  1392. DEBUGMSG(DBG_TDI, (DTEXT("Endpoint: sin_port = %Xh in_addr = %Xh\n"),
  1393. pEaTaIp->Address[0].Address[0].sin_port,
  1394. pEaTaIp->Address[0].Address[0].in_addr));
  1395. NdisZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  1396. NtStatus =
  1397. ZwCreateFile(
  1398. phFile, /* FileHandle */
  1399. FILE_READ_DATA | FILE_WRITE_DATA, /* Desired Access */
  1400. &ObjectAttributes, /* Object Attributes */
  1401. &IoStatusBlock, /* IO Status Block */
  1402. NULL, /* Allocation Size */
  1403. FILE_ATTRIBUTE_NORMAL, /* File Attributes */
  1404. 0, /* Share Access */
  1405. FILE_OPEN, /* Create Disposition */
  1406. 0, /* Create Options */
  1407. pEa, /* EaBuffer */
  1408. sizeof(EaBuffer) /* EaLength */
  1409. );
  1410. if (NtStatus!=STATUS_SUCCESS)
  1411. {
  1412. DEBUGMSG(DBG_ERROR, (DTEXT("ZwCreateFile failed %08x\n"), NtStatus));
  1413. goto copDone;
  1414. }
  1415. // Convert the address file handle to a FILE_OBJECT
  1416. NtStatus =
  1417. ObReferenceObjectByHandle(
  1418. *phFile, /* Handle */
  1419. 0, /* DesiredAccess */
  1420. NULL, /* ObjectType */
  1421. KernelMode, /* AccessMode */
  1422. ppFileObject, /* Object */
  1423. NULL /* HandleInfo */
  1424. );
  1425. copDone:
  1426. if (NtStatus!=STATUS_SUCCESS && *phFile)
  1427. {
  1428. WPLOG(LL_A, LM_TDI, ("Failed %08x", NtStatus));
  1429. ZwClose(*phFile);
  1430. *phFile = 0;
  1431. *ppFileObject = NULL;
  1432. }
  1433. DEBUGMSG(DBG_FUNC|DBG_ERR(NtStatus), (DTEXT("-CtdipOpenProtocol %08x\n"), NtStatus));
  1434. return NtStatus;
  1435. }
  1436. STATIC NTSTATUS
  1437. CtdipReceiveCompleteCallback(
  1438. IN PDEVICE_OBJECT pDeviceObject,
  1439. IN PIRP pIrp,
  1440. IN PVOID Context
  1441. )
  1442. {
  1443. PCTDI_DATA pCtdi = Context;
  1444. PUCHAR pData;
  1445. ULONG Length;
  1446. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipReceiveCompleteCallback\n")));
  1447. pData = MmGetMdlVirtualAddress(pIrp->MdlAddress);
  1448. Length = MmGetMdlByteCount(pIrp->MdlAddress);
  1449. if (pIrp->IoStatus.Status==STATUS_SUCCESS && pCtdi->RecvCallback && !pCtdi->Closed)
  1450. {
  1451. pCtdi->RecvCallback(pCtdi->Connection.Context, pData, Length);
  1452. }
  1453. #if PROBE
  1454. MmUnlockPages(pIrp->MdlAddress);
  1455. #endif
  1456. IoFreeMdl(pIrp->MdlAddress);
  1457. MyMemFree(pData, Length);
  1458. IoFreeIrp(pIrp);
  1459. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipReceiveCompleteCallback\n")));
  1460. return STATUS_MORE_PROCESSING_REQUIRED;
  1461. }
  1462. STATIC NTSTATUS
  1463. CtdipReceiveCallback(
  1464. IN PVOID TdiEventContext,
  1465. IN CONNECTION_CONTEXT ConnectionContext,
  1466. IN ULONG ReceiveFlags,
  1467. IN ULONG BytesIndicated,
  1468. IN ULONG BytesAvailable,
  1469. OUT ULONG *BytesTaken,
  1470. IN PVOID Tsdu,
  1471. OUT PIRP *IoRequestPacket
  1472. )
  1473. {
  1474. PCTDI_DATA pCtdi = ConnectionContext;
  1475. NTSTATUS NtStatus = STATUS_DATA_NOT_ACCEPTED;
  1476. NDIS_STATUS Status;
  1477. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipReceiveCallback\n")));
  1478. if (pCtdi->RecvCallback && !pCtdi->Closed)
  1479. {
  1480. if (ReceiveFlags&TDI_RECEIVE_ENTIRE_MESSAGE ||
  1481. BytesIndicated==BytesAvailable)
  1482. {
  1483. Status = pCtdi->RecvCallback(pCtdi->Connection.Context,
  1484. Tsdu,
  1485. BytesIndicated);
  1486. // Data must be used in this call
  1487. ASSERT(Status==NDIS_STATUS_SUCCESS);
  1488. NtStatus = STATUS_SUCCESS;
  1489. *BytesTaken = BytesIndicated;
  1490. }
  1491. else
  1492. {
  1493. // We need an irp to receive all the data.
  1494. PIRP pIrp;
  1495. PUCHAR pBuffer;
  1496. PMDL pMdl = NULL;
  1497. pIrp = IoAllocateIrp(pCtdi->pFileObject->DeviceObject->StackSize, FALSE);
  1498. if(!pIrp)
  1499. {
  1500. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  1501. gCounters.ulIoAllocateIrpFail++;
  1502. return NtStatus;
  1503. }
  1504. pBuffer = MyMemAlloc(BytesAvailable, TAG_CTDI_MESSAGE);
  1505. if(!pBuffer)
  1506. {
  1507. WPLOG(LL_A, LM_Res, ("Failed to alloc breceive buffer"));
  1508. }
  1509. else
  1510. {
  1511. pMdl = IoAllocateMdl(pBuffer, BytesAvailable, FALSE, FALSE, pIrp);
  1512. if (!pMdl)
  1513. {
  1514. WPLOG(LL_A, LM_Res, ("Failed to alloc MDL"));
  1515. gCounters.ulIoAllocateMdlFail++;
  1516. }
  1517. else
  1518. {
  1519. #if PROBE
  1520. __try
  1521. {
  1522. MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess);
  1523. }
  1524. __except (EXCEPTION_EXECUTE_HANDLER)
  1525. {
  1526. IoFreeMdl(pMdl);
  1527. pMdl = NULL;
  1528. }
  1529. #else
  1530. MmBuildMdlForNonPagedPool(pMdl);
  1531. #endif
  1532. }
  1533. }
  1534. if (pMdl)
  1535. {
  1536. TdiBuildReceive(pIrp,
  1537. pCtdi->pFileObject->DeviceObject,
  1538. pCtdi->pFileObject,
  1539. CtdipReceiveCompleteCallback,
  1540. pCtdi,
  1541. pMdl,
  1542. 0,
  1543. BytesAvailable);
  1544. // We're not calling IoCallDriver, so we need to set the proper
  1545. // stack location.
  1546. IoSetNextIrpStackLocation(pIrp);
  1547. *IoRequestPacket = pIrp;
  1548. *BytesTaken = 0;
  1549. NtStatus = STATUS_MORE_PROCESSING_REQUIRED;
  1550. }
  1551. else
  1552. {
  1553. // Some alloc failure occurred, free everything.
  1554. WPLOG(LL_A, LM_Res, ("Failed to alloc memory"));
  1555. NtStatus = STATUS_DATA_NOT_ACCEPTED;
  1556. *BytesTaken = 0;
  1557. if (pBuffer)
  1558. {
  1559. MyMemFree(pBuffer, BytesAvailable);
  1560. }
  1561. if (pIrp)
  1562. {
  1563. IoFreeIrp(pIrp);
  1564. }
  1565. }
  1566. }
  1567. }
  1568. DEBUGMSG(DBG_FUNC|DBG_ERR(NtStatus), (DTEXT("-CtdipReceiveCallback %08x\n"), NtStatus));
  1569. return NtStatus;
  1570. }
  1571. typedef struct {
  1572. TA_IP_ADDRESS SourceAddress;
  1573. ULONG Length;
  1574. PVOID pBuffer;
  1575. } RECV_DATAGRAM_CONTEXT, *PRECV_DATAGRAM_CONTEXT;
  1576. STATIC NTSTATUS
  1577. CtdipReceiveDatagramCompleteCallback(
  1578. IN PDEVICE_OBJECT pDeviceObject,
  1579. IN PIRP pIrp,
  1580. IN PVOID Context
  1581. )
  1582. {
  1583. PRECV_DATAGRAM_CONTEXT pRecvContext;
  1584. PCTDI_DATA pCtdi = Context;
  1585. NDIS_STATUS Status = (NDIS_STATUS)pIrp->IoStatus.Status;
  1586. PNDIS_BUFFER pNdisBuffer;
  1587. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipReceiveDatagramCompleteCallback\n")));
  1588. pRecvContext = (PRECV_DATAGRAM_CONTEXT)IoGetCurrentIrpStackLocation(pIrp);
  1589. pNdisBuffer = NdisBufferFromBuffer(pRecvContext->pBuffer);
  1590. ASSERT(MmGetMdlVirtualAddress(pNdisBuffer)==pRecvContext->pBuffer);
  1591. if (pCtdi->RecvDatagramCallback && !pCtdi->Closed && Status==NDIS_STATUS_SUCCESS)
  1592. {
  1593. // We took a reference for the buffer when we created the irp.
  1594. (void)// ToDo: We don't care about the return value?
  1595. pCtdi->RecvDatagramCallback(pCtdi->RecvContext,
  1596. (PTRANSPORT_ADDRESS)&pRecvContext->SourceAddress,
  1597. pRecvContext->pBuffer,
  1598. pRecvContext->Length);
  1599. // The above layer owns the buffer now.
  1600. }
  1601. else
  1602. {
  1603. FreeBufferToPool(&pCtdi->Datagram.RxPool, pRecvContext->pBuffer, TRUE);
  1604. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_RECVDG);
  1605. }
  1606. RELEASE_CONTEXT(pIrp, RECV_DATAGRAM_CONTEXT);
  1607. IoFreeIrp(pIrp);
  1608. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipReceiveDatagramCompleteCallback\n")));
  1609. return STATUS_MORE_PROCESSING_REQUIRED;
  1610. }
  1611. NTSTATUS
  1612. CtdipReceiveDatagramCallback(
  1613. IN PVOID TdiEventContext,
  1614. IN LONG SourceAddressLength,
  1615. IN PVOID SourceAddress,
  1616. IN LONG OptionsLength,
  1617. IN PVOID Options,
  1618. IN ULONG ReceiveDatagramFlags,
  1619. IN ULONG BytesIndicated,
  1620. IN ULONG BytesAvailable,
  1621. OUT ULONG* BytesTaken,
  1622. IN PVOID Tsdu,
  1623. OUT PIRP* IoRequestPacket )
  1624. {
  1625. PUCHAR pBuffer = NULL;
  1626. PNDIS_BUFFER pNdisBuffer;
  1627. PCTDI_DATA pCtdi = TdiEventContext;
  1628. NTSTATUS NtStatus = STATUS_SUCCESS;
  1629. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipReceiveDatagramCallback\n")));
  1630. if (pCtdi->RecvDatagramCallback==NULL)
  1631. {
  1632. DEBUGMSG(DBG_ERROR, (DTEXT("Datagram received, no handler registered. Drop it\n")));
  1633. WPLOG(LL_A, LM_TDI, ("Datagram received, no handler registered. Drop it"));
  1634. NtStatus = STATUS_DATA_NOT_ACCEPTED;
  1635. goto crdcDone;
  1636. }
  1637. pBuffer = GetBufferFromPool(&pCtdi->Datagram.RxPool);
  1638. if (!pBuffer)
  1639. {
  1640. DEBUGMSG(DBG_ERROR, (DTEXT("No buffers, dropping datagram\n")));
  1641. WPLOG(LL_A, LM_TDI, ("No buffers, dropping datagram"));
  1642. NtStatus = STATUS_DATA_NOT_ACCEPTED;
  1643. goto crdcDone;
  1644. }
  1645. pNdisBuffer = NdisBufferFromBuffer(pBuffer);
  1646. if (pCtdi->RecvDatagramCallback && !pCtdi->Closed)
  1647. {
  1648. if (BytesAvailable>PPTP_MAX_RECEIVE_SIZE)
  1649. {
  1650. DEBUGMSG(DBG_ERROR, (DTEXT("WAY too many bytes received. %d\n"), BytesAvailable));
  1651. WPLOG(LL_A, LM_TDI, ("WAY too many bytes received. %d", BytesAvailable));
  1652. NtStatus = STATUS_DATA_NOT_ACCEPTED;
  1653. ASSERT(BytesAvailable<PPTP_MAX_RECEIVE_SIZE);
  1654. }
  1655. else if (ReceiveDatagramFlags&TDI_RECEIVE_ENTIRE_MESSAGE ||
  1656. BytesAvailable==BytesIndicated)
  1657. {
  1658. ULONG BytesCopied;
  1659. // Let's just do a copy here.
  1660. TdiCopyBufferToMdl(Tsdu,
  1661. 0,
  1662. BytesIndicated,
  1663. pNdisBuffer,
  1664. 0,
  1665. &BytesCopied);
  1666. ASSERT(BytesCopied==BytesIndicated);
  1667. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_RECVDG); // pair in CtdiReceiveComplete
  1668. (void)// ToDo: We don't care about the return value?
  1669. pCtdi->RecvDatagramCallback(pCtdi->RecvContext,
  1670. SourceAddress,
  1671. pBuffer,
  1672. BytesIndicated);
  1673. // We've handed the buffer to the layer above. Clear the var so we don't
  1674. // free it when we leave here.
  1675. pBuffer = NULL;
  1676. *BytesTaken = BytesIndicated;
  1677. }
  1678. else
  1679. {
  1680. PRECV_DATAGRAM_CONTEXT pContext;
  1681. PIRP pIrp = IoAllocateIrp((CCHAR)(pCtdi->pFileObject->DeviceObject->StackSize +
  1682. NUM_STACKS_FOR_CONTEXT(sizeof(RECV_DATAGRAM_CONTEXT))),
  1683. FALSE);
  1684. if (!pIrp)
  1685. {
  1686. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  1687. NtStatus = STATUS_DATA_NOT_ACCEPTED;
  1688. gCounters.ulIoAllocateIrpFail++;
  1689. }
  1690. else
  1691. {
  1692. pContext = GET_CONTEXT(pIrp, RECV_DATAGRAM_CONTEXT);
  1693. pContext->SourceAddress = *(PTA_IP_ADDRESS)SourceAddress;
  1694. pContext->Length = BytesAvailable;
  1695. pContext->pBuffer = pBuffer;
  1696. TdiBuildReceiveDatagram(pIrp,
  1697. pCtdi->pFileObject->DeviceObject,
  1698. pCtdi->pFileObject,
  1699. CtdipReceiveDatagramCompleteCallback,
  1700. pCtdi,
  1701. pNdisBuffer,
  1702. PPTP_MAX_RECEIVE_SIZE,
  1703. NULL,
  1704. NULL,
  1705. 0);
  1706. IoSetNextIrpStackLocation(pIrp); // Required by TDI
  1707. *BytesTaken = 0;
  1708. *IoRequestPacket = pIrp;
  1709. NtStatus = STATUS_MORE_PROCESSING_REQUIRED;
  1710. pBuffer = NULL; // to keep us from freeing it here.
  1711. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_RECVDG); // pair in CtdipReceiveDatagramCompleteCallback
  1712. }
  1713. }
  1714. }
  1715. else
  1716. {
  1717. NtStatus = STATUS_DATA_NOT_ACCEPTED;
  1718. }
  1719. crdcDone:
  1720. if (pBuffer)
  1721. {
  1722. FreeBufferToPool(&pCtdi->Datagram.RxPool, pBuffer, TRUE);
  1723. }
  1724. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipReceiveDatagramCallback %08x\n"), NtStatus));
  1725. return NtStatus;
  1726. }
  1727. STATIC NTSTATUS
  1728. CtdipSendCallback(
  1729. IN PDEVICE_OBJECT pDeviceObject,
  1730. IN PIRP pIrp,
  1731. IN PVOID Context
  1732. )
  1733. {
  1734. PCTDI_DATA pCtdi = Context;
  1735. PVOID pData = NULL;
  1736. NDIS_STATUS Status = (NDIS_STATUS)pIrp->IoStatus.Status;
  1737. PCTDI_SEND_CONTEXT pSendContext;
  1738. CTDI_EVENT_SEND_COMPLETE pSendCompleteCallback;
  1739. PVOID CtdiContext;
  1740. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipSendCallback %08x\n"), Status));
  1741. pSendContext = (PCTDI_SEND_CONTEXT)IoGetCurrentIrpStackLocation(pIrp);
  1742. CtdiContext = pSendContext->Context;
  1743. pSendCompleteCallback = pSendContext->pSendCompleteCallback;
  1744. // ToDo: take action if the irp returns failure.
  1745. if (!pIrp->MdlAddress)
  1746. {
  1747. DEBUGMSG(DBG_WARN, (DTEXT("MdlAddress NULL\n")));
  1748. WPLOG(LL_A, LM_TDI, ("pIrp %p MdlAddress NULL", pIrp));
  1749. }
  1750. else
  1751. {
  1752. ASSERT(pIrp->MdlAddress->Next == NULL);
  1753. pData = MmGetMdlVirtualAddress(pIrp->MdlAddress);
  1754. #if PROBE
  1755. MmUnlockPages(pIrp->MdlAddress);
  1756. #endif
  1757. IoFreeMdl(pIrp->MdlAddress);
  1758. }
  1759. RELEASE_CONTEXT(pIrp, CTDI_SEND_CONTEXT);
  1760. IoFreeIrp(pIrp);
  1761. pSendCompleteCallback(CtdiContext, NULL, pData, Status);
  1762. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_SEND); // Pair in CtdiSend
  1763. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipSendCallback\n")));
  1764. return STATUS_MORE_PROCESSING_REQUIRED;
  1765. }
  1766. STATIC NTSTATUS
  1767. CtdipSendDatagramCallback(
  1768. IN PDEVICE_OBJECT pDeviceObject,
  1769. IN PIRP pIrp,
  1770. IN PVOID Context
  1771. )
  1772. {
  1773. PCTDI_DATA pCtdi = Context;
  1774. PVOID pData = NULL;
  1775. NDIS_STATUS Status = (NDIS_STATUS)pIrp->IoStatus.Status;
  1776. PCTDI_SEND_DATAGRAM_CONTEXT pSendContext;
  1777. CTDI_EVENT_SEND_COMPLETE pSendCompleteCallback;
  1778. PVOID CtdiContext, DatagramContext;
  1779. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipSendDatagramCallback %08x\n"), Status));
  1780. pSendContext = (PCTDI_SEND_DATAGRAM_CONTEXT)IoGetCurrentIrpStackLocation(pIrp);
  1781. CtdiContext = pSendContext->Context;
  1782. DatagramContext = pSendContext->DatagramContext;
  1783. pSendCompleteCallback = pSendContext->pSendCompleteCallback;
  1784. // ToDo: take action if the irp returns failure.
  1785. if (!pIrp->MdlAddress)
  1786. {
  1787. DEBUGMSG(DBG_WARN, (DTEXT("MdlAddress NULL\n")));
  1788. WPLOG(LL_A, LM_TDI, ("pIrp %p MdlAddress NULL", pIrp));
  1789. }
  1790. else
  1791. {
  1792. ASSERT(pIrp->MdlAddress->Next == NULL);
  1793. pData = MmGetMdlVirtualAddress(pIrp->MdlAddress);
  1794. #if PROBE
  1795. MmUnlockPages(pIrp->MdlAddress);
  1796. #endif
  1797. IoFreeMdl(pIrp->MdlAddress);
  1798. }
  1799. RELEASE_CONTEXT(pIrp, CTDI_SEND_DATAGRAM_CONTEXT);
  1800. IoFreeIrp(pIrp);
  1801. if (pSendCompleteCallback)
  1802. {
  1803. pSendCompleteCallback(CtdiContext, DatagramContext, pData, Status);
  1804. }
  1805. else
  1806. {
  1807. ASSERT(!"No SendCompleteHandler for datagram");
  1808. }
  1809. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_SENDDG); // Pair in CtdiSendDatagram
  1810. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipSendDatagramCallback\n")));
  1811. return STATUS_MORE_PROCESSING_REQUIRED;
  1812. }
  1813. /** public functions **/
  1814. NDIS_STATUS
  1815. CtdiInitialize(
  1816. IN ULONG ulFlags
  1817. )
  1818. {
  1819. TA_IP_ADDRESS Local;
  1820. UNICODE_STRING DeviceName;
  1821. NTSTATUS Status = STATUS_SUCCESS;
  1822. DEBUGMSG(DBG_FUNC|DBG_TDI, (DTEXT("+CtdiInitialize\n")));
  1823. if( fCtdiInitialized ){
  1824. goto ciDone;
  1825. }
  1826. InitializeListHead(&CtdiList);
  1827. InitializeListHead(&CtdiFreeList);
  1828. InitializeListHead(&CtdiRouteList);
  1829. // InitializeListHead(&CtdiRouteNotifyList);
  1830. NdisAllocateSpinLock(&CtdiListLock);
  1831. fCtdiInitialized = TRUE;
  1832. if (ulFlags&CTDI_FLAG_NETWORK_HEADER)
  1833. {
  1834. CtdiMdlFlags |= MDL_NETWORK_HEADER;
  1835. }
  1836. if (ulFlags&CTDI_FLAG_ENABLE_ROUTING)
  1837. {
  1838. NdisZeroMemory(&Local, sizeof(Local));
  1839. Local.TAAddressCount = 1;
  1840. Local.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  1841. Local.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1842. Local.Address[0].Address[0].sin_port = 0;
  1843. Local.Address[0].Address[0].in_addr = 0;
  1844. RtlInitUnicodeString(&DeviceName, DD_TCP_DEVICE_NAME);
  1845. Status = CtdipOpenProtocol(&DeviceName,
  1846. (PTRANSPORT_ADDRESS)&Local,
  1847. &hTcp,
  1848. &pFileTcp);
  1849. if (Status!=STATUS_SUCCESS)
  1850. {
  1851. goto ciDone;
  1852. }
  1853. RtlInitUnicodeString(&DeviceName, DD_IP_DEVICE_NAME);
  1854. Status = CtdipOpenProtocol(&DeviceName,
  1855. (PTRANSPORT_ADDRESS)&Local,
  1856. &hIp,
  1857. &pFileIp);
  1858. if (Status!=STATUS_SUCCESS)
  1859. {
  1860. goto ciDone;
  1861. }
  1862. }
  1863. ciDone:
  1864. if (Status!=STATUS_SUCCESS)
  1865. {
  1866. if (hTcp)
  1867. {
  1868. CtdipCloseProtocol(hTcp, pFileTcp);
  1869. hTcp = 0;
  1870. pFileTcp = NULL;
  1871. }
  1872. if (hIp)
  1873. {
  1874. CtdipCloseProtocol(hIp, pFileIp);
  1875. hIp = 0;
  1876. pFileIp = NULL;
  1877. }
  1878. NdisFreeSpinLock(&CtdiListLock);
  1879. fCtdiInitialized = FALSE;
  1880. }
  1881. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtdiInitialize %08x\n"), Status));
  1882. return (NDIS_STATUS)Status;
  1883. }
  1884. VOID
  1885. CtdiShutdown(
  1886. )
  1887. {
  1888. HANDLE h;
  1889. PFILE_OBJECT pFile;
  1890. UINT i;
  1891. DEBUGMSG(DBG_FUNC|DBG_TDI, (DTEXT("+CtdiShutdown\n")));
  1892. if (fCtdiInitialized)
  1893. {
  1894. fCtdiInitialized = FALSE;
  1895. NdisMSleep(30000);
  1896. // Allow code using these handles on other processors to complete
  1897. // before we close them.
  1898. if (hIp || pFileIp)
  1899. {
  1900. h = hIp;
  1901. hIp = 0;
  1902. pFile = pFileIp;
  1903. pFileIp = NULL;
  1904. CtdipCloseProtocol(h, pFile);
  1905. }
  1906. if (hTcp || pFileTcp)
  1907. {
  1908. h = hTcp;
  1909. hTcp = 0;
  1910. pFile = pFileTcp;
  1911. pFileTcp = NULL;
  1912. CtdipCloseProtocol(h, pFile);
  1913. }
  1914. // Some irps seem very slow to be cancelled by TCP.
  1915. for (i=0; i<300; i++)
  1916. {
  1917. if (IsListEmpty(&CtdiList) &&
  1918. IsListEmpty(&CtdiRouteList) &&
  1919. // IsListEmpty(&CtdiRouteNotifyList) &&
  1920. IsListEmpty(&CtdiFreeList))
  1921. {
  1922. break;
  1923. }
  1924. NdisMSleep(10000);
  1925. // Small window to allow irps to complete after closing their handles.
  1926. }
  1927. ASSERT(IsListEmpty(&CtdiList));
  1928. ASSERT(IsListEmpty(&CtdiRouteList));
  1929. // ASSERT(IsListEmpty(&CtdiRouteNotifyList));
  1930. NdisFreeSpinLock(&CtdiListLock);
  1931. }
  1932. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdiShutdown\n")));
  1933. }
  1934. NDIS_STATUS
  1935. CtdiClose(
  1936. IN HANDLE hCtdi
  1937. )
  1938. {
  1939. PCTDI_DATA pCtdi = (PCTDI_DATA)hCtdi;
  1940. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiClose\n")));
  1941. if (!IS_CTDI(pCtdi))
  1942. {
  1943. return NDIS_STATUS_SUCCESS;
  1944. }
  1945. WPLOG(LL_I, LM_TDI, ("pCtdi %p", pCtdi));
  1946. NdisAcquireSpinLock(&pCtdi->Lock);
  1947. if (!pCtdi->Closed)
  1948. {
  1949. pCtdi->Closed = TRUE;
  1950. switch (pCtdi->Type)
  1951. {
  1952. case CTDI_ENDPOINT:
  1953. case CTDI_CONNECTION:
  1954. {
  1955. break;
  1956. }
  1957. case CTDI_LISTEN:
  1958. {
  1959. while (!IsListEmpty(&pCtdi->Listen.ConnectList))
  1960. {
  1961. PLIST_ENTRY pListEntry;
  1962. PCTDI_DATA pConnect;
  1963. PIRP pIrp;
  1964. pListEntry = RemoveHeadList(&pCtdi->Listen.ConnectList);
  1965. pConnect = CONTAINING_RECORD(pListEntry,
  1966. CTDI_DATA,
  1967. Connection.ListEntry);
  1968. NdisReleaseSpinLock(&pCtdi->Lock);
  1969. // these derefs are for the double references placed when these are placed on
  1970. // the list
  1971. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_LIST);
  1972. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_LIST);
  1973. pIrp = IoAllocateIrp(pConnect->pFileObject->DeviceObject->StackSize, FALSE);
  1974. if (pIrp)
  1975. {
  1976. // Normally we would take a reference to pConnect for this irp, but
  1977. // these handles won't be getting a close from above, which means they
  1978. // are in need of one extra dereference.
  1979. SET_DBGFLAG(pConnect, CTDI_F_BUILD_DISASSOC);
  1980. TdiBuildDisassociateAddress(pIrp,
  1981. pConnect->pFileObject->DeviceObject,
  1982. pConnect->pFileObject,
  1983. CtdipDisassociateAddressCallback,
  1984. pConnect);
  1985. DEBUGMSG(DBG_TDI, (DTEXT("IoCallDriver TDI_DISASSOCIATE_ADDRESS\n")));
  1986. // Completion handler always called, don't care on return value.
  1987. (void)IoCallDriver(pConnect->pFileObject->DeviceObject, pIrp);
  1988. }
  1989. else
  1990. {
  1991. WPLOG(LL_A, LM_TDI, ("Failed to alloc IRP"));
  1992. gCounters.ulIoAllocateIrpFail++;
  1993. DEREFERENCE_OBJECT_EX(pConnect, CTDI_REF_DISASSO);
  1994. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_ADDRREF); // Pair in CtdipAddListenConnection
  1995. }
  1996. NdisAcquireSpinLock(&pCtdi->Lock);
  1997. }
  1998. CtlpCleanupCtls(pgAdapter);
  1999. break;
  2000. }
  2001. default:
  2002. break;
  2003. }
  2004. NdisReleaseSpinLock(&pCtdi->Lock);
  2005. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_INITIAL); // This derefs the initial reference
  2006. }
  2007. else
  2008. {
  2009. NdisReleaseSpinLock(&pCtdi->Lock);
  2010. }
  2011. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdiClose\n")));
  2012. return NDIS_STATUS_SUCCESS;
  2013. }
  2014. NDIS_STATUS
  2015. CtdiListen(
  2016. IN HANDLE hCtdi,
  2017. IN ULONG_PTR NumListen,
  2018. IN CTDI_EVENT_CONNECT_QUERY pConnectQueryHandler,
  2019. IN CTDI_EVENT_RECEIVE pReceiveHandler,
  2020. IN CTDI_EVENT_DISCONNECT pDisconnectHandler,
  2021. IN PVOID pContext
  2022. )
  2023. {
  2024. UINT i;
  2025. NDIS_STATUS ReturnStatus = NDIS_STATUS_SUCCESS;
  2026. PCTDI_DATA pCtdi = (PCTDI_DATA)hCtdi;
  2027. BOOLEAN Reference = FALSE;
  2028. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiListen\n")));
  2029. if (!IS_CTDI(pCtdi))
  2030. {
  2031. DEBUGMSG(DBG_ERROR, (DTEXT("Ctdi: Bad handle %p\n"), pCtdi));
  2032. WPLOG(LL_A, LM_TDI, ("Ctdi: Bad handle %p", pCtdi));
  2033. ReturnStatus = NDIS_STATUS_FAILURE;
  2034. goto clDone;
  2035. }
  2036. NdisAcquireSpinLock(&pCtdi->Lock);
  2037. pCtdi->Type = CTDI_LISTEN;
  2038. pCtdi->Listen.Context = pContext;
  2039. pCtdi->RecvCallback = pReceiveHandler;
  2040. pCtdi->ConnectQueryCallback = pConnectQueryHandler;
  2041. pCtdi->DisconnectCallback = pDisconnectHandler;
  2042. InitializeListHead(&pCtdi->Listen.ConnectList);
  2043. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_INLISTEN); // Pair in this func.
  2044. Reference = TRUE;
  2045. NdisReleaseSpinLock(&pCtdi->Lock);
  2046. for (i=0; i<NumListen; i++)
  2047. {
  2048. ReturnStatus = CtdipAddListenConnection(pCtdi);
  2049. if (ReturnStatus!=NDIS_STATUS_SUCCESS)
  2050. {
  2051. goto clDone;
  2052. }
  2053. }
  2054. ReturnStatus = CtdipSetEventHandler(pCtdi,
  2055. TDI_EVENT_CONNECT,
  2056. CtdipConnectCallback);
  2057. if (ReturnStatus!=NDIS_STATUS_SUCCESS)
  2058. {
  2059. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiSetEventHandler TDI_EVENT_CONNECT failed\n")));
  2060. WPLOG(LL_A, LM_TDI, ("CtdiSetEventHandler TDI_EVENT_CONNECT failed"));
  2061. goto clDone;
  2062. }
  2063. ReturnStatus = CtdipSetEventHandler(pCtdi,
  2064. TDI_EVENT_RECEIVE,
  2065. CtdipReceiveCallback);
  2066. if (ReturnStatus!=NDIS_STATUS_SUCCESS)
  2067. {
  2068. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiSetEventHandler TDI_EVENT_RECEIVE failed\n")));
  2069. WPLOG(LL_A, LM_TDI, ("CtdiSetEventHandler TDI_EVENT_RECEIVE failed"));
  2070. goto clDone;
  2071. }
  2072. ReturnStatus = CtdipSetEventHandler(pCtdi,
  2073. TDI_EVENT_DISCONNECT,
  2074. CtdipDisconnectCallback);
  2075. if (ReturnStatus!=NDIS_STATUS_SUCCESS)
  2076. {
  2077. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiSetEventHandler TDI_EVENT_DISCONNECT failed\n")));
  2078. WPLOG(LL_A, LM_TDI, ("CtdiSetEventHandler TDI_EVENT_DISCONNECT failed"));
  2079. goto clDone;
  2080. }
  2081. clDone:
  2082. if (Reference)
  2083. {
  2084. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_INLISTEN); // Pair in this func.
  2085. }
  2086. if (ReturnStatus!=NDIS_STATUS_SUCCESS)
  2087. {
  2088. // ToDo: cleanup on failure.
  2089. // Figure out how to undo address association, if necessary.
  2090. }
  2091. DEBUGMSG(DBG_FUNC|DBG_ERR(ReturnStatus), (DTEXT("-CtdiListen %08x\n"), ReturnStatus));
  2092. return ReturnStatus;
  2093. }
  2094. NDIS_STATUS
  2095. CtdiConnect(
  2096. IN HANDLE hCtdi,
  2097. IN PTRANSPORT_ADDRESS pAddress,
  2098. IN CTDI_EVENT_CONNECT_COMPLETE pConnectCompleteHandler,
  2099. IN CTDI_EVENT_RECEIVE pReceiveHandler,
  2100. IN CTDI_EVENT_DISCONNECT pDisconnectHandler,
  2101. IN PVOID pContext
  2102. )
  2103. {
  2104. UNICODE_STRING DeviceName;
  2105. OBJECT_ATTRIBUTES ObjectAttributes;
  2106. NDIS_STATUS ReturnStatus = NDIS_STATUS_SUCCESS;
  2107. NTSTATUS NtStatus;
  2108. PTIME pTimeout = NULL;
  2109. PIRP pIrp = NULL;
  2110. IO_STATUS_BLOCK IoStatusBlock;
  2111. PCTDI_DATA pEndpoint = (PCTDI_DATA)hCtdi;
  2112. PCTDI_DATA pConnect = NULL;
  2113. PTDI_CONNECTION_INFORMATION pRequestInfo = NULL;
  2114. PTDI_CONNECTION_INFORMATION pReturnInfo = NULL;
  2115. PTA_IP_ADDRESS pRemoteAddress;
  2116. PBOOLEAN pInboundFlag;
  2117. BOOLEAN CloseConnection = FALSE;
  2118. UCHAR EaBuffer[sizeof(FILE_FULL_EA_INFORMATION) +
  2119. TDI_CONNECTION_CONTEXT_LENGTH +
  2120. sizeof(PVOID)];
  2121. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION)EaBuffer;
  2122. PVOID *ppContext = (PVOID*)(pEa->EaName + TDI_CONNECTION_CONTEXT_LENGTH + 1);
  2123. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiConnect\n")));
  2124. ASSERT(KeGetCurrentIrql()<DISPATCH_LEVEL);
  2125. if (!IS_CTDI(pEndpoint))
  2126. {
  2127. DEBUGMSG(DBG_ERROR, (DTEXT("Ctdi: Bad handle %p\n"), pEndpoint));
  2128. WPLOG(LL_A, LM_TDI, ("Ctdi: Bad handle %p", pEndpoint));
  2129. ReturnStatus = NDIS_STATUS_FAILURE;
  2130. goto ccDone;
  2131. }
  2132. pConnect = CtdipDataAlloc();
  2133. if (!pConnect)
  2134. {
  2135. return NDIS_STATUS_RESOURCES;
  2136. }
  2137. pConnect->Type = CTDI_CONNECTION;
  2138. pConnect->Connection.Context = pContext;
  2139. pConnect->Connection.LocalEndpoint = pEndpoint;
  2140. pConnect->ConnectCompleteCallback = pConnectCompleteHandler;
  2141. pConnect->RecvCallback = pReceiveHandler;
  2142. pConnect->DisconnectCallback = pDisconnectHandler;
  2143. DeviceName.Length = sizeof(DD_TCP_DEVICE_NAME) - sizeof(WCHAR);
  2144. DeviceName.Buffer = DD_TCP_DEVICE_NAME;
  2145. InitializeObjectAttributes(&ObjectAttributes,
  2146. &DeviceName,
  2147. OBJ_CASE_INSENSITIVE,
  2148. NULL,
  2149. NULL);
  2150. NdisZeroMemory(pEa, sizeof(EaBuffer));
  2151. pEa->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  2152. pEa->EaValueLength = sizeof(PVOID);
  2153. NdisMoveMemory(pEa->EaName, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH);
  2154. *ppContext = pConnect;
  2155. NdisZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  2156. NtStatus =
  2157. ZwCreateFile(&pConnect->hFile, /* FileHandle */
  2158. FILE_READ_DATA | FILE_WRITE_DATA, /* Desired Access */
  2159. &ObjectAttributes, /* Object Attributes */
  2160. &IoStatusBlock, /* IO Status Block */
  2161. NULL, /* Allocation Size */
  2162. FILE_ATTRIBUTE_NORMAL, /* File Attributes */
  2163. 0, /* Share Access */
  2164. FILE_OPEN, /* Create Disposition */
  2165. 0, /* Create Options */
  2166. pEa, /* EaBuffer */
  2167. sizeof(EaBuffer) /* EaLength */
  2168. );
  2169. if (NtStatus!=STATUS_SUCCESS)
  2170. {
  2171. WPLOG(LL_A, LM_TDI, ("ZwCreateFile failed %08x", NtStatus));
  2172. ReturnStatus = NtStatus;
  2173. goto ccDone;
  2174. }
  2175. // Convert the address file handle to a FILE_OBJECT
  2176. NtStatus =
  2177. ObReferenceObjectByHandle(pConnect->hFile, /* Handle */
  2178. 0, /* DesiredAccess */
  2179. NULL, /* ObjectType */
  2180. KernelMode, /* AccessMode */
  2181. &pConnect->pFileObject, /* Object */
  2182. NULL /* HandleInfo */
  2183. );
  2184. if (NtStatus != STATUS_SUCCESS)
  2185. {
  2186. WPLOG(LL_A, LM_TDI, ("ObReferenceObjectByHandle failed %08x", NtStatus));
  2187. ReturnStatus = NtStatus;
  2188. goto ccDone;
  2189. }
  2190. // Make an irp to associate the endpoint and connection.
  2191. pIrp = IoAllocateIrp(pConnect->pFileObject->DeviceObject->StackSize, FALSE);
  2192. if (!pIrp)
  2193. {
  2194. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  2195. gCounters.ulIoAllocateIrpFail++;
  2196. ReturnStatus = NDIS_STATUS_RESOURCES;
  2197. goto ccDone;
  2198. }
  2199. REFERENCE_OBJECT_EX(pConnect, CTDI_REF_ASSOADDR); // Pair in CtdipAssociateAddressCallback
  2200. TdiBuildAssociateAddress(pIrp,
  2201. pConnect->pFileObject->DeviceObject,
  2202. pConnect->pFileObject,
  2203. CtdipAssociateAddressCallback,
  2204. pConnect,
  2205. pEndpoint->hFile);
  2206. // Associate address creates a reference from the connection to the endpoint.
  2207. REFERENCE_OBJECT_EX(pEndpoint, CTDI_REF_ADDRREF); // Pair in CtdipDisassociateAddressCallback
  2208. DEBUGMSG(DBG_TDI, (DTEXT("IoCallDriver TDI_ASSOCIATE_ADDRESS\n")));
  2209. // Completion handler always called, don't care on return value.
  2210. (void)IoCallDriver(pConnect->pFileObject->DeviceObject, pIrp);
  2211. ReturnStatus = CtdipSetEventHandler(pEndpoint,
  2212. TDI_EVENT_RECEIVE,
  2213. CtdipReceiveCallback);
  2214. if (ReturnStatus!=NDIS_STATUS_SUCCESS)
  2215. {
  2216. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiSetEventHandler TDI_EVENT_RECEIVE failed\n")));
  2217. WPLOG(LL_A, LM_TDI, ("CtdiSetEventHandler TDI_EVENT_RECEIVE failed"));
  2218. goto ccDone;
  2219. }
  2220. ReturnStatus = CtdipSetEventHandler(pEndpoint,
  2221. TDI_EVENT_DISCONNECT,
  2222. CtdipDisconnectCallback);
  2223. if (ReturnStatus!=NDIS_STATUS_SUCCESS)
  2224. {
  2225. DEBUGMSG(DBG_ERROR, (DTEXT("CtdiSetEventHandler TDI_EVENT_DISCONNECT failed\n")));
  2226. WPLOG(LL_A, LM_TDI, ("CtdiSetEventHandler TDI_EVENT_DISCONNECT failed"));
  2227. goto ccDone;
  2228. }
  2229. // Make an irp to establish the connection
  2230. pIrp = IoAllocateIrp(pConnect->pFileObject->DeviceObject->StackSize, FALSE);
  2231. if(!pIrp)
  2232. {
  2233. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  2234. gCounters.ulIoAllocateIrpFail++;
  2235. ReturnStatus = NDIS_STATUS_RESOURCES;
  2236. goto ccDone;
  2237. }
  2238. // No sign saying we can't allocate the request info, return info and address buffers
  2239. // in one shot.
  2240. pRequestInfo = MyMemAlloc(2*(sizeof(TDI_CONNECTION_INFORMATION)+
  2241. sizeof(TA_IP_ADDRESS)) +
  2242. 3*sizeof(PVOID) + sizeof(BOOLEAN),
  2243. TAG_CTDI_CONNECT_INFO);
  2244. if (!pRequestInfo)
  2245. {
  2246. WPLOG(LL_A, LM_Res, ("Failed to alloc memory"));
  2247. IoFreeIrp(pIrp);
  2248. pIrp = NULL;
  2249. ReturnStatus = NDIS_STATUS_RESOURCES;
  2250. goto ccDone;
  2251. }
  2252. NdisZeroMemory(pRequestInfo,
  2253. 2*(sizeof(TDI_CONNECTION_INFORMATION)+sizeof(TA_IP_ADDRESS))
  2254. + sizeof(BOOLEAN) + 3*sizeof(PVOID));
  2255. pConnect->Connection.ConnectInfo = pRequestInfo;
  2256. pRequestInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
  2257. pRemoteAddress =
  2258. (PTA_IP_ADDRESS)((PUCHAR)(pRequestInfo + 1) + sizeof(PVOID));
  2259. (ULONG_PTR)pRemoteAddress &=
  2260. ~((ULONG_PTR)sizeof(PVOID) - 1);
  2261. pRequestInfo->RemoteAddress = pRemoteAddress;
  2262. *pRemoteAddress = *(PTA_IP_ADDRESS)pAddress;
  2263. pReturnInfo =
  2264. (PTDI_CONNECTION_INFORMATION)
  2265. ((PUCHAR)(pRemoteAddress + 1) + sizeof(PVOID));
  2266. (ULONG_PTR)pReturnInfo &=
  2267. ~((ULONG_PTR)sizeof(PVOID) - 1);
  2268. pReturnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
  2269. pRemoteAddress =
  2270. (PTA_IP_ADDRESS)((PUCHAR)(pReturnInfo + 1) + sizeof(PVOID));
  2271. (ULONG_PTR)pRemoteAddress &=
  2272. ~((ULONG_PTR)sizeof(PVOID) - 1);
  2273. pReturnInfo->RemoteAddress = pRemoteAddress;
  2274. pInboundFlag = (PBOOLEAN)(pRemoteAddress + 1);
  2275. *pInboundFlag = FALSE;
  2276. pRemoteAddress->TAAddressCount = 1;
  2277. pRemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  2278. pRemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  2279. REFERENCE_OBJECT_EX(pConnect, CTDI_REF_CONNECT); // Pair in CtdipConnectCompleteCallback
  2280. TdiBuildConnect(pIrp,
  2281. pConnect->pFileObject->DeviceObject,
  2282. pConnect->pFileObject,
  2283. CtdipConnectCompleteCallback,
  2284. pConnect,
  2285. NULL, // ToDo: allow them to specify timeout
  2286. pRequestInfo,
  2287. pReturnInfo);
  2288. DEBUGMSG(DBG_TDI, (DTEXT("IoCallDriver TDI_CONNECT\n")));
  2289. // Completion handler always called, don't care on return value.
  2290. (void)IoCallDriver(pConnect->pFileObject->DeviceObject, pIrp);
  2291. ReturnStatus = STATUS_PENDING;
  2292. NdisInterlockedIncrement(&gCounters.OutboundConnectAttempts);
  2293. ccDone:;
  2294. if (!NT_SUCCESS(ReturnStatus))
  2295. {
  2296. if(pConnectCompleteHandler)
  2297. {
  2298. pConnectCompleteHandler(pContext, 0, ReturnStatus);
  2299. ReturnStatus = NDIS_STATUS_PENDING;
  2300. }
  2301. CtdiDisconnect(pConnect, TRUE);
  2302. CtdiClose(pConnect);
  2303. }
  2304. DEBUGMSG(DBG_FUNC|DBG_ERR(ReturnStatus), (DTEXT("-CtdiConnect %08x\n"), ReturnStatus));
  2305. return ReturnStatus;
  2306. }
  2307. NDIS_STATUS
  2308. CtdiDisconnect(
  2309. IN HANDLE hCtdi,
  2310. IN BOOLEAN Abort
  2311. )
  2312. {
  2313. PCTDI_DATA pCtdi = (PCTDI_DATA)hCtdi;
  2314. NDIS_STATUS Status;
  2315. PIRP pIrp = NULL;
  2316. PTIME pTimeout;
  2317. PTDI_CONNECTION_INFORMATION pConnectInfo;
  2318. BOOLEAN Disconnected = FALSE;
  2319. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiDisconnect\n")));
  2320. if (!IS_CTDI(pCtdi))
  2321. {
  2322. Status = NDIS_STATUS_SUCCESS;
  2323. goto cdDone;
  2324. }
  2325. SET_DBGFLAG(pCtdi, CTDI_F_DISCONNECT);
  2326. NdisAcquireSpinLock(&pCtdi->Lock);
  2327. if ((Abort && pCtdi->Connection.Abort) ||
  2328. (!Abort && pCtdi->Connection.Disconnect))
  2329. {
  2330. // Already disconnecting, bail out.
  2331. NdisReleaseSpinLock(&pCtdi->Lock);
  2332. Status = NDIS_STATUS_SUCCESS;
  2333. goto cdDone;
  2334. }
  2335. if (Abort)
  2336. {
  2337. pCtdi->Connection.Abort = TRUE;
  2338. }
  2339. pCtdi->Connection.Disconnect = TRUE;
  2340. pCtdi->Connection.DisconnectCount++;
  2341. if (pCtdi->pFileObject)
  2342. {
  2343. pIrp = IoAllocateIrp((CCHAR)(pCtdi->pFileObject->DeviceObject->StackSize +
  2344. NUM_STACKS_FOR_CONTEXT(sizeof(TIME)+sizeof(TDI_CONNECTION_INFORMATION))),
  2345. FALSE);
  2346. }
  2347. NdisReleaseSpinLock(&pCtdi->Lock);
  2348. if (!pIrp)
  2349. {
  2350. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  2351. gCounters.ulIoAllocateIrpFail++;
  2352. Status = STATUS_INSUFFICIENT_RESOURCES;
  2353. goto cdDone;
  2354. }
  2355. pTimeout = (PTIME)GetContextArea(pIrp, sizeof(TIME)+sizeof(TDI_CONNECTION_INFORMATION));
  2356. pConnectInfo = (PTDI_CONNECTION_INFORMATION)(pTimeout + 1);
  2357. pTimeout->LowPart = CtdiTcpDisconnectTimeout * -10000000L;
  2358. pTimeout->HighPart = (pTimeout->LowPart) ? -1 : 0;
  2359. // Responding to a controlled disconnect, we don't provide
  2360. // TDI_CONNECTION_INFORMATION, but we request it from the peer.
  2361. SET_DBGFLAG(pCtdi, CTDI_F_BUILD_DISCONNECT_2);
  2362. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_DISCONNECT); // Pair in CtdipDisconnectCompleteCallback
  2363. TdiBuildDisconnect(pIrp,
  2364. pCtdi->pFileObject->DeviceObject,
  2365. pCtdi->pFileObject,
  2366. CtdipDisconnectCompleteCallback,
  2367. pCtdi,
  2368. pTimeout,
  2369. (Abort ? TDI_DISCONNECT_ABORT : TDI_DISCONNECT_RELEASE),
  2370. NULL,
  2371. pConnectInfo);
  2372. // Completion handler always called, don't care on return value.
  2373. (void)IoCallDriver(pCtdi->pFileObject->DeviceObject, pIrp);
  2374. Status = NDIS_STATUS_SUCCESS;
  2375. cdDone:
  2376. if (!NT_SUCCESS(Status))
  2377. {
  2378. if (pIrp)
  2379. {
  2380. IoFreeIrp(pIrp);
  2381. }
  2382. }
  2383. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtdiDisconnect %08x\n"), Status));
  2384. return Status;
  2385. }
  2386. NDIS_STATUS
  2387. CtdiReceiveComplete(
  2388. IN HANDLE hCtdi,
  2389. IN PUCHAR pBuffer
  2390. )
  2391. {
  2392. PCTDI_DATA pCtdi = (PCTDI_DATA)hCtdi;
  2393. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiReceiveComplete\n")));
  2394. FreeBufferToPool(&pCtdi->Datagram.RxPool, pBuffer, TRUE);
  2395. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_RECVDG); // Pair in CtdiReceiveComplete
  2396. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdiReceiveComplete\n")));
  2397. return NDIS_STATUS_SUCCESS;
  2398. }
  2399. NDIS_STATUS
  2400. CtdiSend(
  2401. IN HANDLE hCtdi,
  2402. IN CTDI_EVENT_SEND_COMPLETE pSendCompleteHandler,
  2403. IN PVOID pContext,
  2404. IN PVOID pvBuffer,
  2405. IN ULONG ulLength
  2406. )
  2407. // We require that pBuffer not be temporary storage, as we will use it to send
  2408. // the data in an async call.
  2409. {
  2410. PCTDI_DATA pCtdi = (PCTDI_DATA)hCtdi;
  2411. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  2412. PIRP pIrp = NULL;
  2413. PMDL pMdl = NULL;
  2414. PUCHAR pBuffer = pvBuffer;
  2415. PCTDI_SEND_CONTEXT pSendContext;
  2416. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiSend\n")));
  2417. if (!IS_CTDI(pCtdi))
  2418. {
  2419. DEBUGMSG(DBG_ERROR, (DTEXT("Ctdi: Bad handle %p\n"), pCtdi));
  2420. WPLOG(LL_A, LM_TDI, ("Ctdi: Bad handle %p", pCtdi));
  2421. Status = NDIS_STATUS_FAILURE;
  2422. goto csDone;
  2423. }
  2424. // Allocate one extra stack location for context data.
  2425. pIrp = IoAllocateIrp((CCHAR)(pCtdi->pFileObject->DeviceObject->StackSize +
  2426. NUM_STACKS_FOR_CONTEXT(sizeof(CTDI_SEND_CONTEXT))), FALSE);
  2427. if (!pIrp)
  2428. {
  2429. WPLOG(LL_A, LM_TDI, ("Failed to alloc IRP"));
  2430. gCounters.ulIoAllocateIrpFail++;
  2431. Status = NDIS_STATUS_RESOURCES;
  2432. goto csDone;
  2433. }
  2434. pMdl = IoAllocateMdl(pBuffer,
  2435. ulLength,
  2436. FALSE,
  2437. FALSE,
  2438. pIrp);
  2439. if (!pMdl)
  2440. {
  2441. WPLOG(LL_A, LM_TDI, ("Failed to alloc MDL"));
  2442. gCounters.ulIoAllocateMdlFail++;
  2443. Status = NDIS_STATUS_RESOURCES;
  2444. goto csDone;
  2445. }
  2446. #if PROBE
  2447. __try
  2448. {
  2449. MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess);
  2450. }
  2451. __except (EXCEPTION_EXECUTE_HANDLER)
  2452. {
  2453. IoFreeMdl(pMdl);
  2454. pMdl = NULL;
  2455. }
  2456. #else
  2457. MmBuildMdlForNonPagedPool(pMdl);
  2458. #endif
  2459. // Get the first stack location for our own context use
  2460. pSendContext = GET_CONTEXT(pIrp, CTDI_SEND_CONTEXT);
  2461. pSendContext->Context = pContext;
  2462. pSendContext->pSendCompleteCallback = pSendCompleteHandler;
  2463. TdiBuildSend(pIrp,
  2464. pCtdi->pFileObject->DeviceObject,
  2465. pCtdi->pFileObject,
  2466. CtdipSendCallback,
  2467. pCtdi,
  2468. pMdl,
  2469. 0,
  2470. ulLength);
  2471. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_SEND); // pair in CtdipSendCallback
  2472. // Completion handler always called, don't care on return value.
  2473. (void)IoCallDriver(pCtdi->pFileObject->DeviceObject, pIrp);
  2474. Status = STATUS_PENDING;
  2475. csDone:
  2476. if (!NT_SUCCESS(Status))
  2477. {
  2478. if(pSendCompleteHandler)
  2479. {
  2480. pSendCompleteHandler(pContext, NULL, pBuffer, Status);
  2481. Status = NDIS_STATUS_PENDING;
  2482. }
  2483. if (pMdl)
  2484. {
  2485. IoFreeMdl(pMdl);
  2486. }
  2487. if (pIrp)
  2488. {
  2489. IoFreeIrp(pIrp);
  2490. }
  2491. }
  2492. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtdiSend %08x\n"), Status));
  2493. return Status;
  2494. }
  2495. NDIS_STATUS
  2496. CtdiSendDatagram(
  2497. IN HANDLE hCtdi,
  2498. IN CTDI_EVENT_SEND_COMPLETE pSendCompleteHandler,
  2499. IN PVOID pContext,
  2500. IN PVOID pDatagramContext,
  2501. IN PTRANSPORT_ADDRESS pDestination,
  2502. IN PUCHAR pBuffer,
  2503. IN ULONG ulLength
  2504. )
  2505. {
  2506. PCTDI_DATA pCtdi = (PCTDI_DATA)hCtdi;
  2507. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  2508. PIRP pIrp = NULL;
  2509. PMDL pMdl = NULL;
  2510. CTDI_SEND_DATAGRAM_CONTEXT *pSendContext;
  2511. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiSendDatagram\n")));
  2512. if (!IS_CTDI(pCtdi) || pCtdi->Closed)
  2513. {
  2514. Status = NDIS_STATUS_CLOSED;
  2515. goto csdDone;
  2516. }
  2517. pIrp = IoAllocateIrp((CCHAR)(pCtdi->pFileObject->DeviceObject->StackSize +
  2518. NUM_STACKS_FOR_CONTEXT(sizeof(CTDI_SEND_DATAGRAM_CONTEXT))), FALSE);
  2519. if (!pIrp)
  2520. {
  2521. WPLOG(LL_A, LM_TDI, ("Failed to alloc IRP"));
  2522. gCounters.ulIoAllocateIrpFail++;
  2523. Status = NDIS_STATUS_RESOURCES;
  2524. goto csdDone;
  2525. }
  2526. ASSERT(pCtdi->pFileObject->DeviceObject->StackSize + NUM_STACKS_FOR_CONTEXT(sizeof(CTDI_SEND_DATAGRAM_CONTEXT))<7);
  2527. pMdl = IoAllocateMdl(pBuffer,
  2528. ulLength,
  2529. FALSE,
  2530. FALSE,
  2531. NULL);
  2532. if (!pMdl)
  2533. {
  2534. WPLOG(LL_A, LM_TDI, ("Failed to alloc MDL"));
  2535. gCounters.ulIoAllocateMdlFail++;
  2536. Status = NDIS_STATUS_RESOURCES;
  2537. goto csdDone;
  2538. }
  2539. #if PROBE
  2540. __try
  2541. {
  2542. MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess);
  2543. }
  2544. __except (EXCEPTION_EXECUTE_HANDLER)
  2545. {
  2546. IoFreeMdl(pMdl);
  2547. pMdl = NULL;
  2548. }
  2549. #else
  2550. MmBuildMdlForNonPagedPool(pMdl);
  2551. #endif
  2552. pMdl->MdlFlags |= CtdiMdlFlags;
  2553. // Get the first stack location for our own context use
  2554. pSendContext = GET_CONTEXT(pIrp, CTDI_SEND_DATAGRAM_CONTEXT);
  2555. NdisZeroMemory(pSendContext, sizeof(CTDI_SEND_DATAGRAM_CONTEXT));
  2556. pSendContext->pSendCompleteCallback = pSendCompleteHandler;
  2557. pSendContext->Context = pContext;
  2558. pSendContext->DatagramContext = pDatagramContext;
  2559. pSendContext->TdiConnectionInfo.RemoteAddressLength = sizeof(pSendContext->Ip);
  2560. pSendContext->TdiConnectionInfo.RemoteAddress = &pSendContext->Ip;
  2561. pSendContext->Ip = *(PTA_IP_ADDRESS)pDestination;
  2562. if (pSendContext->Ip.Address[0].AddressLength!=TDI_ADDRESS_LENGTH_IP ||
  2563. pSendContext->Ip.Address[0].AddressType!=TDI_ADDRESS_TYPE_IP)
  2564. {
  2565. DEBUGMSG(DBG_WARN, (DTEXT("Misformed transmit address on %p\n"), pCtdi));
  2566. WPLOG(LL_A, LM_TDI, ("Misformed transmit address on %p", pCtdi));
  2567. }
  2568. TdiBuildSendDatagram(pIrp,
  2569. pCtdi->pFileObject->DeviceObject,
  2570. pCtdi->pFileObject,
  2571. CtdipSendDatagramCallback,
  2572. pCtdi,
  2573. pMdl,
  2574. ulLength,
  2575. &pSendContext->TdiConnectionInfo);
  2576. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_SENDDG); // Pair in CtdipSendDatagramCallback
  2577. // Completion handler always called, don't care on return value.
  2578. (void)IoCallDriver(pCtdi->pFileObject->DeviceObject, pIrp);
  2579. Status = STATUS_PENDING;
  2580. csdDone:
  2581. if (!NT_SUCCESS(Status))
  2582. {
  2583. if (pSendCompleteHandler)
  2584. {
  2585. pSendCompleteHandler(pContext, pDatagramContext, pBuffer, Status);
  2586. Status = NDIS_STATUS_PENDING;
  2587. }
  2588. if (pMdl)
  2589. {
  2590. IoFreeMdl(pMdl);
  2591. }
  2592. if (pIrp)
  2593. {
  2594. IoFreeIrp(pIrp);
  2595. }
  2596. }
  2597. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtdiSendDatagram %08x\n"), Status));
  2598. return Status;
  2599. }
  2600. STATIC VOID
  2601. CtdipDeleteHostRoute(
  2602. PCTDI_ROUTE pRoute
  2603. )
  2604. {
  2605. PFILE_OBJECT pFileObject = pFileTcp;
  2606. BOOLEAN NewRoute = FALSE;
  2607. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  2608. IPRouteEntry *pQueryBuffer = NULL;
  2609. IPRouteEntry *pNewRoute = NULL;
  2610. IPRouteEntry BestRoute;
  2611. BOOLEAN BestRouteFound = FALSE;
  2612. PIRP pIrp;
  2613. IO_STATUS_BLOCK IoStatusBlock;
  2614. PIO_STACK_LOCATION IrpSp;
  2615. TCP_REQUEST_QUERY_INFORMATION_EX QueryRoute;
  2616. TCP_REQUEST_SET_INFORMATION_EX *pSetRoute = NULL;
  2617. ULONG NumRoutes = 20;
  2618. ULONG Size = 0, QuerySize = 0;
  2619. ULONG i;
  2620. KEVENT Event;
  2621. #ifdef IP_ROUTE_REFCOUNT
  2622. OBJECT_ATTRIBUTES ObjectAttributes;
  2623. HANDLE IpFileHandle = 0;
  2624. #endif
  2625. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipDeleteHostRoute\n")));
  2626. if (!fCtdiInitialized)
  2627. {
  2628. Status = NDIS_STATUS_FAILURE;
  2629. goto cdhrDone;
  2630. }
  2631. if (!pRoute->ExternalRoute)
  2632. {
  2633. // Query TCPfor the current routing table
  2634. Status = CtdipIpQueryRouteTable(&pQueryBuffer, &QuerySize, &NumRoutes);
  2635. if (Status!=NDIS_STATUS_SUCCESS)
  2636. {
  2637. goto cdhrDone;
  2638. }
  2639. BestRoute.ire_mask = 0;
  2640. BestRoute.ire_metric1 = (ULONG)-1;
  2641. for (i=0; i<NumRoutes; i++)
  2642. {
  2643. DEBUGMSG(DBG_TDI, (DTEXT("Route %d.%d.%d.%d Type %d NextHop %d.%d.%d.%d Mask %d.%d.%d.%d Metric %d Index %d\n"),
  2644. IPADDR(pQueryBuffer[i].ire_dest),
  2645. pQueryBuffer[i].ire_type,
  2646. IPADDR(pQueryBuffer[i].ire_nexthop),
  2647. IPADDR(pQueryBuffer[i].ire_mask),
  2648. pQueryBuffer[i].ire_metric1,
  2649. pQueryBuffer[i].ire_index));
  2650. if (pQueryBuffer[i].ire_dest == pRoute->IpAddress &&
  2651. pQueryBuffer[i].ire_proto == IRE_PROTO_NETMGMT)
  2652. {
  2653. BestRoute = pQueryBuffer[i];
  2654. BestRouteFound = TRUE;
  2655. break;
  2656. }
  2657. }
  2658. // We've taken what we need from the route list. Free it.
  2659. MyMemFree(pQueryBuffer, QuerySize);
  2660. pQueryBuffer = NULL;
  2661. if (BestRouteFound)
  2662. {
  2663. #ifdef IP_ROUTE_REFCOUNT
  2664. Size = sizeof(IPRouteEntry);
  2665. pNewRoute = MyMemAlloc(Size, TAG_CTDI_ROUTE);
  2666. pSetRoute = (PVOID)pNewRoute;
  2667. if (!pNewRoute)
  2668. {
  2669. WPLOG(LL_A, LM_Res, ("Failed to alloc CTDI_ROUTE"));
  2670. Status = NDIS_STATUS_RESOURCES;
  2671. goto cdhrDone;
  2672. }
  2673. NdisZeroMemory(pNewRoute, Size);
  2674. #else
  2675. Size = sizeof(TCP_REQUEST_SET_INFORMATION_EX) + sizeof(IPRouteEntry);
  2676. pSetRoute = MyMemAlloc(Size, TAG_CTDI_ROUTE);
  2677. if (!pSetRoute)
  2678. {
  2679. WPLOG(LL_A, LM_Res, ("Failed to alloc CTDI_ROUTE"));
  2680. Status = NDIS_STATUS_RESOURCES;
  2681. goto cdhrDone;
  2682. }
  2683. NdisZeroMemory(pSetRoute, Size);
  2684. pSetRoute->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2685. pSetRoute->ID.toi_entity.tei_instance = 0;
  2686. pSetRoute->ID.toi_class = INFO_CLASS_PROTOCOL;
  2687. pSetRoute->ID.toi_type = INFO_TYPE_PROVIDER;
  2688. pSetRoute->ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  2689. pSetRoute->BufferSize = sizeof(IPRouteEntry);
  2690. pNewRoute = (IPRouteEntry*)&pSetRoute->Buffer[0];
  2691. #endif
  2692. *pNewRoute = BestRoute;
  2693. pNewRoute->ire_type = IRE_TYPE_INVALID;
  2694. DEBUGMSG(DBG_TDI, (DTEXT("DeleteHostRoute %d.%d.%d.%d Type %d NextHop %d.%d.%d.%d Index %d\n"),
  2695. IPADDR(pNewRoute->ire_dest), pNewRoute->ire_type,
  2696. IPADDR(pNewRoute->ire_nexthop), pNewRoute->ire_index));
  2697. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  2698. #ifdef IP_ROUTE_REFCOUNT
  2699. pFileObject = pFileIp;
  2700. pIrp = IoBuildDeviceIoControlRequest(
  2701. IOCTL_IP_SET_ROUTEWITHREF,
  2702. pFileObject->DeviceObject,
  2703. pNewRoute,
  2704. Size,
  2705. NULL,
  2706. 0,
  2707. FALSE,
  2708. &Event,
  2709. &IoStatusBlock);
  2710. #else
  2711. pIrp = IoBuildDeviceIoControlRequest(
  2712. IOCTL_TCP_SET_INFORMATION_EX,
  2713. pFileObject->DeviceObject,
  2714. pSetRoute,
  2715. Size,
  2716. NULL,
  2717. 0,
  2718. FALSE,
  2719. &Event,
  2720. &IoStatusBlock);
  2721. #endif
  2722. if (!pIrp ) {
  2723. WPLOG(LL_A, LM_Res, ("Failed to build IP_SET_ROUTEWITHREF IRP"));
  2724. gCounters.ulIoBuildIrpFail++;
  2725. goto cdhrDone;
  2726. }
  2727. IrpSp = IoGetNextIrpStackLocation(pIrp);
  2728. IrpSp->FileObject = pFileObject;
  2729. Status = IoCallDriver(pFileObject->DeviceObject, pIrp);
  2730. if (Status == STATUS_PENDING) {
  2731. KeWaitForSingleObject(&Event,
  2732. Executive,
  2733. KernelMode,
  2734. FALSE,
  2735. NULL);
  2736. Status = IoStatusBlock.Status;
  2737. }
  2738. if (Status != STATUS_SUCCESS) {
  2739. DEBUGMSG(DBG_TDI, (DTEXT("Create host route failed %08x\n"), Status));
  2740. goto cdhrDone;
  2741. }
  2742. }
  2743. }
  2744. cdhrDone:
  2745. if (pRoute)
  2746. {
  2747. MyInterlockedRemoveEntryList(&pRoute->ListEntry, &CtdiListLock);
  2748. MyMemFree(pRoute, sizeof(CTDI_ROUTE));
  2749. }
  2750. if (pSetRoute)
  2751. {
  2752. MyMemFree(pSetRoute, Size);
  2753. }
  2754. if (pQueryBuffer)
  2755. {
  2756. MyMemFree(pQueryBuffer, QuerySize);
  2757. }
  2758. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipDeleteHostRoute\n")));
  2759. }
  2760. NDIS_STATUS
  2761. CtdiAddHostRoute(
  2762. IN PTA_IP_ADDRESS pIpAddress
  2763. )
  2764. {
  2765. PFILE_OBJECT pFileObject = pFileTcp;
  2766. PCTDI_ROUTE pRoute = NULL;
  2767. BOOLEAN NewRoute = FALSE;
  2768. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  2769. IPRouteEntry *pQueryBuffer = NULL;
  2770. IPRouteEntry *pNewRoute = NULL;
  2771. IPRouteEntry BestRoute;
  2772. BOOLEAN BestRouteFound = FALSE;
  2773. PIRP pIrp = NULL;
  2774. IO_STATUS_BLOCK IoStatusBlock;
  2775. PIO_STACK_LOCATION IrpSp;
  2776. TCP_REQUEST_QUERY_INFORMATION_EX QueryRoute;
  2777. TCP_REQUEST_SET_INFORMATION_EX *pSetRoute = NULL;
  2778. ULONG NumRoutes = 20;
  2779. ULONG Size = 0, QuerySize = 0;
  2780. ULONG i;
  2781. KEVENT Event;
  2782. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiAddHostRoute %d.%d.%d.%d\n"),
  2783. IPADDR(pIpAddress->Address[0].Address[0].in_addr)));
  2784. NdisAcquireSpinLock(&CtdiListLock);
  2785. pRoute = CtdipFindRoute(pIpAddress->Address[0].Address[0].in_addr);
  2786. if (pRoute)
  2787. {
  2788. REFERENCE_OBJECT(pRoute); // Pair in CtdiDeleteHostRoute
  2789. pRoute = NULL;
  2790. }
  2791. else
  2792. {
  2793. NewRoute = TRUE;
  2794. pRoute = MyMemAlloc(sizeof(CTDI_ROUTE), TAG_CTDI_ROUTE);
  2795. if (!pRoute)
  2796. {
  2797. WPLOG(LL_A, LM_Res, ("Failed to alloc CTDI_ROUTE"));
  2798. Status = NDIS_STATUS_RESOURCES;
  2799. NdisReleaseSpinLock(&CtdiListLock);
  2800. goto cahrDone;
  2801. }
  2802. NdisZeroMemory(pRoute, sizeof(CTDI_ROUTE));
  2803. pRoute->IpAddress = pIpAddress->Address[0].Address[0].in_addr;
  2804. INIT_REFERENCE_OBJECT(pRoute, CtdipDeleteHostRoute); // Pair in CtdiDeleteHostRoute
  2805. InsertTailList(&CtdiRouteList, &pRoute->ListEntry);
  2806. }
  2807. NdisReleaseSpinLock(&CtdiListLock);
  2808. if (NewRoute)
  2809. {
  2810. // Query TCPfor the current routing table
  2811. Status = CtdipIpQueryRouteTable(&pQueryBuffer, &QuerySize, &NumRoutes);
  2812. if (Status!=NDIS_STATUS_SUCCESS)
  2813. {
  2814. goto cahrDone;
  2815. }
  2816. BestRoute.ire_mask = 0;
  2817. BestRoute.ire_metric1 = (ULONG)-1;
  2818. for (i=0; i<NumRoutes; i++)
  2819. {
  2820. DEBUGMSG(DBG_TDI, (DTEXT("Route %d.%d.%d.%d Type %d NextHop %d.%d.%d.%d Mask %d.%d.%d.%d Metric %d Index %d\n"),
  2821. IPADDR(pQueryBuffer[i].ire_dest),
  2822. pQueryBuffer[i].ire_type,
  2823. IPADDR(pQueryBuffer[i].ire_nexthop),
  2824. IPADDR(pQueryBuffer[i].ire_mask),
  2825. pQueryBuffer[i].ire_metric1,
  2826. pQueryBuffer[i].ire_index));
  2827. if (pQueryBuffer[i].ire_dest == (pIpAddress->Address[0].Address[0].in_addr &
  2828. pQueryBuffer[i].ire_mask))
  2829. {
  2830. if ((BestRoute.ire_mask == pQueryBuffer[i].ire_mask &&
  2831. BestRoute.ire_metric1 > pQueryBuffer[i].ire_metric1) ||
  2832. ntohl(pQueryBuffer[i].ire_mask) > ntohl(BestRoute.ire_mask))
  2833. {
  2834. BestRoute = pQueryBuffer[i];
  2835. BestRouteFound = TRUE;
  2836. }
  2837. }
  2838. }
  2839. // We've taken what we need from the route list. Free it.
  2840. MyMemFree(pQueryBuffer, QuerySize);
  2841. pQueryBuffer = NULL;
  2842. if (!BestRouteFound)
  2843. {
  2844. DEBUGMSG(DBG_WARN, (DTEXT("Add host route. No route found\n")));
  2845. WPLOG(LL_A, LM_TDI, ("Add host route. No route found"));
  2846. }
  2847. else
  2848. {
  2849. // If we're using the IP refcounts, always add and delete the route.
  2850. #ifndef IP_ROUTE_REFCOUNT
  2851. if (BestRoute.ire_dest == pIpAddress->Address[0].Address[0].in_addr &&
  2852. BestRoute.ire_mask == 0xFFFFFFFF) {
  2853. //
  2854. // A route already exists so don't add
  2855. //
  2856. pRoute->ExternalRoute = TRUE;
  2857. Status = NDIS_STATUS_SUCCESS;
  2858. goto cahrDone;
  2859. }
  2860. #endif
  2861. #ifdef IP_ROUTE_REFCOUNT
  2862. Size = sizeof(IPRouteEntry);
  2863. pNewRoute = MyMemAlloc(Size, TAG_CTDI_ROUTE);
  2864. pSetRoute = (PVOID)pNewRoute;
  2865. if (!pNewRoute)
  2866. {
  2867. WPLOG(LL_A, LM_Res, ("Failed to alloc CTDI_ROUTE"));
  2868. Status = NDIS_STATUS_RESOURCES;
  2869. goto cahrDone;
  2870. }
  2871. NdisZeroMemory(pNewRoute, Size);
  2872. #else
  2873. Size = sizeof(TCP_REQUEST_SET_INFORMATION_EX) + sizeof(IPRouteEntry);
  2874. pSetRoute = MyMemAlloc(Size, TAG_CTDI_ROUTE);
  2875. if (!pSetRoute)
  2876. {
  2877. WPLOG(LL_A, LM_Res, ("Failed to alloc CTDI_ROUTE"));
  2878. Status = NDIS_STATUS_RESOURCES;
  2879. goto cahrDone;
  2880. }
  2881. NdisZeroMemory(pSetRoute, Size);
  2882. pSetRoute->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2883. pSetRoute->ID.toi_entity.tei_instance = 0;
  2884. pSetRoute->ID.toi_class = INFO_CLASS_PROTOCOL;
  2885. pSetRoute->ID.toi_type = INFO_TYPE_PROVIDER;
  2886. pSetRoute->ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  2887. pSetRoute->BufferSize = sizeof(IPRouteEntry);
  2888. pNewRoute = (IPRouteEntry*)&pSetRoute->Buffer[0];
  2889. #endif
  2890. *pNewRoute = BestRoute;
  2891. pNewRoute->ire_dest = pIpAddress->Address[0].Address[0].in_addr;
  2892. pNewRoute->ire_mask = 0xFFFFFFFF;
  2893. pNewRoute->ire_proto = IRE_PROTO_NETMGMT;
  2894. // Check DIRECT/INDIRECT only if this is not a host route
  2895. if(BestRoute.ire_mask != 0xFFFFFFFF)
  2896. {
  2897. if ((BestRoute.ire_mask & pIpAddress->Address[0].Address[0].in_addr) ==
  2898. (BestRoute.ire_mask & BestRoute.ire_nexthop))
  2899. {
  2900. pNewRoute->ire_type = IRE_TYPE_DIRECT;
  2901. }
  2902. else
  2903. {
  2904. pNewRoute->ire_type = IRE_TYPE_INDIRECT;
  2905. }
  2906. }
  2907. DEBUGMSG(DBG_TDI, (DTEXT("AddHostRoute %d.%d.%d.%d Type %d NextHop %d.%d.%d.%d Index %d\n"),
  2908. IPADDR(pNewRoute->ire_dest), pNewRoute->ire_type,
  2909. IPADDR(pNewRoute->ire_nexthop), pNewRoute->ire_index));
  2910. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  2911. #ifdef IP_ROUTE_REFCOUNT
  2912. pFileObject = pFileIp;
  2913. pIrp = IoBuildDeviceIoControlRequest(
  2914. IOCTL_IP_SET_ROUTEWITHREF,
  2915. pFileObject->DeviceObject,
  2916. pNewRoute,
  2917. Size,
  2918. NULL,
  2919. 0,
  2920. FALSE,
  2921. &Event,
  2922. &IoStatusBlock);
  2923. #else
  2924. pIrp = IoBuildDeviceIoControlRequest(
  2925. IOCTL_TCP_SET_INFORMATION_EX,
  2926. pFileObject->DeviceObject,
  2927. pSetRoute,
  2928. Size,
  2929. NULL,
  2930. 0,
  2931. FALSE,
  2932. &Event,
  2933. &IoStatusBlock);
  2934. #endif
  2935. if (!pIrp) {
  2936. WPLOG(LL_A, LM_Res, ("Failed to build IP_SET_ROUTEWITHREF IRP"));
  2937. gCounters.ulIoBuildIrpFail++;
  2938. goto cahrDone;
  2939. }
  2940. IrpSp = IoGetNextIrpStackLocation(pIrp);
  2941. IrpSp->FileObject = pFileObject;
  2942. Status = IoCallDriver(pFileObject->DeviceObject, pIrp);
  2943. if (Status == STATUS_PENDING) {
  2944. KeWaitForSingleObject(&Event,
  2945. Executive,
  2946. KernelMode,
  2947. FALSE,
  2948. NULL);
  2949. Status = IoStatusBlock.Status;
  2950. }
  2951. if (Status != STATUS_SUCCESS) {
  2952. DEBUGMSG(DBG_TDI, (DTEXT("Create host route failed %08x\n"), Status));
  2953. goto cahrDone;
  2954. }
  2955. //CtdipIpRequestRoutingNotification(pIpAddress->Address[0].Address[0].in_addr);
  2956. // The route's a keeper. Set the var to null so we don't free it
  2957. pRoute = NULL;
  2958. }
  2959. }
  2960. cahrDone:
  2961. if (pRoute)
  2962. {
  2963. MyInterlockedRemoveEntryList(&pRoute->ListEntry, &CtdiListLock);
  2964. MyMemFree(pRoute, sizeof(CTDI_ROUTE));
  2965. }
  2966. if (pSetRoute)
  2967. {
  2968. MyMemFree(pSetRoute, Size);
  2969. }
  2970. if (pQueryBuffer)
  2971. {
  2972. MyMemFree(pQueryBuffer, QuerySize);
  2973. }
  2974. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtdiAddHostRoute %08x\n"), Status));
  2975. return Status;
  2976. }
  2977. NDIS_STATUS
  2978. CtdiDeleteHostRoute(
  2979. IN PTA_IP_ADDRESS pIpAddress
  2980. )
  2981. {
  2982. PCTDI_ROUTE pRoute = NULL;
  2983. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiDeleteHostRoute\n")));
  2984. NdisAcquireSpinLock(&CtdiListLock);
  2985. pRoute = CtdipFindRoute(pIpAddress->Address[0].Address[0].in_addr);
  2986. NdisReleaseSpinLock(&CtdiListLock);
  2987. if (pRoute)
  2988. {
  2989. DEREFERENCE_OBJECT(pRoute); // Pair in CtdiAddHostRoute
  2990. }
  2991. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdiDeleteHostRoute\n")));
  2992. return NDIS_STATUS_SUCCESS;
  2993. }
  2994. NDIS_STATUS
  2995. CtdiCreateEndpoint(
  2996. OUT PHANDLE phCtdi,
  2997. IN ULONG_PTR ulAddressFamily,
  2998. IN ULONG_PTR ulType,
  2999. IN PTRANSPORT_ADDRESS pAddress,
  3000. IN ULONG_PTR ulRxPadding
  3001. )
  3002. {
  3003. UNICODE_STRING DeviceName;
  3004. OBJECT_ATTRIBUTES ObjectAttributes;
  3005. NDIS_STATUS ReturnStatus = NDIS_STATUS_SUCCESS;
  3006. NTSTATUS NtStatus;
  3007. IO_STATUS_BLOCK IoStatusBlock;
  3008. PCTDI_DATA pCtdi = NULL;
  3009. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiCreateEndpoint\n")));
  3010. DBG_D(DBG_TAPI, KeGetCurrentIrql());
  3011. // Validate TDI initialized
  3012. if ( !fCtdiInitialized ) {
  3013. DEBUGMSG(DBG_ERROR | DBG_TDI, (DTEXT("CtdiCreateEndpoint: TDI interface hasn't been initialized!\n")));
  3014. WPLOG(LL_A, LM_TDI, ("CtdiCreateEndpoint: TDI interface hasn't been initialized!"));
  3015. ReturnStatus = NDIS_STATUS_FAILURE;
  3016. goto cceDone;
  3017. }
  3018. ASSERT(ulAddressFamily==AF_INET);
  3019. if (ulAddressFamily!=AF_INET)
  3020. {
  3021. DEBUGMSG(DBG_ERROR|DBG_TDI, (DTEXT("unsupported family\n")));
  3022. WPLOG(LL_A, LM_TDI, ("unsupported family"));
  3023. ReturnStatus = NDIS_STATUS_OPEN_FAILED;
  3024. goto cceDone;
  3025. }
  3026. // Alloc our endpoint structure.
  3027. pCtdi = CtdipDataAlloc();
  3028. if (!pCtdi)
  3029. {
  3030. ReturnStatus = NDIS_STATUS_RESOURCES;
  3031. goto cceDone;
  3032. }
  3033. pCtdi->Type = CTDI_ENDPOINT;
  3034. switch (ulType)
  3035. {
  3036. case SOCK_RAW:
  3037. {
  3038. WCHAR DeviceNameBuffer[sizeof(DD_RAW_IP_DEVICE_NAME) + 16];
  3039. WCHAR ProtocolNumberBuffer[8];
  3040. UNICODE_STRING ProtocolNumber;
  3041. TA_IP_ADDRESS TmpAddress = *(PTA_IP_ADDRESS)pAddress;
  3042. pCtdi->Type = CTDI_DATAGRAM;
  3043. InitBufferPool(&pCtdi->Datagram.RxPool,
  3044. ALIGN_UP(PPTP_MAX_RECEIVE_SIZE+ulRxPadding, ULONG_PTR),
  3045. 0, // MaxBuffers, no limit
  3046. 10, // Buffers per block
  3047. 0, // Frees per collection
  3048. TRUE, // These are MDLs
  3049. TAG_CTDI_DGRAM);
  3050. NdisZeroMemory(DeviceNameBuffer, sizeof(DeviceNameBuffer));
  3051. DeviceName.Buffer = DeviceNameBuffer;
  3052. DeviceName.MaximumLength = sizeof(DeviceNameBuffer);
  3053. DeviceName.Length = 0;
  3054. RtlAppendUnicodeToString(&DeviceName, DD_RAW_IP_DEVICE_NAME);
  3055. RtlAppendUnicodeToString(&DeviceName, L"\\");
  3056. ProtocolNumber.Buffer = ProtocolNumberBuffer;
  3057. ProtocolNumber.MaximumLength = sizeof(ProtocolNumberBuffer);
  3058. ProtocolNumber.Length = 0;
  3059. RtlIntegerToUnicodeString(((PTA_IP_ADDRESS)pAddress)->Address[0].Address[0].sin_port,
  3060. 10,
  3061. &ProtocolNumber);
  3062. RtlAppendUnicodeStringToString(&DeviceName, &ProtocolNumber);
  3063. TmpAddress.Address[0].Address[0].sin_port = 0;
  3064. TmpAddress.Address[0].Address[0].in_addr = 0;
  3065. NdisZeroMemory(TmpAddress.Address[0].Address[0].sin_zero,
  3066. sizeof(TmpAddress.Address[0].Address[0].sin_zero));
  3067. NtStatus = CtdipOpenProtocol(&DeviceName,
  3068. pAddress,
  3069. &pCtdi->hFile,
  3070. &pCtdi->pFileObject);
  3071. if (NtStatus!=STATUS_SUCCESS)
  3072. {
  3073. ReturnStatus = NtStatus;
  3074. goto cceDone;
  3075. }
  3076. break;
  3077. }
  3078. case SOCK_DGRAM: // for UDP
  3079. {
  3080. DeviceName.Length = sizeof(DD_UDP_DEVICE_NAME) - sizeof(WCHAR);
  3081. DeviceName.Buffer = DD_UDP_DEVICE_NAME;
  3082. pCtdi->Type = CTDI_DATAGRAM;
  3083. InitBufferPool(&pCtdi->Datagram.RxPool,
  3084. ALIGN_UP(PPTP_MAX_RECEIVE_SIZE+ulRxPadding, ULONG_PTR),
  3085. 0, // MaxBuffers, no limit
  3086. 10, // Buffers per block
  3087. 0, // Frees per collection
  3088. TRUE, // These are MDLs
  3089. TAG_CTDI_DGRAM);
  3090. NtStatus = CtdipOpenProtocol(&DeviceName,
  3091. pAddress,
  3092. &pCtdi->hFile,
  3093. &pCtdi->pFileObject);
  3094. if (NtStatus!=STATUS_SUCCESS)
  3095. {
  3096. ReturnStatus = NtStatus;
  3097. goto cceDone;
  3098. }
  3099. break;
  3100. }
  3101. case SOCK_STREAM:
  3102. {
  3103. RtlInitUnicodeString(&DeviceName, DD_TCP_DEVICE_NAME);
  3104. NtStatus = CtdipOpenProtocol(&DeviceName,
  3105. pAddress,
  3106. &pCtdi->hFile,
  3107. &pCtdi->pFileObject);
  3108. if (NtStatus!=STATUS_SUCCESS)
  3109. {
  3110. ReturnStatus = NtStatus;
  3111. goto cceDone;
  3112. }
  3113. break;
  3114. }
  3115. default:
  3116. DEBUGMSG(DBG_ERROR|DBG_TDI, (DTEXT("unsupported Type\n")));
  3117. WPLOG(LL_A, LM_TDI, ("unsupported Type"));
  3118. ReturnStatus = NDIS_STATUS_OPEN_FAILED;
  3119. goto cceDone;
  3120. }
  3121. cceDone:
  3122. if (ReturnStatus!=NDIS_STATUS_SUCCESS)
  3123. {
  3124. if (pCtdi)
  3125. {
  3126. CtdipDataFree(pCtdi);
  3127. pCtdi = NULL;
  3128. }
  3129. }
  3130. // Return the CTDI_DATA as a handle.
  3131. *phCtdi = (HANDLE)pCtdi;
  3132. DEBUGMSG(DBG_FUNC|DBG_ERR(ReturnStatus), (DTEXT("-CtdiCreateEndpoint Sts:%08x hCtdi:%08x\n"), ReturnStatus, pCtdi));
  3133. return ReturnStatus;
  3134. }
  3135. NDIS_STATUS
  3136. CtdiSetEventHandler(
  3137. IN HANDLE hCtdi,
  3138. IN ULONG ulEventType,
  3139. IN PVOID pEventHandler,
  3140. IN PVOID pContext
  3141. )
  3142. {
  3143. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  3144. PCTDI_DATA pCtdi = (PCTDI_DATA)hCtdi;
  3145. PVOID PrivateCallback = NULL;
  3146. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiSetEventHandler Type:%d\n"), ulEventType));
  3147. switch (ulEventType)
  3148. {
  3149. case TDI_EVENT_RECEIVE_DATAGRAM:
  3150. {
  3151. if (pCtdi->Type==CTDI_DATAGRAM)
  3152. {
  3153. PrivateCallback = CtdipReceiveDatagramCallback;
  3154. pCtdi->RecvDatagramCallback = pEventHandler;
  3155. pCtdi->RecvContext = pContext;
  3156. }
  3157. else
  3158. {
  3159. DEBUGMSG(DBG_ERROR, (DTEXT("Tried to register RecvDgram handler on wrong handle.\n")));
  3160. WPLOG(LL_A, LM_TDI, ("Tried to register RecvDgram handler on wrong handle."));
  3161. Status = NDIS_STATUS_FAILURE;
  3162. }
  3163. break;
  3164. }
  3165. default:
  3166. Status = NDIS_STATUS_NOT_SUPPORTED;
  3167. break;
  3168. }
  3169. if (Status==NDIS_STATUS_SUCCESS && PrivateCallback!=NULL)
  3170. {
  3171. Status = CtdipSetEventHandler(pCtdi,
  3172. ulEventType,
  3173. PrivateCallback);
  3174. }
  3175. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiSetEventHandler %08x\n"), Status));
  3176. return Status;
  3177. }
  3178. NDIS_STATUS
  3179. CtdiSetInformation(
  3180. IN HANDLE hCtdi,
  3181. IN ULONG_PTR ulSetType,
  3182. IN PTDI_CONNECTION_INFORMATION pConnectionInformation,
  3183. IN CTDI_EVENT_SET_COMPLETE pSetCompleteHandler,
  3184. IN PVOID pContext
  3185. )
  3186. {
  3187. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiSetInformation\n")));
  3188. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdiSetInformation\n")));
  3189. return NDIS_STATUS_FAILURE;
  3190. }
  3191. STATIC NTSTATUS
  3192. CtdipQueryInformationCallback(
  3193. PDEVICE_OBJECT pDeviceObject,
  3194. PIRP pIrp,
  3195. PVOID Context
  3196. )
  3197. {
  3198. PCTDI_DATA pCtdi = Context;
  3199. NDIS_STATUS Status = (NDIS_STATUS)pIrp->IoStatus.Status;
  3200. PCTDI_QUERY_CONTEXT pQuery;
  3201. CTDI_EVENT_QUERY_COMPLETE pQueryCompleteCallback;
  3202. PVOID CtdiContext;
  3203. PVOID pBuffer;
  3204. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdipQueryInformationCallback\n")));
  3205. pQuery = (PCTDI_QUERY_CONTEXT)IoGetCurrentIrpStackLocation(pIrp);
  3206. CtdiContext = pQuery->Context;
  3207. pQueryCompleteCallback = pQuery->pQueryCompleteCallback;
  3208. pBuffer = MmGetMdlVirtualAddress(pIrp->MdlAddress);
  3209. #if PROBE
  3210. MmUnlockPages(pIrp->MdlAddress);
  3211. #endif
  3212. IoFreeMdl(pIrp->MdlAddress);
  3213. RELEASE_CONTEXT(pIrp, CTDI_QUERY_CONTEXT);
  3214. IoFreeIrp(pIrp);
  3215. pQueryCompleteCallback(CtdiContext, pBuffer, Status);
  3216. DEREFERENCE_OBJECT_EX(pCtdi, CTDI_REF_QUERY);
  3217. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdipQueryInformationCallback\n")));
  3218. return STATUS_MORE_PROCESSING_REQUIRED;
  3219. }
  3220. NDIS_STATUS
  3221. CtdiQueryInformation(
  3222. IN HANDLE hCtdi,
  3223. IN ULONG ulQueryType,
  3224. IN OUT PVOID pBuffer,
  3225. IN ULONG Length,
  3226. IN CTDI_EVENT_QUERY_COMPLETE pQueryCompleteHandler,
  3227. IN PVOID pContext
  3228. )
  3229. {
  3230. PIRP pIrp = NULL;
  3231. PMDL pMdl = NULL;
  3232. PCTDI_DATA pCtdi = (PCTDI_DATA) hCtdi;
  3233. NDIS_STATUS Status = NDIS_STATUS_PENDING;
  3234. PCTDI_QUERY_CONTEXT pQuery;
  3235. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiQueryInformation\n")));
  3236. pIrp = IoAllocateIrp((CCHAR)(pCtdi->pFileObject->DeviceObject->StackSize +
  3237. NUM_STACKS_FOR_CONTEXT(sizeof(CTDI_QUERY_CONTEXT))),
  3238. FALSE);
  3239. if (!pIrp)
  3240. {
  3241. WPLOG(LL_A, LM_Res, ("Failed to alloc IRP"));
  3242. gCounters.ulIoAllocateIrpFail++;
  3243. Status = NDIS_STATUS_RESOURCES;
  3244. goto cqiDone;
  3245. }
  3246. pMdl = IoAllocateMdl(pBuffer, Length, FALSE, FALSE, pIrp);
  3247. if (!pMdl)
  3248. {
  3249. IoFreeIrp(pIrp);
  3250. WPLOG(LL_A, LM_Res, ("Failed to alloc MDL"));
  3251. gCounters.ulIoAllocateMdlFail++;
  3252. Status = NDIS_STATUS_RESOURCES;
  3253. goto cqiDone;
  3254. }
  3255. #if PROBE
  3256. __try
  3257. {
  3258. MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess);
  3259. }
  3260. __except (EXCEPTION_EXECUTE_HANDLER)
  3261. {
  3262. IoFreeMdl(pMdl);
  3263. pMdl = NULL;
  3264. Status = NDIS_STATUS_RESOURCES;
  3265. }
  3266. #else
  3267. MmBuildMdlForNonPagedPool(pMdl);
  3268. #endif
  3269. pQuery = GET_CONTEXT(pIrp, CTDI_QUERY_CONTEXT);
  3270. pQuery->Context = pContext;
  3271. pQuery->pQueryCompleteCallback = pQueryCompleteHandler;
  3272. TdiBuildQueryInformation(pIrp,
  3273. pCtdi->pFileObject->DeviceObject,
  3274. pCtdi->pFileObject,
  3275. CtdipQueryInformationCallback,
  3276. pCtdi,
  3277. ulQueryType,
  3278. pMdl);
  3279. REFERENCE_OBJECT_EX(pCtdi, CTDI_REF_QUERY);
  3280. // Completion handler always called, don't care on return value.
  3281. (void)IoCallDriver(pCtdi->pFileObject->DeviceObject, pIrp);
  3282. cqiDone:
  3283. if (pQueryCompleteHandler && !NT_SUCCESS(Status))
  3284. {
  3285. pQueryCompleteHandler(pContext, pBuffer, Status);
  3286. Status = NDIS_STATUS_PENDING;
  3287. }
  3288. DEBUGMSG(DBG_FUNC|DBG_ERR(Status), (DTEXT("-CtdiQueryInformation %08x\n"), Status));
  3289. return Status;
  3290. }
  3291. VOID CtdiCleanupLooseEnds()
  3292. {
  3293. PLIST_ENTRY ListEntry;
  3294. if (!fCtdiInitialized)
  3295. {
  3296. return;
  3297. }
  3298. DEBUGMSG(DBG_FUNC, (DTEXT("+CtdiCleanupLooseEnds\n")));
  3299. if (!IsListEmpty(&CtdiFreeList))
  3300. {
  3301. ScheduleWorkItem(CtdipDataFreeWorker, NULL, NULL, 0);
  3302. }
  3303. DEBUGMSG(DBG_FUNC, (DTEXT("-CtdiCleanupLooseEnds\n")));
  3304. }
  3305. VOID CtdiSetRequestPending(
  3306. IN HANDLE hCtdi
  3307. )
  3308. {
  3309. PCTDI_DATA pCtdi = (PCTDI_DATA) hCtdi;
  3310. pCtdi->CloseReqPending = TRUE;
  3311. }
  3312. NTSTATUS
  3313. CtdiSetTdiAOOption(
  3314. IN FILE_OBJECT* pAddress,
  3315. IN ULONG ulOption,
  3316. IN ULONG ulValue)
  3317. // Turn off UDP checksums on open UDP address object 'pAddress'.
  3318. //
  3319. {
  3320. NTSTATUS status;
  3321. PDEVICE_OBJECT pDeviceObject;
  3322. PIO_STACK_LOCATION pIrpSp;
  3323. IO_STATUS_BLOCK iosb;
  3324. PIRP pIrp;
  3325. TCP_REQUEST_SET_INFORMATION_EX* pInfo;
  3326. CHAR achBuf[ sizeof(*pInfo) + sizeof(ULONG) ];
  3327. pInfo = (TCP_REQUEST_SET_INFORMATION_EX* )achBuf;
  3328. pInfo->ID.toi_entity.tei_entity = CL_TL_ENTITY;
  3329. pInfo->ID.toi_entity.tei_instance = 0;
  3330. pInfo->ID.toi_class = INFO_CLASS_PROTOCOL;
  3331. pInfo->ID.toi_type = INFO_TYPE_ADDRESS_OBJECT;
  3332. pInfo->ID.toi_id = ulOption;
  3333. NdisMoveMemory( pInfo->Buffer, &ulValue, sizeof(ulValue) );
  3334. pInfo->BufferSize = sizeof(ulValue);
  3335. pDeviceObject = IoGetRelatedDeviceObject( pAddress );
  3336. pIrp = IoBuildDeviceIoControlRequest(
  3337. IOCTL_TCP_WSH_SET_INFORMATION_EX,
  3338. pDeviceObject,
  3339. (PVOID )pInfo,
  3340. sizeof(*pInfo) + sizeof(ulValue),
  3341. NULL,
  3342. 0,
  3343. FALSE,
  3344. NULL,
  3345. &iosb );
  3346. if (!pIrp)
  3347. {
  3348. DEBUGMSG(DBG_ERROR, (DTEXT("TdixSetTdiAOOption Irp?\n")));
  3349. WPLOG( LL_A, LM_TDI, ( "TdixSetTdiAOOption Irp?" ) );
  3350. return NDIS_STATUS_RESOURCES;
  3351. }
  3352. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  3353. pIrpSp->FileObject = pAddress;
  3354. status = IoCallDriver( pDeviceObject, pIrp );
  3355. if(NT_SUCCESS(status))
  3356. {
  3357. status = iosb.Status;
  3358. }
  3359. return status;
  3360. }
  3361. VOID
  3362. CtdiEnableIpHdrIncl(
  3363. IN HANDLE hCtdi)
  3364. // Turn on IP_HDRINCL on raw IP address object.
  3365. //
  3366. {
  3367. NTSTATUS status;
  3368. PCTDI_DATA pCtdi = (PCTDI_DATA) hCtdi;
  3369. status = CtdiSetTdiAOOption(pCtdi->pFileObject, AO_OPTION_IP_HDRINCL, TRUE);
  3370. ASSERT(status == STATUS_SUCCESS);
  3371. }