Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1791 lines
40 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Ipx.c
  5. Abstract:
  6. This module implements the low level Ipx support routines for the NetWare
  7. redirector.
  8. Author:
  9. Colin Watson [ColinW] 28-Dec-1992
  10. Revision History:
  11. --*/
  12. #include "Procs.h"
  13. #include "wsnwlink.h"
  14. //
  15. // Define IPX interfaces that should be in a public header file but aren't
  16. // (at least for NT 1.0). For Daytona, include isnkrnl.h.
  17. //
  18. #define IPX_ID 'M'<<24 | 'I'<<16 | 'P'<<8 | 'X'
  19. #define I_MIPX (('I' << 24) | ('D' << 16) | ('P' << 8))
  20. #define MIPX_SENDPTYPE I_MIPX | 118 /* Send ptype in options on recv*/
  21. #define MIPX_RERIPNETNUM I_MIPX | 144 /* ReRip a network */
  22. #define MIPX_GETNETINFO I_MIPX | 135 /* Get info on a network num */
  23. #define MIPX_LINECHANGE I_MIPX | 310 /* queued until WAN line goes up/down */
  24. #define Dbg (DEBUG_TRACE_IPX)
  25. extern BOOLEAN WorkerRunning; // From timer.c
  26. extern POBJECT_TYPE *IoFileObjectType;
  27. typedef TA_IPX_ADDRESS UNALIGNED *PUTA_IPX_ADDRESS;
  28. typedef struct _ADDRESS_INFORMATION {
  29. ULONG ActivityCount;
  30. TA_IPX_ADDRESS NetworkName;
  31. ULONG Unused; // Junk needed to work around streams NWLINK bug.
  32. } ADDRESS_INFORMATION, *PADDRESS_INFORMATION;
  33. //
  34. // Handle difference between NT1.0 and use of ntifs.h
  35. //
  36. #ifdef IFS
  37. #define ATTACHPROCESS(_X) KeAttachProcess(_X);
  38. #else
  39. #define ATTACHPROCESS(_X) KeAttachProcess(&(_X)->Pcb);
  40. #endif
  41. NTSTATUS
  42. SubmitTdiRequest (
  43. IN PDEVICE_OBJECT pDeviceObject,
  44. IN PIRP pIrp
  45. );
  46. NTSTATUS
  47. CompletionEvent(
  48. IN PDEVICE_OBJECT DeviceObject,
  49. IN PIRP Irp,
  50. IN PVOID Context
  51. );
  52. NTSTATUS
  53. QueryAddressInformation(
  54. IN PIRP_CONTEXT pIrpContext,
  55. IN PNW_TDI_STRUCT pTdiStruct,
  56. OUT PADDRESS_INFORMATION AddressInformation
  57. );
  58. NTSTATUS
  59. QueryProviderInformation(
  60. IN PIRP_CONTEXT pIrpContext,
  61. IN PNW_TDI_STRUCT pTdiStruct,
  62. OUT PTDI_PROVIDER_INFO ProviderInfo
  63. );
  64. USHORT
  65. GetSocketNumber(
  66. IN PIRP_CONTEXT pIrpC,
  67. IN PNW_TDI_STRUCT pTdiStruc
  68. );
  69. NTSTATUS
  70. SetTransportOption(
  71. IN PIRP_CONTEXT pIrpC,
  72. IN PNW_TDI_STRUCT pTdiStruc,
  73. IN ULONG Option
  74. );
  75. #ifndef QFE_BUILD
  76. NTSTATUS
  77. CompletionLineChange(
  78. IN PDEVICE_OBJECT DeviceObject,
  79. IN PIRP Irp,
  80. IN PVOID Context
  81. );
  82. #endif
  83. #ifdef ALLOC_PRAGMA
  84. #pragma alloc_text( PAGE, IPX_Get_Local_Target )
  85. #pragma alloc_text( PAGE, IPX_Get_Internetwork_Address )
  86. #pragma alloc_text( PAGE, IPX_Get_Interval_Marker )
  87. #pragma alloc_text( PAGE, IPX_Open_Socket )
  88. #pragma alloc_text( PAGE, IPX_Close_Socket )
  89. #pragma alloc_text( PAGE, IpxOpen )
  90. #pragma alloc_text( PAGE, IpxOpenHandle )
  91. #pragma alloc_text( PAGE, BuildIpxAddressEa )
  92. #pragma alloc_text( PAGE, IpxClose )
  93. #pragma alloc_text( PAGE, SetEventHandler )
  94. #pragma alloc_text( PAGE, SubmitTdiRequest )
  95. #pragma alloc_text( PAGE, GetSocketNumber )
  96. #pragma alloc_text( PAGE, GetMaximumPacketSize )
  97. #pragma alloc_text( PAGE, QueryAddressInformation )
  98. #pragma alloc_text( PAGE, QueryProviderInformation )
  99. #pragma alloc_text( PAGE, SetTransportOption )
  100. #pragma alloc_text( PAGE, GetNewRoute )
  101. #ifndef QFE_BUILD
  102. #pragma alloc_text( PAGE, SubmitLineChangeRequest )
  103. #pragma alloc_text( PAGE, FspProcessLineChange )
  104. #endif
  105. #ifndef QFE_BUILD
  106. #pragma alloc_text( PAGE1, CompletionEvent )
  107. #endif
  108. #endif
  109. #if 0 // Not pageable
  110. BuildIpxAddress
  111. CompletionLineChange
  112. // see ifndef QFE_BUILD above
  113. #endif
  114. NTSTATUS
  115. IPX_Get_Local_Target(
  116. IN IPXaddress* RemoteAddress,
  117. OUT NodeAddress* LocalTarget,
  118. OUT word* Ticks
  119. )
  120. /*++
  121. Routine Description:
  122. Determine the address in the caller's own network to which to transmit
  123. in order to reach the specified machine.
  124. This is not required for NT since the IPX transport handles the
  125. issue of determining routing between this machine and the remote
  126. address.
  127. Arguments:
  128. RemoteAddress - Supplies the remote computers address
  129. NodeAddress - Where to store the intermediate machine address
  130. Ticks - Returns the expected number of ticks to reach the remote address
  131. Return Value:
  132. status of the operation
  133. --*/
  134. {
  135. PAGED_CODE();
  136. DebugTrace(0, Dbg, "IPX_Get_Local_Target\n", 0);
  137. return STATUS_NOT_IMPLEMENTED;
  138. }
  139. VOID
  140. IPX_Get_Internetwork_Address(
  141. OUT IPXaddress* LocalAddress
  142. )
  143. /*++
  144. Routine Description:
  145. Determine the callers full address in a set of interconnected networks.
  146. in order to reach the specified machine.
  147. This is not required for NT since the IPX transport handles the
  148. issue of determining routing between this machine and the remote
  149. address.
  150. Arguments:
  151. LocalAddress - Where to store the local address
  152. Return Value:
  153. none
  154. --*/
  155. {
  156. PAGED_CODE();
  157. DebugTrace(0, Dbg, "IPX_Get_Internetwork_Address\n", 0);
  158. RtlFillMemory(LocalAddress, sizeof(IPXaddress), 0xff);
  159. }
  160. word
  161. IPX_Get_Interval_Marker(
  162. VOID
  163. )
  164. /*++
  165. Routine Description:
  166. Determine the interval marker in clock ticks.
  167. Arguments:
  168. Return Value:
  169. interval marker
  170. --*/
  171. {
  172. PAGED_CODE();
  173. DebugTrace(0, Dbg, "IPX_Get_Interval_Marker\n", 0);
  174. return 0xff;
  175. }
  176. NTSTATUS
  177. IPX_Open_Socket(
  178. IN PIRP_CONTEXT pIrpC,
  179. IN PNW_TDI_STRUCT pTdiStruc
  180. )
  181. /*++
  182. Routine Description:
  183. Open a local socket to be used for a conection to a remote server.
  184. Arguments:
  185. pIrpC - supplies the irp context for the request creating the socket.
  186. pTdiStruc - supplies where to record the handle and both device and file
  187. object pointers
  188. Return Value:
  189. 0 success
  190. --*/
  191. {
  192. NTSTATUS Status;
  193. UCHAR NetworkName[ sizeof( FILE_FULL_EA_INFORMATION )-1 +
  194. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  195. sizeof(TA_IPX_ADDRESS)];
  196. static UCHAR LocalNodeAddress[6] = {0,0,0,0,0,0};
  197. PAGED_CODE();
  198. DebugTrace(+1, Dbg, "IPX_Open_Socket %X\n", pTdiStruc->Socket);
  199. //
  200. // Let the transport decide the network number and node address
  201. // if the caller specified socket 0. This will allow the transport
  202. // to use whatever local adapters are available to get to the
  203. // remote server.
  204. //
  205. BuildIpxAddressEa( (ULONG)0,
  206. LocalNodeAddress,
  207. (USHORT)pTdiStruc->Socket,
  208. NetworkName );
  209. Status = IpxOpenHandle( &pTdiStruc->Handle,
  210. &pTdiStruc->pDeviceObject,
  211. &pTdiStruc->pFileObject,
  212. NetworkName,
  213. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  214. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  215. sizeof(TA_IPX_ADDRESS));
  216. if ( !NT_SUCCESS(Status) ) {
  217. return( Status );
  218. }
  219. if ( pTdiStruc->Socket == 0 ) {
  220. //
  221. // Find out the socket number assigned by the transport
  222. //
  223. pTdiStruc->Socket = GetSocketNumber( pIrpC, pTdiStruc );
  224. DebugTrace(0, Dbg, "Assigned socket number %X\n", pTdiStruc->Socket );
  225. }
  226. //
  227. // Tell transport to accept packet type being set in the connection
  228. // information provided with the send datagram. Transport reports
  229. // the packet type similarly on receive datagram.
  230. //
  231. Status = SetTransportOption(
  232. pIrpC,
  233. pTdiStruc,
  234. MIPX_SENDPTYPE );
  235. DebugTrace(-1, Dbg, " %X\n", Status );
  236. return Status;
  237. }
  238. VOID
  239. IPX_Close_Socket(
  240. IN PNW_TDI_STRUCT pTdiStruc
  241. )
  242. /*++
  243. Routine Description:
  244. Terminate a connection over the network.
  245. Arguments:
  246. pTdiStruc - supplies where to record the handle and both device and file
  247. object pointers
  248. Return Value:
  249. none
  250. --*/
  251. {
  252. BOOLEAN ProcessAttached = FALSE;
  253. PAGED_CODE();
  254. DebugTrace(+1, Dbg, "IPX_Close_Socket %x\n", pTdiStruc->Socket);
  255. if ( pTdiStruc->Handle == NULL ) {
  256. return;
  257. }
  258. ObDereferenceObject( pTdiStruc->pFileObject );
  259. //
  260. // Attach to the redirector's FSP to allow the handle for the
  261. // connection to hang around.
  262. //
  263. if (PsGetCurrentProcess() != FspProcess) {
  264. ATTACHPROCESS(FspProcess);
  265. ProcessAttached = TRUE;
  266. }
  267. ZwClose( pTdiStruc->Handle );
  268. if (ProcessAttached) {
  269. //
  270. // Now re-attach back to our original process
  271. //
  272. KeDetachProcess();
  273. }
  274. pTdiStruc->Handle = NULL;
  275. pTdiStruc->pFileObject = NULL;
  276. DebugTrace(-1, Dbg, "IPX_Close_Socket\n", 0);
  277. return;
  278. }
  279. NTSTATUS
  280. IpxOpen(
  281. VOID
  282. )
  283. /*++
  284. Routine Description:
  285. Open handle to the Ipx transport.
  286. Arguments:
  287. none.
  288. Return Value:
  289. none
  290. --*/
  291. {
  292. NTSTATUS Status;
  293. Status = IpxOpenHandle( &IpxHandle,
  294. &pIpxDeviceObject,
  295. &pIpxFileObject,
  296. NULL,
  297. 0 );
  298. DebugTrace(-1, Dbg, "IpxOpen of local node address %X\n", Status);
  299. return Status;
  300. }
  301. NTSTATUS
  302. IpxOpenHandle(
  303. OUT PHANDLE pHandle,
  304. OUT PDEVICE_OBJECT* ppDeviceObject,
  305. OUT PFILE_OBJECT* ppFileObject,
  306. IN PVOID EaBuffer OPTIONAL,
  307. IN ULONG EaLength
  308. )
  309. /*++
  310. Routine Description:
  311. Open handle to the Ipx transport.
  312. Arguments:
  313. OUT Handle - The handle to the transport if return value is NT_SUCCESS
  314. Return Value:
  315. none
  316. --*/
  317. {
  318. OBJECT_ATTRIBUTES AddressAttributes;
  319. IO_STATUS_BLOCK IoStatusBlock;
  320. NTSTATUS Status;
  321. BOOLEAN ProcessAttached = FALSE;
  322. PAGED_CODE();
  323. DebugTrace(+1, Dbg, "IpxOpenHandle\n", 0);
  324. *pHandle = NULL;
  325. if (IpxTransportName.Buffer == NULL) {
  326. //
  327. // we are being called with an open ipx when transport is not bound
  328. //
  329. Status = STATUS_CONNECTION_INVALID ;
  330. DebugTrace(-1, Dbg, "IpxOpenHandle %X\n", Status);
  331. return Status ;
  332. }
  333. InitializeObjectAttributes (&AddressAttributes,
  334. &IpxTransportName,
  335. OBJ_CASE_INSENSITIVE,// Attributes
  336. NULL, // RootDirectory
  337. NULL); // SecurityDescriptor
  338. //
  339. // Attach to the redirector's FSP to allow the handle for the
  340. // connection to hang around. Normally we create 3 handles at once
  341. // so the outer code already has done this to avoid the expensive
  342. // attach procedure.
  343. //
  344. if (PsGetCurrentProcess() != FspProcess) {
  345. ATTACHPROCESS(FspProcess);
  346. ProcessAttached = TRUE;
  347. }
  348. Status = ZwCreateFile(pHandle,
  349. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  350. &AddressAttributes, // Object Attributes
  351. &IoStatusBlock, // Final I/O status block
  352. NULL, // Allocation Size
  353. FILE_ATTRIBUTE_NORMAL, // Normal attributes
  354. FILE_SHARE_READ,// Sharing attributes
  355. FILE_OPEN_IF, // Create disposition
  356. 0, // CreateOptions
  357. EaBuffer,EaLength);
  358. if (!NT_SUCCESS(Status) ||
  359. !NT_SUCCESS(Status = IoStatusBlock.Status)) {
  360. goto error_cleanup2;
  361. }
  362. //
  363. // Obtain a referenced pointer to the file object.
  364. //
  365. Status = ObReferenceObjectByHandle (
  366. *pHandle,
  367. 0,
  368. NULL,
  369. KernelMode,
  370. ppFileObject,
  371. NULL
  372. );
  373. if (!NT_SUCCESS(Status)) {
  374. goto error_cleanup;
  375. }
  376. if (ProcessAttached) {
  377. //
  378. // Now re-attach back to our original process
  379. //
  380. KeDetachProcess();
  381. }
  382. *ppDeviceObject = IoGetRelatedDeviceObject( *ppFileObject );
  383. DebugTrace(-1, Dbg, "IpxOpenHandle %X\n", Status);
  384. return Status;
  385. error_cleanup2:
  386. if ( *pHandle != NULL ) {
  387. ZwClose( *pHandle );
  388. *pHandle = NULL;
  389. }
  390. error_cleanup:
  391. if (ProcessAttached) {
  392. //
  393. // Now re-attach back to our original process
  394. //
  395. KeDetachProcess();
  396. }
  397. DebugTrace(-1, Dbg, "IpxOpenHandle %X\n", Status);
  398. return Status;
  399. }
  400. VOID
  401. BuildIpxAddress(
  402. IN ULONG NetworkAddress,
  403. IN PUCHAR NodeAddress,
  404. IN USHORT Socket,
  405. OUT PTA_IPX_ADDRESS NetworkName
  406. )
  407. /*++
  408. Routine Description:
  409. This routine builds a TA_NETBIOS_ADDRESS structure in the locations pointed
  410. to by NetworkName. All fields are filled out.
  411. Arguments:
  412. NetworkAddress - Supplies the network number
  413. NodeAddress - Supplies the node number
  414. Socket - The socket number (in Hi-Lo order)
  415. NetworkName - Supplies the structure to place the address
  416. Return Value:
  417. none.
  418. --*/
  419. {
  420. // Warn compiler that TAAddressCount may be mis-aligned.
  421. PUTA_IPX_ADDRESS UNetworkName = (PUTA_IPX_ADDRESS)NetworkName;
  422. DebugTrace(+0, Dbg, "BuildIpxAddress\n", 0);
  423. UNetworkName->TAAddressCount = 1;
  424. UNetworkName->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
  425. UNetworkName->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IPX;
  426. RtlMoveMemory (
  427. UNetworkName->Address[0].Address[0].NodeAddress,
  428. NodeAddress,
  429. 6);
  430. UNetworkName->Address[0].Address[0].NetworkAddress = NetworkAddress;
  431. UNetworkName->Address[0].Address[0].Socket = Socket;
  432. } /* TdiBuildIpxAddress */
  433. VOID
  434. BuildIpxAddressEa (
  435. IN ULONG NetworkAddress,
  436. IN PUCHAR NodeAddress,
  437. IN USHORT Socket,
  438. OUT PVOID NetworkName
  439. )
  440. /*++
  441. Routine Description:
  442. Builds an EA describing a Netbios address in the buffer supplied by the
  443. user.
  444. Arguments:
  445. NetworkAddress - Supplies the network number
  446. NodeAddress - Supplies the node number
  447. Socket -
  448. NetworkName - The Ea structure that describes the input parameters.
  449. Return Value:
  450. An informative error code if something goes wrong. STATUS_SUCCESS if the
  451. ea is built properly.
  452. --*/
  453. {
  454. PFILE_FULL_EA_INFORMATION EaBuffer;
  455. PTA_IPX_ADDRESS TAAddress;
  456. ULONG Length;
  457. DebugTrace(+0, Dbg, "BuildIpxAddressEa\n", 0);
  458. Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  459. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  460. sizeof (TA_IPX_ADDRESS);
  461. EaBuffer = (PFILE_FULL_EA_INFORMATION)NetworkName;
  462. EaBuffer->NextEntryOffset = 0;
  463. EaBuffer->Flags = 0;
  464. EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  465. EaBuffer->EaValueLength = sizeof (TA_IPX_ADDRESS);
  466. RtlCopyMemory (
  467. EaBuffer->EaName,
  468. TdiTransportAddress,
  469. EaBuffer->EaNameLength + 1);
  470. TAAddress = (PTA_IPX_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
  471. BuildIpxAddress(
  472. NetworkAddress,
  473. NodeAddress,
  474. Socket,
  475. TAAddress);
  476. return;
  477. }
  478. VOID
  479. IpxClose(
  480. VOID
  481. )
  482. /*++
  483. Routine Description:
  484. Close handle to the Ipx transport.
  485. Arguments:
  486. none
  487. Return Value:
  488. none
  489. --*/
  490. {
  491. PAGED_CODE();
  492. DebugTrace(+1, Dbg, "IpxClose...\n", 0);
  493. if ( pIpxFileObject ) {
  494. ObDereferenceObject( pIpxFileObject );
  495. pIpxFileObject = NULL;
  496. }
  497. // if ( pIpxDeviceObject ) {
  498. // ObDereferenceObject( pIpxDeviceObject );
  499. // pIpxDeviceObject = NULL;
  500. // }
  501. pIpxDeviceObject = NULL;
  502. if ( IpxTransportName.Buffer != NULL ) {
  503. FREE_POOL( IpxTransportName.Buffer );
  504. IpxTransportName.Buffer = NULL;
  505. }
  506. if (IpxHandle) {
  507. //
  508. // Attach to the redirector's FSP to allow the handle for the
  509. // connection to hang around.
  510. //
  511. if (PsGetCurrentProcess() != FspProcess) {
  512. ATTACHPROCESS(FspProcess);
  513. ZwClose( IpxHandle );
  514. KeDetachProcess();
  515. } else {
  516. ZwClose( IpxHandle );
  517. }
  518. IpxHandle = NULL;
  519. }
  520. DebugTrace(-1, Dbg, "IpxClose\n", 0);
  521. }
  522. NTSTATUS
  523. SetEventHandler (
  524. IN PIRP_CONTEXT pIrpC,
  525. IN PNW_TDI_STRUCT pTdiStruc,
  526. IN ULONG EventType,
  527. IN PVOID pEventHandler,
  528. IN PVOID pContext
  529. )
  530. /*++
  531. Routine Description:
  532. This routine registers an event handler with a TDI transport provider.
  533. Arguments:
  534. pIrpC - supplies an Irp among other things.
  535. pTdiStruc - supplies the handle and both device and file object pointers
  536. to the transport.
  537. IN ULONG EventType, - Supplies the type of event.
  538. IN PVOID pEventHandler - Supplies the event handler.
  539. IN PVOID pContext - Supplies the context to be supplied to the event
  540. handler.
  541. Return Value:
  542. NTSTATUS - Final status of the set event operation
  543. --*/
  544. {
  545. NTSTATUS Status;
  546. PAGED_CODE();
  547. TdiBuildSetEventHandler(pIrpC->pOriginalIrp,
  548. pTdiStruc->pDeviceObject,
  549. pTdiStruc->pFileObject,
  550. NULL,
  551. NULL,
  552. EventType,
  553. pEventHandler,
  554. pContext);
  555. Status = SubmitTdiRequest(pTdiStruc->pDeviceObject,
  556. pIrpC->pOriginalIrp);
  557. return Status;
  558. }
  559. NTSTATUS
  560. SubmitTdiRequest (
  561. IN PDEVICE_OBJECT pDeviceObject,
  562. IN PIRP pIrp
  563. )
  564. /*++
  565. Routine Description:
  566. This routine submits a request to TDI and waits for it to complete.
  567. Arguments:
  568. IN PDevice_OBJECT DeviceObject - Connection or Address handle for TDI request
  569. IN PIRP Irp - TDI request to submit.
  570. Return Value:
  571. NTSTATUS - Final status of request.
  572. --*/
  573. {
  574. NTSTATUS Status;
  575. KEVENT Event;
  576. PAGED_CODE();
  577. DebugTrace(+1, Dbg, "SubmitTdiRequest\n", 0);
  578. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  579. IoSetCompletionRoutine(pIrp, CompletionEvent, &Event, TRUE, TRUE, TRUE);
  580. //
  581. // Submit the request
  582. //
  583. Status = IoCallDriver(pDeviceObject, pIrp);
  584. //
  585. // If it failed immediately, return now, otherwise wait.
  586. //
  587. if (!NT_SUCCESS(Status)) {
  588. DebugTrace(-1, Dbg, "SubmitTdiRequest %X\n", Status);
  589. return Status;
  590. }
  591. if (Status == STATUS_PENDING) {
  592. DebugTrace(+0, Dbg, "Waiting....\n", 0);
  593. Status = KeWaitForSingleObject(&Event, // Object to wait on.
  594. Executive, // Reason for waiting
  595. KernelMode, // Processor mode
  596. FALSE, // Alertable
  597. NULL); // Timeout
  598. if (!NT_SUCCESS(Status)) {
  599. DebugTrace(-1, Dbg, "SubmitTdiRequest could not wait %X\n", Status);
  600. return Status;
  601. }
  602. Status = pIrp->IoStatus.Status;
  603. }
  604. DebugTrace(-1, Dbg, "SubmitTdiRequest %X\n", Status);
  605. return(Status);
  606. }
  607. NTSTATUS
  608. CompletionEvent(
  609. IN PDEVICE_OBJECT DeviceObject,
  610. IN PIRP Irp,
  611. IN PVOID Context
  612. )
  613. /*++
  614. Routine Description:
  615. This routine does not complete the Irp. It is used to signal to a
  616. synchronous part of the driver that it can proceed.
  617. Arguments:
  618. DeviceObject - unused.
  619. Irp - Supplies Irp that the transport has finished processing.
  620. Context - Supplies the event associated with the Irp.
  621. Return Value:
  622. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  623. processing Irp stack locations at this point.
  624. --*/
  625. {
  626. DebugTrace( 0, Dbg, "CompletionEvent\n", 0 );
  627. KeSetEvent((PKEVENT )Context, 0, FALSE);
  628. return STATUS_MORE_PROCESSING_REQUIRED;
  629. UNREFERENCED_PARAMETER( DeviceObject );
  630. UNREFERENCED_PARAMETER( Irp );
  631. }
  632. USHORT
  633. GetSocketNumber(
  634. IN PIRP_CONTEXT pIrpC,
  635. IN PNW_TDI_STRUCT pTdiStruc
  636. )
  637. /*++
  638. Routine Description:
  639. Use a TDI_ACTION to set the Option.
  640. Arguments:
  641. pIrpC - supplies an Irp among other things.
  642. pTdiStruc - supplies the handle and both device and file object pointers
  643. to the transport.
  644. Option - supplies the option to set.
  645. Return Value:
  646. 0 failed otherwise the socket number.
  647. --*/
  648. {
  649. ADDRESS_INFORMATION AddressInfo;
  650. NTSTATUS Status;
  651. USHORT SocketNumber;
  652. PAGED_CODE();
  653. Status = QueryAddressInformation( pIrpC, pTdiStruc, &AddressInfo );
  654. if ( !NT_SUCCESS( Status ) ) {
  655. SocketNumber = 0;
  656. } else {
  657. SocketNumber = AddressInfo.NetworkName.Address[0].Address[0].Socket;
  658. RtlCopyMemory( &OurAddress,
  659. &AddressInfo.NetworkName.Address[0].Address[0],
  660. sizeof(TDI_ADDRESS_IPX));
  661. }
  662. return( SocketNumber );
  663. }
  664. NTSTATUS
  665. GetMaximumPacketSize(
  666. IN PIRP_CONTEXT pIrpContext,
  667. IN PNW_TDI_STRUCT pTdiStruct,
  668. OUT PULONG pMaximumPacketSize
  669. )
  670. /*++
  671. Routine Description:
  672. Query the maximum packet size for this network.
  673. Arguments:
  674. pIrpContext - supplies an Irp among other things.
  675. pTdiStruct - supplies the handle and both device and file object pointers
  676. to the transport.
  677. pMaximumPacketSize - Returns the maximum packet size for the network.
  678. Return Value:
  679. The status of the query.
  680. --*/
  681. {
  682. TDI_PROVIDER_INFO ProviderInfo;
  683. NTSTATUS Status;
  684. PAGED_CODE();
  685. Status = QueryProviderInformation( pIrpContext, pTdiStruct, &ProviderInfo );
  686. if ( NT_SUCCESS( Status ) ) {
  687. *pMaximumPacketSize = ProviderInfo.MaxDatagramSize;
  688. }
  689. return( Status );
  690. }
  691. NTSTATUS
  692. QueryAddressInformation(
  693. PIRP_CONTEXT pIrpContext,
  694. IN PNW_TDI_STRUCT pTdiStruct,
  695. PADDRESS_INFORMATION AddressInformation
  696. )
  697. {
  698. NTSTATUS Status;
  699. PMDL MdlSave = pIrpContext->pOriginalIrp->MdlAddress;
  700. PMDL Mdl;
  701. PAGED_CODE();
  702. Mdl = ALLOCATE_MDL(
  703. AddressInformation,
  704. sizeof( *AddressInformation ),
  705. FALSE, // Secondary Buffer
  706. FALSE, // Charge Quota
  707. NULL);
  708. if ( Mdl == NULL ) {
  709. return STATUS_INSUFFICIENT_RESOURCES;
  710. }
  711. try {
  712. MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess );
  713. } except( EXCEPTION_EXECUTE_HANDLER ) {
  714. FREE_MDL( Mdl );
  715. return GetExceptionCode();
  716. }
  717. TdiBuildQueryInformation(
  718. pIrpContext->pOriginalIrp,
  719. pTdiStruct->pDeviceObject,
  720. pTdiStruct->pFileObject,
  721. CompletionEvent,
  722. NULL,
  723. TDI_QUERY_ADDRESS_INFO,
  724. Mdl);
  725. Status = SubmitTdiRequest( pTdiStruct->pDeviceObject, pIrpContext->pOriginalIrp);
  726. pIrpContext->pOriginalIrp->MdlAddress = MdlSave;
  727. MmUnlockPages( Mdl );
  728. FREE_MDL( Mdl );
  729. return( Status );
  730. }
  731. NTSTATUS
  732. QueryProviderInformation(
  733. IN PIRP_CONTEXT pIrpContext,
  734. IN PNW_TDI_STRUCT pTdiStruct,
  735. PTDI_PROVIDER_INFO ProviderInfo
  736. )
  737. {
  738. NTSTATUS Status;
  739. PMDL MdlSave = pIrpContext->pOriginalIrp->MdlAddress;
  740. PMDL Mdl;
  741. PAGED_CODE();
  742. Mdl = ALLOCATE_MDL(
  743. ProviderInfo,
  744. sizeof( *ProviderInfo ),
  745. FALSE, // Secondary Buffer
  746. FALSE, // Charge Quota
  747. NULL);
  748. if ( Mdl == NULL ) {
  749. return STATUS_INSUFFICIENT_RESOURCES;
  750. }
  751. try {
  752. MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess );
  753. } except( EXCEPTION_EXECUTE_HANDLER ) {
  754. FREE_MDL( Mdl );
  755. return GetExceptionCode();
  756. }
  757. TdiBuildQueryInformation(
  758. pIrpContext->pOriginalIrp,
  759. pTdiStruct->pDeviceObject,
  760. pTdiStruct->pFileObject,
  761. CompletionEvent,
  762. NULL,
  763. TDI_QUERY_PROVIDER_INFO,
  764. Mdl);
  765. Status = SubmitTdiRequest(pTdiStruct->pDeviceObject, pIrpContext->pOriginalIrp);
  766. pIrpContext->pOriginalIrp->MdlAddress = MdlSave;
  767. MmUnlockPages( Mdl );
  768. FREE_MDL( Mdl );
  769. return( Status );
  770. }
  771. NTSTATUS
  772. SetTransportOption(
  773. IN PIRP_CONTEXT pIrpC,
  774. IN PNW_TDI_STRUCT pTdiStruc,
  775. IN ULONG Option
  776. )
  777. /*++
  778. Routine Description:
  779. Use a TDI_ACTION to set the Option.
  780. Arguments:
  781. pIrpC - supplies an Irp among other things.
  782. pTdiStruc - supplies the handle and both device and file object pointers
  783. to the transport.
  784. Option - supplies the option to set.
  785. Return Value:
  786. 0 success
  787. --*/
  788. {
  789. static struct {
  790. TDI_ACTION_HEADER Header;
  791. BOOLEAN DatagramOption;
  792. ULONG BufferLength;
  793. ULONG Option;
  794. } SetPacketType = {
  795. IPX_ID,
  796. 0, // ActionCode
  797. 0, // Reserved
  798. TRUE, // DatagramOption
  799. sizeof(ULONG) // BufferLength
  800. };
  801. KEVENT Event;
  802. NTSTATUS Status;
  803. PIRP pIrp = pIrpC->pOriginalIrp;
  804. //
  805. // Save the original MDL and System buffer address, to restore
  806. // after the IRP completes.
  807. //
  808. // We use both the MDL and SystemBuffer because NWLINK assumes that
  809. // we are using SystemBuffer even though we are supposed to use the
  810. // MDL to pass a pointer to the action buffer.
  811. //
  812. PMDL MdlSave = pIrp->MdlAddress;
  813. PCHAR SystemBufferSave = pIrp->AssociatedIrp.SystemBuffer;
  814. PMDL Mdl;
  815. PAGED_CODE();
  816. Mdl = ALLOCATE_MDL(
  817. &SetPacketType,
  818. sizeof( SetPacketType ),
  819. FALSE, // Secondary Buffer
  820. FALSE, // Charge Quota
  821. NULL );
  822. if ( Mdl == NULL ) {
  823. IPX_Close_Socket( pTdiStruc );
  824. return STATUS_INSUFFICIENT_RESOURCES;
  825. }
  826. SetPacketType.Option = Option;
  827. try {
  828. MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess );
  829. } except( EXCEPTION_EXECUTE_HANDLER ) {
  830. FREE_MDL( Mdl );
  831. return GetExceptionCode();
  832. }
  833. KeInitializeEvent (
  834. &Event,
  835. SynchronizationEvent,
  836. FALSE);
  837. TdiBuildAction(
  838. pIrp,
  839. pTdiStruc->pDeviceObject,
  840. pTdiStruc->pFileObject,
  841. CompletionEvent,
  842. &Event,
  843. Mdl );
  844. //
  845. // Set up the system buffer for NWLINK.
  846. //
  847. pIrp->AssociatedIrp.SystemBuffer = &SetPacketType;
  848. Status = IoCallDriver (pTdiStruc->pDeviceObject, pIrp);
  849. if ( Status == STATUS_PENDING ) {
  850. Status = KeWaitForSingleObject (
  851. &Event,
  852. Executive,
  853. KernelMode,
  854. FALSE,
  855. NULL );
  856. if ( NT_SUCCESS( Status ) ) {
  857. Status = pIrp->IoStatus.Status;
  858. }
  859. }
  860. //
  861. // Now restore the system buffer and MDL address in the IRP
  862. //
  863. pIrp->AssociatedIrp.SystemBuffer = SystemBufferSave;
  864. pIrp->MdlAddress = MdlSave;
  865. MmUnlockPages( Mdl );
  866. FREE_MDL( Mdl );
  867. return Status;
  868. }
  869. NTSTATUS
  870. GetNewRoute(
  871. IN PIRP_CONTEXT pIrpContext
  872. )
  873. /*++
  874. Routine Description:
  875. Use a TDI_ACTION to get a new route.
  876. Arguments:
  877. pIrpContext - Supplies IRP context information.
  878. Return Value:
  879. The status of the operation.
  880. --*/
  881. {
  882. struct {
  883. TDI_ACTION_HEADER Header;
  884. BOOLEAN DatagramOption;
  885. ULONG BufferLength;
  886. ULONG Option;
  887. ULONG info_netnum;
  888. USHORT info_hopcount;
  889. USHORT info_netdelay;
  890. int info_cardnum;
  891. UCHAR info_router[6];
  892. } ReRipRequest = {
  893. IPX_ID,
  894. 0, // ActionCode
  895. 0, // Reserved
  896. TRUE, // DatagramOption
  897. 24 // Buffer length (not including header)
  898. };
  899. KEVENT Event;
  900. NTSTATUS Status;
  901. PIRP pIrp = pIrpContext->pOriginalIrp;
  902. //
  903. // Save the original MDL and System buffer address, to restore
  904. // after the IRP completes.
  905. //
  906. // We use both the MDL and SystemBuffer because NWLINK assumes that
  907. // we are using SystemBuffer even though we are supposed to use the
  908. // MDL to pass a pointer to the action buffer.
  909. //
  910. PMDL MdlSave = pIrp->MdlAddress;
  911. PCHAR SystemBufferSave = pIrp->AssociatedIrp.SystemBuffer;
  912. PMDL Mdl;
  913. PAGED_CODE();
  914. Mdl = ALLOCATE_MDL(
  915. &ReRipRequest,
  916. sizeof( ReRipRequest ),
  917. FALSE, // Secondary Buffer
  918. FALSE, // Charge Quota
  919. NULL );
  920. if ( Mdl == NULL ) {
  921. return STATUS_INSUFFICIENT_RESOURCES;
  922. }
  923. ReRipRequest.Option = MIPX_RERIPNETNUM;
  924. ReRipRequest.info_netnum = pIrpContext->pNpScb->ServerAddress.Net;
  925. try {
  926. MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess );
  927. } except( EXCEPTION_EXECUTE_HANDLER ) {
  928. FREE_MDL( Mdl );
  929. return GetExceptionCode();
  930. }
  931. KeInitializeEvent (
  932. &Event,
  933. SynchronizationEvent,
  934. FALSE);
  935. TdiBuildAction(
  936. pIrp,
  937. pIrpContext->pNpScb->Server.pDeviceObject,
  938. pIrpContext->pNpScb->Server.pFileObject,
  939. CompletionEvent,
  940. &Event,
  941. Mdl );
  942. //
  943. // Set up the system buffer for NWLINK.
  944. //
  945. pIrp->AssociatedIrp.SystemBuffer = &ReRipRequest;
  946. Status = IoCallDriver ( pIrpContext->pNpScb->Server.pDeviceObject, pIrp);
  947. if ( Status == STATUS_PENDING ) {
  948. Status = KeWaitForSingleObject (
  949. &Event,
  950. Executive,
  951. KernelMode,
  952. FALSE,
  953. NULL );
  954. if ( NT_SUCCESS( Status ) ) {
  955. Status = pIrp->IoStatus.Status;
  956. }
  957. }
  958. //
  959. // Now restore the system buffer and MDL address in the IRP
  960. //
  961. pIrp->AssociatedIrp.SystemBuffer = SystemBufferSave;
  962. pIrp->MdlAddress = MdlSave;
  963. MmUnlockPages( Mdl );
  964. FREE_MDL( Mdl );
  965. return Status;
  966. }
  967. NTSTATUS
  968. GetTickCount(
  969. IN PIRP_CONTEXT pIrpContext,
  970. OUT PUSHORT TickCount
  971. )
  972. /*++
  973. Routine Description:
  974. Use a TDI_ACTION to get a new route.
  975. Arguments:
  976. pIrpContext - Supplies IRP context information.
  977. Return Value:
  978. The status of the operation.
  979. --*/
  980. {
  981. struct {
  982. TDI_ACTION_HEADER Header;
  983. BOOLEAN DatagramOption;
  984. ULONG BufferLength;
  985. ULONG Option;
  986. IPX_NETNUM_DATA NetNumData;
  987. } GetTickCountInput = {
  988. IPX_ID,
  989. 0, // ActionCode
  990. 0, // Reserved
  991. TRUE, // DatagramOption
  992. sizeof( IPX_NETNUM_DATA) + 2 * sizeof( ULONG )
  993. };
  994. struct _GET_TICK_COUNT_OUTPUT {
  995. ULONG Option;
  996. IPX_NETNUM_DATA NetNumData;
  997. };
  998. struct _GET_TICK_COUNT_OUTPUT *GetTickCountOutput;
  999. KEVENT Event;
  1000. NTSTATUS Status;
  1001. PIRP pIrp = pIrpContext->pOriginalIrp;
  1002. //
  1003. // Save the original MDL and System buffer address, to restore
  1004. // after the IRP completes.
  1005. //
  1006. // We use both the MDL and SystemBuffer because NWLINK assumes that
  1007. // we are using SystemBuffer even though we are supposed to use the
  1008. // MDL to pass a pointer to the action buffer.
  1009. //
  1010. PMDL MdlSave = pIrp->MdlAddress;
  1011. PCHAR SystemBufferSave = pIrp->AssociatedIrp.SystemBuffer;
  1012. PMDL Mdl;
  1013. PAGED_CODE();
  1014. Mdl = ALLOCATE_MDL(
  1015. &GetTickCountInput,
  1016. sizeof( GetTickCountInput ),
  1017. FALSE, // Secondary Buffer
  1018. FALSE, // Charge Quota
  1019. NULL );
  1020. if ( Mdl == NULL ) {
  1021. return STATUS_INSUFFICIENT_RESOURCES;
  1022. }
  1023. GetTickCountInput.Option = MIPX_GETNETINFO;
  1024. *(PULONG)GetTickCountInput.NetNumData.netnum = pIrpContext->pNpScb->ServerAddress.Net;
  1025. try {
  1026. MmProbeAndLockPages( Mdl, KernelMode, IoReadAccess );
  1027. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1028. FREE_MDL( Mdl );
  1029. return GetExceptionCode();
  1030. }
  1031. KeInitializeEvent (
  1032. &Event,
  1033. SynchronizationEvent,
  1034. FALSE);
  1035. TdiBuildAction(
  1036. pIrp,
  1037. pIrpContext->pNpScb->Server.pDeviceObject,
  1038. pIrpContext->pNpScb->Server.pFileObject,
  1039. CompletionEvent,
  1040. &Event,
  1041. Mdl );
  1042. //
  1043. // Set up the system buffer for NWLINK.
  1044. //
  1045. pIrp->AssociatedIrp.SystemBuffer = &GetTickCountInput;
  1046. Status = IoCallDriver ( pIrpContext->pNpScb->Server.pDeviceObject, pIrp);
  1047. if ( Status == STATUS_PENDING ) {
  1048. Status = KeWaitForSingleObject (
  1049. &Event,
  1050. Executive,
  1051. KernelMode,
  1052. FALSE,
  1053. NULL );
  1054. if ( NT_SUCCESS( Status ) ) {
  1055. Status = pIrp->IoStatus.Status;
  1056. }
  1057. }
  1058. DebugTrace( +0, Dbg, "Get Tick Count, net= %x\n", pIrpContext->pNpScb->ServerAddress.Net );
  1059. if ( NT_SUCCESS( Status ) ) {
  1060. //
  1061. // HACK-o-rama. Streams and non-streams IPX have different output
  1062. // buffer formats. For now accept both.
  1063. //
  1064. if ( IpxTransportName.Length == 32 ) {
  1065. // ISNIPX format
  1066. *TickCount = GetTickCountInput.NetNumData.netdelay;
  1067. } else {
  1068. // NWLINK format
  1069. GetTickCountOutput = (struct _GET_TICK_COUNT_OUTPUT *)&GetTickCountInput;
  1070. *TickCount = GetTickCountOutput->NetNumData.netdelay;
  1071. }
  1072. DebugTrace( +0, Dbg, "Tick Count = %d\n", *TickCount );
  1073. //
  1074. // Don't let the transport have us wait forever.
  1075. //
  1076. if ( *TickCount > 600 ) {
  1077. ASSERT( FALSE );
  1078. }
  1079. } else {
  1080. DebugTrace( +0, Dbg, "GetTickCount failed, status = %X\n", Status );
  1081. }
  1082. //
  1083. // Now restore the system buffer and MDL address in the IRP
  1084. //
  1085. pIrp->AssociatedIrp.SystemBuffer = SystemBufferSave;
  1086. pIrp->MdlAddress = MdlSave;
  1087. MmUnlockPages( Mdl );
  1088. FREE_MDL( Mdl );
  1089. return Status;
  1090. }
  1091. #ifndef QFE_BUILD
  1092. static PIRP LineChangeIrp = NULL;
  1093. NTSTATUS
  1094. SubmitLineChangeRequest(
  1095. VOID
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. Use a TDI_ACTION to get a new route.
  1100. Arguments:
  1101. pIrpContext - Supplies IRP context information.
  1102. Return Value:
  1103. The status of the operation.
  1104. --*/
  1105. {
  1106. NTSTATUS Status;
  1107. struct _LINE_CHANGE {
  1108. TDI_ACTION_HEADER Header;
  1109. BOOLEAN DatagramOption;
  1110. ULONG BufferLength;
  1111. ULONG Option;
  1112. } *LineChangeInput;
  1113. PIRP pIrp;
  1114. PMDL Mdl;
  1115. PAGED_CODE();
  1116. LineChangeInput = ALLOCATE_POOL( NonPagedPool, sizeof( struct _LINE_CHANGE ) );
  1117. if (!LineChangeInput) {
  1118. return STATUS_INSUFFICIENT_RESOURCES;
  1119. }
  1120. //
  1121. // Complete initialization of the request, and allocate and build an
  1122. // MDL for the request input buffer.
  1123. //
  1124. LineChangeInput->Header.TransportId = IPX_ID;
  1125. LineChangeInput->Header.ActionCode = 0;
  1126. LineChangeInput->Header.Reserved = 0;
  1127. LineChangeInput->DatagramOption = 2;
  1128. LineChangeInput->BufferLength = 2 * sizeof( ULONG );
  1129. LineChangeInput->Option = MIPX_LINECHANGE;
  1130. Mdl = ALLOCATE_MDL(
  1131. LineChangeInput,
  1132. sizeof( *LineChangeInput ),
  1133. FALSE, // Secondary Buffer
  1134. FALSE, // Charge Quota
  1135. NULL );
  1136. if ( Mdl == NULL ) {
  1137. FREE_POOL( LineChangeInput );
  1138. return STATUS_INSUFFICIENT_RESOURCES;
  1139. }
  1140. pIrp = ALLOCATE_IRP( pIpxDeviceObject->StackSize, FALSE );
  1141. if ( pIrp == NULL ) {
  1142. FREE_POOL( LineChangeInput );
  1143. FREE_MDL( Mdl );
  1144. return STATUS_INSUFFICIENT_RESOURCES;
  1145. }
  1146. //
  1147. // Remember this IRP so that we can cancel it.
  1148. //
  1149. LineChangeIrp = pIrp;
  1150. MmBuildMdlForNonPagedPool( Mdl );
  1151. //
  1152. // Build and submit a TDI request packet.
  1153. //
  1154. TdiBuildAction(
  1155. pIrp,
  1156. pIpxDeviceObject,
  1157. pIpxFileObject,
  1158. CompletionLineChange,
  1159. NULL,
  1160. Mdl );
  1161. Status = IoCallDriver ( pIpxDeviceObject, pIrp );
  1162. return( Status );
  1163. }
  1164. NTSTATUS
  1165. CompletionLineChange(
  1166. IN PDEVICE_OBJECT DeviceObject,
  1167. IN PIRP Irp,
  1168. IN PVOID Context
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. This routine is called when the transport completes a line change IRP.
  1173. This means that we have switched nets, and that we should mark
  1174. all of our servers disconnected.
  1175. Arguments:
  1176. DeviceObject - unused.
  1177. Irp - Supplies Irp that the transport has finished processing.
  1178. Context - unused.
  1179. Return Value:
  1180. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  1181. processing Irp stack locations at this point.
  1182. --*/
  1183. {
  1184. PMDL Mdl;
  1185. PWORK_QUEUE_ITEM WorkQueueItem;
  1186. DebugTrace( 0, Dbg, "CompletionLineChange\n", 0 );
  1187. Mdl = Irp->MdlAddress;
  1188. if ( !NT_SUCCESS( Irp->IoStatus.Status ) ) {
  1189. FREE_POOL( Mdl->MappedSystemVa );
  1190. FREE_MDL( Mdl );
  1191. FREE_IRP( Irp );
  1192. return( STATUS_MORE_PROCESSING_REQUIRED );
  1193. }
  1194. //
  1195. // If the scavenger is running, simply make a note that
  1196. // we need to do this when it is finished.
  1197. //
  1198. KeAcquireSpinLockAtDpcLevel( &NwScavengerSpinLock );
  1199. if ( WorkerRunning ) {
  1200. if ( ( DelayedProcessLineChange != FALSE ) &&
  1201. ( DelayedLineChangeIrp != NULL ) ) {
  1202. //
  1203. // We've already got a line change. Dump this one.
  1204. //
  1205. KeReleaseSpinLockFromDpcLevel( &NwScavengerSpinLock );
  1206. DebugTrace( 0, Dbg, "Dumping an additional line change request.\n", 0 );
  1207. FREE_POOL( Mdl->MappedSystemVa );
  1208. FREE_MDL( Mdl );
  1209. FREE_IRP( Irp );
  1210. return( STATUS_MORE_PROCESSING_REQUIRED );
  1211. } else {
  1212. DebugTrace( 0, Dbg, "Delaying a line change request.\n", 0 );
  1213. DelayedProcessLineChange = TRUE;
  1214. DelayedLineChangeIrp = Irp;
  1215. KeReleaseSpinLockFromDpcLevel( &NwScavengerSpinLock );
  1216. return STATUS_MORE_PROCESSING_REQUIRED;
  1217. }
  1218. } else {
  1219. //
  1220. // Don't let the scavenger start up while we're running.
  1221. //
  1222. WorkerRunning = TRUE;
  1223. KeReleaseSpinLockFromDpcLevel( &NwScavengerSpinLock );
  1224. }
  1225. WorkQueueItem = ALLOCATE_POOL( NonPagedPool, sizeof( *WorkQueueItem ) );
  1226. if ( WorkQueueItem == NULL ) {
  1227. FREE_POOL( Mdl->MappedSystemVa );
  1228. FREE_MDL( Mdl );
  1229. FREE_IRP( Irp );
  1230. return( STATUS_MORE_PROCESSING_REQUIRED );
  1231. }
  1232. //
  1233. // Use the user buffer field as a convenient place to remember where
  1234. // the address of the WorkQueueItem. We can get away with this since
  1235. // we don't let this IRP complete.
  1236. //
  1237. Irp->UserBuffer = WorkQueueItem;
  1238. //
  1239. // Process the line change in the FSP.
  1240. //
  1241. ExInitializeWorkItem( WorkQueueItem, FspProcessLineChange, Irp );
  1242. ExQueueWorkItem( WorkQueueItem, DelayedWorkQueue );
  1243. return( STATUS_MORE_PROCESSING_REQUIRED );
  1244. }
  1245. VOID
  1246. FspProcessLineChange(
  1247. IN PVOID Context
  1248. )
  1249. {
  1250. PIRP Irp;
  1251. ULONG ActiveHandles;
  1252. NwReferenceUnlockableCodeSection();
  1253. Irp = (PIRP)Context;
  1254. //
  1255. // Free the work queue item
  1256. //
  1257. FREE_POOL( Irp->UserBuffer );
  1258. Irp->UserBuffer = NULL;
  1259. //
  1260. // Invalid all remote handles
  1261. //
  1262. ActiveHandles = NwInvalidateAllHandles(NULL, NULL);
  1263. //
  1264. // Now that we're done walking all the servers, it's safe
  1265. // to let the scavenger run again.
  1266. //
  1267. WorkerRunning = FALSE;
  1268. //
  1269. // Resubmit the IRP
  1270. //
  1271. TdiBuildAction(
  1272. Irp,
  1273. pIpxDeviceObject,
  1274. pIpxFileObject,
  1275. CompletionLineChange,
  1276. NULL,
  1277. Irp->MdlAddress );
  1278. IoCallDriver ( pIpxDeviceObject, Irp );
  1279. NwDereferenceUnlockableCodeSection ();
  1280. return;
  1281. }
  1282. #endif