TDIClient.c
上传用户:zanmei2
上传日期:2010-03-06
资源大小:775k
文件大小:32k
源码类别:

通讯编程文档

开发平台:

C/C++

  1. /*++
  2. Copyright (c) 2005  Changzhi Zhou All Rights Reserved
  3. Module Name:
  4.     TDIClient.c
  5. Abstract:
  6.     This module contains the routines relevant to TDI client calls.
  7. Environment:
  8.     Kernel mode
  9. Revision History:
  10. Changzhi Zhou Feb 5, 2005
  11. --*/
  12. #include "TDIClient.h"
  13. #include "main.h"
  14. NTSTATUS InitializeConnection( PDEVICE_EXTENSION deviceExtension )
  15. /*++
  16. Routine Description:
  17. 1. Open a transport address and get the highest deviceobject of the transport stack.
  18. 2. Build RecvContext in the DeviceExtension
  19. 3. SetTdiEventHandle, includes TDI_EVENT_RECEIVE_DATAGRAM and TDI_EVENT_ERROR
  20. Arguments:
  21.     deviceExtension - pointer to a device object extension.
  22. Return Value:
  23.     NT status code.
  24. --*/
  25. {
  26. NTSTATUS status;
  27. static USHORT Port = LOCAL_PORT;
  28. if ( ( deviceExtension->hTransAddr ) || ( deviceExtension->lpTransAddrFileObject ) )
  29. return STATUS_INVALID_DEVICE_STATE;
  30. status = TDIOpenTransportAddress( wcharNetDevName,
  31. &deviceExtension->hTransAddr,
  32. &deviceExtension->lpTransAddrFileObject,
  33. Port
  34. );
  35. DebugPrint(("OpenTransAddr: handle = %x, lpFileObj = %x, status = %xn",
  36. deviceExtension->hTransAddr, deviceExtension->lpTransAddrFileObject, status ));
  37. if ( status != STATUS_SUCCESS )
  38. {
  39. deviceExtension->lpTransAddrFileObject = NULL;
  40. deviceExtension->hTransAddr = NULL;
  41. return status;
  42. }
  43. Port += 0x100;
  44. deviceExtension->TDILowerDeviceObject = IoGetRelatedDeviceObject( deviceExtension->lpTransAddrFileObject );
  45. DebugPrint(("TDI Provider: 0x%xn", deviceExtension->TDILowerDeviceObject ));
  46. if ( deviceExtension->TDILowerDeviceObject == NULL )
  47. {
  48. ObDereferenceObject ( deviceExtension->lpTransAddrFileObject );
  49. ZwClose ( deviceExtension->hTransAddr );
  50. deviceExtension->lpTransAddrFileObject = NULL;
  51. deviceExtension->hTransAddr = NULL;
  52. return STATUS_UNSUCCESSFUL;
  53. }
  54. TDIBuildRecvContext( &deviceExtension->recvContext );
  55. TDIClnSetEventHandler( deviceExtension->lpTransAddrFileObject,
  56. deviceExtension->TDILowerDeviceObject, TDI_EVENT_RECEIVE_DATAGRAM,
  57. TDIEventRecvDatagram, deviceExtension );
  58. TDIClnSetEventHandler( deviceExtension->lpTransAddrFileObject,
  59. deviceExtension->TDILowerDeviceObject, TDI_EVENT_ERROR,
  60. TDIEventError, NULL );
  61. return status;
  62. }
  63. NTSTATUS Disconnection ( PDEVICE_EXTENSION deviceExtension )
  64. /*++
  65. Routine Description:
  66. 1. SetTdiEventhandle TDI_EVENT_RECEIVE_DATAGRAM to NULL
  67. 2. Free RecvContext in the DeviceExtension
  68. 3. Close an opened transport address.
  69. 3. SetTdiEventHandle, includes TDI_EVENT_RECEIVE_DATAGRAM and TDI_EVENT_ERROR
  70. Arguments:
  71.     deviceExtension - pointer to a device object extension.
  72. Return Value:
  73.     NT status code.
  74. --*/
  75. {
  76. NTSTATUS status;
  77. if ( ( deviceExtension->hTransAddr == NULL ) || ( deviceExtension->lpTransAddrFileObject == NULL ) )
  78. return STATUS_INVALID_DEVICE_STATE;
  79. TDIClnSetEventHandler( deviceExtension->lpTransAddrFileObject,
  80. deviceExtension->TDILowerDeviceObject, TDI_EVENT_RECEIVE_DATAGRAM,
  81. NULL, deviceExtension );
  82. TDIFreeRecvContext( &deviceExtension->recvContext );
  83. ObDereferenceObject ( deviceExtension->lpTransAddrFileObject );
  84. deviceExtension->lpTransAddrFileObject = NULL;
  85. status = ZwClose ( deviceExtension->hTransAddr );
  86. if ( status == STATUS_SUCCESS )
  87. deviceExtension->hTransAddr = NULL;
  88. else
  89. {
  90. DebugPrint(("ZwClose hTransAddr failed with status %x !n", status ));
  91. }
  92. return status;
  93. }
  94. NTSTATUS TDISendDatagram(
  95.     IN PDEVICE_OBJECT DeviceObject,
  96.     IN PIRP Irp
  97. )
  98. /*++
  99. Routine Description:
  100.   This function is called in SampleWrite. It builds a internel irp and send down 
  101.   to the underlying transport. Until the irp completes or timeout, it will return.
  102.   The remote peer's IP address and port are indicated by RemoteAddress and 
  103.   RemotePort in deviceExtension.
  104. 1. TdiBuildInternalDeviceControlIrp for TDI_SEND_DATAGRAM
  105. 2. Allocate and lockpage a MDL based on Irp->MdlAddress
  106. 3. TdiBuildSendDatagram and pass down to the underlying transport device.
  107. 4. Wait 3 seconds for the completion. If timeout, cancel the irp
  108. 5. Set the Irp according with the completed irp.
  109. Note:
  110. This routine is synchronous.
  111. It must be running at IRQL = PASSIVE_LEVEL
  112. Arguments:
  113.    DeviceObject - pointer to a device object.
  114.    Irp - pointer to an I/O Request Packet for IRP_MJ_WRITE.
  115. Return Value:
  116.     NT status code.
  117. --*/
  118. {
  119. NTSTATUS status;
  120. PIRP pIrp;
  121. PDEVICE_EXTENSION deviceExtension;
  122. KEVENT Event;
  123. IO_STATUS_BLOCK IoStatus;
  124. PMDL pMdl;
  125. PVOID VirtualAddress;
  126. ULONG Length;
  127. EXCEPTION_POINTERS        * pExceptionInfo;
  128. ULONG                       lclExceptionCode;
  129. PVOID                       lclExceptionAddr;
  130. PVOID SystemAddress;
  131. TA_IP_ADDRESS RmtAddress = {1, {TDI_ADDRESS_LENGTH_IP, TDI_ADDRESS_TYPE_IP, { REMOTE_PORT, REMOTE_ADDRESS}}};
  132. TDI_CONNECTION_INFORMATION RmtInfo = {0, 0, 0, 0, sizeof(RmtAddress), &RmtAddress};
  133. deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension;
  134. RmtAddress.Address->Address->sin_port = deviceExtension->RemotePort;
  135. RmtAddress.Address->Address->in_addr = deviceExtension->RemoteAddress;
  136. status = STATUS_SUCCESS;
  137. KeInitializeEvent( &Event, NotificationEvent, FALSE);
  138. pIrp = TdiBuildInternalDeviceControlIrp(
  139. TDI_SEND_DATAGRAM,
  140. deviceExtension->TDILowerDeviceObject,
  141. deviceExtension->lpTransAddrFileObject,
  142. &Event,
  143. &IoStatus );
  144. if ( NULL == pIrp )
  145. {
  146. DebugPrint(("TDISendDatagram: Allocate Irp failedn"));
  147. return STATUS_INSUFFICIENT_RESOURCES;
  148. }
  149. VirtualAddress = MmGetMdlVirtualAddress ( Irp->MdlAddress );
  150. Length = MmGetMdlByteCount( Irp->MdlAddress );
  151. ASSERT ( VirtualAddress && Length );
  152. pMdl = IoAllocateMdl ( VirtualAddress, Length, FALSE, FALSE, pIrp );
  153. if ( NULL == pMdl )
  154. {
  155. DebugPrint(("TDISendDatagram: Allocate Mdl failedn"));
  156. return STATUS_INSUFFICIENT_RESOURCES;
  157. }
  158. _try
  159. {
  160. MmProbeAndLockPages(pMdl,                     // (Try to) fix buffer.
  161. KernelMode,
  162. IoModifyAccess
  163. );
  164. }
  165. _except(
  166. pExceptionInfo = GetExceptionInformation(),                                                                                                                                                                                                    
  167. lclExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode,                                                                                                                                                                             
  168. lclExceptionAddr = pExceptionInfo->ExceptionRecord->ExceptionAddress,                                                                                                                                                                          
  169. EXCEPTION_EXECUTE_HANDLER                                                                                                                                                                                                                      
  170. )                                                                                                                                                                                                                                               
  171. {                                                                                                                                                                                                                                                    
  172. DebugPrint((".TDISendDatagram:  MmProbeAndLockPages() failed.  Error = 0x%08x at 0x%08xn",
  173. lclExceptionCode, lclExceptionAddr));
  174. status = STATUS_UNSUCCESSFUL;
  175. IoFreeMdl ( pMdl );
  176. CompleteRequest ( pIrp, status, 0 );
  177. Irp->IoStatus.Information = 0;
  178. return status;
  179. }
  180. TdiBuildSendDatagram(
  181. pIrp,
  182. deviceExtension->TDILowerDeviceObject,
  183. deviceExtension->lpTransAddrFileObject,
  184. NULL,
  185. NULL,
  186. pMdl,
  187. Length,
  188. &RmtInfo
  189. );
  190. status = IoCallDriver ( deviceExtension->TDILowerDeviceObject, pIrp );
  191. if( ( status != STATUS_SUCCESS ) || ( STATUS_PENDING != status ) )
  192. {
  193. DebugPrint(("TDISendDatagram: Problem in IoCallDriver with status %xn", status ));
  194. }
  195. if ( status == STATUS_PENDING )
  196. {
  197.         LARGE_INTEGER TimeOut;
  198. NTSTATUS waitStatus;
  199. DebugPrint(("Send data pending... wait for 3 secondsn"));
  200.         TimeOut.QuadPart = -30000 * 1000;         // Calculate timeout value (5 seconds from now).
  201. waitStatus = KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, &TimeOut);
  202. if ( STATUS_TIMEOUT == waitStatus )
  203. {
  204. DebugPrint(("TDISendDatagram: Send data time out...n"));
  205. IoCancelIrp ( pIrp );
  206. KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, 0);
  207. }
  208. }
  209. Irp->IoStatus.Information = IoStatus.Information;
  210. DebugPrint(("TDISendDatagram: Send %d bytesn", Irp->IoStatus.Information ));
  211. status = ((STATUS_SUCCESS==status) || (STATUS_PENDING== status)) ? IoStatus.Status : status;
  212. return status;
  213. }
  214. NTSTATUS TDIEventError(
  215.    IN PVOID TdiEventContext,  // The endpoint's file object.
  216.    IN NTSTATUS Status         // Status code indicating error type.
  217.    )
  218. /*++
  219. Tdi error handle.
  220. --*/
  221. {
  222.    DebugPrint(("Sample ErrorEventHandler: Status: 0x%8.8Xn", Status) );
  223.    return( STATUS_SUCCESS );
  224. }
  225. NTSTATUS TDIEventRecvDatagram(
  226.     IN PVOID  TdiEventContext,
  227.     IN LONG  SourceAddressLength,
  228.     IN PVOID  SourceAddress,
  229.     IN LONG  OptionsLength,
  230.     IN PVOID  Options,
  231.     IN ULONG  ReceiveDatagramFlags,
  232.     IN ULONG  BytesIndicated,
  233.     IN ULONG  BytesAvailable,
  234.     OUT ULONG  *BytesTaken,
  235.     IN PVOID  Tsdu,
  236.     OUT PIRP  *IoRequestPacket
  237.     )
  238. /*++
  239. Routine Description:
  240.   TDI_EVENT_RECEIVE_DATAGRAM handle.
  241.   When a UDP packet from particular address and port arrive, this callback function will be called.
  242.   Usually BytesIndicated is less than or equal to BytesAvailable. If less, a Irp should be buildt
  243.   for the remainder data. This irp has be pre-allocated by TDIBuildRecvContext.
  244. Note:
  245. Don't forget to call IoSetNextIrpStackLocation to handle the IoRequestPacket.
  246. Because the stack locations of this irp between this function and underlying transport are identical.
  247.   Pls refer to Windows DDK documentation chapter relevant to this handle.
  248. --*/
  249. {
  250. LONG i;
  251. PUCHAR p;
  252. PIRP pIrp;
  253. NTSTATUS status;
  254. ULONG BytesToCopy;
  255. ULONG stageSize;
  256. PDEVICE_EXTENSION deviceExtension;
  257. deviceExtension = (PDEVICE_EXTENSION)TdiEventContext;
  258. DebugPrint(("SourceAddress: "));
  259. p = (PUCHAR)SourceAddress;
  260. for( i = 0; i < SourceAddressLength; i++)
  261. {
  262. DbgPrint("%2x ", p[ i ] );
  263. }
  264. DbgPrint(("n"));
  265. DebugPrint(("ReceiveDatagramFlags: %xn", ReceiveDatagramFlags ));
  266. DebugPrint(("BytesIndicated: %dn", BytesIndicated ));
  267. DebugPrint(("BytesAvailable: %dn", BytesAvailable ));
  268. *BytesTaken = BytesIndicated;
  269. CopyToRingBuffer( deviceExtension, (PUCHAR)Tsdu, BytesIndicated );
  270. *IoRequestPacket = NULL;
  271. status = STATUS_SUCCESS;
  272. if ( BytesIndicated < BytesAvailable )
  273. {
  274. if ( deviceExtension->recvContext.pIrp )
  275. {
  276. pIrp = deviceExtension->recvContext.pIrp;
  277. DebugPrint(("EventRecvDatagram: pIrp = %xn", deviceExtension->recvContext.pIrp ));
  278. TdiBuildReceiveDatagram( pIrp,
  279. deviceExtension->TDILowerDeviceObject,
  280. deviceExtension->lpTransAddrFileObject,
  281. TDIRecvRemainderCompRoutine,
  282. deviceExtension,
  283. deviceExtension->recvContext.pMdl,
  284. 0,
  285. &(deviceExtension->recvContext.ReceiveDatagramInfo),
  286. &(deviceExtension->recvContext.ReturnInfo),
  287. TDI_RECEIVE_NORMAL);
  288. IoSetNextIrpStackLocation ( pIrp );
  289. *IoRequestPacket = pIrp;
  290. status = STATUS_MORE_PROCESSING_REQUIRED;
  291. }
  292. }
  293. return status;
  294. }
  295. VOID CopyToRingBuffer(
  296. PDEVICE_EXTENSION deviceExtension,
  297. PUCHAR LinearBuffer,
  298. ULONG BytesIndicated )
  299. /*++
  300. Routine Description:
  301.   This function is called by TDIEventRecvDatagram and TDIRecvRemainderCompRoutine.
  302.   It copies linear buffer containing network packet to ring buffer. If source buffer length
  303.   is more than the length of ReceiveBuffer, the last part of LinearBuffer will be copied
  304.   to destination buffer.
  305.   If there is WaitOnMaskIrp in deviceExtension and the WaitMask meets SERIAL_EV_RXCHAR || SERIAL_EV_RLSD,
  306.   it will complete the WaitOnMaskIrp to indicate the application that there are some data arrive.
  307.   The destination ringbuffer, deviceExtension->RxBuffer, is shared with IRP_MJ_READ.
  308.   So the access to the ringbuffer must be synchronous.
  309. Arguments:
  310.   deviceExtension - pointer to device object extension
  311.   LinearBuffer - Tsdu containing network packets.
  312.   BytesIndicated - the length of LinearBuffer
  313. Return Value:
  314.     NT status code.
  315. --*/
  316. {
  317. ULONG stageSize;
  318. KIRQL oldIrql;
  319. ULONG BytesToCopy;
  320. PUCHAR lpSrc;
  321. BytesToCopy = BytesIndicated;
  322. lpSrc = LinearBuffer;
  323. if ( BytesIndicated > RINGBUFFER_SIZE )
  324. {
  325. lpSrc = (PUCHAR)LinearBuffer + BytesIndicated - RINGBUFFER_SIZE;
  326. BytesToCopy = RINGBUFFER_SIZE;
  327. }
  328. KeAcquireSpinLock(&deviceExtension->ThreadSpinLock, &oldIrql);
  329. stageSize = deviceExtension->RxBuffer + RINGBUFFER_SIZE - deviceExtension->lpRx;
  330. if( BytesToCopy <= stageSize )
  331. RtlCopyMemory ( deviceExtension->lpRx, lpSrc, BytesToCopy );
  332. else
  333. {
  334. RtlCopyMemory ( deviceExtension->lpRx, lpSrc, stageSize );
  335. RtlCopyMemory ( deviceExtension->RxBuffer, lpSrc + stageSize, ( BytesToCopy - stageSize ) );
  336. }
  337. deviceExtension->lpRx = deviceExtension->RxBuffer + ( ( RINGBUFFER_SIZE - stageSize + BytesToCopy ) % RINGBUFFER_SIZE );
  338. deviceExtension->SerialStatus.AmountInInQueue += BytesToCopy;
  339. if ( deviceExtension->SerialStatus.AmountInInQueue > RINGBUFFER_SIZE )
  340. {
  341. deviceExtension->lpRead = deviceExtension->lpRx;
  342. deviceExtension->SerialStatus.AmountInInQueue = RINGBUFFER_SIZE;
  343. }
  344. if( ( deviceExtension->WaitOnMaskIrp ) &&
  345. ( ( deviceExtension->WaitMask & SERIAL_EV_RXCHAR ) || ( deviceExtension->WaitMask & SERIAL_EV_RLSD ) ) )
  346. {
  347. DebugPrint(("ClientEventRecv: Complete WaitOnMaskIrpn"));
  348. deviceExtension->SerialStatus.EofReceived = TRUE;
  349. *(PULONG)deviceExtension->WaitOnMaskIrp->AssociatedIrp.SystemBuffer = ( SERIAL_EV_RXCHAR | SERIAL_EV_RLSD );
  350. CompleteRequest( deviceExtension->WaitOnMaskIrp, STATUS_SUCCESS, sizeof( ULONG ) );
  351. deviceExtension->WaitOnMaskIrp = NULL;
  352. SampleIoDecrement( deviceExtension );
  353. }
  354. KeReleaseSpinLock( &deviceExtension->ThreadSpinLock, oldIrql );
  355. }
  356. NTSTATUS TDIBuildRecvContext( PRECV_CONTEXT lpContext)
  357. /*++
  358. Routine Description:
  359.   This function is called by InitializeConnection.
  360.   It builds RecvContext, including pIrp, pMdl, and locks the Mdl.
  361. Arguments:
  362.   lpContext - pointer to deviceExtension->recvContext
  363. Return Value:
  364.     NT status code.
  365. --*/
  366. {
  367. PIRP pIrp;
  368. PMDL pMdl;
  369. PDEVICE_EXTENSION deviceExtension;
  370. EXCEPTION_POINTERS        * pExceptionInfo;
  371. ULONG                       lclExceptionCode;
  372. PVOID                       lclExceptionAddr;
  373. PIO_STACK_LOCATION ioStack;
  374. if( lpContext->pIrp || lpContext->pMdl || ( lpContext->RemainderBuffer == NULL ) )
  375. return STATUS_UNSUCCESSFUL;
  376. deviceExtension = CONTAINING_RECORD( lpContext, DEVICE_EXTENSION, recvContext );
  377. pIrp = IoAllocateIrp ( deviceExtension->TDILowerDeviceObject->StackSize + 2, FALSE );
  378. /*
  379. Because the irp will be used for many times, TdiBuildInternalDeviceControlIrp is not best.
  380. */
  381. /* pIrp = TdiBuildInternalDeviceControlIrp(
  382. TDI_RECEIVE_DATAGRAM,
  383. deviceExtension->TDILowerDeviceObject,
  384. deviceExtension->lpTransAddrFileObject,
  385. &lpContext->Event,
  386. &lpContext->IoStatus
  387. );
  388. */
  389. if (NULL == pIrp)
  390. {
  391. DebugPrint(("TdiBuildInternalIrp failedn"));
  392. return STATUS_INSUFFICIENT_RESOURCES;
  393. }else
  394. {
  395. DebugPrint(("TDIBuildRecvContext: pIrp = %xn", pIrp ));
  396. }
  397. pMdl = IoAllocateMdl ( lpContext->RemainderBuffer,
  398. RECVREMAINDER_BUFFER_SIZE, FALSE, FALSE, NULL );
  399. if (NULL==pMdl)
  400. {
  401. goto Error_Exit;
  402. }
  403. _try
  404. {
  405. // lockpage the Mdl, even though it is allocated based on NonPagesPool
  406. MmProbeAndLockPages(pMdl,                     // (Try to) fix buffer.
  407. KernelMode,
  408. IoModifyAccess
  409. );
  410. lpContext->bLocked = TRUE;
  411. DebugPrint(("RemainderBuffer: 0x%x,  pMdl: 0x%xn", lpContext->RemainderBuffer, pMdl ));
  412. }
  413. _except(
  414. pExceptionInfo = GetExceptionInformation(),                                                                                                                                                                                                    
  415. lclExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode,                                                                                                                                                                             
  416. lclExceptionAddr = pExceptionInfo->ExceptionRecord->ExceptionAddress,                                                                                                                                                                          
  417. EXCEPTION_EXECUTE_HANDLER                                                                                                                                                                                                                      
  418. )                                                                                                                                                                                                                                               
  419. {                                                                                                                                                                                                                                                    
  420. DebugPrint((".TDIClnRecv:  MmProbeAndLockPages() failed.  Error = 0x%08x at 0x%08xn",
  421. lclExceptionCode, lclExceptionAddr));
  422. goto Error_Exit;
  423. }
  424. lpContext->pIrp = pIrp;
  425. lpContext->pMdl = pMdl;
  426. return STATUS_SUCCESS;
  427. Error_Exit:
  428. if ( pMdl )
  429. IoFreeMdl ( pMdl );
  430. if ( pIrp )
  431. IoFreeIrp ( pIrp );
  432. return STATUS_UNSUCCESSFUL;
  433. }
  434. NTSTATUS                                          
  435. TDIRecvRemainderCompRoutine(
  436. PDEVICE_OBJECT      DeviceObject, // TDI driver's device object.
  437. PIRP                pIrp,    // Address of completed Irp.
  438. PVOID               pCtx     // Pointer to context.
  439. )
  440. /*++
  441. Routine Description:
  442.   Completion routine of IoRequestPacket in TDIEventRecvDatagram.
  443.   It copies receiving data in recvContext.RemainderBuffer to RxBuffer.
  444.   The length of receining data is indicated by pIrp->IoStatus.Information.
  445. Arguments:
  446.     DeviceObject - pointer to the device object
  447. pIrp - pointer to completed Irp, which is recvContext->pIrp
  448. pCtx - pointer to context, which is deviceExtension
  449. Return Value:
  450.     NT status code.
  451. --*/
  452. {
  453. PDEVICE_EXTENSION deviceExtension;
  454. PRECV_CONTEXT lpContext;
  455. ULONG RecvDataLength;
  456. PUCHAR lpSrc;
  457. DebugPrint(("TDIRecvRemainderCompRoutine...n"));
  458. RecvDataLength = pIrp->IoStatus.Information;
  459. deviceExtension = (PDEVICE_EXTENSION)pCtx;
  460. DebugPrint(("Remainder length: %dn", RecvDataLength ));
  461. CopyToRingBuffer ( deviceExtension,
  462. (PUCHAR)deviceExtension->recvContext.RemainderBuffer,
  463. RecvDataLength );
  464. return STATUS_MORE_PROCESSING_REQUIRED;
  465. }
  466. NTSTATUS TDIFreeRecvContext( PRECV_CONTEXT lpContext )
  467. /*++
  468. Routine Description:
  469. Free recvContext.
  470. Arguments:
  471. lpContext - pointer to recvContext.
  472. Return Value:
  473.     NT status code.
  474. --*/
  475. {
  476. if ( lpContext->pIrp )
  477. {
  478. IoFreeIrp ( lpContext->pIrp );
  479. lpContext->pIrp = NULL;
  480. }
  481. if ( lpContext->bLocked )
  482. {
  483. MmUnlockPages ( lpContext->pMdl );
  484. lpContext->bLocked = FALSE;
  485. }
  486. if ( lpContext->pMdl )
  487. {
  488. IoFreeMdl ( lpContext->pMdl );
  489. lpContext->pMdl = NULL;
  490. }
  491. return STATUS_SUCCESS;
  492. }
  493. /**************************************************************************************************/
  494. /*                                                                                                */
  495. /* Build and send down an Irp for Receive.                                                        */
  496. /*                                                                                                */
  497. /* Notes:                                                                                         */
  498. /*        1) This routine is NOT synchronous (no particular reason it's not, other than to show   */
  499. /*           off asynchronous operation of an Irp).                                               */
  500. /*                                                                                                */
  501. /*        2) There are indications that an MDL and probe-and-lock are needed even if the buffer   */
  502. /*           is from the non-paged pool.  Eg, microsoft.public.win32.programmer.kernel,           */
  503. /*           "MmProbeAndLockPages bug checks," dave porter, 2001-03-02.  But see the further      */
  504. /*           discussion in comp.os.ms-windows.programmer.nt.kernel-mode, "Free MDL in completion  */
  505. /*           routine," 1999/05/09.                                                                */
  506. /*                                                                                                */
  507. /*        3) Although not documented, it appears that the Irp, the Mdl and the locking are undone */
  508. /*           by the transport.  There are claims to that effect in several places in newsgroups,  */
  509. /*           and freeing the MDL always caused errors in a test (eg, bad pool caller or touching  */
  510. /*           paged storage at wrong IRQL).  Further, testing showed that IoFreeMdl() was being    */
  511. /*           called by somebody (presumably, the transport) for a given MDL.                      */
  512. /*                                                                                                */
  513. /*        4) The supplied context (pCtx) is an event, which the I/O completion routine for the    */
  514. /*           Receive Irp will signal.                                                             */
  515. /*                                                                                                */
  516. /**************************************************************************************************/
  517. NTSTATUS TDIQueryNetworkInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp )
  518. {
  519. PDEVICE_EXTENSION deviceExtension;
  520. PIO_STACK_LOCATION IrpStack;
  521. IO_STATUS_BLOCK IoStatus;
  522. NTSTATUS status;
  523. ULONG InputLength, OutputLength;
  524. ULONG QType;
  525. PIRP pIrp;
  526. KEVENT Event;
  527. PMDL pMdl;
  528. ULONG_PTR virtualAddress;
  529. EXCEPTION_POINTERS        * pExceptionInfo;
  530. ULONG                       lclExceptionCode;
  531. PVOID                       lclExceptionAddr;
  532. BOOLEAN pageLocked;
  533. deviceExtension = DeviceObject->DeviceExtension;
  534. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  535. QType = *((ULONG *)Irp->AssociatedIrp.SystemBuffer);
  536. DebugPrint(("QueryNetworkInformation: QType = %xn", QType ));
  537. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  538. pIrp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION ,
  539. deviceExtension->TDILowerDeviceObject,   // TDI driver's device object.
  540. deviceExtension->lpTransAddrFileObject, // Address file object.
  541. &Event,       // Event to be signalled when Irp completes.
  542. &IoStatus     // I/O status block.
  543. );
  544. if (NULL==pIrp)
  545.         return STATUS_INSUFFICIENT_RESOURCES;
  546. virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
  547. OutputLength = MmGetMdlByteCount(Irp->MdlAddress);
  548. pMdl = IoAllocateMdl( (PVOID)virtualAddress, OutputLength, FALSE, FALSE, NULL);
  549. pageLocked = FALSE;
  550. _try{
  551. MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess );
  552. pageLocked = TRUE;
  553. }
  554. _except(
  555. pExceptionInfo = GetExceptionInformation(),                                                                                                                                                                                                    
  556. lclExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode,                                                                                                                                                                             
  557. lclExceptionAddr = pExceptionInfo->ExceptionRecord->ExceptionAddress,                                                                                                                                                                          
  558. EXCEPTION_EXECUTE_HANDLER                                                                                                                                                                                                                      
  559. )                                                                                                                                                                                                                                               
  560. {                                                                                                                                                                                                                                                    
  561. DebugPrint((".TDIClnRecv:  MmProbeAndLockPages() failed.  Error = 0x%08x at 0x%08xn",
  562. lclExceptionCode, lclExceptionAddr));
  563. status = lclExceptionCode;                                                                                                                                                                                                                          
  564. goto done;
  565. }         
  566. TdiBuildQueryInformation ( pIrp, deviceExtension->TDILowerDeviceObject,
  567. deviceExtension->lpTransAddrFileObject,
  568. NULL, NULL, QType, pMdl );
  569. status = IoCallDriver ( deviceExtension->TDILowerDeviceObject, pIrp );
  570. if (STATUS_PENDING==status)
  571. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);
  572. done:
  573. status = ((STATUS_SUCCESS==status) || (STATUS_PENDING==status)) ? IoStatus.Status : status;
  574. Irp->IoStatus.Information = IoStatus.Information;
  575. DebugPrint(("QueryInfo: status %x, Info %dn", status, Irp->IoStatus.Information ));
  576. return status;
  577. }
  578. NTSTATUS
  579. TDIClnSetEventHandler(
  580.                       PFILE_OBJECT   pAddrFileObj,    // Address file object.
  581.                       PDEVICE_OBJECT pTcpDevObj,      // TDI driver's device object.
  582.                       LONG           EventType,       // Type of event.
  583.                       PVOID          pEventHandler,   // Event handler routine.
  584.                       PVOID          pEventContext    // Context for event handler.
  585.   )
  586. /**************************************************************************************************/
  587. /*                                                                                                */
  588. /* Set up an event handler.                                                                       */
  589. /*                                                                                                */
  590. /* Note:  This routine is synchronous.                                                            */
  591. /*                                                                                                */
  592. /**************************************************************************************************/
  593. {
  594. NTSTATUS            status;
  595. KEVENT              Event;
  596. IO_STATUS_BLOCK     IoStatus;
  597. PIRP pIrp;
  598. do {                                                 // Single-iteration loop, to make possible escape via break.
  599. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  600. // Get an Irp for internal device ioctl.
  601. pIrp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER,
  602. pTcpDevObj,   // TDI driver's device object.
  603. pAddrFileObj, // Address file object.
  604. &Event,       // Event to be signalled when Irp completes.
  605. &IoStatus     // I/O status block.
  606. );
  607. if (NULL==pIrp)
  608. {
  609. status = STATUS_INSUFFICIENT_RESOURCES;
  610. break;
  611. }
  612. TdiBuildSetEventHandler(pIrp,
  613. pTcpDevObj,
  614. pAddrFileObj,
  615. NULL,                    // I/O completion routine.
  616. NULL,                    // Context for I/O completion routine.
  617. EventType,
  618. pEventHandler,           // Event handler routine.
  619. pEventContext            // Context for event handler routine.
  620. );
  621. status = IoCallDriver(pTcpDevObj, pIrp);
  622. if (STATUS_PENDING==status)                      // Have to wait on this Irp?
  623. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);
  624. // Problem from IoCallDriver() or Problem discovered in completion?
  625. if ( ( STATUS_SUCCESS!=status && STATUS_PENDING!=status )
  626. || ( STATUS_PENDING==status && 0!=IoStatus.Status ) )
  627. {
  628. // Note:  If problem was in IoCallDriver(), IoStatus.Status probably won't be meaningful.
  629. DebugPrint(("TDIClnSetEventHandler:  Problem in IoCallDriver().  status = 0x%08x, IoStatus.Status = 0x%08xn",
  630. STATUS_PENDING==status ? 0 : status , IoStatus.Status));
  631. }
  632.     } while(0);                                       // End 'do-while' single-iteration loop.
  633. status = ((STATUS_SUCCESS==status) || (STATUS_PENDING==status)) ? IoStatus.Status : status;
  634. return status;
  635. }                                                     // End TDIClnSetEventHandler().
  636. NTSTATUS
  637. TDIOpenTransportAddress(
  638.                     PWSTR          pTransDevName,     // Transport device name.
  639.                     PHANDLE        pHandle,           // Output handle address.
  640.                     PFILE_OBJECT * ppAddrFileObj,     // Output address file object.
  641.                     USHORT         Port               // Port to open.
  642. )
  643. /**************************************************************************************************/
  644. /*                                                                                                */
  645. /* Open transport address.                                                                        */
  646. /*                                                                                                */
  647. /**************************************************************************************************/
  648. {
  649. NTSTATUS                    status;
  650. UNICODE_STRING              TransDeviceName;
  651. OBJECT_ATTRIBUTES           Attr;
  652. IO_STATUS_BLOCK             IoStatus;
  653. PTA_IP_ADDRESS pSin;
  654. PFILE_FULL_EA_INFORMATION pEa;
  655. char Buffer[sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_IP_ADDRESS)];
  656. ASSERT ( *pHandle == NULL );
  657. ASSERT ( *ppAddrFileObj == NULL );
  658. RtlInitUnicodeString(&TransDeviceName,               // Build Unicode transport device name.
  659. pTransDevName
  660. );
  661. InitializeObjectAttributes(&Attr,                    // Attributes (to be initialized);
  662. &TransDeviceName,
  663. OBJ_CASE_INSENSITIVE
  664. |
  665. OBJ_KERNEL_HANDLE,        // Only in kernel mode but in any process.
  666. 0,
  667. 0
  668. );
  669. pEa = (PFILE_FULL_EA_INFORMATION)Buffer;
  670. pEa->NextEntryOffset= 0;
  671. pEa->Flags = 0;
  672. pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;    // Length of TdiTransportAddress, namely of "TransportAddress" string less 1 (ie, without terminator).
  673. RtlCopyMemory ( pEa->EaName, TdiTransportAddress, pEa->EaNameLength + 1 );
  674. pEa->EaValueLength = sizeof(TA_IP_ADDRESS);          // Length of structure.
  675.     // Point to Buffer just after what's been used (ie, after terminator).
  676. pSin =(PTA_IP_ADDRESS) ( pEa->EaName + pEa->EaNameLength + 1);
  677. pSin->TAAddressCount= 1;                                                                                                                                                                                                                                     
  678. pSin->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  679. pSin->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  680. pSin->Address[0].Address[0].sin_port = Port;
  681. pSin->Address[0].Address[0].in_addr = 0;//0x601a8c0; // 192.168.1.6
  682. RtlZeroMemory ( pSin->Address[ 0 ].Address[ 0 ].sin_zero, sizeof ( pSin->Address[ 0 ].Address[ 0 ].sin_zero ) );
  683. status = ZwCreateFile(pHandle,                       // Actual open of transport address.
  684. GENERIC_READ | GENERIC_WRITE,
  685. &Attr,
  686. &IoStatus,
  687. 0,
  688. FILE_ATTRIBUTE_NORMAL,
  689. FILE_SHARE_READ,
  690. FILE_OPEN_IF,
  691. 0,
  692. pEa, //NULL,
  693. sizeof ( Buffer )
  694. );
  695. if (!NT_SUCCESS(status))
  696. {
  697. DebugPrint(("ZwCreateFile failed with status %xn", status ));
  698. return status;
  699. }
  700. status = ObReferenceObjectByHandle(*pHandle,         // Get the object pointer for the address file object's handle.
  701. GENERIC_READ | GENERIC_WRITE,
  702. 0,
  703. KernelMode,
  704. (PVOID *)ppAddrFileObj,
  705. NULL
  706. );
  707. if (!NT_SUCCESS(status))
  708. {
  709. DebugPrint(("ObReferenceObject failed with status %xn", status ));
  710. ZwClose ( *pHandle );
  711. *pHandle = NULL;
  712. }
  713. return status;
  714. }