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.

4162 lines
104 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. nb.c
  5. Abstract:
  6. This module contains code which defines the NetBIOS driver's
  7. device object.
  8. Author:
  9. Colin Watson (ColinW) 13-Mar-1991
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "nb.h"
  15. //#include <zwapi.h>
  16. //#include <ntos.h>
  17. typedef ADAPTER_STATUS UNALIGNED *PUADAPTER_STATUS;
  18. typedef NAME_BUFFER UNALIGNED *PUNAME_BUFFER;
  19. typedef SESSION_HEADER UNALIGNED *PUSESSION_HEADER;
  20. typedef SESSION_BUFFER UNALIGNED *PUSESSION_BUFFER;
  21. #if DBG
  22. ULONG NbDebug = 0;
  23. #endif
  24. #if PAGED_DBG
  25. ULONG ThisCodeCantBePaged;
  26. #endif
  27. PEPROCESS NbFspProcess = NULL;
  28. //
  29. // for PNP the list of devices is not static and hence cannot be read
  30. // from the registry. A global list of active devices is maintained.
  31. // This list is updated by the bind and unbind handlers. In addition
  32. // to the device list the MaxLana and the LanaEnum also need to be
  33. // updated to reflect the presence/absence of devices.
  34. //
  35. ULONG g_ulMaxLana;
  36. LANA_ENUM g_leLanaEnum;
  37. PUNICODE_STRING g_pusActiveDeviceList;
  38. HANDLE g_hBindHandle;
  39. UNICODE_STRING g_usRegistryPath;
  40. //
  41. // every load of the netapi32.dll results in an open call (IRP_MJ_CREATE)
  42. // call to the netbios.sys driver. Each open creates an FCB that contains
  43. // a list of devices, MaxLana and a LanaEnum. Each FCB needs to be updated
  44. // to reflect the changes to the active device list.
  45. //
  46. // In addition the LanaInfo structure corresponding to a Lana that has
  47. // been unbound needs to be cleaned up.
  48. //
  49. LIST_ENTRY g_leFCBList;
  50. ERESOURCE g_erGlobalLock;
  51. //
  52. // Each application that uses the NETBIOS api (via the netapi32.dll),
  53. // opens a handle to \\Device\Netbios. This file handle is not closed
  54. // until netapi32.dll is unloaded.
  55. //
  56. // In order to be able to unload netbios.sys these handles have to be
  57. // closed. To force these handles to be closed, the NETAPI32.DLL now
  58. // posts an IOCTL (IOCTL_NB_REGISTER) to listen for shutdown
  59. // notifications. The IRPs corresponding to these IOCTLs are pended,
  60. //
  61. // When the driver is being stopped (unloaded), the pended IRPs are
  62. // completed indicating to netapi32 that it needs to close the open
  63. // handles on \\Device\netbios.
  64. //
  65. // Once all the handles have been closed NETBIOS.SYS can be unloaded.
  66. //
  67. ERESOURCE g_erStopLock; // protects g_ulNumOpens and
  68. // g_dwnetbiosState
  69. DWORD g_dwNetbiosState;
  70. ULONG g_ulNumOpens;
  71. LIST_ENTRY g_leWaitList;
  72. KEVENT g_keAllHandlesClosed;
  73. NTSTATUS
  74. NbAstat(
  75. IN PDNCB pdncb,
  76. IN PIRP Irp,
  77. IN PIO_STACK_LOCATION IrpSp,
  78. IN ULONG Buffer2Length
  79. );
  80. VOID
  81. CopyAddresses(
  82. IN PDNCB pdncb,
  83. IN PIRP Irp,
  84. IN PIO_STACK_LOCATION IrpSp,
  85. IN ULONG Buffer2Length
  86. );
  87. NTSTATUS
  88. NbFindName(
  89. IN PDNCB pdncb,
  90. IN PIRP Irp,
  91. IN PIO_STACK_LOCATION IrpSp,
  92. IN ULONG Buffer2Length
  93. );
  94. NTSTATUS
  95. NbSstat(
  96. IN PDNCB pdncb,
  97. IN PIRP Irp,
  98. IN PIO_STACK_LOCATION IrpSp,
  99. IN ULONG Buffer2Length
  100. );
  101. VOID
  102. CopySessionStatus(
  103. IN PDNCB pdncb,
  104. IN PCB pcb,
  105. IN PUSESSION_HEADER pSessionHeader,
  106. IN PUSESSION_BUFFER* ppSessionBuffer,
  107. IN PULONG pLengthRemaining
  108. );
  109. NTSTATUS
  110. NbEnum(
  111. IN PDNCB pdncb,
  112. IN PIRP Irp,
  113. IN PIO_STACK_LOCATION IrpSp,
  114. IN ULONG Buffer2Length
  115. );
  116. NTSTATUS
  117. NbReset(
  118. IN PDNCB pdncb,
  119. IN PIRP Irp,
  120. IN PIO_STACK_LOCATION IrpSp
  121. );
  122. NTSTATUS
  123. NbAction(
  124. IN PDNCB pdncb,
  125. IN PIRP Irp,
  126. IN PIO_STACK_LOCATION IrpSp
  127. );
  128. NTSTATUS
  129. NbCancel(
  130. IN PDNCB pdncb,
  131. IN PIRP Irp,
  132. IN PIO_STACK_LOCATION IrpSp
  133. );
  134. VOID
  135. CancelRoutine(
  136. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  137. IN PIRP Irp
  138. );
  139. //
  140. // Pnp Stop related functions
  141. //
  142. NTSTATUS
  143. NbRegisterWait(
  144. IN PIRP pIrp
  145. );
  146. VOID
  147. CancelIrp(
  148. IN PDEVICE_OBJECT DeviceObject,
  149. IN PIRP Irp
  150. );
  151. NTSTATUS
  152. NbStop(
  153. );
  154. #if AUTO_RESET
  155. NTSTATUS
  156. NbRegisterReset(
  157. IN PIRP pIrp,
  158. IN PIO_STACK_LOCATION pIrpSp
  159. );
  160. #endif
  161. NTSTATUS
  162. DriverEntry(
  163. IN PDRIVER_OBJECT DriverObject,
  164. IN PUNICODE_STRING RegistryPath
  165. );
  166. #ifdef ALLOC_PRAGMA
  167. #pragma alloc_text(INIT, DriverEntry)
  168. #pragma alloc_text(PAGE, NbDispatch)
  169. #pragma alloc_text(PAGE, NbDeviceControl)
  170. #pragma alloc_text(PAGE, NbOpen)
  171. #pragma alloc_text(PAGE, NbClose)
  172. #pragma alloc_text(PAGE, NbAstat)
  173. #pragma alloc_text(PAGE, NbEnum)
  174. #pragma alloc_text(PAGE, NbReset)
  175. #pragma alloc_text(PAGE, NbFindName)
  176. #pragma alloc_text(PAGE, AllocateAndCopyUnicodeString)
  177. #endif
  178. NTSTATUS
  179. NbCompletionEvent(
  180. IN PDEVICE_OBJECT DeviceObject,
  181. IN PIRP Irp,
  182. IN PVOID Context
  183. )
  184. /*++
  185. Routine Description:
  186. This routine does not complete the Irp. It is used to signal to a
  187. synchronous part of the Netbios driver that it can proceed.
  188. Arguments:
  189. DeviceObject - unused.
  190. Irp - Supplies Irp that the transport has finished processing.
  191. Context - Supplies the event associated with the Irp.
  192. Return Value:
  193. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  194. processing Irp stack locations at this point.
  195. --*/
  196. {
  197. IF_NBDBG (NB_DEBUG_COMPLETE) {
  198. NbPrint( ("NbCompletion event: %lx, Irp: %lx, DeviceObject: %lx\n",
  199. Context,
  200. Irp,
  201. DeviceObject));
  202. }
  203. KeSetEvent((PKEVENT )Context, 0, FALSE);
  204. return STATUS_MORE_PROCESSING_REQUIRED;
  205. UNREFERENCED_PARAMETER( DeviceObject );
  206. UNREFERENCED_PARAMETER( Irp );
  207. }
  208. NTSTATUS
  209. FindNameCompletion(
  210. IN PDEVICE_OBJECT DeviceObject,
  211. IN PIRP Irp,
  212. IN PVOID Context
  213. )
  214. /*++
  215. Routine Description:
  216. This routine completes the TDI Irp used to issue a Find Name to netbt.
  217. It's main job is to clear the MdlAddress field in the IRP since it was
  218. borrowed from the original user mode IRP.
  219. Arguments:
  220. DeviceObject - unused.
  221. Irp - Supplies Irp that the transport has finished processing.
  222. Context - User supplied context arg (not used)
  223. Return Value:
  224. STATUS_SUCCESS
  225. --*/
  226. {
  227. IF_NBDBG (NB_DEBUG_COMPLETE) {
  228. NbPrint( ("FindNameCompletion: Irp: %lx, DeviceObject: %lx\n",
  229. Irp,
  230. DeviceObject));
  231. }
  232. Irp->MdlAddress = NULL;
  233. return STATUS_SUCCESS;
  234. UNREFERENCED_PARAMETER( DeviceObject );
  235. UNREFERENCED_PARAMETER( Context );
  236. }
  237. NTSTATUS
  238. NbCompletionPDNCB(
  239. IN PDEVICE_OBJECT DeviceObject,
  240. IN PIRP Irp,
  241. IN PVOID Context
  242. )
  243. /*++
  244. Routine Description:
  245. This routine completes the Irp by setting the length and status bytes
  246. in the NCB supplied in context.
  247. Send requests have additional processing to remove the send request from
  248. the connection block send list.
  249. Arguments:
  250. DeviceObject - unused.
  251. Irp - Supplies Irp that the transport has finished processing.
  252. Context - Supplies the NCB associated with the Irp.
  253. Return Value:
  254. The final status from the operation (success or an exception).
  255. --*/
  256. {
  257. PDNCB pdncb = (PDNCB) Context;
  258. NTSTATUS Status = STATUS_SUCCESS;
  259. IF_NBDBG (NB_DEBUG_COMPLETE) {
  260. NbPrint(("NbCompletionPDNCB pdncb: %lx, Command: %lx, Lana: %lx,"
  261. "Status: %lx, Length: %lx\n",
  262. Context,
  263. pdncb-> ncb_command,
  264. pdncb-> ncb_lana_num,
  265. Irp->IoStatus.Status,
  266. Irp->IoStatus.Information));
  267. }
  268. // Tell application how many bytes were transferred
  269. pdncb->ncb_length = (unsigned short)Irp->IoStatus.Information;
  270. if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
  271. NCB_COMPLETE( pdncb, NRC_GOODRET );
  272. } else {
  273. if (((pdncb->ncb_command & ~ASYNCH) == NCBRECV ) ||
  274. ((pdncb->ncb_command & ~ASYNCH) == NCBRECVANY )) {
  275. if ( Irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW ) {
  276. PIRP LocalIrp = NULL;
  277. KIRQL OldIrql; // Used when SpinLock held.
  278. PPCB ppcb;
  279. PDEVICE_OBJECT LocalDeviceObject;
  280. LOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  281. //
  282. // The transport will not indicate again so we must put
  283. // another receive down if we can.
  284. // If an Irp cannot be built then BuildReceiveIrp will
  285. // set ReceiveIndicated.
  286. //
  287. ppcb = FindCb( pdncb->pfcb, pdncb, FALSE );
  288. if ( ppcb != NULL ) {
  289. LocalDeviceObject = (*ppcb)->DeviceObject;
  290. LocalIrp = BuildReceiveIrp( *ppcb );
  291. }
  292. UNLOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  293. if ( LocalIrp != NULL ) {
  294. IoCallDriver (LocalDeviceObject, LocalIrp);
  295. }
  296. }
  297. }
  298. NCB_COMPLETE( pdncb, NbMakeNbError( Irp->IoStatus.Status ) );
  299. }
  300. //
  301. // Tell IopCompleteRequest how much to copy back when the request
  302. // completes.
  303. //
  304. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  305. //
  306. // Remove the Send request from the send queue. We have to scan
  307. // the queue because they may be completed out of order if a send
  308. // is rejected because of resource limitations.
  309. //
  310. if (((pdncb->ncb_command & ~ASYNCH) == NCBSEND ) ||
  311. ((pdncb->ncb_command & ~ASYNCH) == NCBCHAINSEND ) ||
  312. ((pdncb->ncb_command & ~ASYNCH) == NCBSENDNA ) ||
  313. ((pdncb->ncb_command & ~ASYNCH) == NCBCHAINSENDNA )) {
  314. PLIST_ENTRY SendEntry;
  315. PPCB ppcb;
  316. KIRQL OldIrql; // Used when SpinLock held.
  317. LOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  318. ppcb = FindCb( pdncb->pfcb, pdncb, FALSE );
  319. //
  320. // If the connection block still exists remove the send. If the connection
  321. // has gone then we no longer need to worry about maintaining the list.
  322. //
  323. if ( ppcb != NULL ) {
  324. #if DBG
  325. BOOLEAN Found = FALSE;
  326. #endif
  327. PCB pcb = *ppcb;
  328. for (SendEntry = pcb->SendList.Flink ;
  329. SendEntry != &pcb->SendList ;
  330. SendEntry = SendEntry->Flink) {
  331. PDNCB pSend = CONTAINING_RECORD( SendEntry, DNCB, ncb_next);
  332. if ( pSend == pdncb ) {
  333. #if DBG
  334. Found = TRUE;
  335. #endif
  336. RemoveEntryList( &pdncb->ncb_next );
  337. break;
  338. }
  339. }
  340. ASSERT( Found == TRUE);
  341. //
  342. // If the session is being hung up then we may wish to cleanup the connection
  343. // as well. STATUS_HANGUP_REQUIRED will cause the dll to manufacture
  344. // another hangup. The manufactured hangup will complete along with
  345. // pcb->pdncbHangup. This method is used to ensure that when a
  346. // hangup is delayed by an outstanding send and the send finally
  347. // completes, that the user hangup completes after all operations
  348. // on the connection.
  349. //
  350. if (( IsListEmpty( &pcb->SendList) ) &&
  351. ( pcb->pdncbHangup != NULL )) {
  352. IF_NBDBG (NB_DEBUG_COMPLETE) {
  353. NbPrint( ("NbCompletionPDNCB Hangup session: %lx\n", ppcb ));
  354. }
  355. Status = STATUS_HANGUP_REQUIRED;
  356. }
  357. }
  358. UNLOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  359. }
  360. //
  361. // Must return a non-error status otherwise the IO system will not copy
  362. // back the NCB into the users buffer.
  363. //
  364. Irp->IoStatus.Status = Status;
  365. NbCheckAndCompleteIrp32(Irp);
  366. return Status;
  367. UNREFERENCED_PARAMETER( DeviceObject );
  368. }
  369. NTSTATUS
  370. DriverEntry(
  371. IN PDRIVER_OBJECT DriverObject,
  372. IN PUNICODE_STRING RegistryPath
  373. )
  374. /*++
  375. Routine Description:
  376. This routine performs initialization of the NetBIOS driver.
  377. Arguments:
  378. DriverObject - Pointer to driver object created by the system.
  379. RegistryPath - The name of the Netbios node in the registry.
  380. Return Value:
  381. The function value is the final status from the initialization operation.
  382. --*/
  383. {
  384. PDEVICE_CONTEXT DeviceContext;
  385. NTSTATUS status;
  386. UNICODE_STRING UnicodeString;
  387. //STRING AnsiNameString;
  388. //
  389. // bind handler info.
  390. //
  391. TDI_CLIENT_INTERFACE_INFO tcii;
  392. PWSTR wsClientName = NETBIOS;
  393. UNICODE_STRING usClientName;
  394. UCHAR ucInd = 0;
  395. PAGED_CODE();
  396. //
  397. #ifdef MEMPRINT
  398. MemPrintInitialize ();
  399. #endif
  400. //
  401. // Create the device object for NETBIOS. For now, we simply create
  402. // \Device\Netbios using a unicode string.
  403. //
  404. NbFspProcess = PsGetCurrentProcess();
  405. RtlInitUnicodeString( &UnicodeString, NB_DEVICE_NAME);
  406. status = NbCreateDeviceContext (DriverObject,
  407. &UnicodeString,
  408. &DeviceContext,
  409. RegistryPath);
  410. if (!NT_SUCCESS (status)) {
  411. NbPrint( ("NbInitialize: Netbios failed to initialize\n"));
  412. return status;
  413. }
  414. //
  415. // PnP additions - V Raman
  416. //
  417. //
  418. // save registry path.
  419. //
  420. g_usRegistryPath.Buffer = (PWSTR) ExAllocatePoolWithTag(
  421. NonPagedPool,
  422. sizeof( WCHAR ) * (RegistryPath-> Length + 1),
  423. 'fSBN'
  424. );
  425. if ( g_usRegistryPath.Buffer == NULL )
  426. {
  427. NbPrint( (
  428. "DriverEntry : Netbios failed to allocate memory for registry path\n"
  429. ) );
  430. return STATUS_NO_MEMORY;
  431. }
  432. g_usRegistryPath.MaximumLength =
  433. sizeof( WCHAR ) * (RegistryPath-> Length + 1);
  434. RtlCopyUnicodeString( &g_usRegistryPath, RegistryPath );
  435. //
  436. // Save lana information.
  437. //
  438. status = GetMaxLana( &g_usRegistryPath, &g_ulMaxLana );
  439. if ( !NT_SUCCESS( status ) )
  440. {
  441. ExFreePool( g_usRegistryPath.Buffer );
  442. return status;
  443. }
  444. //
  445. // On starup there are no devices and no Lanas enabled.
  446. //
  447. g_leLanaEnum.length = 0;
  448. g_pusActiveDeviceList = ExAllocatePoolWithTag(
  449. NonPagedPool,
  450. sizeof( UNICODE_STRING ) * ( MAX_LANA + 1 ),
  451. 'fSBN'
  452. );
  453. if ( g_pusActiveDeviceList == NULL )
  454. {
  455. ExFreePool( g_usRegistryPath.Buffer );
  456. NbPrint( (
  457. "DriverEntry : Netbios failed to allocate memory for device list\n"
  458. ) );
  459. return STATUS_NO_MEMORY;
  460. }
  461. for ( ucInd = 0; ucInd <= MAX_LANA; ucInd++ )
  462. {
  463. RtlInitUnicodeString( &g_pusActiveDeviceList[ ucInd ], NULL );
  464. }
  465. //
  466. // There are no FCBs.
  467. //
  468. InitializeListHead( &g_leFCBList );
  469. ExInitializeResourceLite( &g_erGlobalLock );
  470. InitializeListHead( &g_leWaitList );
  471. ExInitializeResourceLite( &g_erStopLock );
  472. KeInitializeEvent( &g_keAllHandlesClosed, SynchronizationEvent, FALSE );
  473. g_ulNumOpens = 0;
  474. g_dwNetbiosState = NETBIOS_RUNNING;
  475. DeviceContext->Initialized = TRUE;
  476. //
  477. // set up binding handlers
  478. //
  479. RtlZeroMemory( &tcii, sizeof( TDI_CLIENT_INTERFACE_INFO ) );
  480. tcii.TdiVersion = TDI_CURRENT_VERSION;
  481. RtlInitUnicodeString( &usClientName, wsClientName );
  482. tcii.ClientName = &usClientName;
  483. tcii.BindingHandler = NbBindHandler;
  484. tcii.PnPPowerHandler = NbPowerHandler;
  485. status = TdiRegisterPnPHandlers(
  486. &tcii,
  487. sizeof( TDI_CLIENT_INTERFACE_INFO ),
  488. &g_hBindHandle
  489. );
  490. if ( status != STATUS_SUCCESS )
  491. {
  492. //
  493. // failed to register bind/unbind handlers
  494. //
  495. NbPrint( (
  496. "Netbios : DriverEntry : failed to register Bind handlers %0x\n", status
  497. ) );
  498. g_hBindHandle = NULL;
  499. ExDeleteResourceLite( &g_erStopLock );
  500. ExDeleteResourceLite( &g_erGlobalLock );
  501. ExFreePool( g_pusActiveDeviceList );
  502. ExFreePool( g_usRegistryPath.Buffer );
  503. DeviceContext->Initialized = FALSE;
  504. return status;
  505. }
  506. IF_NBDBG (NB_DEBUG_DISPATCH) {
  507. NbPrint( ("NbInitialize: Netbios initialized.\n"));
  508. }
  509. return (status);
  510. }
  511. VOID
  512. NbDriverUnload(
  513. IN PDRIVER_OBJECT DriverObject
  514. )
  515. /*++
  516. Routine Description:
  517. This routine is the unload routine for the NB device driver.
  518. In response to an unload request this function deletes the
  519. "\\device\netbios" created by DriverEntry.
  520. Arguments:
  521. DriverObject - Pointer to the driver object created by the system
  522. Return Value:
  523. None
  524. --*/
  525. {
  526. NTSTATUS nsStatus;
  527. UCHAR ucIndex = 0;
  528. nsStatus = TdiDeregisterPnPHandlers( g_hBindHandle );
  529. if ( !NT_SUCCESS( nsStatus ) )
  530. {
  531. NbPrint( (
  532. "Netbios : NbDriverUnload : Failed to de-register bind handler\n"
  533. ) );
  534. }
  535. //
  536. // all opens to Netbios have been closed.
  537. // All devices have been unbound
  538. // remove all global resources
  539. //
  540. LOCK_GLOBAL();
  541. for ( ucIndex = 0; ucIndex < g_ulMaxLana; ucIndex++ )
  542. {
  543. if ( g_pusActiveDeviceList[ ucIndex ].Buffer != NULL )
  544. {
  545. ExFreePool ( g_pusActiveDeviceList[ ucIndex ].Buffer );
  546. }
  547. }
  548. ExDeleteResourceLite( &g_erStopLock );
  549. ExFreePool( g_pusActiveDeviceList );
  550. ExFreePool( g_usRegistryPath.Buffer );
  551. UNLOCK_GLOBAL();
  552. ExDeleteResourceLite( &g_erGlobalLock );
  553. IoDeleteDevice( DriverObject-> DeviceObject );
  554. }
  555. NTSTATUS
  556. NbDispatch(
  557. IN PDEVICE_OBJECT DeviceObject,
  558. IN PIRP Irp
  559. )
  560. /*++
  561. Routine Description:
  562. This routine is the main dispatch routine for the NB device driver.
  563. It accepts an I/O Request Packet, performs the request, and then
  564. returns with the appropriate status.
  565. Arguments:
  566. DeviceObject - Pointer to the device object for this driver.
  567. Irp - Pointer to the request packet representing the I/O request.
  568. Return Value:
  569. The function value is the status of the operation.
  570. --*/
  571. {
  572. NTSTATUS Status;
  573. PIO_STACK_LOCATION IrpSp;
  574. PDEVICE_CONTEXT DeviceContext;
  575. PAGED_CODE();
  576. //
  577. // Check to see if NB has been initialized; if not, don't allow any use.
  578. //
  579. DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
  580. if (!DeviceContext->Initialized) {
  581. NbCompleteRequest( Irp, STATUS_SUCCESS);
  582. return STATUS_UNSUCCESSFUL;
  583. }
  584. //
  585. // Get a pointer to the current stack location in the IRP. This is where
  586. // the function codes and parameters are stored.
  587. //
  588. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  589. //
  590. // Case on the function that is being performed by the requestor. If the
  591. // operation is a valid one for this device, then make it look like it was
  592. // successfully completed, where possible.
  593. //
  594. switch (IrpSp->MajorFunction) {
  595. //
  596. // The Create function opens a handle that can be used with fsctl's
  597. // to build all interesting operations.
  598. //
  599. case IRP_MJ_CREATE:
  600. IF_NBDBG (NB_DEBUG_DISPATCH) {
  601. NbPrint( ("NbDispatch: IRP_MJ_CREATE.\n"));
  602. }
  603. //
  604. // check if netbios is in the process of stopping
  605. //
  606. LOCK_STOP();
  607. if ( g_dwNetbiosState == NETBIOS_STOPPING )
  608. {
  609. //
  610. // fail the CREATE operation and quit
  611. //
  612. Status = STATUS_NO_SUCH_DEVICE;
  613. Irp->IoStatus.Information = 0;
  614. UNLOCK_STOP();
  615. }
  616. else
  617. {
  618. //
  619. // netbios is still running. Increment count of
  620. // open handles
  621. //
  622. g_ulNumOpens++;
  623. IF_NBDBG (NB_DEBUG_DISPATCH)
  624. {
  625. NbPrint( ( "[NETBIOS] : NbOpen OpenCount %d\n", g_ulNumOpens ) );
  626. }
  627. UNLOCK_STOP();
  628. Status = NbOpen ( DeviceContext, IrpSp );
  629. Irp->IoStatus.Information = FILE_OPENED;
  630. //
  631. // if NbOpen failed, decrement count and return error
  632. //
  633. if ( !NT_SUCCESS( Status ) )
  634. {
  635. LOCK_STOP();
  636. g_ulNumOpens--;
  637. IF_NBDBG (NB_DEBUG_DISPATCH)
  638. {
  639. NbPrint( ( "[NETBIOS] : NbOpen Open Error %lx, numopens : %d\n", Status, g_ulNumOpens ) );
  640. }
  641. //
  642. // check if netbios is in the process of being stopped
  643. //
  644. if ( ( g_ulNumOpens == 0 ) &&
  645. ( g_dwNetbiosState == NETBIOS_STOPPING ) )
  646. {
  647. //
  648. // signal the stopping thread
  649. //
  650. KeSetEvent( &g_keAllHandlesClosed, 0, FALSE );
  651. IF_NBDBG (NB_DEBUG_DISPATCH)
  652. {
  653. NbPrint( ( "[NETBIOS] : NbOpen error %lx; ", Status ) );
  654. NbPrint( ( "Set stop event\n" ) );
  655. }
  656. }
  657. UNLOCK_STOP();
  658. }
  659. }
  660. break;
  661. //
  662. // The Close function closes a transport , terminates
  663. // all outstanding transport activity on the transport, and unbinds
  664. // the from its transport address, if any. If this
  665. // is the last transport endpoint bound to the address, then
  666. // the address is removed by the provider.
  667. //
  668. case IRP_MJ_CLOSE:
  669. IF_NBDBG (NB_DEBUG_DISPATCH) {
  670. NbPrint( ("NbDispatch: IRP_MJ_CLOSE.\n"));
  671. }
  672. Status = NbClose( IrpSp);
  673. if ( NT_SUCCESS( Status ) )
  674. {
  675. LOCK_STOP();
  676. g_ulNumOpens--;
  677. IF_NBDBG (NB_DEBUG_DISPATCH)
  678. {
  679. NbPrint( ( "[NETBIOS] : NbClose OpenCount %d\n", g_ulNumOpens ) );
  680. }
  681. if ( ( g_ulNumOpens == 0 ) &&
  682. ( g_dwNetbiosState == NETBIOS_STOPPING ) )
  683. {
  684. //
  685. // netbios is shutting down and this is the
  686. // last open file handle, signal the stopping
  687. // thread
  688. //
  689. KeSetEvent( &g_keAllHandlesClosed, 0, FALSE );
  690. IF_NBDBG (NB_DEBUG_DISPATCH)
  691. {
  692. NbPrint( ( "[NETBIOS] : NbClose, Set stop event\n" ) );
  693. }
  694. }
  695. UNLOCK_STOP();
  696. }
  697. break;
  698. //
  699. // The DeviceControl function is the main path to the transport
  700. // driver interface. Every TDI request is assigned a minor
  701. // function code that is processed by this function.
  702. //
  703. case IRP_MJ_DEVICE_CONTROL:
  704. IF_NBDBG (NB_DEBUG_DISPATCH) {
  705. NbPrint( ("NbDispatch: IRP_MJ_DEVICE_CONTROL, Irp: %lx.\n", Irp ));
  706. }
  707. Status = NbDeviceControl (DeviceObject, Irp, IrpSp);
  708. if ((Status != STATUS_PENDING) &&
  709. (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_NB_NCB)) {
  710. //
  711. // Bug # : 340042
  712. //
  713. // Set the IoStatus.Information field only for IOCTL_NB_NCB.
  714. // For other IOCTLs it is either irrelevant or the IOCTL processing
  715. // will set it itself
  716. //
  717. //
  718. // Tell IopCompleteRequest how much to copy back when the
  719. // request completes. We need to do this for cases where
  720. // NbCompletionPDNCB is not used.
  721. //
  722. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  723. }
  724. #if DBG
  725. if ( (Status != STATUS_SUCCESS) &&
  726. (Status != STATUS_PENDING ) &&
  727. (Status != STATUS_HANGUP_REQUIRED )) {
  728. IF_NBDBG (NB_DEBUG_DISPATCH) {
  729. NbPrint( ("NbDispatch: Invalid status: %X.\n", Status ));
  730. ASSERT( FALSE );
  731. }
  732. }
  733. #endif
  734. break;
  735. //
  736. // Handle the two stage IRP for a file close operation. When the first
  737. // stage hits, ignore it. We will do all the work on the close Irp.
  738. //
  739. case IRP_MJ_CLEANUP:
  740. IF_NBDBG (NB_DEBUG_DISPATCH) {
  741. NbPrint( ("NbDispatch: IRP_MJ_CLEANUP.\n"));
  742. }
  743. Status = STATUS_SUCCESS;
  744. break;
  745. default:
  746. IF_NBDBG (NB_DEBUG_DISPATCH) {
  747. NbPrint( ("NbDispatch: OTHER (DEFAULT).\n"));
  748. }
  749. Status = STATUS_INVALID_DEVICE_REQUEST;
  750. } /* major function switch */
  751. if (Status == STATUS_PENDING) {
  752. IF_NBDBG (NB_DEBUG_DISPATCH) {
  753. NbPrint( ("NbDispatch: request PENDING from handler.\n"));
  754. }
  755. } else {
  756. IF_NBDBG (NB_DEBUG_DISPATCH) {
  757. NbPrint( ("NbDispatch: request COMPLETED by handler.\n"));
  758. }
  759. /*
  760. * Thunk the NCB back to 32-bit compatible
  761. * structure if the caller is a 32-bit app.
  762. */
  763. NbCheckAndCompleteIrp32(Irp);
  764. NbCompleteRequest( Irp, Status);
  765. }
  766. return Status;
  767. } /* NbDispatch */
  768. NTSTATUS
  769. NbDeviceControl(
  770. IN PDEVICE_OBJECT DeviceObject,
  771. IN PIRP Irp,
  772. IN PIO_STACK_LOCATION IrpSp
  773. )
  774. /*++
  775. Routine Description:
  776. This routine dispatches NetBios request types to different handlers based
  777. on the minor IOCTL function code in the IRP's current stack location.
  778. In addition to cracking the minor function code, this routine also
  779. reaches into the IRP and passes the packetized parameters stored there
  780. as parameters to the various request handlers so that they are
  781. not IRP-dependent.
  782. Arguments:
  783. DeviceObject - Pointer to the device object for this driver.
  784. Irp - Pointer to the request packet representing the I/O request.
  785. IrpSp - Pointer to current IRP stack frame.
  786. Return Value:
  787. The function value is the status of the operation.
  788. --*/
  789. {
  790. NTSTATUS Status = STATUS_SUCCESS;
  791. PNCB pUsersNcb;
  792. PDNCB pdncb = NULL;
  793. PUCHAR Buffer2;
  794. ULONG Buffer2Length;
  795. ULONG RequestLength;
  796. BOOLEAN Is32bitProcess;
  797. PAGED_CODE();
  798. IF_NBDBG (NB_DEBUG_DEVICE_CONTROL) {
  799. NbPrint( ("NbDeviceControl: Entered...\n"));
  800. }
  801. switch ( IrpSp->Parameters.DeviceIoControl.IoControlCode )
  802. {
  803. case IOCTL_NB_NCB :
  804. break;
  805. case IOCTL_NB_REGISTER_STOP :
  806. Status = NbRegisterWait( Irp );
  807. return Status;
  808. case IOCTL_NB_STOP :
  809. Status = NbStop();
  810. return Status;
  811. #if AUTO_RESET
  812. case IOCTL_NB_REGISTER_RESET :
  813. Status = NbRegisterReset( Irp, IrpSp );
  814. return Status;
  815. #endif
  816. default:
  817. {
  818. IF_NBDBG (NB_DEBUG_DEVICE_CONTROL)
  819. {
  820. NbPrint( ("NbDeviceControl: invalid request type.\n"));
  821. }
  822. return STATUS_INVALID_DEVICE_REQUEST;
  823. }
  824. }
  825. //
  826. // Caller provided 2 buffers. The first is the NCB.
  827. // The second is an optional buffer for send or receive data.
  828. // Since the Netbios driver only operates in the context of the
  829. // calling application, these buffers are directly accessable.
  830. // however they can be deleted by the user so try-except clauses are
  831. // required.
  832. //
  833. pUsersNcb = (PNCB)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  834. RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  835. Buffer2 = Irp->UserBuffer;
  836. Buffer2Length = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  837. #if defined(_WIN64)
  838. Is32bitProcess = IoIs32bitProcess(Irp);
  839. if (Is32bitProcess == TRUE) {
  840. if (RequestLength != sizeof( NCB32 )) {
  841. return STATUS_INVALID_PARAMETER;
  842. }
  843. } else {
  844. #endif
  845. if ( RequestLength != sizeof( NCB ) ) {
  846. return STATUS_INVALID_PARAMETER;
  847. }
  848. #if defined(_WIN64)
  849. }
  850. #endif
  851. try {
  852. //
  853. // Probe the input buffer
  854. //
  855. if (ExGetPreviousMode() != KernelMode) {
  856. ProbeForWrite(pUsersNcb, RequestLength, 4);
  857. }
  858. //
  859. // Create a copy of the NCB and convince the IO system to
  860. // copy it back (and deallocate it) when the IRP completes.
  861. //
  862. Irp->AssociatedIrp.SystemBuffer =
  863. ExAllocatePoolWithTag( NonPagedPool, sizeof( DNCB ), 'nSBN' );
  864. if (Irp->AssociatedIrp.SystemBuffer == NULL) {
  865. //
  866. // Since we cannot allocate the drivers copy of the NCB, we
  867. // must turn around and use the original Ncb to return the error.
  868. //
  869. #if defined(_WIN64)
  870. if (Is32bitProcess) {
  871. NCB32 *pUsersNcb32 = (PNCB32)
  872. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  873. pUsersNcb32->ncb_retcode = NRC_NORES;
  874. } else {
  875. #endif
  876. pUsersNcb->ncb_retcode = NRC_NORES;
  877. #if defined(_WIN64)
  878. }
  879. #endif
  880. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  881. return STATUS_SUCCESS;
  882. }
  883. //
  884. // Tell the IO system where to copy the ncb back to during
  885. // IoCompleteRequest.
  886. //
  887. Irp->Flags |= (ULONG) (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER |
  888. IRP_INPUT_OPERATION );
  889. Irp->UserBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  890. // In the driver we should now use our copy of the NCB
  891. pdncb = Irp->AssociatedIrp.SystemBuffer;
  892. #if defined(_WIN64)
  893. if (Is32bitProcess == TRUE) {
  894. RtlZeroMemory(pdncb, sizeof( DNCB ));
  895. NbThunkNcb((PNCB32)pUsersNcb, pdncb);
  896. } else {
  897. #endif
  898. RtlMoveMemory( pdncb,
  899. pUsersNcb,
  900. FIELD_OFFSET( DNCB, ncb_cmd_cplt )+1 );
  901. #if defined(_WIN64)
  902. }
  903. #endif
  904. //
  905. // Save the users virtual address for the NCB just in case the
  906. // virtual address is supplied in an NCBCANCEL. This is the same
  907. // as Irp->UserBuffer.
  908. //
  909. pdncb->users_ncb = pUsersNcb;
  910. } except(EXCEPTION_EXECUTE_HANDLER) {
  911. Status = GetExceptionCode();
  912. IF_NBDBG (NB_DEBUG_DEVICE_CONTROL) {
  913. NbPrint( ("NbDeviceControl: Exception1 %X.\n", Status));
  914. }
  915. if (pdncb != NULL) {
  916. NCB_COMPLETE( pdncb, NbMakeNbError(Status) );
  917. }
  918. return Status;
  919. }
  920. if ( Buffer2Length ) {
  921. // Mdl will be freed by IopCompleteRequest.
  922. Irp->MdlAddress = IoAllocateMdl( Buffer2,
  923. Buffer2Length,
  924. FALSE,
  925. FALSE,
  926. Irp );
  927. ASSERT( Irp->MdlAddress != NULL );
  928. //
  929. // Added by V Raman for bug fix : 127223
  930. //
  931. // Check if MDL allocate failed and return.
  932. //
  933. if ( Irp-> MdlAddress == NULL )
  934. {
  935. IF_NBDBG(NB_DEBUG_DEVICE_CONTROL)
  936. NbPrint( ("[NETBIOS] NbDeviceControl: Failed to allocate MDL") );
  937. NCB_COMPLETE( pdncb, NRC_NORES );
  938. return STATUS_SUCCESS;
  939. }
  940. try {
  941. MmProbeAndLockPages( Irp->MdlAddress,
  942. Irp->RequestorMode,
  943. (LOCK_OPERATION) IoModifyAccess);
  944. } except(EXCEPTION_EXECUTE_HANDLER) {
  945. Status = GetExceptionCode();
  946. IF_NBDBG (NB_DEBUG_DEVICE_CONTROL) {
  947. NbPrint( ("NbDeviceControl: Exception2 %X.\n", Status));
  948. NbPrint( ("NbDeviceControl: IoContolCode: %lx, Fcb: %lx,"
  949. " ncb_command %lx, Buffer2Length: %lx\n",
  950. IrpSp->Parameters.DeviceIoControl.IoControlCode,
  951. IrpSp->FileObject->FsContext2,
  952. pdncb->ncb_command,
  953. Buffer2Length));
  954. }
  955. if ( Irp->MdlAddress != NULL ) {
  956. IoFreeMdl(Irp->MdlAddress);
  957. Irp->MdlAddress = NULL;
  958. }
  959. NCB_COMPLETE( pdncb, NbMakeNbError(Status) );
  960. return STATUS_SUCCESS;
  961. }
  962. } else {
  963. ASSERT( Irp->MdlAddress == NULL );
  964. }
  965. IF_NBDBG (NB_DEBUG_DEVICE_CONTROL) {
  966. NbPrint( ("NbDeviceControl: Fcb: %lx, Ncb: %lx"
  967. " ncb_command %lx, ncb_lana_num: %lx\n",
  968. IrpSp->FileObject->FsContext2,
  969. pdncb,
  970. pdncb->ncb_command,
  971. pdncb->ncb_lana_num));
  972. }
  973. switch ( pdncb->ncb_command & ~ASYNCH ) {
  974. case NCBCALL:
  975. case NCALLNIU:
  976. Status = NbCall( pdncb, Irp, IrpSp );
  977. break;
  978. case NCBCANCEL:
  979. Status = NbCancel( pdncb, Irp, IrpSp );
  980. break;
  981. case NCBLISTEN:
  982. Status = NbListen( pdncb, Irp, IrpSp );
  983. break;
  984. case NCBHANGUP:
  985. Status = NbHangup( pdncb, Irp, IrpSp );
  986. break;
  987. case NCBASTAT:
  988. Status = NbAstat( pdncb, Irp, IrpSp, Buffer2Length );
  989. break;
  990. case NCBFINDNAME:
  991. Status = NbFindName( pdncb, Irp, IrpSp, Buffer2Length );
  992. break;
  993. case NCBSSTAT:
  994. Status = NbSstat( pdncb, Irp, IrpSp, Buffer2Length );
  995. break;
  996. case NCBENUM:
  997. NbEnum( pdncb, Irp, IrpSp, Buffer2Length );
  998. break;
  999. case NCBRECV:
  1000. Status = NbReceive( pdncb, Irp, IrpSp, Buffer2Length, FALSE, 0 );
  1001. break;
  1002. case NCBRECVANY:
  1003. Status = NbReceiveAny( pdncb, Irp, IrpSp, Buffer2Length );
  1004. break;
  1005. case NCBDGRECV:
  1006. case NCBDGRECVBC:
  1007. Status = NbReceiveDatagram( pdncb, Irp, IrpSp, Buffer2Length );
  1008. break;
  1009. case NCBSEND:
  1010. case NCBSENDNA:
  1011. case NCBCHAINSEND:
  1012. case NCBCHAINSENDNA:
  1013. Status = NbSend( pdncb, Irp, IrpSp, Buffer2Length );
  1014. break;
  1015. case NCBDGSEND:
  1016. case NCBDGSENDBC:
  1017. Status = NbSendDatagram( pdncb, Irp, IrpSp, Buffer2Length );
  1018. break;
  1019. case NCBADDNAME:
  1020. case NCBADDGRNAME:
  1021. case NCBQUICKADDNAME:
  1022. case NCBQUICKADDGRNAME:
  1023. NbAddName( pdncb, IrpSp );
  1024. break;
  1025. case NCBDELNAME:
  1026. NbDeleteName( pdncb, IrpSp );
  1027. break;
  1028. case NCBLANSTALERT:
  1029. Status = NbLanStatusAlert( pdncb, Irp, IrpSp );
  1030. break;
  1031. case NCBRESET:
  1032. Status = NbReset( pdncb, Irp, IrpSp );
  1033. break;
  1034. case NCBACTION:
  1035. Status = NbAction( pdncb, Irp, IrpSp);
  1036. break;
  1037. // The following are No-operations that return success for compatibility
  1038. case NCBUNLINK:
  1039. case NCBTRACE:
  1040. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1041. break;
  1042. default:
  1043. NCB_COMPLETE( pdncb, NRC_ILLCMD );
  1044. break;
  1045. }
  1046. return Status;
  1047. UNREFERENCED_PARAMETER( DeviceObject );
  1048. } /* NbDeviceControl */
  1049. NTSTATUS
  1050. NbOpen(
  1051. IN PDEVICE_CONTEXT DeviceContext,
  1052. IN PIO_STACK_LOCATION IrpSp
  1053. )
  1054. /*++
  1055. Routine Description:
  1056. Arguments:
  1057. DeviceContext - Includes the name of the netbios node in the registry.
  1058. IrpSp - Pointer to current IRP stack frame.
  1059. Return Value:
  1060. The function value is the status of the operation.
  1061. --*/
  1062. {
  1063. PAGED_CODE();
  1064. return NewFcb( DeviceContext, IrpSp );
  1065. } /* NbOpen */
  1066. NTSTATUS
  1067. NbClose(
  1068. IN PIO_STACK_LOCATION IrpSp
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. This routine is called to close an existing handle. This
  1073. involves running down all of the current and pending activity associated
  1074. with the handle, and dereferencing structures as appropriate.
  1075. Arguments:
  1076. Irp - Pointer to the request packet representing the I/O request.
  1077. IrpSp - Pointer to current IRP stack frame.
  1078. Return Value:
  1079. The function value is the status of the operation.
  1080. --*/
  1081. {
  1082. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1083. PAGED_CODE();
  1084. if (pfcb!=NULL) {
  1085. CleanupFcb( IrpSp, pfcb );
  1086. }
  1087. return STATUS_SUCCESS;
  1088. } /* NbClose */
  1089. NTSTATUS
  1090. NbAstat(
  1091. IN PDNCB pdncb,
  1092. IN PIRP Irp,
  1093. IN PIO_STACK_LOCATION IrpSp,
  1094. IN ULONG Buffer2Length
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. This routine is called to return the adapter status. It queries the
  1099. transport for the main adapter status data such as number of FRMR frames
  1100. received and then uses CopyAddresses to fill in the status for the names
  1101. that THIS application has added.
  1102. Arguments:
  1103. pdncb - Pointer to the NCB.
  1104. Irp - Pointer to the request packet representing the I/O request.
  1105. IrpSp - Pointer to current IRP stack frame.
  1106. Buffer2Length - User provided buffer length for data.
  1107. Return Value:
  1108. The function value is the status of the operation.
  1109. --*/
  1110. {
  1111. NTSTATUS Status = STATUS_SUCCESS;
  1112. TDI_CONNECTION_INFORMATION RequestInformation;
  1113. TA_NETBIOS_ADDRESS ConnectBlock;
  1114. PTDI_ADDRESS_NETBIOS temp;
  1115. KPROCESSOR_MODE PreviousMode;
  1116. BOOLEAN ChangedMode=FALSE;
  1117. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1118. UNICODE_STRING usDeviceName;
  1119. PAGED_CODE();
  1120. RtlInitUnicodeString( &usDeviceName, NULL );
  1121. if ( Buffer2Length >= sizeof(ADAPTER_STATUS) ) {
  1122. KEVENT Event1;
  1123. NTSTATUS Status;
  1124. HANDLE TdiHandle;
  1125. PFILE_OBJECT TdiObject;
  1126. PDEVICE_OBJECT DeviceObject;
  1127. RtlInitUnicodeString( &usDeviceName, NULL );
  1128. //
  1129. // for PNP
  1130. //
  1131. LOCK_RESOURCE( pfcb );
  1132. if ( ( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  1133. ( pfcb->pDriverName[pdncb->ncb_lana_num].MaximumLength == 0 ) ||
  1134. ( pfcb->pDriverName[pdncb->ncb_lana_num].Buffer == NULL ) ) {
  1135. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1136. UNLOCK_RESOURCE( pfcb );
  1137. return STATUS_SUCCESS;
  1138. }
  1139. if (( pfcb == NULL ) ||
  1140. (pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  1141. (pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED)) {
  1142. NCB_COMPLETE( pdncb, NRC_ENVNOTDEF ); // need a reset
  1143. UNLOCK_RESOURCE( pfcb );
  1144. return STATUS_SUCCESS;
  1145. }
  1146. Status = AllocateAndCopyUnicodeString(
  1147. &usDeviceName, &pfcb->pDriverName[pdncb->ncb_lana_num]
  1148. );
  1149. if ( !NT_SUCCESS( Status ) )
  1150. {
  1151. NCB_COMPLETE( pdncb, NRC_NORESOURCES );
  1152. UNLOCK_RESOURCE( pfcb );
  1153. return STATUS_SUCCESS;
  1154. }
  1155. UNLOCK_RESOURCE( pfcb );
  1156. // NULL returns a handle for doing control functions
  1157. Status = NbOpenAddress (
  1158. &TdiHandle, (PVOID*)&TdiObject, &usDeviceName,
  1159. pdncb->ncb_lana_num, NULL
  1160. );
  1161. if (!NT_SUCCESS(Status)) {
  1162. IF_NBDBG (NB_DEBUG_ASTAT) {
  1163. NbPrint(( "\n FAILED on open of Tdi: %X ******\n", Status ));
  1164. }
  1165. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  1166. ExFreePool( usDeviceName.Buffer );
  1167. return STATUS_SUCCESS;
  1168. }
  1169. KeInitializeEvent (
  1170. &Event1,
  1171. SynchronizationEvent,
  1172. FALSE);
  1173. DeviceObject = IoGetRelatedDeviceObject( TdiObject );
  1174. TdiBuildQueryInformation( Irp,
  1175. DeviceObject,
  1176. TdiObject,
  1177. NbCompletionEvent,
  1178. &Event1,
  1179. TDI_QUERY_ADAPTER_STATUS,
  1180. Irp->MdlAddress);
  1181. if ( pdncb->ncb_callname[0] != '*') {
  1182. //
  1183. // Remote Astat. The variables used to specify the remote adapter name
  1184. // are kept the same as those in connect.c to aid maintenance.
  1185. //
  1186. PIO_STACK_LOCATION NewIrpSp = IoGetNextIrpStackLocation (Irp);
  1187. ConnectBlock.TAAddressCount = 1;
  1188. ConnectBlock.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  1189. ConnectBlock.Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
  1190. temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock.Address[0].Address;
  1191. temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1192. RtlMoveMemory( temp->NetbiosName, pdncb->ncb_callname, NCBNAMSZ );
  1193. RequestInformation.RemoteAddress = &ConnectBlock;
  1194. RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
  1195. sizeof (TDI_ADDRESS_NETBIOS);
  1196. ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&NewIrpSp->Parameters)
  1197. ->RequestConnectionInformation = &RequestInformation;
  1198. PreviousMode = Irp->RequestorMode;
  1199. Irp->RequestorMode = KernelMode;
  1200. ChangedMode=TRUE;
  1201. } else {
  1202. //
  1203. // Avoid situation where adapter has more names added than the process and
  1204. // then extra names get added to the end of the buffer.
  1205. //
  1206. //
  1207. // Map the users buffer now so that the whole buffer is mapped (not
  1208. // just sizeof ADAPTER_STATUS).
  1209. //
  1210. if (Irp->MdlAddress) {
  1211. if (MmGetSystemAddressForMdlSafe(
  1212. Irp->MdlAddress, NormalPagePriority
  1213. ) == NULL) {
  1214. IF_NBDBG (NB_DEBUG_ASTAT) {
  1215. NbPrint(( "\nFAILED on mapping MDL ******\n" ));
  1216. }
  1217. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  1218. ExFreePool( usDeviceName.Buffer );
  1219. return STATUS_SUCCESS;
  1220. }
  1221. } else {
  1222. ASSERT(FALSE);
  1223. }
  1224. Irp->MdlAddress->ByteCount = sizeof(ADAPTER_STATUS);
  1225. }
  1226. IoCallDriver (DeviceObject, Irp);
  1227. if (ChangedMode) {
  1228. Irp->RequestorMode = PreviousMode;
  1229. }
  1230. do {
  1231. Status = KeWaitForSingleObject(
  1232. &Event1, Executive, KernelMode, TRUE, NULL
  1233. );
  1234. } while (Status == STATUS_ALERTED);
  1235. //
  1236. // Restore length now that the transport has filled in no more than
  1237. // is required of it.
  1238. //
  1239. if (Irp->MdlAddress) {
  1240. Irp->MdlAddress->ByteCount = Buffer2Length;
  1241. }
  1242. NbAddressClose( TdiHandle, TdiObject );
  1243. if (!NT_SUCCESS(Status)) {
  1244. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  1245. ExFreePool( usDeviceName.Buffer );
  1246. return Status;
  1247. }
  1248. Status = Irp->IoStatus.Status;
  1249. if (( Status == STATUS_BUFFER_OVERFLOW ) &&
  1250. ( pdncb->ncb_callname[0] == '*')) {
  1251. //
  1252. // This is a local ASTAT. Don't worry if there was not enough room in the
  1253. // users buffer for all the addresses that the transport knows about. There
  1254. // only needs to be space for the names the user has added and we will check
  1255. // that later.
  1256. //
  1257. Status = STATUS_SUCCESS;
  1258. }
  1259. if (!NT_SUCCESS(Status)) {
  1260. pdncb->ncb_length = (WORD)Irp->IoStatus.Information;
  1261. NCB_COMPLETE( pdncb, NbMakeNbError(Status) );
  1262. } else {
  1263. if ( pdncb->ncb_callname[0] == '*') {
  1264. //
  1265. // Append the addresses and Netbios maintained counts.
  1266. //
  1267. CopyAddresses(
  1268. pdncb,
  1269. Irp,
  1270. IrpSp,
  1271. Buffer2Length);
  1272. // CopyAddresses completes the NCB appropriately.
  1273. } else {
  1274. pdncb->ncb_length = (WORD)Irp->IoStatus.Information;
  1275. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1276. }
  1277. }
  1278. } else {
  1279. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  1280. }
  1281. //
  1282. // Because the completion routine returned STATUS_MORE_PROCESSING_REQUIRED
  1283. // NbAstat must return a status other than STATUS_PENDING so that the
  1284. // users Irp gets completed.
  1285. //
  1286. if ( usDeviceName.Buffer != NULL )
  1287. {
  1288. ExFreePool( usDeviceName.Buffer );
  1289. }
  1290. ASSERT( Status != STATUS_PENDING );
  1291. return Status;
  1292. UNREFERENCED_PARAMETER( IrpSp );
  1293. }
  1294. VOID
  1295. CopyAddresses(
  1296. IN PDNCB pdncb,
  1297. IN PIRP Irp,
  1298. IN PIO_STACK_LOCATION IrpSp,
  1299. IN ULONG Buffer2Length
  1300. )
  1301. /*++
  1302. Routine Description:
  1303. This routine is called to finish the adapter status.
  1304. Arguments:
  1305. pdncb - Pointer to the NCB.
  1306. Irp - Pointer to the request packet representing the I/O request.
  1307. IrpSp - Pointer to current IRP stack frame.
  1308. Buffer2Length - User provided buffer length for data.
  1309. Return Value:
  1310. none.
  1311. --*/
  1312. {
  1313. ULONG LengthRemaining = Buffer2Length - sizeof(ADAPTER_STATUS);
  1314. PUADAPTER_STATUS pAdapter;
  1315. PUNAME_BUFFER pNameArray;
  1316. int NextEntry = 0; // Used to walk pNameArray
  1317. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1318. PLANA_INFO plana;
  1319. int index; // Used to access AddressBlocks
  1320. KIRQL OldIrql; // Used when SpinLock held.
  1321. LOCK( pfcb, OldIrql );
  1322. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  1323. if ((plana == NULL ) ||
  1324. (plana->Status != NB_INITIALIZED)) {
  1325. NCB_COMPLETE( pdncb, NRC_ENVNOTDEF ); // need a reset
  1326. UNLOCK( pfcb, OldIrql );
  1327. return;
  1328. }
  1329. //
  1330. // Map the users buffer so we can poke around inside
  1331. //
  1332. if (Irp->MdlAddress) {
  1333. pAdapter = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
  1334. if (pAdapter == NULL) {
  1335. NCB_COMPLETE( pdncb, NRC_NORES );
  1336. UNLOCK( pfcb, OldIrql );
  1337. return;
  1338. }
  1339. } else {
  1340. ASSERT(FALSE);
  1341. return;
  1342. }
  1343. pNameArray = (PUNAME_BUFFER)((PUCHAR)pAdapter + sizeof(ADAPTER_STATUS));
  1344. pAdapter->rev_major = 0x03;
  1345. pAdapter->rev_minor = 0x00;
  1346. pAdapter->free_ncbs = 255;
  1347. pAdapter->max_cfg_ncbs = 255;
  1348. pAdapter->max_ncbs = 255;
  1349. pAdapter->pending_sess = 0;
  1350. for ( index = 0; index <= MAXIMUM_CONNECTION; index++ ) {
  1351. if ( plana->ConnectionBlocks[index] != NULL) {
  1352. pAdapter->pending_sess++;
  1353. }
  1354. }
  1355. pAdapter->max_cfg_sess = (WORD)plana->MaximumConnection;
  1356. pAdapter->max_sess = (WORD)plana->MaximumConnection;
  1357. pAdapter->name_count = 0;
  1358. // Don't include the reserved address so start at index=2.
  1359. for ( index = 2; index < MAXIMUM_ADDRESS; index++ ) {
  1360. if ( plana->AddressBlocks[index] != NULL ) {
  1361. if ( LengthRemaining >= sizeof(NAME_BUFFER) ) {
  1362. RtlCopyMemory( (PUCHAR)&pNameArray[NextEntry],
  1363. &plana->AddressBlocks[index]->Name,
  1364. sizeof(NAME));
  1365. pNameArray[NextEntry].name_num =
  1366. plana->AddressBlocks[index]->NameNumber;
  1367. pNameArray[NextEntry].name_flags =
  1368. plana->AddressBlocks[index]->Status;
  1369. LengthRemaining -= sizeof(NAME_BUFFER);
  1370. NextEntry++;
  1371. pAdapter->name_count++;
  1372. } else {
  1373. NCB_COMPLETE( pdncb, NRC_INCOMP );
  1374. goto exit;
  1375. }
  1376. }
  1377. }
  1378. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1379. exit:
  1380. pdncb->ncb_length = (unsigned short)( sizeof(ADAPTER_STATUS) +
  1381. ( sizeof(NAME_BUFFER) * NextEntry));
  1382. UNLOCK( pfcb, OldIrql );
  1383. }
  1384. NTSTATUS
  1385. NbFindName(
  1386. IN PDNCB pdncb,
  1387. IN PIRP Irp,
  1388. IN PIO_STACK_LOCATION IrpSp,
  1389. IN ULONG Buffer2Length
  1390. )
  1391. /*++
  1392. Routine Description:
  1393. This routine is called to return the result of a name query.
  1394. Arguments:
  1395. pdncb - Pointer to the NCB.
  1396. Irp - Pointer to the request packet representing the I/O request.
  1397. IrpSp - Pointer to current IRP stack frame.
  1398. Buffer2Length - User provided buffer length for data.
  1399. Return Value:
  1400. The function value is the status of the operation.
  1401. --*/
  1402. {
  1403. NTSTATUS Status = STATUS_SUCCESS;
  1404. TDI_CONNECTION_INFORMATION RequestInformation;
  1405. TA_NETBIOS_ADDRESS ConnectBlock;
  1406. PTDI_ADDRESS_NETBIOS temp;
  1407. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1408. KEVENT Event1;
  1409. HANDLE TdiHandle;
  1410. PFILE_OBJECT TdiObject;
  1411. PDEVICE_OBJECT DeviceObject;
  1412. UNICODE_STRING usDeviceName;
  1413. PIRP nbtIrp;
  1414. PIO_STACK_LOCATION nbtIrpSp;
  1415. IO_STATUS_BLOCK ioStatus;
  1416. PAGED_CODE();
  1417. if ((pfcb == NULL) || (Buffer2Length < (sizeof(FIND_NAME_HEADER) + sizeof(FIND_NAME_BUFFER)))) {
  1418. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  1419. return STATUS_SUCCESS;
  1420. }
  1421. RtlInitUnicodeString( &usDeviceName, NULL );
  1422. LOCK_RESOURCE( pfcb );
  1423. if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  1424. ( pfcb == NULL ) ||
  1425. (pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  1426. (pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED)) {
  1427. UNLOCK_RESOURCE( pfcb );
  1428. NCB_COMPLETE( pdncb, NRC_ENVNOTDEF ); // need a reset
  1429. return STATUS_SUCCESS;
  1430. }
  1431. if ( ( pfcb->pDriverName[pdncb->ncb_lana_num].MaximumLength == 0 ) ||
  1432. ( pfcb->pDriverName[pdncb->ncb_lana_num].Buffer == NULL ) ) {
  1433. UNLOCK_RESOURCE( pfcb );
  1434. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1435. return STATUS_SUCCESS;
  1436. }
  1437. Status = AllocateAndCopyUnicodeString(
  1438. &usDeviceName, &pfcb->pDriverName[pdncb->ncb_lana_num]
  1439. );
  1440. if ( !NT_SUCCESS( Status ) )
  1441. {
  1442. UNLOCK_RESOURCE( pfcb );
  1443. NCB_COMPLETE( pdncb, NRC_NORESOURCES );
  1444. return STATUS_SUCCESS;
  1445. }
  1446. UNLOCK_RESOURCE( pfcb );
  1447. // NULL returns a handle for doing control functions
  1448. Status = NbOpenAddress (
  1449. &TdiHandle, (PVOID*)&TdiObject, &usDeviceName,
  1450. pdncb->ncb_lana_num, NULL
  1451. );
  1452. if (!NT_SUCCESS(Status)) {
  1453. IF_NBDBG (NB_DEBUG_ASTAT) {
  1454. NbPrint(( "\n FAILED on open of Tdi: %X ******\n", Status ));
  1455. }
  1456. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  1457. ExFreePool( usDeviceName.Buffer );
  1458. return STATUS_SUCCESS;
  1459. }
  1460. KeInitializeEvent (
  1461. &Event1,
  1462. SynchronizationEvent,
  1463. FALSE);
  1464. DeviceObject = IoGetRelatedDeviceObject( TdiObject );
  1465. //
  1466. // DDK sez we shouldn't hijack the user mode IRP. We create one of our own
  1467. // to issue to Netbt for the query.
  1468. //
  1469. nbtIrp = TdiBuildInternalDeviceControlIrp(TdiBuildQueryInformation,
  1470. DeviceObject,
  1471. TdiObject,
  1472. &Event1,
  1473. &ioStatus);
  1474. if ( nbtIrp == NULL ) {
  1475. IF_NBDBG (NB_DEBUG_ASTAT) {
  1476. NbPrint(( "\n FAILED to allocate internal Irp for Tdi: %X ******\n", ioStatus.Status ));
  1477. }
  1478. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  1479. ExFreePool( usDeviceName.Buffer );
  1480. return STATUS_SUCCESS;
  1481. }
  1482. IF_NBDBG (NB_DEBUG_ASTAT) {
  1483. NbPrint(("NbFindName: Allocated IRP %08x for TdiBuildQueryInfo\n", nbtIrp ));
  1484. }
  1485. //
  1486. // we use our own find name completion routine. We "borrow" the MDL from
  1487. // the user mode IRP, hence it must be cleared from the TDI IRP before it
  1488. // is completed. Findname's completion routine takes care of that detail.
  1489. //
  1490. TdiBuildQueryInformation( nbtIrp,
  1491. DeviceObject,
  1492. TdiObject,
  1493. FindNameCompletion,
  1494. 0,
  1495. TDI_QUERY_FIND_NAME,
  1496. Irp->MdlAddress);
  1497. nbtIrpSp = IoGetNextIrpStackLocation (nbtIrp);
  1498. //
  1499. // The variables used to specify the remote adapter name
  1500. // are kept the same as those in connect.c to aid maintenance.
  1501. //
  1502. ConnectBlock.TAAddressCount = 1;
  1503. ConnectBlock.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  1504. ConnectBlock.Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
  1505. temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock.Address[0].Address;
  1506. temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1507. RtlMoveMemory( temp->NetbiosName, pdncb->ncb_callname, NCBNAMSZ );
  1508. RequestInformation.RemoteAddress = &ConnectBlock;
  1509. RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
  1510. sizeof (TDI_ADDRESS_NETBIOS);
  1511. ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&nbtIrpSp->Parameters)
  1512. ->RequestConnectionInformation = &RequestInformation;
  1513. Status = IoCallDriver (DeviceObject, nbtIrp);
  1514. if ( Status == STATUS_PENDING ) {
  1515. do {
  1516. Status = KeWaitForSingleObject(
  1517. &Event1, Executive, KernelMode, TRUE, NULL
  1518. );
  1519. } while (Status == STATUS_ALERTED);
  1520. }
  1521. NbAddressClose( TdiHandle, TdiObject );
  1522. if (NT_SUCCESS(Status)) {
  1523. Status = ioStatus.Status;
  1524. }
  1525. if (!NT_SUCCESS(Status)) {
  1526. NCB_COMPLETE( pdncb, NbMakeNbError(Status) );
  1527. Status = STATUS_SUCCESS;
  1528. } else {
  1529. pdncb->ncb_length = (WORD)ioStatus.Information;
  1530. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1531. }
  1532. //
  1533. // Because the completion routine returned STATUS_MORE_PROCESSING_REQUIRED
  1534. // NbFindName must return a status other than STATUS_PENDING so that the
  1535. // users Irp gets completed.
  1536. //
  1537. ASSERT( Status != STATUS_PENDING );
  1538. if ( usDeviceName.Buffer != NULL )
  1539. {
  1540. ExFreePool( usDeviceName.Buffer );
  1541. }
  1542. return Status;
  1543. }
  1544. NTSTATUS
  1545. NbSstat(
  1546. IN PDNCB pdncb,
  1547. IN PIRP Irp,
  1548. IN PIO_STACK_LOCATION IrpSp,
  1549. IN ULONG Buffer2Length
  1550. )
  1551. /*++
  1552. Routine Description:
  1553. This routine is called to return session status. It uses only structures
  1554. internal to this driver.
  1555. Arguments:
  1556. pdncb - Pointer to the NCB.
  1557. Irp - Pointer to the request packet representing the I/O request.
  1558. IrpSp - Pointer to current IRP stack frame.
  1559. Buffer2Length - User provided buffer length for data.
  1560. Return Value:
  1561. The function value is the status of the operation.
  1562. --*/
  1563. {
  1564. NTSTATUS Status = STATUS_SUCCESS;
  1565. if ( Buffer2Length >= sizeof(SESSION_HEADER) ) {
  1566. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1567. PLANA_INFO plana;
  1568. int index;
  1569. PUSESSION_HEADER pSessionHeader = NULL;
  1570. PUSESSION_BUFFER pSessionBuffer = NULL;
  1571. ULONG LengthRemaining;
  1572. PAB pab;
  1573. KIRQL OldIrql; // Used when SpinLock held.
  1574. //
  1575. // Prevent indications from the transport, post routines being called
  1576. // and another thread making a request while manipulating the netbios
  1577. // data structures.
  1578. //
  1579. LOCK( pfcb, OldIrql );
  1580. if (pdncb->ncb_lana_num > pfcb->MaxLana ) {
  1581. UNLOCK( pfcb, OldIrql );
  1582. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1583. return STATUS_SUCCESS;
  1584. }
  1585. if (( pfcb == NULL ) ||
  1586. ( pfcb->ppLana[pdncb->ncb_lana_num] == (LANA_INFO *) NULL ) ||
  1587. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  1588. UNLOCK( pfcb, OldIrql );
  1589. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1590. return STATUS_SUCCESS;
  1591. }
  1592. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  1593. if ( pdncb->ncb_name[0] != '*') {
  1594. PPAB ppab = FindAb(pfcb, pdncb, FALSE);
  1595. if ( ppab == NULL) {
  1596. UNLOCK( pfcb, OldIrql );
  1597. pdncb->ncb_retcode = NRC_PENDING;
  1598. NCB_COMPLETE( pdncb, NRC_NOWILD );
  1599. return STATUS_SUCCESS;
  1600. }
  1601. pab = *ppab;
  1602. }
  1603. //
  1604. // Map the users buffer so we can poke around inside
  1605. //
  1606. if (Irp->MdlAddress) {
  1607. pSessionHeader = MmGetSystemAddressForMdlSafe(
  1608. Irp->MdlAddress, NormalPagePriority);
  1609. }
  1610. if ((Irp->MdlAddress == NULL) ||
  1611. (pSessionHeader == NULL)) {
  1612. UNLOCK( pfcb, OldIrql );
  1613. pdncb->ncb_retcode = NRC_PENDING;
  1614. NCB_COMPLETE( pdncb, NRC_NORES );
  1615. return STATUS_SUCCESS;
  1616. }
  1617. pSessionHeader->sess_name = 0;
  1618. pSessionHeader->num_sess = 0;
  1619. pSessionHeader->rcv_dg_outstanding = 0;
  1620. pSessionHeader->rcv_any_outstanding = 0;
  1621. if ( pdncb->ncb_name[0] == '*') {
  1622. for ( index = 0; index <= MAXIMUM_ADDRESS; index++ ) {
  1623. if ( plana->AddressBlocks[index] != NULL ) {
  1624. PLIST_ENTRY Entry;
  1625. pab = plana->AddressBlocks[index];
  1626. for (Entry = pab->ReceiveDatagramList.Flink ;
  1627. Entry != &pab->ReceiveDatagramList ;
  1628. Entry = Entry->Flink) {
  1629. pSessionHeader->rcv_dg_outstanding++ ;
  1630. }
  1631. for (Entry = pab->ReceiveBroadcastDatagramList.Flink ;
  1632. Entry != &pab->ReceiveBroadcastDatagramList ;
  1633. Entry = Entry->Flink) {
  1634. pSessionHeader->rcv_dg_outstanding++ ;
  1635. }
  1636. for (Entry = pab->ReceiveAnyList.Flink ;
  1637. Entry != &pab->ReceiveAnyList ;
  1638. Entry = Entry->Flink) {
  1639. pSessionHeader->rcv_any_outstanding++;
  1640. }
  1641. }
  1642. }
  1643. pSessionHeader->sess_name = MAXIMUM_ADDRESS;
  1644. } else {
  1645. PLIST_ENTRY Entry;
  1646. PAB pab255;
  1647. // Add entries for this name alone.
  1648. for (Entry = pab->ReceiveDatagramList.Flink ;
  1649. Entry != &pab->ReceiveDatagramList ;
  1650. Entry = Entry->Flink) {
  1651. pSessionHeader->rcv_dg_outstanding++ ;
  1652. }
  1653. pab255 = plana->AddressBlocks[MAXIMUM_ADDRESS];
  1654. for (Entry = pab255->ReceiveBroadcastDatagramList.Flink ;
  1655. Entry != &pab255->ReceiveBroadcastDatagramList ;
  1656. Entry = Entry->Flink) {
  1657. PDNCB pdncbEntry = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  1658. if ( pdncbEntry->ncb_num == pab->NameNumber ) {
  1659. pSessionHeader->rcv_dg_outstanding++ ;
  1660. }
  1661. }
  1662. for (Entry = pab->ReceiveAnyList.Flink ;
  1663. Entry != &pab->ReceiveAnyList ;
  1664. Entry = Entry->Flink) {
  1665. pSessionHeader->rcv_any_outstanding++;
  1666. }
  1667. pSessionHeader->sess_name = pab->NameNumber;
  1668. }
  1669. LengthRemaining = Buffer2Length - sizeof(SESSION_HEADER);
  1670. pSessionBuffer = (PUSESSION_BUFFER)( pSessionHeader+1 );
  1671. for ( index=1 ; index <= MAXIMUM_CONNECTION; index++ ) {
  1672. CopySessionStatus( pdncb,
  1673. plana->ConnectionBlocks[index],
  1674. pSessionHeader,
  1675. &pSessionBuffer,
  1676. &LengthRemaining);
  1677. }
  1678. /* Undocumented Netbios 3.0 feature, returned length == requested
  1679. length and not the length of data returned. The following
  1680. expression gives the number of bytes actually used.
  1681. pdncb->ncb_length = (USHORT)
  1682. (sizeof(SESSION_HEADER)+
  1683. (sizeof(SESSION_BUFFER) * pSessionHeader->num_sess));
  1684. */
  1685. UNLOCK( pfcb, OldIrql );
  1686. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1687. } else {
  1688. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  1689. }
  1690. return STATUS_SUCCESS;
  1691. UNREFERENCED_PARAMETER( IrpSp );
  1692. }
  1693. VOID
  1694. CopySessionStatus(
  1695. IN PDNCB pdncb,
  1696. IN PCB pcb,
  1697. IN PUSESSION_HEADER pSessionHeader,
  1698. IN PUSESSION_BUFFER* ppSessionBuffer,
  1699. IN PULONG pLengthRemaining
  1700. )
  1701. /*++
  1702. Routine Description:
  1703. This routine is called to determine if a session should be added
  1704. to the callers buffer and if so it fills in the data. If there is an
  1705. error it records the problem in the callers NCB.
  1706. Arguments:
  1707. pdncb - Pointer to the NCB.
  1708. pcb - Connection Block for a particular session
  1709. pSessionHeader - Start of the callers buffer
  1710. ppSessionBuffer - Next position to fill in inside the users buffer.
  1711. pLengthRemaining - size in bytes remaining to be filled.
  1712. Return Value:
  1713. none.
  1714. --*/
  1715. {
  1716. PAB pab;
  1717. PLIST_ENTRY Entry;
  1718. if ( pcb == NULL ) {
  1719. return;
  1720. }
  1721. pab = *(pcb->ppab);
  1722. if (( pdncb->ncb_name[0] == '*') ||
  1723. (RtlEqualMemory( &pab->Name, pdncb->ncb_name, NCBNAMSZ))) {
  1724. pSessionHeader->num_sess++;
  1725. if ( *pLengthRemaining < sizeof(SESSION_BUFFER) ) {
  1726. NCB_COMPLETE( pdncb, NRC_INCOMP );
  1727. return;
  1728. }
  1729. (*ppSessionBuffer)->lsn = pcb->SessionNumber;
  1730. (*ppSessionBuffer)->state = pcb->Status;
  1731. RtlMoveMemory((*ppSessionBuffer)->local_name, &pab->Name, NCBNAMSZ);
  1732. RtlMoveMemory((*ppSessionBuffer)->remote_name, &pcb->RemoteName, NCBNAMSZ);
  1733. (*ppSessionBuffer)->sends_outstanding = 0;
  1734. (*ppSessionBuffer)->rcvs_outstanding = 0;
  1735. for (Entry = pcb->SendList.Flink ;
  1736. Entry != &pcb->SendList ;
  1737. Entry = Entry->Flink) {
  1738. (*ppSessionBuffer)->sends_outstanding++;
  1739. }
  1740. for (Entry = pcb->ReceiveList.Flink ;
  1741. Entry != &pcb->ReceiveList ;
  1742. Entry = Entry->Flink) {
  1743. (*ppSessionBuffer)->rcvs_outstanding++;
  1744. }
  1745. *ppSessionBuffer +=1;
  1746. *pLengthRemaining -= sizeof(SESSION_BUFFER);
  1747. }
  1748. }
  1749. NTSTATUS
  1750. NbEnum(
  1751. IN PDNCB pdncb,
  1752. IN PIRP Irp,
  1753. IN PIO_STACK_LOCATION IrpSp,
  1754. IN ULONG Buffer2Length
  1755. )
  1756. /*++
  1757. Routine Description:
  1758. This routine is called to discover the available lana numbers.
  1759. Arguments:
  1760. pdncb - Pointer to the NCB.
  1761. Irp - Pointer to the request packet representing the I/O request.
  1762. IrpSp - Pointer to current IRP stack frame.
  1763. Buffer2Length - Length of user provided buffer for data.
  1764. Return Value:
  1765. The function value is the status of the operation.
  1766. --*/
  1767. {
  1768. NTSTATUS Status = STATUS_SUCCESS;
  1769. PUCHAR Buffer2;
  1770. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1771. PAGED_CODE();
  1772. //
  1773. // Map the users buffer so we can poke around inside
  1774. //
  1775. if (Irp->MdlAddress) {
  1776. Buffer2 = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,
  1777. NormalPagePriority);
  1778. if (Buffer2 == NULL) {
  1779. Buffer2Length = 0;
  1780. }
  1781. } else {
  1782. //
  1783. // Either a zero byte read/write or the request only has an NCB.
  1784. //
  1785. Buffer2 = NULL;
  1786. Buffer2Length = 0;
  1787. }
  1788. //
  1789. // For PNP
  1790. //
  1791. LOCK_RESOURCE( pfcb );
  1792. // Copy over as much information as the user allows.
  1793. if ( (ULONG)pfcb->LanaEnum.length + 1 > Buffer2Length ) {
  1794. if ( Buffer2Length > 0 ) {
  1795. RtlMoveMemory( Buffer2, &pfcb->LanaEnum, Buffer2Length);
  1796. }
  1797. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  1798. } else {
  1799. RtlMoveMemory(
  1800. Buffer2,
  1801. &pfcb->LanaEnum,
  1802. (ULONG)pfcb->LanaEnum.length + 1 );
  1803. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1804. }
  1805. UNLOCK_RESOURCE( pfcb );
  1806. return Status;
  1807. }
  1808. NTSTATUS
  1809. NbReset(
  1810. IN PDNCB pdncb,
  1811. IN PIRP Irp,
  1812. IN PIO_STACK_LOCATION IrpSp
  1813. )
  1814. /*++
  1815. Routine Description:
  1816. This routine is called to reset an adapter. Until an adapter is reset,
  1817. no access to the lan is allowed.
  1818. Arguments:
  1819. pdncb - Pointer to the NCB.
  1820. Irp - Pointer to the request packet representing the I/O request.
  1821. IrpSp - Pointer to current IRP stack frame.
  1822. Return Value:
  1823. The function value is the status of the operation.
  1824. --*/
  1825. {
  1826. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1827. BOOLEAN bCleanupLana = FALSE;
  1828. PAGED_CODE();
  1829. IF_NBDBG (NB_DEBUG_FILE | NB_DEBUG_CREATE_FILE) {
  1830. NbPrint(( "\n**** RRRRRRRRESETT ***** LANA : %x, pdncb %lx\n",
  1831. pdncb-> ncb_lana_num, pdncb ));
  1832. NbPrint(( "FCB : %lx\n", pfcb ));
  1833. }
  1834. LOCK_RESOURCE( pfcb );
  1835. // MaxLana is really the last assigned lana number hence > not >=
  1836. if ( pdncb->ncb_lana_num > pfcb->MaxLana) {
  1837. UNLOCK_RESOURCE( pfcb );
  1838. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1839. return STATUS_SUCCESS;
  1840. }
  1841. if ( pfcb->ppLana[pdncb->ncb_lana_num] != NULL ) {
  1842. bCleanupLana = TRUE;
  1843. }
  1844. UNLOCK_RESOURCE( pfcb );
  1845. //
  1846. // Wait till all addnames are completed and prevent any new
  1847. // ones while we reset the lana. Note We lock out addnames for all
  1848. // lanas. This is ok since addnames are pretty rare as are resets.
  1849. //
  1850. KeEnterCriticalRegion();
  1851. ExAcquireResourceExclusiveLite( &pfcb->AddResource, TRUE);
  1852. IF_NBDBG (NB_DEBUG_CALL) {
  1853. NbPrint(( "\nNbReset have resource exclusive\n" ));
  1854. }
  1855. if ( bCleanupLana ) {
  1856. CleanupLana( pfcb, pdncb->ncb_lana_num, TRUE);
  1857. }
  1858. if ( pdncb->ncb_lsn == 0 ) {
  1859. // Allocate resources
  1860. OpenLana( pdncb, Irp, IrpSp );
  1861. } else {
  1862. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1863. }
  1864. // Allow more addnames
  1865. ExReleaseResourceLite( &pfcb->AddResource );
  1866. KeLeaveCriticalRegion();
  1867. return STATUS_SUCCESS;
  1868. }
  1869. NTSTATUS
  1870. NbAction(
  1871. IN PDNCB pdncb,
  1872. IN PIRP Irp,
  1873. IN PIO_STACK_LOCATION IrpSp
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. This routine is called to access a transport specific extension. Netbios does not know
  1878. anything about what the extension does.
  1879. Arguments:
  1880. pdncb - Pointer to the NCB.
  1881. Irp - Pointer to the request packet representing the I/O request.
  1882. IrpSp - Pointer to current IRP stack frame.
  1883. Return Value:
  1884. The function value is the status of the operation.
  1885. --*/
  1886. {
  1887. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1888. PCB pcb;
  1889. PDEVICE_OBJECT DeviceObject;
  1890. KIRQL OldIrql; // Used when SpinLock held.
  1891. IF_NBDBG (NB_DEBUG_CALL) {
  1892. NbPrint(( "\n****** Start of NbAction ****** pdncb %lx\n", pdncb ));
  1893. }
  1894. //
  1895. // The operation can only be performed on one handle so if the NCB specifies both
  1896. // a connection and an address then reject the request.
  1897. //
  1898. if (( pdncb->ncb_lsn != 0) &&
  1899. ( pdncb->ncb_num != 0)) {
  1900. NCB_COMPLETE( pdncb, NRC_ILLCMD ); // No really good errorcode for this
  1901. return STATUS_SUCCESS;
  1902. }
  1903. if ( pdncb->ncb_length < sizeof(ACTION_HEADER) ) {
  1904. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  1905. return STATUS_SUCCESS;
  1906. }
  1907. if ( (ULONG_PTR)pdncb->ncb_buffer & 3 ) {
  1908. NCB_COMPLETE( pdncb, NRC_BADDR ); // Buffer not word aligned
  1909. return STATUS_SUCCESS;
  1910. }
  1911. LOCK( pfcb, OldIrql );
  1912. if ( pdncb->ncb_lana_num > pfcb->MaxLana) {
  1913. UNLOCK( pfcb, OldIrql );
  1914. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1915. return STATUS_SUCCESS;
  1916. }
  1917. pdncb->irp = Irp;
  1918. pdncb->pfcb = pfcb;
  1919. if ( pdncb->ncb_lsn != 0) {
  1920. // Use handle associated with this connection
  1921. PPCB ppcb;
  1922. ppcb = FindCb( pfcb, pdncb, FALSE);
  1923. if ( ppcb == NULL ) {
  1924. // FindCb has put the error in the NCB
  1925. UNLOCK( pfcb, OldIrql );
  1926. if ( pdncb->ncb_retcode == NRC_SCLOSED ) {
  1927. // Tell dll to hangup the connection.
  1928. return STATUS_HANGUP_REQUIRED;
  1929. } else {
  1930. return STATUS_SUCCESS;
  1931. }
  1932. }
  1933. pcb = *ppcb;
  1934. if ( (pcb->DeviceObject == NULL) || (pcb->ConnectionObject == NULL)) {
  1935. UNLOCK( pfcb, OldIrql );
  1936. NCB_COMPLETE( pdncb, NRC_SCLOSED );
  1937. return STATUS_SUCCESS;
  1938. }
  1939. TdiBuildAction (Irp,
  1940. pcb->DeviceObject,
  1941. pcb->ConnectionObject,
  1942. NbCompletionPDNCB,
  1943. pdncb,
  1944. Irp->MdlAddress);
  1945. DeviceObject = pcb->DeviceObject;
  1946. UNLOCK( pfcb, OldIrql );
  1947. IoMarkIrpPending( Irp );
  1948. IoCallDriver (DeviceObject, Irp);
  1949. IF_NBDBG (NB_DEBUG_ACTION) {
  1950. NbPrint(( "NB ACTION submit connection: %X\n", Irp->IoStatus.Status ));
  1951. }
  1952. //
  1953. // Transport will complete the request. Return pending so that
  1954. // netbios does not complete as well.
  1955. //
  1956. return STATUS_PENDING;
  1957. } else if ( pdncb->ncb_num != 0) {
  1958. // Use handle associated with this name
  1959. PPAB ppab;
  1960. PAB pab;
  1961. ppab = FindAbUsingNum( pfcb, pdncb, pdncb->ncb_num );
  1962. if ( ppab == NULL ) {
  1963. UNLOCK( pfcb, OldIrql );
  1964. return STATUS_SUCCESS;
  1965. }
  1966. pab = *ppab;
  1967. TdiBuildAction (Irp,
  1968. pab->DeviceObject,
  1969. pab->AddressObject,
  1970. NbCompletionPDNCB,
  1971. pdncb,
  1972. Irp->MdlAddress);
  1973. DeviceObject = pab->DeviceObject;
  1974. UNLOCK( pfcb, OldIrql );
  1975. IoMarkIrpPending( Irp );
  1976. IoCallDriver (DeviceObject, Irp);
  1977. IF_NBDBG (NB_DEBUG_ACTION) {
  1978. NbPrint(( "NB ACTION submit address: %X\n", Irp->IoStatus.Status ));
  1979. }
  1980. //
  1981. // Transport will complete the request. Return pending so that
  1982. // netbios does not complete as well.
  1983. //
  1984. return STATUS_PENDING;
  1985. } else {
  1986. // Use the control channel
  1987. PLANA_INFO plana;
  1988. if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  1989. ( pfcb == NULL ) ||
  1990. ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL) ||
  1991. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  1992. UNLOCK( pfcb, OldIrql );
  1993. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1994. return STATUS_SUCCESS;
  1995. }
  1996. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  1997. TdiBuildAction (Irp,
  1998. plana->ControlDeviceObject,
  1999. plana->ControlFileObject,
  2000. NbCompletionPDNCB,
  2001. pdncb,
  2002. Irp->MdlAddress);
  2003. DeviceObject = plana->ControlDeviceObject;
  2004. UNLOCK( pfcb, OldIrql );
  2005. IoMarkIrpPending( Irp );
  2006. IoCallDriver (DeviceObject, Irp);
  2007. IF_NBDBG (NB_DEBUG_ACTION) {
  2008. NbPrint(( "NB ACTION submit control: %X\n", Irp->IoStatus.Status ));
  2009. }
  2010. //
  2011. // Transport will complete the request. Return pending so that
  2012. // netbios does not complete as well.
  2013. //
  2014. return STATUS_PENDING;
  2015. }
  2016. }
  2017. NTSTATUS
  2018. NbCancel(
  2019. IN PDNCB pdncb,
  2020. IN PIRP Irp,
  2021. IN PIO_STACK_LOCATION IrpSp
  2022. )
  2023. /*++
  2024. Routine Description:
  2025. This routine is called to cancel the ncb pointed to by NCB_BUFFER.
  2026. Arguments:
  2027. pdncb - Pointer to the NCB.
  2028. Irp - Pointer to the request packet representing the I/O request.
  2029. IrpSp - Pointer to current IRP stack frame.
  2030. Return Value:
  2031. The function value is the status of the operation.
  2032. --*/
  2033. {
  2034. PFCB pfcb = IrpSp->FileObject->FsContext2;
  2035. PDNCB target; // Mapped in location of the USERS NCB. Not the drivers copy of the DNCB!
  2036. BOOL SpinLockHeld;
  2037. KIRQL OldIrql; // Used when SpinLock held.
  2038. IF_NBDBG (NB_DEBUG_CALL) {
  2039. NbPrint(( "\n****** Start of NbCancel ****** pdncb %lx\n", pdncb ));
  2040. }
  2041. LOCK( pfcb, OldIrql );
  2042. SpinLockHeld = TRUE;
  2043. if ( pdncb->ncb_lana_num > pfcb->MaxLana) {
  2044. UNLOCK( pfcb, OldIrql );
  2045. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  2046. return STATUS_SUCCESS;
  2047. }
  2048. if (( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  2049. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  2050. UNLOCK( pfcb, OldIrql );
  2051. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  2052. return STATUS_SUCCESS;
  2053. }
  2054. //
  2055. // Map the users buffer so we can poke around inside
  2056. //
  2057. if (Irp->MdlAddress) {
  2058. target = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
  2059. }
  2060. if ((Irp->MdlAddress == NULL) ||
  2061. (target == NULL )) {
  2062. ASSERT(FALSE);
  2063. UNLOCK( pfcb, OldIrql );
  2064. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2065. return STATUS_SUCCESS;
  2066. }
  2067. IF_NBDBG (NB_DEBUG_CALL) {
  2068. NbDisplayNcb( target );
  2069. }
  2070. try {
  2071. if ( target->ncb_lana_num == pdncb->ncb_lana_num ) {
  2072. switch ( target->ncb_command & ~ASYNCH ) {
  2073. case NCBCALL:
  2074. case NCALLNIU:
  2075. case NCBLISTEN:
  2076. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  2077. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2078. } else {
  2079. PPCB ppcb;
  2080. UCHAR ucLana;
  2081. UNLOCK_SPINLOCK(pfcb, OldIrql);
  2082. SpinLockHeld = FALSE;
  2083. //
  2084. // Probe the NCB buffer
  2085. //
  2086. if (ExGetPreviousMode() != KernelMode) {
  2087. ProbeForRead(pdncb->ncb_buffer, sizeof(NCB), 4);
  2088. }
  2089. //
  2090. // Get the Lana number for the NCB being cancelled
  2091. // This is to prevent dereferencing the user buffer
  2092. // once the spinlock has been taken (bug #340218)
  2093. //
  2094. ucLana = ((PNCB)(pdncb->ncb_buffer))->ncb_lana_num;
  2095. LOCK_SPINLOCK(pfcb, OldIrql);
  2096. SpinLockHeld = TRUE;
  2097. //
  2098. // Search for the correct ppcb. We cannot use FindCb
  2099. // because the I/O system will not copy back the ncb_lsn
  2100. // field into target until the I/O request completes.
  2101. //
  2102. //
  2103. // Note : Though we are passing in the user buffer to
  2104. // the following routine, the buffer is never dereferenced
  2105. // in the routine. It is passed in only for address comp.
  2106. // and should not result in a pagefault ever, (with the
  2107. // spinlock held)
  2108. //
  2109. ppcb = FindCallCb( pfcb, (PNCB)pdncb->ncb_buffer, ucLana);
  2110. if (( ppcb == NULL ) ||
  2111. ((*ppcb)->pdncbCall->ncb_cmd_cplt != NRC_PENDING ) ||
  2112. (( (*ppcb)->Status != CALL_PENDING ) &&
  2113. ( (*ppcb)->Status != LISTEN_OUTSTANDING ))) {
  2114. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2115. } else {
  2116. NCB_COMPLETE( (*ppcb)->pdncbCall, NRC_CMDCAN );
  2117. SpinLockHeld = FALSE;
  2118. (*ppcb)->DisconnectReported = TRUE;
  2119. UNLOCK_SPINLOCK( pfcb, OldIrql );
  2120. CleanupCb( ppcb, NULL );
  2121. NCB_COMPLETE( pdncb, NRC_GOODRET );
  2122. }
  2123. }
  2124. break;
  2125. case NCBHANGUP:
  2126. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  2127. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2128. } else {
  2129. PPCB ppcb = FindCb( pfcb, target, FALSE );
  2130. if (( ppcb != NULL ) &&
  2131. ((*ppcb)->Status == HANGUP_PENDING )) {
  2132. PDNCB pdncbHangup;
  2133. // Restore the session status and remove the hangup.
  2134. (*ppcb)->Status = SESSION_ESTABLISHED;
  2135. pdncbHangup = (*ppcb)->pdncbHangup;
  2136. (*ppcb)->pdncbHangup = NULL;
  2137. if ( pdncbHangup != NULL ) {
  2138. NCB_COMPLETE( pdncbHangup, NRC_CMDCAN );
  2139. pdncbHangup->irp->IoStatus.Information =
  2140. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  2141. NbCompleteRequest( pdncbHangup->irp ,STATUS_SUCCESS);
  2142. }
  2143. NCB_COMPLETE( pdncb, NRC_GOODRET );
  2144. } else {
  2145. // Doesn't look like this is a real hangup so refuse.
  2146. NCB_COMPLETE( pdncb, NRC_CANCEL );
  2147. }
  2148. }
  2149. break;
  2150. case NCBASTAT:
  2151. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2152. break;
  2153. case NCBLANSTALERT:
  2154. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  2155. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2156. } else {
  2157. CancelLanAlert( pfcb, pdncb );
  2158. }
  2159. break;
  2160. case NCBRECVANY:
  2161. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  2162. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2163. } else {
  2164. PPAB ppab;
  2165. PLIST_ENTRY Entry;
  2166. ppab = FindAbUsingNum( pfcb, target, target->ncb_num );
  2167. if ( ppab == NULL ) {
  2168. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2169. break;
  2170. }
  2171. for (Entry = (*ppab)->ReceiveAnyList.Flink ;
  2172. Entry != &(*ppab)->ReceiveAnyList;
  2173. Entry = Entry->Flink) {
  2174. PDNCB pReceive = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  2175. if ( pReceive->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  2176. PIRP Irp;
  2177. RemoveEntryList( &pReceive->ncb_next );
  2178. SpinLockHeld = FALSE;
  2179. UNLOCK_SPINLOCK( pfcb, OldIrql );
  2180. Irp = pReceive->irp;
  2181. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  2182. //
  2183. // Remove the cancel request for this IRP. If its cancelled then its
  2184. // ok to just process it because we will be returning it to the caller.
  2185. //
  2186. Irp->Cancel = FALSE;
  2187. IoSetCancelRoutine(Irp, NULL);
  2188. IoReleaseCancelSpinLock(Irp->CancelIrql);
  2189. NCB_COMPLETE( pReceive, NRC_CMDCAN );
  2190. Irp->IoStatus.Status = STATUS_SUCCESS,
  2191. Irp->IoStatus.Information =
  2192. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  2193. NbCompleteRequest( Irp, STATUS_SUCCESS );
  2194. // The receive is cancelled, complete the cancel
  2195. NCB_COMPLETE( pdncb, NRC_GOODRET );
  2196. break;
  2197. }
  2198. }
  2199. // Command not in receive list!
  2200. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2201. }
  2202. break;
  2203. case NCBDGRECV:
  2204. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  2205. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2206. } else {
  2207. PPAB ppab;
  2208. PLIST_ENTRY Entry;
  2209. ppab = FindAbUsingNum( pfcb, target, target->ncb_num );
  2210. if ( ppab == NULL ) {
  2211. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2212. break;
  2213. }
  2214. for (Entry = (*ppab)->ReceiveDatagramList.Flink ;
  2215. Entry != &(*ppab)->ReceiveDatagramList;
  2216. Entry = Entry->Flink) {
  2217. PDNCB pReceive = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  2218. if ( pReceive->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  2219. PIRP Irp;
  2220. RemoveEntryList( &pReceive->ncb_next );
  2221. SpinLockHeld = FALSE;
  2222. UNLOCK_SPINLOCK( pfcb, OldIrql );
  2223. Irp = pReceive->irp;
  2224. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  2225. //
  2226. // Remove the cancel request for this IRP. If its cancelled then its
  2227. // ok to just process it because we will be returning it to the caller.
  2228. //
  2229. Irp->Cancel = FALSE;
  2230. IoSetCancelRoutine(Irp, NULL);
  2231. IoReleaseCancelSpinLock(Irp->CancelIrql);
  2232. NCB_COMPLETE( pReceive, NRC_CMDCAN );
  2233. Irp->IoStatus.Status = STATUS_SUCCESS,
  2234. Irp->IoStatus.Information =
  2235. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  2236. NbCompleteRequest( Irp, STATUS_SUCCESS );
  2237. // The receive is cancelled, complete the cancel
  2238. NCB_COMPLETE( pdncb, NRC_GOODRET );
  2239. break;
  2240. }
  2241. }
  2242. // Command not in receive list!
  2243. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2244. }
  2245. break;
  2246. case NCBDGRECVBC:
  2247. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  2248. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2249. } else {
  2250. PPAB ppab;
  2251. PLIST_ENTRY Entry;
  2252. ppab = FindAbUsingNum( pfcb, target, MAXIMUM_ADDRESS );
  2253. if ( ppab == NULL ) {
  2254. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2255. break;
  2256. }
  2257. for (Entry = (*ppab)->ReceiveBroadcastDatagramList.Flink ;
  2258. Entry != &(*ppab)->ReceiveBroadcastDatagramList;
  2259. Entry = Entry->Flink) {
  2260. PDNCB pReceive = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  2261. if ( pReceive->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  2262. PIRP Irp;
  2263. RemoveEntryList( &pReceive->ncb_next );
  2264. SpinLockHeld = FALSE;
  2265. UNLOCK_SPINLOCK( pfcb, OldIrql );
  2266. Irp = pReceive->irp;
  2267. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  2268. //
  2269. // Remove the cancel request for this IRP. If its cancelled then its
  2270. // ok to just process it because we will be returning it to the caller.
  2271. //
  2272. Irp->Cancel = FALSE;
  2273. IoSetCancelRoutine(Irp, NULL);
  2274. IoReleaseCancelSpinLock(Irp->CancelIrql);
  2275. NCB_COMPLETE( pReceive, NRC_CMDCAN );
  2276. Irp->IoStatus.Status = STATUS_SUCCESS,
  2277. Irp->IoStatus.Information =
  2278. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  2279. NbCompleteRequest( Irp, STATUS_SUCCESS );
  2280. // The receive is cancelled, complete the cancel
  2281. NCB_COMPLETE( pdncb, NRC_GOODRET );
  2282. break;
  2283. }
  2284. }
  2285. // Command not in receive list!
  2286. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2287. }
  2288. break;
  2289. // Session cancels close the connection.
  2290. case NCBRECV:
  2291. case NCBSEND:
  2292. case NCBSENDNA:
  2293. case NCBCHAINSEND:
  2294. case NCBCHAINSENDNA:
  2295. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  2296. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2297. } else {
  2298. PPCB ppcb;
  2299. ppcb = FindCb( pfcb, target, FALSE);
  2300. if ( ppcb == NULL ) {
  2301. // No such connection
  2302. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2303. } else {
  2304. PDNCB pTarget = NULL;
  2305. PLIST_ENTRY Entry;
  2306. if ((target->ncb_command & ~ASYNCH) == NCBRECV ) {
  2307. for (Entry = (*ppcb)->ReceiveList.Flink ;
  2308. Entry != &(*ppcb)->ReceiveList;
  2309. Entry = Entry->Flink) {
  2310. pTarget = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  2311. if ( pTarget->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  2312. break;
  2313. }
  2314. pTarget = NULL;
  2315. }
  2316. } else {
  2317. for (Entry = (*ppcb)->SendList.Flink ;
  2318. Entry != &(*ppcb)->SendList;
  2319. Entry = Entry->Flink) {
  2320. pTarget = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  2321. if ( pTarget->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  2322. break;
  2323. }
  2324. pTarget = NULL;
  2325. }
  2326. }
  2327. if ( pTarget != NULL ) {
  2328. // pTarget points to the real Netbios drivers DNCB.
  2329. NCB_COMPLETE( pTarget, NRC_CMDCAN );
  2330. SpinLockHeld = FALSE;
  2331. (*ppcb)->DisconnectReported = TRUE;
  2332. UNLOCK_SPINLOCK( pfcb, OldIrql );
  2333. CleanupCb( ppcb, NULL );
  2334. NCB_COMPLETE( pdncb, NRC_GOODRET );
  2335. } else {
  2336. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  2337. }
  2338. }
  2339. }
  2340. break;
  2341. default:
  2342. NCB_COMPLETE( pdncb, NRC_CANCEL ); // Invalid command to cancel
  2343. break;
  2344. }
  2345. } else {
  2346. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  2347. }
  2348. } except(EXCEPTION_EXECUTE_HANDLER) {
  2349. if ( SpinLockHeld == TRUE ) {
  2350. UNLOCK( pfcb, OldIrql );
  2351. } else {
  2352. UNLOCK_RESOURCE( pfcb );
  2353. }
  2354. IF_NBDBG (NB_DEBUG_DEVICE_CONTROL) {
  2355. NTSTATUS Status = GetExceptionCode();
  2356. NbPrint( ("NbCancel: Exception1 %X.\n", Status));
  2357. }
  2358. NCB_COMPLETE( pdncb, NRC_INVADDRESS );
  2359. return STATUS_SUCCESS;
  2360. }
  2361. if ( SpinLockHeld == TRUE ) {
  2362. UNLOCK( pfcb, OldIrql );
  2363. } else {
  2364. UNLOCK_RESOURCE( pfcb );
  2365. }
  2366. NCB_COMPLETE( pdncb, NRC_GOODRET );
  2367. return STATUS_SUCCESS;
  2368. UNREFERENCED_PARAMETER( Irp );
  2369. }
  2370. VOID
  2371. QueueRequest(
  2372. IN PLIST_ENTRY List,
  2373. IN PDNCB pdncb,
  2374. IN PIRP Irp,
  2375. IN PFCB pfcb,
  2376. IN KIRQL OldIrql,
  2377. IN BOOLEAN Head)
  2378. /*++
  2379. Routine Description:
  2380. This routine is called to add a dncb to List.
  2381. Note: QueueRequest UNLOCKS the fcb. This means the resource and
  2382. spinlock are owned when this routine is called.
  2383. Arguments:
  2384. List - List of pdncb's.
  2385. pdncb - Pointer to the NCB.
  2386. Irp - Pointer to the request packet representing the I/O request.
  2387. pfcb & OldIrql - Used to free locks
  2388. Head - TRUE if pdncb should be inserted at head of list
  2389. Return Value:
  2390. None.
  2391. --*/
  2392. {
  2393. pdncb->irp = Irp;
  2394. pdncb->pfcb = pfcb;
  2395. IoMarkIrpPending( Irp );
  2396. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  2397. if ( Head == FALSE ) {
  2398. InsertTailList(List, &pdncb->ncb_next);
  2399. } else {
  2400. InsertHeadList(List, &pdncb->ncb_next);
  2401. }
  2402. if (Irp->Cancel) {
  2403. //
  2404. // CancelRoutine will lock the resource & spinlock and try to find the
  2405. // request from scratch. It may fail to find the request if it has
  2406. // been picked up by an indication from the transport.
  2407. //
  2408. UNLOCK( pfcb, OldIrql );
  2409. CancelRoutine (NULL, Irp);
  2410. } else {
  2411. IoSetCancelRoutine(Irp, CancelRoutine);
  2412. IoReleaseCancelSpinLock (Irp->CancelIrql);
  2413. UNLOCK( pfcb, OldIrql );
  2414. }
  2415. }
  2416. PDNCB
  2417. DequeueRequest(
  2418. IN PLIST_ENTRY List
  2419. )
  2420. /*++
  2421. Routine Description:
  2422. This routine is called to remove a dncb from List.
  2423. Assume fcb spinlock held.
  2424. Arguments:
  2425. List - List of pdncb's.
  2426. Return Value:
  2427. PDNCB or NULL.
  2428. --*/
  2429. {
  2430. PIRP Irp;
  2431. PDNCB pdncb;
  2432. PLIST_ENTRY ReceiveEntry;
  2433. if (IsListEmpty(List)) {
  2434. //
  2435. // There are no waiting request announcement FsControls, so
  2436. // return success.
  2437. //
  2438. return NULL;
  2439. }
  2440. ReceiveEntry = RemoveHeadList( List);
  2441. pdncb = CONTAINING_RECORD( ReceiveEntry, DNCB, ncb_next);
  2442. Irp = pdncb->irp;
  2443. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  2444. //
  2445. // Remove the cancel request for this IRP. If its cancelled then its
  2446. // ok to just process it because we will be returning it to the caller.
  2447. //
  2448. Irp->Cancel = FALSE;
  2449. IoSetCancelRoutine(Irp, NULL);
  2450. IoReleaseCancelSpinLock(Irp->CancelIrql);
  2451. return pdncb;
  2452. }
  2453. VOID
  2454. CancelRoutine(
  2455. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  2456. IN PIRP Irp
  2457. )
  2458. /*++
  2459. Routine Description:
  2460. This routine is called when the IO system wants to cancel a queued
  2461. request. The netbios driver queues LanAlerts, Receives and Receive
  2462. Datagrams
  2463. Arguments:
  2464. IN PDEVICE_OBJECT DeviceObject - Ignored.
  2465. IN PIRP Irp - Irp to cancel.
  2466. Return Value:
  2467. None
  2468. --*/
  2469. {
  2470. PFCB pfcb;
  2471. PDNCB pdncb;
  2472. DNCB LocalCopy;
  2473. PLIST_ENTRY List = NULL;
  2474. PPAB ppab;
  2475. PPCB ppcb;
  2476. PFILE_OBJECT FileObject;
  2477. KIRQL OldIrql;
  2478. //
  2479. // Clear the cancel routine from the IRP - It can't be cancelled anymore.
  2480. //
  2481. IoSetCancelRoutine(Irp, NULL);
  2482. //
  2483. // Remove all the info from the pdncb that we will need to find the
  2484. // request. Once we release the cancel spinlock this request could be
  2485. // completed by another action so it is possible that we will not find
  2486. // the request to cancel.
  2487. //
  2488. pdncb = Irp->AssociatedIrp.SystemBuffer;
  2489. RtlMoveMemory( &LocalCopy, pdncb, sizeof( DNCB ) );
  2490. IF_NBDBG (NB_DEBUG_IOCANCEL) {
  2491. NbPrint(( "IoCancel Irp %lx\n", Irp ));
  2492. NbDisplayNcb(&LocalCopy);
  2493. }
  2494. #if DBG
  2495. #ifdef _WIN64
  2496. pdncb = (PDNCB)0xDEADBEEFDEADBEEF;
  2497. #else
  2498. pdncb = (PDNCB)0xDEADBEEF;
  2499. #endif
  2500. #endif
  2501. pfcb = LocalCopy.pfcb;
  2502. //
  2503. // Reference the FileObject associated with this Irp. This will stop
  2504. // the callers handle to \device\netbios from closing and therefore
  2505. // the fcb will not get deleted while we try to lock the fcb.
  2506. //
  2507. FileObject = (IoGetCurrentIrpStackLocation (Irp))->FileObject;
  2508. ObReferenceObject(FileObject);
  2509. IoReleaseCancelSpinLock( Irp->CancelIrql );
  2510. LOCK( pfcb, OldIrql );
  2511. //
  2512. // We now have exclusive access to all CB's and AB's with their associated
  2513. // lists.
  2514. //
  2515. switch ( LocalCopy.ncb_command & ~ASYNCH ) {
  2516. case NCBRECV:
  2517. ppcb = FindCb( pfcb, &LocalCopy, TRUE);
  2518. if ( ppcb != NULL ) {
  2519. List = &(*ppcb)->ReceiveList;
  2520. }
  2521. break;
  2522. case NCBRECVANY:
  2523. ppab = FindAbUsingNum( pfcb, &LocalCopy, LocalCopy.ncb_num );
  2524. if ( ppab != NULL ) {
  2525. List = &(*ppab)->ReceiveAnyList;
  2526. }
  2527. break;
  2528. case NCBDGRECVBC:
  2529. ppab = FindAbUsingNum( pfcb, &LocalCopy, MAXIMUM_ADDRESS );
  2530. if ( ppab != NULL ) {
  2531. List = &(*ppab)->ReceiveBroadcastDatagramList;
  2532. }
  2533. break;
  2534. case NCBDGRECV:
  2535. ppab = FindAbUsingNum( pfcb, &LocalCopy, LocalCopy.ncb_num );
  2536. if ( ppab != NULL ) {
  2537. List = &(*ppab)->ReceiveDatagramList;
  2538. }
  2539. break;
  2540. case NCBLANSTALERT:
  2541. List = &(pfcb->ppLana[LocalCopy.ncb_lana_num]->LanAlertList);
  2542. break;
  2543. }
  2544. if ( List != NULL ) {
  2545. //
  2546. // We have a list to scan for canceled pdncb's
  2547. //
  2548. PLIST_ENTRY Entry;
  2549. RestartScan:
  2550. for (Entry = List->Flink ;
  2551. Entry != List ;
  2552. Entry = Entry->Flink) {
  2553. PDNCB p = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  2554. IoAcquireCancelSpinLock( &p->irp->CancelIrql );
  2555. if ( p->irp->Cancel ) {
  2556. RemoveEntryList( &p->ncb_next );
  2557. NCB_COMPLETE( p, NRC_CMDCAN );
  2558. p->irp->IoStatus.Status = STATUS_SUCCESS;
  2559. p->irp->IoStatus.Information =
  2560. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  2561. IoSetCancelRoutine( p->irp, NULL );
  2562. IoReleaseCancelSpinLock( p->irp->CancelIrql );
  2563. IoCompleteRequest( p->irp, IO_NETWORK_INCREMENT);
  2564. goto RestartScan;
  2565. }
  2566. IoReleaseCancelSpinLock( p->irp->CancelIrql );
  2567. }
  2568. }
  2569. UNLOCK( pfcb, OldIrql );
  2570. ObDereferenceObject(FileObject);
  2571. }
  2572. NTSTATUS
  2573. AllocateAndCopyUnicodeString(
  2574. IN OUT PUNICODE_STRING pusDest,
  2575. IN PUNICODE_STRING pusSource
  2576. )
  2577. /*++
  2578. Routine Description :
  2579. This function allocates and copies a unicode string.
  2580. Arguements :
  2581. pusDest : Destination that the unicode string is to be copied
  2582. pusSource : Source string that is to be copied
  2583. Return Value :
  2584. STATUS_SUCCESS if function is successful.
  2585. STATUS_NO_MEMORY if function fails to allocate buffer for the dest.
  2586. Environment :
  2587. --*/
  2588. {
  2589. PAGED_CODE();
  2590. pusDest-> Buffer = ExAllocatePoolWithTag(
  2591. NonPagedPool, pusSource-> MaximumLength, 'nSBN'
  2592. );
  2593. if ( pusDest-> Buffer == NULL )
  2594. {
  2595. return STATUS_NO_MEMORY;
  2596. }
  2597. pusDest-> MaximumLength = pusSource-> MaximumLength;
  2598. RtlCopyUnicodeString( pusDest, pusSource );
  2599. return STATUS_SUCCESS;
  2600. }
  2601. NTSTATUS
  2602. NbRegisterWait(
  2603. IN PIRP pIrp
  2604. )
  2605. /*++
  2606. Routine Description :
  2607. This function marks the specified IRP as pending and inserts it into
  2608. the global list of IRP that are waiting for stop notification. These
  2609. IRPs will be completed when netbios is being stopped.
  2610. N.B : NbStop
  2611. Arguements :
  2612. pIrp : IRP that needs to be pending until netbios is being stopped
  2613. Return value :
  2614. Environment :
  2615. This function is invoked in response to a IOCTL_NB_REGISTER sent down
  2616. by a user mode component. Acquires/releases the CancelSpinLock and
  2617. g_keStopLock.
  2618. --*/
  2619. {
  2620. KIRQL irql;
  2621. NTSTATUS status;
  2622. LOCK_STOP();
  2623. IF_NBDBG( NB_DEBUG_DISPATCH )
  2624. {
  2625. NbPrint( ("[NETBIOS]: ENTERED NbRegisterWait, Stop status %d, "
  2626. "Num Opens %d\n", g_dwNetbiosState, g_ulNumOpens ) );
  2627. }
  2628. if ( g_dwNetbiosState == NETBIOS_STOPPING )
  2629. {
  2630. //
  2631. // Netbios is shutting down, complete this IRP, right away
  2632. //
  2633. status = STATUS_SUCCESS;
  2634. }
  2635. else
  2636. {
  2637. //
  2638. // setup the cancellation routine and pend this IRP
  2639. //
  2640. IoAcquireCancelSpinLock( &irql );
  2641. IoMarkIrpPending( pIrp );
  2642. InsertTailList( &g_leWaitList, &(pIrp->Tail.Overlay.ListEntry) );
  2643. IoSetCancelRoutine( pIrp, CancelIrp );
  2644. IoReleaseCancelSpinLock( irql );
  2645. status = STATUS_PENDING;
  2646. }
  2647. UNLOCK_STOP();
  2648. return status;
  2649. }
  2650. VOID
  2651. CancelIrp(
  2652. IN PDEVICE_OBJECT DeviceObject,
  2653. IN PIRP Irp
  2654. )
  2655. /*++
  2656. Routine Description :
  2657. This function cancels an IRP that has been pended on behalf of a
  2658. user mode process. This is invoked when the user-mode process
  2659. the had an open FileHandle to this device closes the handle.
  2660. Arguments :
  2661. DeviceObject : DeviceObject correponding to the Filehandle that was closed
  2662. Irp : Pended Irp that is being cancelled.
  2663. Return Value :
  2664. Environment :
  2665. Invoked by the IO subsystem when an open Filehandle to \\Device\netbios is
  2666. closed. This is invoked while holding the CancelSpinLock.
  2667. --*/
  2668. {
  2669. //
  2670. // Mark this Irp as cancelled
  2671. //
  2672. Irp->IoStatus.Status = STATUS_CANCELLED;
  2673. Irp->IoStatus.Information = 0;
  2674. //
  2675. // Take off our own list
  2676. //
  2677. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  2678. //
  2679. // Release cancel spin lock which the IO system acquired
  2680. //
  2681. IoReleaseCancelSpinLock(Irp->CancelIrql);
  2682. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2683. }
  2684. NTSTATUS
  2685. NbStop(
  2686. )
  2687. /*++
  2688. Routine Description :
  2689. This function initiates the process of stopping the netbios driver.
  2690. It does this by completing the pending stop-notification IRPs. The
  2691. user mode components (netapi32.dll) which have open file handles are
  2692. expected to close these handles when the pending IRPs have been
  2693. completed. After completing the IRPs this function waits for
  2694. all the open handles to be closed.
  2695. Arguments :
  2696. Return Value :
  2697. STATUS_SUCCESS if all the handles were closed, STATUS_TIMEOUT if
  2698. the wait timed out.
  2699. Environment :
  2700. This function is invoked from Services.exe when the netbios driver
  2701. is to be stopped. This is special case behavior for netbios.
  2702. This function acquires (and releases) the global lock g_erStopLock
  2703. and the CancelSpinLock
  2704. --*/
  2705. {
  2706. NTSTATUS ntStatus = STATUS_SUCCESS;
  2707. PIRP pIrp;
  2708. BOOLEAN bWait = FALSE ;
  2709. DWORD dwTimeOut = 10000 * 1000 * 15;
  2710. LARGE_INTEGER TimeOut;
  2711. KIRQL irql;
  2712. PLIST_ENTRY pleNode;
  2713. #if AUTO_RESET
  2714. PLIST_ENTRY ple;
  2715. PFCB_ENTRY pfe;
  2716. PNCB pUsersNCB;
  2717. #endif
  2718. //
  2719. // Acquire the lock protecting stop related data.
  2720. //
  2721. LOCK_STOP();
  2722. //
  2723. // Decrement Num Opens, since an extra open has been performed to
  2724. // send the stop IOCTL
  2725. //
  2726. g_ulNumOpens--;
  2727. IF_NBDBG( NB_DEBUG_DISPATCH )
  2728. {
  2729. NbPrint( ("[NETBIOS]: ENTERED NbStop, Stop status %d, "
  2730. "Num Opens %d\n", g_dwNetbiosState, g_ulNumOpens ) );
  2731. }
  2732. //
  2733. // set netbios state to stopping
  2734. //
  2735. g_dwNetbiosState = NETBIOS_STOPPING;
  2736. if ( g_ulNumOpens )
  2737. {
  2738. //
  2739. // if there are open file handles to \\Device\Netbios,
  2740. // wait for them to close
  2741. //
  2742. bWait = TRUE;
  2743. }
  2744. #if AUTO_RESET
  2745. LOCK_GLOBAL();
  2746. #endif
  2747. //
  2748. // Complete each of the pending IRPs to signal the stop event.
  2749. // This causes netapi32.dll to close the open handles
  2750. //
  2751. IoAcquireCancelSpinLock( &irql );
  2752. while ( !IsListEmpty( &g_leWaitList ) )
  2753. {
  2754. pleNode = RemoveHeadList( &g_leWaitList );
  2755. pIrp = CONTAINING_RECORD( pleNode, IRP, Tail.Overlay.ListEntry );
  2756. IoSetCancelRoutine( pIrp, NULL );
  2757. pIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  2758. pIrp->IoStatus.Information = 0;
  2759. //
  2760. // release lock to complete the IRP
  2761. //
  2762. IoReleaseCancelSpinLock( irql );
  2763. IoCompleteRequest( pIrp, IO_NETWORK_INCREMENT );
  2764. //
  2765. // Reaquire the lock
  2766. //
  2767. IoAcquireCancelSpinLock(&irql);
  2768. }
  2769. #if AUTO_RESET
  2770. //
  2771. // Complete IRPs that have been pended for notfication
  2772. // of a new LANA (in case the LANA needs to be automatically
  2773. // reset)
  2774. //
  2775. for ( pleNode = g_leFCBList.Flink;
  2776. pleNode != &g_leFCBList;
  2777. pleNode = pleNode-> Flink )
  2778. {
  2779. pfe = CONTAINING_RECORD( pleNode, FCB_ENTRY, leList );
  2780. if ( !IsListEmpty( &pfe-> leResetIrp ) )
  2781. {
  2782. ple = RemoveHeadList( &pfe-> leResetIrp );
  2783. pIrp = CONTAINING_RECORD( ple, IRP, Tail.Overlay.ListEntry );
  2784. IoSetCancelRoutine( pIrp, NULL );
  2785. pIrp->IoStatus.Status = STATUS_SUCCESS;
  2786. pIrp->IoStatus.Information = sizeof( NCB );
  2787. //
  2788. // Set the LANA to be reset to special value since NETBIOS
  2789. // is stopping
  2790. //
  2791. pUsersNCB = (PNCB) pIrp-> AssociatedIrp.SystemBuffer;
  2792. pUsersNCB->ncb_lana_num = MAX_LANA + 1;
  2793. NbCheckAndCompleteIrp32(pIrp);
  2794. //
  2795. // release lock to complete the IRP
  2796. //
  2797. IoReleaseCancelSpinLock( irql );
  2798. IoCompleteRequest( pIrp, IO_NETWORK_INCREMENT );
  2799. //
  2800. // Reaquire the lock
  2801. //
  2802. IoAcquireCancelSpinLock(&irql);
  2803. }
  2804. }
  2805. #endif
  2806. IoReleaseCancelSpinLock( irql );
  2807. #if AUTO_RESET
  2808. UNLOCK_GLOBAL();
  2809. #endif
  2810. //
  2811. // release stop lock
  2812. //
  2813. UNLOCK_STOP();
  2814. //
  2815. // if there are open file handles wait for them to stop
  2816. //
  2817. IF_NBDBG( NB_DEBUG_DISPATCH )
  2818. {
  2819. NbPrint( ("[NETBIOS]: NbStop : Wait %d\n", bWait ) );
  2820. }
  2821. if ( bWait )
  2822. {
  2823. TimeOut.QuadPart = Int32x32To64( -1, dwTimeOut );
  2824. do
  2825. {
  2826. ntStatus = KeWaitForSingleObject(
  2827. &g_keAllHandlesClosed, Executive, KernelMode,
  2828. TRUE, &TimeOut
  2829. );
  2830. } while (ntStatus == STATUS_ALERTED);
  2831. }
  2832. IF_NBDBG( NB_DEBUG_DISPATCH )
  2833. {
  2834. LOCK_STOP();
  2835. NbPrint( ("[NETBIOS]: LEAVING NbStop, Stop status %d, "
  2836. "Num Opens %d\n", ntStatus, g_ulNumOpens ) );
  2837. UNLOCK_STOP();
  2838. }
  2839. return ntStatus;
  2840. }
  2841. #if AUTO_RESET
  2842. NTSTATUS
  2843. NbRegisterReset(
  2844. IN PIRP pIrp,
  2845. IN PIO_STACK_LOCATION pIrpSp
  2846. )
  2847. /*++
  2848. Routine Description :
  2849. This function marks the specified IRP as pending and inserts it into
  2850. the global FCB list. This IRP will be completed when an adapter is bound
  2851. to netbios, thereby notifying the user mode of a new adapter.
  2852. Arguements :
  2853. pIrp : IRP that needs to be pending until an adapater (LANA) is bound
  2854. to netbios
  2855. Return value :
  2856. Environment :
  2857. This function is invoked in response to a IOCTL_NB_REGISTER_RESET sent down
  2858. by a user mode component. Acquires/releases the CancelSpinLock and
  2859. g_erGlobalLost.
  2860. --*/
  2861. {
  2862. NTSTATUS Status;
  2863. PFCB pfcb;
  2864. PLIST_ENTRY ple;
  2865. PFCB_ENTRY pfe;
  2866. PRESET_LANA_ENTRY prle;
  2867. PNCB pUsersNCB;
  2868. KIRQL irql;
  2869. ULONG RequiredLength;
  2870. IF_NBDBG( NB_DEBUG_CREATE_FILE )
  2871. {
  2872. NbPrint( ("\n++++ Netbios : ENTERED NbRegisterReset : ++++\n") );
  2873. }
  2874. LOCK_STOP();
  2875. do
  2876. {
  2877. //
  2878. // Check if Netbios is stopping
  2879. //
  2880. if ( g_dwNetbiosState == NETBIOS_STOPPING )
  2881. {
  2882. NbPrint( ("[NETBIOS] : NbRegisterReset : Netbios is stopping\n") );
  2883. Status = STATUS_SUCCESS;
  2884. break;
  2885. }
  2886. //
  2887. // Acquire the global lock
  2888. //
  2889. LOCK_GLOBAL();
  2890. //
  2891. // find the FCB for the user-mode application that sent down
  2892. // the IOCTL
  2893. //
  2894. pfcb = pIrpSp-> FileObject-> FsContext2;
  2895. for ( ple = g_leFCBList.Flink; ple != &g_leFCBList; ple = ple-> Flink )
  2896. {
  2897. pfe = CONTAINING_RECORD( ple, FCB_ENTRY, leList );
  2898. if ( pfe-> pfcb == pfcb )
  2899. {
  2900. break;
  2901. }
  2902. }
  2903. //
  2904. // if the FCB is not found, print error and quit
  2905. //
  2906. if ( ple == &g_leFCBList )
  2907. {
  2908. UNLOCK_GLOBAL();
  2909. NbPrint(
  2910. ("[NETBIOS] : NbRegisterReset : FCB %p not found\n", pfcb )
  2911. );
  2912. Status = STATUS_SUCCESS;
  2913. break;
  2914. }
  2915. //
  2916. // Fix for bug 297936, buffer validation
  2917. //
  2918. RequiredLength = sizeof(NCB);
  2919. #if defined(_WIN64)
  2920. if (IoIs32bitProcess(pIrp) == TRUE)
  2921. {
  2922. RequiredLength = sizeof(NCB32);
  2923. }
  2924. #endif
  2925. if (pIrpSp-> Parameters.DeviceIoControl.OutputBufferLength < RequiredLength)
  2926. {
  2927. UNLOCK_GLOBAL();
  2928. NbPrint(
  2929. ("[NETBIOS] : NbRegisterReset : Output buffer too small\n")
  2930. );
  2931. Status = STATUS_SUCCESS;
  2932. break;
  2933. }
  2934. //
  2935. // If there are outstanding LANA that are queued,
  2936. // - Remove the first one from the queue
  2937. // - Set the LANA in the output buffer for the IRP
  2938. // - complete the IRP
  2939. //
  2940. if ( !IsListEmpty( &pfe-> leResetList ) )
  2941. {
  2942. ple = RemoveHeadList( &pfe-> leResetList );
  2943. prle = CONTAINING_RECORD( ple, RESET_LANA_ENTRY, leList );
  2944. pUsersNCB = (PNCB) pIrp-> AssociatedIrp.SystemBuffer;
  2945. pUsersNCB-> ncb_lana_num = prle-> ucLanaNum;
  2946. pIrp->IoStatus.Information = sizeof( NCB );
  2947. ExFreePool( prle );
  2948. Status = STATUS_SUCCESS;
  2949. pIrp->IoStatus.Status = STATUS_SUCCESS;
  2950. UNLOCK_GLOBAL();
  2951. IF_NBDBG( NB_DEBUG_CREATE_FILE )
  2952. {
  2953. NbPrint( (
  2954. "FCB %p : Reset for LANA %d\n", pfcb,
  2955. pUsersNCB->ncb_lana_num
  2956. ) );
  2957. }
  2958. break;
  2959. }
  2960. //
  2961. // No outstanding LANAs that need reseting
  2962. // - Acquire the Cancel spin lock
  2963. // - Set the Cancel Routine
  2964. //
  2965. IoAcquireCancelSpinLock( &irql );
  2966. IoMarkIrpPending( pIrp );
  2967. InsertTailList( &pfe-> leResetIrp, &(pIrp->Tail.Overlay.ListEntry) );
  2968. IoSetCancelRoutine( pIrp, CancelIrp );
  2969. IoReleaseCancelSpinLock( irql );
  2970. Status = STATUS_PENDING;
  2971. UNLOCK_GLOBAL();
  2972. } while ( FALSE );
  2973. UNLOCK_STOP();
  2974. IF_NBDBG( NB_DEBUG_CREATE_FILE )
  2975. {
  2976. NbPrint( ("\n++++ Netbios : Exiting NbRegisterReset : %lx ++++\n", Status ) );
  2977. }
  2978. return Status;
  2979. }
  2980. #endif