Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3718 lines
116 KiB

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