Windows NT 4.0 source code leak
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.

2694 lines
71 KiB

4 years ago
  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. NTSTATUS
  29. NbAstat(
  30. IN PDNCB pdncb,
  31. IN PIRP Irp,
  32. IN PIO_STACK_LOCATION IrpSp,
  33. IN ULONG Buffer2Length
  34. );
  35. VOID
  36. CopyAddresses(
  37. IN PDNCB pdncb,
  38. IN PIRP Irp,
  39. IN PIO_STACK_LOCATION IrpSp,
  40. IN ULONG Buffer2Length
  41. );
  42. NTSTATUS
  43. NbFindName(
  44. IN PDNCB pdncb,
  45. IN PIRP Irp,
  46. IN PIO_STACK_LOCATION IrpSp,
  47. IN ULONG Buffer2Length
  48. );
  49. NTSTATUS
  50. NbSstat(
  51. IN PDNCB pdncb,
  52. IN PIRP Irp,
  53. IN PIO_STACK_LOCATION IrpSp,
  54. IN ULONG Buffer2Length
  55. );
  56. VOID
  57. CopySessionStatus(
  58. IN PDNCB pdncb,
  59. IN PCB pcb,
  60. IN PUSESSION_HEADER pSessionHeader,
  61. IN PUSESSION_BUFFER* ppSessionBuffer,
  62. IN PULONG pLengthRemaining
  63. );
  64. NTSTATUS
  65. NbEnum(
  66. IN PDNCB pdncb,
  67. IN PIRP Irp,
  68. IN PIO_STACK_LOCATION IrpSp,
  69. IN ULONG Buffer2Length
  70. );
  71. NTSTATUS
  72. NbReset(
  73. IN PDNCB pdncb,
  74. IN PIRP Irp,
  75. IN PIO_STACK_LOCATION IrpSp
  76. );
  77. NTSTATUS
  78. NbAction(
  79. IN PDNCB pdncb,
  80. IN PIRP Irp,
  81. IN PIO_STACK_LOCATION IrpSp
  82. );
  83. NTSTATUS
  84. NbCancel(
  85. IN PDNCB pdncb,
  86. IN PIRP Irp,
  87. IN PIO_STACK_LOCATION IrpSp
  88. );
  89. VOID
  90. CancelRoutine(
  91. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  92. IN PIRP Irp
  93. );
  94. NTSTATUS
  95. DriverEntry(
  96. IN PDRIVER_OBJECT DriverObject,
  97. IN PUNICODE_STRING RegistryPath
  98. );
  99. #ifdef ALLOC_PRAGMA
  100. #pragma alloc_text(PAGE, DriverEntry)
  101. #pragma alloc_text(PAGE, NbDispatch)
  102. #pragma alloc_text(PAGE, NbDeviceControl)
  103. #pragma alloc_text(PAGE, NbOpen)
  104. #pragma alloc_text(PAGE, NbClose)
  105. #pragma alloc_text(PAGE, NbAstat)
  106. #pragma alloc_text(PAGE, NbEnum)
  107. #pragma alloc_text(PAGE, NbReset)
  108. #pragma alloc_text(PAGE, NbFindName)
  109. #endif
  110. NTSTATUS
  111. NbCompletionEvent(
  112. IN PDEVICE_OBJECT DeviceObject,
  113. IN PIRP Irp,
  114. IN PVOID Context
  115. )
  116. /*++
  117. Routine Description:
  118. This routine does not complete the Irp. It is used to signal to a
  119. synchronous part of the Netbios driver that it can proceed.
  120. Arguments:
  121. DeviceObject - unused.
  122. Irp - Supplies Irp that the transport has finished processing.
  123. Context - Supplies the event associated with the Irp.
  124. Return Value:
  125. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  126. processing Irp stack locations at this point.
  127. --*/
  128. {
  129. IF_NBDBG (NB_DEBUG_COMPLETE) {
  130. NbPrint( ("NbCompletion event: %lx, Irp: %lx, DeviceObject: %lx\n",
  131. Context,
  132. Irp,
  133. DeviceObject));
  134. }
  135. KeSetEvent((PKEVENT )Context, 0, FALSE);
  136. return STATUS_MORE_PROCESSING_REQUIRED;
  137. UNREFERENCED_PARAMETER( DeviceObject );
  138. UNREFERENCED_PARAMETER( Irp );
  139. }
  140. NTSTATUS
  141. NbCompletionPDNCB(
  142. IN PDEVICE_OBJECT DeviceObject,
  143. IN PIRP Irp,
  144. IN PVOID Context
  145. )
  146. /*++
  147. Routine Description:
  148. This routine completes the Irp by setting the length and status bytes
  149. in the NCB supplied in context.
  150. Send requests have additional processing to remove the send request from
  151. the connection block send list.
  152. Arguments:
  153. DeviceObject - unused.
  154. Irp - Supplies Irp that the transport has finished processing.
  155. Context - Supplies the NCB associated with the Irp.
  156. Return Value:
  157. The final status from the operation (success or an exception).
  158. --*/
  159. {
  160. PDNCB pdncb = (PDNCB) Context;
  161. NTSTATUS Status = STATUS_SUCCESS;
  162. IF_NBDBG (NB_DEBUG_COMPLETE) {
  163. NbPrint(("NbCompletionPDNCB pdncb: %lx, Status: %X, Length %lx\n",
  164. Context,
  165. Irp->IoStatus.Status,
  166. Irp->IoStatus.Information ));
  167. }
  168. // Tell application how many bytes were transferred
  169. pdncb->ncb_length = (unsigned short)Irp->IoStatus.Information;
  170. if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
  171. NCB_COMPLETE( pdncb, NRC_GOODRET );
  172. } else {
  173. if (((pdncb->ncb_command & ~ASYNCH) == NCBRECV ) ||
  174. ((pdncb->ncb_command & ~ASYNCH) == NCBRECVANY )) {
  175. if ( Irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW ) {
  176. PIRP LocalIrp = NULL;
  177. KIRQL OldIrql; // Used when SpinLock held.
  178. PPCB ppcb;
  179. PDEVICE_OBJECT LocalDeviceObject;
  180. LOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  181. //
  182. // The transport will not indicate again so we must put
  183. // another receive down if we can.
  184. // If an Irp cannot be built then BuildReceiveIrp will
  185. // set ReceiveIndicated.
  186. //
  187. ppcb = FindCb( pdncb->pfcb, pdncb, FALSE );
  188. if ( ppcb != NULL ) {
  189. LocalDeviceObject = (*ppcb)->DeviceObject;
  190. LocalIrp = BuildReceiveIrp( *ppcb );
  191. }
  192. UNLOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  193. if ( LocalIrp != NULL ) {
  194. IoCallDriver (LocalDeviceObject, LocalIrp);
  195. }
  196. }
  197. }
  198. NCB_COMPLETE( pdncb, NbMakeNbError( Irp->IoStatus.Status ) );
  199. }
  200. //
  201. // Tell IopCompleteRequest how much to copy back when the request
  202. // completes.
  203. //
  204. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  205. //
  206. // Remove the Send request from the send queue. We have to scan
  207. // the queue because they may be completed out of order if a send
  208. // is rejected because of resource limitations.
  209. //
  210. if (((pdncb->ncb_command & ~ASYNCH) == NCBSEND ) ||
  211. ((pdncb->ncb_command & ~ASYNCH) == NCBCHAINSEND ) ||
  212. ((pdncb->ncb_command & ~ASYNCH) == NCBSENDNA ) ||
  213. ((pdncb->ncb_command & ~ASYNCH) == NCBCHAINSENDNA )) {
  214. PLIST_ENTRY SendEntry;
  215. PPCB ppcb;
  216. KIRQL OldIrql; // Used when SpinLock held.
  217. LOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  218. ppcb = FindCb( pdncb->pfcb, pdncb, FALSE );
  219. //
  220. // If the connection block still exists remove the send. If the connection
  221. // has gone then we no longer need to worry about maintaining the list.
  222. //
  223. if ( ppcb != NULL ) {
  224. #if DBG
  225. BOOLEAN Found = FALSE;
  226. #endif
  227. PCB pcb = *ppcb;
  228. for (SendEntry = pcb->SendList.Flink ;
  229. SendEntry != &pcb->SendList ;
  230. SendEntry = SendEntry->Flink) {
  231. PDNCB pSend = CONTAINING_RECORD( SendEntry, DNCB, ncb_next);
  232. if ( pSend == pdncb ) {
  233. #if DBG
  234. Found = TRUE;
  235. #endif
  236. RemoveEntryList( &pdncb->ncb_next );
  237. break;
  238. }
  239. }
  240. ASSERT( Found == TRUE);
  241. //
  242. // If the session is being hung up then we may wish to cleanup the connection
  243. // as well. STATUS_HANGUP_REQUIRED will cause the dll to manufacture
  244. // another hangup. The manufactured hangup will complete along with
  245. // pcb->pdncbHangup. This method is used to ensure that when a
  246. // hangup is delayed by an outstanding send and the send finally
  247. // completes, that the user hangup completes after all operations
  248. // on the connection.
  249. //
  250. if (( IsListEmpty( &pcb->SendList) ) &&
  251. ( pcb->pdncbHangup != NULL )) {
  252. IF_NBDBG (NB_DEBUG_COMPLETE) {
  253. NbPrint( ("NbCompletionPDNCB Hangup session: %lx\n", ppcb ));
  254. }
  255. Status = STATUS_HANGUP_REQUIRED;
  256. }
  257. }
  258. UNLOCK_SPINLOCK( pdncb->pfcb, OldIrql );
  259. }
  260. //
  261. // Must return a non-error status otherwise the IO system will not copy
  262. // back the NCB into the users buffer.
  263. //
  264. Irp->IoStatus.Status = Status;
  265. return Status;
  266. UNREFERENCED_PARAMETER( DeviceObject );
  267. }
  268. NTSTATUS
  269. DriverEntry(
  270. IN PDRIVER_OBJECT DriverObject,
  271. IN PUNICODE_STRING RegistryPath
  272. )
  273. /*++
  274. Routine Description:
  275. This routine performs initialization of the NetBIOS driver.
  276. Arguments:
  277. DriverObject - Pointer to driver object created by the system.
  278. RegistryPath - The name of the Netbios node in the registry.
  279. Return Value:
  280. The function value is the final status from the initialization operation.
  281. --*/
  282. {
  283. PDEVICE_CONTEXT DeviceContext;
  284. NTSTATUS status;
  285. UNICODE_STRING UnicodeString;
  286. //STRING AnsiNameString;
  287. PAGED_CODE();
  288. //
  289. #ifdef MEMPRINT
  290. MemPrintInitialize ();
  291. #endif
  292. //
  293. // Create the device object for NETBEUI. For now, we simply create
  294. // \Device\Netbios using a unicode string.
  295. //
  296. NbFspProcess = PsGetCurrentProcess();
  297. RtlInitUnicodeString( &UnicodeString, NB_DEVICE_NAME);
  298. status = NbCreateDeviceContext (DriverObject,
  299. &UnicodeString,
  300. &DeviceContext,
  301. RegistryPath);
  302. if (!NT_SUCCESS (status)) {
  303. NbPrint( ("NbInitialize: Netbios failed to initialize\n"));
  304. return status;
  305. }
  306. DeviceContext->Initialized = TRUE;
  307. IF_NBDBG (NB_DEBUG_DISPATCH) {
  308. NbPrint( ("NbInitialize: Netbios initialized.\n"));
  309. }
  310. return (status);
  311. }
  312. NTSTATUS
  313. NbDispatch(
  314. IN PDEVICE_OBJECT DeviceObject,
  315. IN PIRP Irp
  316. )
  317. /*++
  318. Routine Description:
  319. This routine is the main dispatch routine for the NB device driver.
  320. It accepts an I/O Request Packet, performs the request, and then
  321. returns with the appropriate status.
  322. Arguments:
  323. DeviceObject - Pointer to the device object for this driver.
  324. Irp - Pointer to the request packet representing the I/O request.
  325. Return Value:
  326. The function value is the status of the operation.
  327. --*/
  328. {
  329. NTSTATUS Status;
  330. PIO_STACK_LOCATION IrpSp;
  331. PDEVICE_CONTEXT DeviceContext;
  332. PAGED_CODE();
  333. //
  334. // Check to see if NB has been initialized; if not, don't allow any use.
  335. //
  336. DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
  337. if (!DeviceContext->Initialized) {
  338. return STATUS_UNSUCCESSFUL;
  339. }
  340. //
  341. // Get a pointer to the current stack location in the IRP. This is where
  342. // the function codes and parameters are stored.
  343. //
  344. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  345. //
  346. // Case on the function that is being performed by the requestor. If the
  347. // operation is a valid one for this device, then make it look like it was
  348. // successfully completed, where possible.
  349. //
  350. switch (IrpSp->MajorFunction) {
  351. //
  352. // The Create function opens a handle that can be used with fsctl's
  353. // to build all interesting operations.
  354. //
  355. case IRP_MJ_CREATE:
  356. IF_NBDBG (NB_DEBUG_DISPATCH) {
  357. NbPrint( ("NbDispatch: IRP_MJ_CREATE.\n"));
  358. }
  359. Status = NbOpen ( DeviceContext, IrpSp );
  360. Irp->IoStatus.Information = FILE_OPENED;
  361. break;
  362. //
  363. // The Close function closes a transport , terminates
  364. // all outstanding transport activity on the transport, and unbinds
  365. // the from its transport address, if any. If this
  366. // is the last transport endpoint bound to the address, then
  367. // the address is removed by the provider.
  368. //
  369. case IRP_MJ_CLOSE:
  370. IF_NBDBG (NB_DEBUG_DISPATCH) {
  371. NbPrint( ("NbDispatch: IRP_MJ_CLOSE.\n"));
  372. }
  373. Status = NbClose( IrpSp);
  374. break;
  375. //
  376. // The DeviceControl function is the main path to the transport
  377. // driver interface. Every TDI request is assigned a minor
  378. // function code that is processed by this function.
  379. //
  380. case IRP_MJ_DEVICE_CONTROL:
  381. IF_NBDBG (NB_DEBUG_DISPATCH) {
  382. NbPrint( ("NbDispatch: IRP_MJ_DEVICE_CONTROL, Irp: %lx.\n", Irp ));
  383. }
  384. Status = NbDeviceControl (DeviceObject, Irp, IrpSp);
  385. if (Status != STATUS_PENDING) {
  386. //
  387. // Tell IopCompleteRequest how much to copy back when the
  388. // request completes. We need to do this for cases where
  389. // NbCompletionPDNCB is not used.
  390. //
  391. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  392. }
  393. #if DBG
  394. if ( (Status != STATUS_SUCCESS) &&
  395. (Status != STATUS_PENDING ) &&
  396. (Status != STATUS_HANGUP_REQUIRED )) {
  397. IF_NBDBG (NB_DEBUG_DISPATCH) {
  398. NbPrint( ("NbDispatch: Invalid status: %X.\n", Status ));
  399. ASSERT( FALSE );
  400. }
  401. }
  402. #endif
  403. break;
  404. //
  405. // Handle the two stage IRP for a file close operation. When the first
  406. // stage hits, ignore it. We will do all the work on the close Irp.
  407. //
  408. case IRP_MJ_CLEANUP:
  409. IF_NBDBG (NB_DEBUG_DISPATCH) {
  410. NbPrint( ("NbDispatch: IRP_MJ_CLEANUP.\n"));
  411. }
  412. Status = STATUS_SUCCESS;
  413. break;
  414. default:
  415. IF_NBDBG (NB_DEBUG_DISPATCH) {
  416. NbPrint( ("NbDispatch: OTHER (DEFAULT).\n"));
  417. }
  418. Status = STATUS_INVALID_DEVICE_REQUEST;
  419. } /* major function switch */
  420. if (Status == STATUS_PENDING) {
  421. IF_NBDBG (NB_DEBUG_DISPATCH) {
  422. NbPrint( ("NbDispatch: request PENDING from handler.\n"));
  423. }
  424. } else {
  425. IF_NBDBG (NB_DEBUG_DISPATCH) {
  426. NbPrint( ("NbDispatch: request COMPLETED by handler.\n"));
  427. }
  428. NbCompleteRequest( Irp, Status);
  429. }
  430. return Status;
  431. } /* NbDispatch */
  432. NTSTATUS
  433. NbDeviceControl(
  434. IN PDEVICE_OBJECT DeviceObject,
  435. IN PIRP Irp,
  436. IN PIO_STACK_LOCATION IrpSp
  437. )
  438. /*++
  439. Routine Description:
  440. This routine dispatches NetBios request types to different handlers based
  441. on the minor IOCTL function code in the IRP's current stack location.
  442. In addition to cracking the minor function code, this routine also
  443. reaches into the IRP and passes the packetized parameters stored there
  444. as parameters to the various request handlers so that they are
  445. not IRP-dependent.
  446. Arguments:
  447. DeviceObject - Pointer to the device object for this driver.
  448. Irp - Pointer to the request packet representing the I/O request.
  449. IrpSp - Pointer to current IRP stack frame.
  450. Return Value:
  451. The function value is the status of the operation.
  452. --*/
  453. {
  454. NTSTATUS Status = STATUS_SUCCESS;
  455. PNCB pUsersNcb;
  456. PDNCB pdncb;
  457. PUCHAR Buffer2;
  458. ULONG Buffer2Length;
  459. ULONG RequestLength;
  460. PAGED_CODE();
  461. IF_NBDBG (NB_DEBUG_DISPATCH) {
  462. NbPrint( ("NbDeviceControl: Entered...\n"));
  463. }
  464. if (IrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_NB_NCB) {
  465. IF_NBDBG (NB_DEBUG_DISPATCH) {
  466. NbPrint( ("NbDeviceControl: invalid request type.\n"));
  467. }
  468. return STATUS_INVALID_DEVICE_REQUEST;
  469. }
  470. //
  471. // Caller provided 2 buffers. The first is the NCB.
  472. // The second is an optional buffer for send or receive data.
  473. // Since the Netbios driver only operates in the context of the
  474. // calling application, these buffers are directly accessable.
  475. // however they can be deleted by the user so try-except clauses are
  476. // required.
  477. //
  478. pUsersNcb = (PNCB)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  479. RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  480. Buffer2 = Irp->UserBuffer;
  481. Buffer2Length = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  482. if ( RequestLength != sizeof( NCB ) ) {
  483. return STATUS_INVALID_PARAMETER;
  484. }
  485. //
  486. // Create a copy of the NCB and convince the IO system to
  487. // copy it back (and deallocate it) when the IRP completes.
  488. //
  489. Irp->AssociatedIrp.SystemBuffer =
  490. ExAllocatePoolWithTag( NonPagedPool, sizeof( DNCB ), 'nSBN' );
  491. if (Irp->AssociatedIrp.SystemBuffer == NULL) {
  492. //
  493. // Since we cannot allocate the drivers copy of the NCB, we
  494. // must turn around and use the original Ncb to return the error.
  495. //
  496. pUsersNcb->ncb_retcode = NRC_NORES;
  497. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  498. return STATUS_SUCCESS;
  499. }
  500. try {
  501. // In the driver we should now use our copy of the NCB
  502. pdncb = Irp->AssociatedIrp.SystemBuffer;
  503. RtlMoveMemory( pdncb,
  504. pUsersNcb,
  505. FIELD_OFFSET( DNCB, ncb_cmd_cplt )+1 );
  506. Irp->Flags |= (ULONG) (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER |
  507. IRP_INPUT_OPERATION );
  508. //
  509. // Save the users virtual address for the NCB just in case the
  510. // virtual address is supplied in an NCBCANCEL. This is the same
  511. // as Irp->UserBuffer.
  512. //
  513. pdncb->users_ncb = pUsersNcb;
  514. //
  515. // Tell the IO system where to copy the ncb back to during
  516. // IoCompleteRequest.
  517. //
  518. Irp->UserBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  519. } except(EXCEPTION_EXECUTE_HANDLER) {
  520. Status = GetExceptionCode();
  521. IF_NBDBG (NB_DEBUG_DISPATCH) {
  522. NbPrint( ("NbDeviceControl: Exception1 %X.\n", Status));
  523. }
  524. NCB_COMPLETE( pdncb, NbMakeNbError(Status) );
  525. return Status;
  526. }
  527. if ( Buffer2Length ) {
  528. // Mdl will be freed by IopCompleteRequest.
  529. Irp->MdlAddress = IoAllocateMdl( Buffer2,
  530. Buffer2Length,
  531. FALSE,
  532. FALSE,
  533. Irp );
  534. ASSERT( Irp->MdlAddress != NULL );
  535. try {
  536. MmProbeAndLockPages( Irp->MdlAddress,
  537. Irp->RequestorMode,
  538. (LOCK_OPERATION) IoModifyAccess);
  539. } except(EXCEPTION_EXECUTE_HANDLER) {
  540. Status = GetExceptionCode();
  541. IF_NBDBG (NB_DEBUG_DISPATCH) {
  542. NbPrint( ("NbDeviceControl: Exception2 %X.\n", Status));
  543. }
  544. if ( Irp->MdlAddress != NULL ) {
  545. IoFreeMdl(Irp->MdlAddress);
  546. Irp->MdlAddress = NULL;
  547. }
  548. NCB_COMPLETE( pdncb, NbMakeNbError(Status) );
  549. return STATUS_SUCCESS;
  550. }
  551. } else {
  552. ASSERT( Irp->MdlAddress == NULL );
  553. }
  554. IF_NBDBG (NB_DEBUG_DISPATCH) {
  555. NbPrint( ("NbDeviceControl: IoContolCode: %lx, Fcb: %lx,"
  556. " ncb_command %lx, Buffer2Length: %lx\n",
  557. IrpSp->Parameters.DeviceIoControl.IoControlCode,
  558. IrpSp->FileObject->FsContext2,
  559. pdncb->ncb_command,
  560. Buffer2Length));
  561. }
  562. switch ( pdncb->ncb_command & ~ASYNCH ) {
  563. case NCBCALL:
  564. case NCALLNIU:
  565. Status = NbCall( pdncb, Irp, IrpSp );
  566. break;
  567. case NCBCANCEL:
  568. Status = NbCancel( pdncb, Irp, IrpSp );
  569. break;
  570. case NCBLISTEN:
  571. Status = NbListen( pdncb, Irp, IrpSp );
  572. break;
  573. case NCBHANGUP:
  574. Status = NbHangup( pdncb, Irp, IrpSp );
  575. break;
  576. case NCBASTAT:
  577. Status = NbAstat( pdncb, Irp, IrpSp, Buffer2Length );
  578. break;
  579. case NCBFINDNAME:
  580. Status = NbFindName( pdncb, Irp, IrpSp, Buffer2Length );
  581. break;
  582. case NCBSSTAT:
  583. Status = NbSstat( pdncb, Irp, IrpSp, Buffer2Length );
  584. break;
  585. case NCBENUM:
  586. NbEnum( pdncb, Irp, IrpSp, Buffer2Length );
  587. break;
  588. case NCBRECV:
  589. Status = NbReceive( pdncb, Irp, IrpSp, Buffer2Length, FALSE, 0 );
  590. break;
  591. case NCBRECVANY:
  592. Status = NbReceiveAny( pdncb, Irp, IrpSp, Buffer2Length );
  593. break;
  594. case NCBDGRECV:
  595. case NCBDGRECVBC:
  596. Status = NbReceiveDatagram( pdncb, Irp, IrpSp, Buffer2Length );
  597. break;
  598. case NCBSEND:
  599. case NCBSENDNA:
  600. case NCBCHAINSEND:
  601. case NCBCHAINSENDNA:
  602. Status = NbSend( pdncb, Irp, IrpSp, Buffer2Length );
  603. break;
  604. case NCBDGSEND:
  605. case NCBDGSENDBC:
  606. Status = NbSendDatagram( pdncb, Irp, IrpSp, Buffer2Length );
  607. break;
  608. case NCBADDNAME:
  609. case NCBADDGRNAME:
  610. case NCBQUICKADDNAME:
  611. case NCBQUICKADDGRNAME:
  612. NbAddName( pdncb, IrpSp );
  613. break;
  614. case NCBDELNAME:
  615. NbDeleteName( pdncb, IrpSp );
  616. break;
  617. case NCBLANSTALERT:
  618. Status = NbLanStatusAlert( pdncb, Irp, IrpSp );
  619. break;
  620. case NCBRESET:
  621. Status = NbReset( pdncb, Irp, IrpSp );
  622. break;
  623. case NCBACTION:
  624. Status = NbAction( pdncb, Irp, IrpSp);
  625. break;
  626. // The following are No-operations that return success for compatibility
  627. case NCBUNLINK:
  628. case NCBTRACE:
  629. NCB_COMPLETE( pdncb, NRC_GOODRET );
  630. break;
  631. default:
  632. NCB_COMPLETE( pdncb, NRC_ILLCMD );
  633. break;
  634. }
  635. return Status;
  636. UNREFERENCED_PARAMETER( DeviceObject );
  637. } /* NbDeviceControl */
  638. NTSTATUS
  639. NbOpen(
  640. IN PDEVICE_CONTEXT DeviceContext,
  641. IN PIO_STACK_LOCATION IrpSp
  642. )
  643. /*++
  644. Routine Description:
  645. Arguments:
  646. DeviceContext - Includes the name of the netbios node in the registry.
  647. IrpSp - Pointer to current IRP stack frame.
  648. Return Value:
  649. The function value is the status of the operation.
  650. --*/
  651. {
  652. PAGED_CODE();
  653. return NewFcb( DeviceContext, IrpSp );
  654. } /* NbOpen */
  655. NTSTATUS
  656. NbClose(
  657. IN PIO_STACK_LOCATION IrpSp
  658. )
  659. /*++
  660. Routine Description:
  661. This routine is called to close an existing handle. This
  662. involves running down all of the current and pending activity associated
  663. with the handle, and dereferencing structures as appropriate.
  664. Arguments:
  665. Irp - Pointer to the request packet representing the I/O request.
  666. IrpSp - Pointer to current IRP stack frame.
  667. Return Value:
  668. The function value is the status of the operation.
  669. --*/
  670. {
  671. PFCB pfcb = IrpSp->FileObject->FsContext2;
  672. PAGED_CODE();
  673. if (pfcb!=NULL) {
  674. CleanupFcb( IrpSp, pfcb );
  675. }
  676. return STATUS_SUCCESS;
  677. } /* NbClose */
  678. NTSTATUS
  679. NbAstat(
  680. IN PDNCB pdncb,
  681. IN PIRP Irp,
  682. IN PIO_STACK_LOCATION IrpSp,
  683. IN ULONG Buffer2Length
  684. )
  685. /*++
  686. Routine Description:
  687. This routine is called to return the adapter status. It queries the
  688. transport for the main adapter status data such as number of FRMR frames
  689. received and then uses CopyAddresses to fill in the status for the names
  690. that THIS application has added.
  691. Arguments:
  692. pdncb - Pointer to the NCB.
  693. Irp - Pointer to the request packet representing the I/O request.
  694. IrpSp - Pointer to current IRP stack frame.
  695. Buffer2Length - User provided buffer length for data.
  696. Return Value:
  697. The function value is the status of the operation.
  698. --*/
  699. {
  700. NTSTATUS Status = STATUS_SUCCESS;
  701. TDI_CONNECTION_INFORMATION RequestInformation;
  702. TA_NETBIOS_ADDRESS ConnectBlock;
  703. PTDI_ADDRESS_NETBIOS temp;
  704. PFCB pfcb = IrpSp->FileObject->FsContext2;
  705. PAGED_CODE();
  706. if ( Buffer2Length >= sizeof(ADAPTER_STATUS) ) {
  707. KEVENT Event1;
  708. NTSTATUS Status;
  709. HANDLE TdiHandle;
  710. PFILE_OBJECT TdiObject;
  711. PDEVICE_OBJECT DeviceObject;
  712. if ( pdncb->ncb_lana_num > pfcb->MaxLana ) {
  713. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  714. return STATUS_SUCCESS;
  715. }
  716. if (( pfcb == NULL ) ||
  717. (pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  718. (pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED)) {
  719. NCB_COMPLETE( pdncb, NRC_ENVNOTDEF ); // need a reset
  720. return STATUS_SUCCESS;
  721. }
  722. // NULL returns a handle for doing control functions
  723. Status = NbOpenAddress ( &TdiHandle, (PVOID*)&TdiObject, pfcb, pdncb->ncb_lana_num, NULL);
  724. if (!NT_SUCCESS(Status)) {
  725. IF_NBDBG (NB_DEBUG_ASTAT) {
  726. NbPrint(( "\n FAILED on open of Tdi: %X ******\n", Status ));
  727. }
  728. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  729. return STATUS_SUCCESS;
  730. }
  731. KeInitializeEvent (
  732. &Event1,
  733. SynchronizationEvent,
  734. FALSE);
  735. DeviceObject = IoGetRelatedDeviceObject( TdiObject );
  736. TdiBuildQueryInformation( Irp,
  737. DeviceObject,
  738. TdiObject,
  739. NbCompletionEvent,
  740. &Event1,
  741. TDI_QUERY_ADAPTER_STATUS,
  742. Irp->MdlAddress);
  743. if ( pdncb->ncb_callname[0] != '*') {
  744. //
  745. // Remote Astat. The variables used to specify the remote adapter name
  746. // are kept the same as those in connect.c to aid maintenance.
  747. //
  748. PIO_STACK_LOCATION NewIrpSp = IoGetNextIrpStackLocation (Irp);
  749. ConnectBlock.TAAddressCount = 1;
  750. ConnectBlock.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  751. ConnectBlock.Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
  752. temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock.Address[0].Address;
  753. temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  754. RtlMoveMemory( temp->NetbiosName, pdncb->ncb_callname, NCBNAMSZ );
  755. RequestInformation.RemoteAddress = &ConnectBlock;
  756. RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
  757. sizeof (TDI_ADDRESS_NETBIOS);
  758. ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&NewIrpSp->Parameters)
  759. ->RequestConnectionInformation = &RequestInformation;
  760. } else {
  761. //
  762. // Avoid situation where adapter has more names added than the process and
  763. // then extra names get added to the end of the buffer.
  764. //
  765. //
  766. // Map the users buffer now so that the whole buffer is mapped (not
  767. // just sizeof ADAPTER_STATUS).
  768. //
  769. if (Irp->MdlAddress) {
  770. MmGetSystemAddressForMdl (Irp->MdlAddress);
  771. } else {
  772. ASSERT(FALSE);
  773. }
  774. Irp->MdlAddress->ByteCount = sizeof(ADAPTER_STATUS);
  775. }
  776. IoCallDriver (DeviceObject, Irp);
  777. Status = KeWaitForSingleObject (&Event1,
  778. Executive,
  779. KernelMode,
  780. TRUE,
  781. NULL);
  782. //
  783. // Restore length now that the transport has filled in no more than
  784. // is required of it.
  785. //
  786. if (Irp->MdlAddress) {
  787. Irp->MdlAddress->ByteCount = Buffer2Length;
  788. }
  789. NbAddressClose( TdiHandle, TdiObject );
  790. if (!NT_SUCCESS(Status)) {
  791. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  792. return Status;
  793. }
  794. Status = Irp->IoStatus.Status;
  795. if (( Status == STATUS_BUFFER_OVERFLOW ) &&
  796. ( pdncb->ncb_callname[0] == '*')) {
  797. //
  798. // This is a local ASTAT. Don't worry if there was not enough room in the
  799. // users buffer for all the addresses that the transport knows about. There
  800. // only needs to be space for the names the user has added and we will check
  801. // that later.
  802. //
  803. Status = STATUS_SUCCESS;
  804. }
  805. if (!NT_SUCCESS(Status)) {
  806. pdncb->ncb_length = (WORD)Irp->IoStatus.Information;
  807. NCB_COMPLETE( pdncb, NbMakeNbError(Status) );
  808. } else {
  809. if ( pdncb->ncb_callname[0] == '*') {
  810. //
  811. // Append the addresses and Netbios maintained counts.
  812. //
  813. CopyAddresses(
  814. pdncb,
  815. Irp,
  816. IrpSp,
  817. Buffer2Length);
  818. // CopyAddresses completes the NCB appropriately.
  819. } else {
  820. pdncb->ncb_length = (WORD)Irp->IoStatus.Information;
  821. NCB_COMPLETE( pdncb, NRC_GOODRET );
  822. }
  823. }
  824. } else {
  825. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  826. }
  827. #if DBG
  828. IF_NBDBG (NB_DEBUG_ASTAT) {
  829. NbFormattedDump(MmGetSystemAddressForMdl (Irp->MdlAddress), pdncb->ncb_length );
  830. }
  831. #endif
  832. //
  833. // Because the completion routine returned STATUS_MORE_PROCESSING_REQUIRED
  834. // NbAstat must return a status other than STATUS_PENDING so that the
  835. // users Irp gets completed.
  836. //
  837. ASSERT( Status != STATUS_PENDING );
  838. return Status;
  839. UNREFERENCED_PARAMETER( IrpSp );
  840. }
  841. VOID
  842. CopyAddresses(
  843. IN PDNCB pdncb,
  844. IN PIRP Irp,
  845. IN PIO_STACK_LOCATION IrpSp,
  846. IN ULONG Buffer2Length
  847. )
  848. /*++
  849. Routine Description:
  850. This routine is called to finish the adapter status.
  851. Arguments:
  852. pdncb - Pointer to the NCB.
  853. Irp - Pointer to the request packet representing the I/O request.
  854. IrpSp - Pointer to current IRP stack frame.
  855. Buffer2Length - User provided buffer length for data.
  856. Return Value:
  857. none.
  858. --*/
  859. {
  860. ULONG LengthRemaining = Buffer2Length - sizeof(ADAPTER_STATUS);
  861. PUADAPTER_STATUS pAdapter;
  862. PUNAME_BUFFER pNameArray;
  863. int NextEntry = 0; // Used to walk pNameArray
  864. PFCB pfcb = IrpSp->FileObject->FsContext2;
  865. PLANA_INFO plana;
  866. int index; // Used to access AddressBlocks
  867. KIRQL OldIrql; // Used when SpinLock held.
  868. LOCK( pfcb, OldIrql );
  869. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  870. if ((plana == NULL ) ||
  871. (plana->Status != NB_INITIALIZED)) {
  872. NCB_COMPLETE( pdncb, NRC_ENVNOTDEF ); // need a reset
  873. UNLOCK( pfcb, OldIrql );
  874. return;
  875. }
  876. //
  877. // Map the users buffer so we can poke around inside
  878. //
  879. if (Irp->MdlAddress) {
  880. pAdapter = MmGetSystemAddressForMdl (Irp->MdlAddress);
  881. } else {
  882. ASSERT(FALSE);
  883. }
  884. pNameArray = (PUNAME_BUFFER)((PUCHAR)pAdapter + sizeof(ADAPTER_STATUS));
  885. pAdapter->rev_major = 0x03;
  886. pAdapter->rev_minor = 0x00;
  887. pAdapter->free_ncbs = 255;
  888. pAdapter->max_cfg_ncbs = 255;
  889. pAdapter->max_ncbs = 255;
  890. pAdapter->pending_sess = 0;
  891. for ( index = 0; index <= MAXIMUM_CONNECTION; index++ ) {
  892. if ( plana->ConnectionBlocks[index] != NULL) {
  893. pAdapter->pending_sess++;
  894. }
  895. }
  896. pAdapter->max_cfg_sess = (WORD)plana->MaximumConnection;
  897. pAdapter->max_sess = (WORD)plana->MaximumConnection;
  898. pAdapter->name_count = 0;
  899. // Don't include the reserved address so start at index=2.
  900. for ( index = 2; index < MAXIMUM_ADDRESS; index++ ) {
  901. if ( plana->AddressBlocks[index] != NULL ) {
  902. if ( LengthRemaining >= sizeof(NAME_BUFFER) ) {
  903. RtlCopyMemory( (PUCHAR)&pNameArray[NextEntry],
  904. &plana->AddressBlocks[index]->Name,
  905. sizeof(NAME));
  906. pNameArray[NextEntry].name_num =
  907. plana->AddressBlocks[index]->NameNumber;
  908. pNameArray[NextEntry].name_flags =
  909. plana->AddressBlocks[index]->Status;
  910. LengthRemaining -= sizeof(NAME_BUFFER);
  911. NextEntry++;
  912. pAdapter->name_count++;
  913. } else {
  914. NCB_COMPLETE( pdncb, NRC_INCOMP );
  915. goto exit;
  916. }
  917. }
  918. }
  919. NCB_COMPLETE( pdncb, NRC_GOODRET );
  920. exit:
  921. pdncb->ncb_length = (unsigned short)( sizeof(ADAPTER_STATUS) +
  922. ( sizeof(NAME_BUFFER) * NextEntry));
  923. UNLOCK( pfcb, OldIrql );
  924. }
  925. NTSTATUS
  926. NbFindName(
  927. IN PDNCB pdncb,
  928. IN PIRP Irp,
  929. IN PIO_STACK_LOCATION IrpSp,
  930. IN ULONG Buffer2Length
  931. )
  932. /*++
  933. Routine Description:
  934. This routine is called to return the result of a name query.
  935. Arguments:
  936. pdncb - Pointer to the NCB.
  937. Irp - Pointer to the request packet representing the I/O request.
  938. IrpSp - Pointer to current IRP stack frame.
  939. Buffer2Length - User provided buffer length for data.
  940. Return Value:
  941. The function value is the status of the operation.
  942. --*/
  943. {
  944. NTSTATUS Status = STATUS_SUCCESS;
  945. TDI_CONNECTION_INFORMATION RequestInformation;
  946. TA_NETBIOS_ADDRESS ConnectBlock;
  947. PTDI_ADDRESS_NETBIOS temp;
  948. PFCB pfcb = IrpSp->FileObject->FsContext2;
  949. KEVENT Event1;
  950. HANDLE TdiHandle;
  951. PFILE_OBJECT TdiObject;
  952. PDEVICE_OBJECT DeviceObject;
  953. PIO_STACK_LOCATION NewIrpSp = IoGetNextIrpStackLocation (Irp);
  954. PAGED_CODE();
  955. if ( Buffer2Length < (sizeof(FIND_NAME_HEADER) + sizeof(FIND_NAME_BUFFER)) ) {
  956. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  957. return STATUS_SUCCESS;
  958. }
  959. LOCK_RESOURCE( pfcb );
  960. if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  961. ( pfcb == NULL ) ||
  962. (pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  963. (pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED)) {
  964. UNLOCK_RESOURCE( pfcb );
  965. NCB_COMPLETE( pdncb, NRC_ENVNOTDEF ); // need a reset
  966. return STATUS_SUCCESS;
  967. }
  968. UNLOCK_RESOURCE( pfcb );
  969. // NULL returns a handle for doing control functions
  970. Status = NbOpenAddress ( &TdiHandle, (PVOID*)&TdiObject, pfcb, pdncb->ncb_lana_num, NULL);
  971. if (!NT_SUCCESS(Status)) {
  972. IF_NBDBG (NB_DEBUG_ASTAT) {
  973. NbPrint(( "\n FAILED on open of Tdi: %X ******\n", Status ));
  974. }
  975. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  976. return STATUS_SUCCESS;
  977. }
  978. KeInitializeEvent (
  979. &Event1,
  980. SynchronizationEvent,
  981. FALSE);
  982. DeviceObject = IoGetRelatedDeviceObject( TdiObject );
  983. TdiBuildQueryInformation( Irp,
  984. DeviceObject,
  985. TdiObject,
  986. NbCompletionEvent,
  987. &Event1,
  988. TDI_QUERY_FIND_NAME,
  989. Irp->MdlAddress);
  990. //
  991. // The variables used to specify the remote adapter name
  992. // are kept the same as those in connect.c to aid maintenance.
  993. //
  994. ConnectBlock.TAAddressCount = 1;
  995. ConnectBlock.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  996. ConnectBlock.Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
  997. temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock.Address[0].Address;
  998. temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  999. RtlMoveMemory( temp->NetbiosName, pdncb->ncb_callname, NCBNAMSZ );
  1000. RequestInformation.RemoteAddress = &ConnectBlock;
  1001. RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
  1002. sizeof (TDI_ADDRESS_NETBIOS);
  1003. ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&NewIrpSp->Parameters)
  1004. ->RequestConnectionInformation = &RequestInformation;
  1005. IoCallDriver (DeviceObject, Irp);
  1006. Status = KeWaitForSingleObject (&Event1,
  1007. Executive,
  1008. KernelMode,
  1009. TRUE,
  1010. NULL);
  1011. NbAddressClose( TdiHandle, TdiObject );
  1012. if (NT_SUCCESS(Status)) {
  1013. Status = Irp->IoStatus.Status;
  1014. }
  1015. if (!NT_SUCCESS(Status)) {
  1016. NCB_COMPLETE( pdncb, NbMakeNbError(Status) );
  1017. Status = STATUS_SUCCESS;
  1018. } else {
  1019. pdncb->ncb_length = (WORD)Irp->IoStatus.Information;
  1020. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1021. }
  1022. //
  1023. // Because the completion routine returned STATUS_MORE_PROCESSING_REQUIRED
  1024. // NbFindName must return a status other than STATUS_PENDING so that the
  1025. // users Irp gets completed.
  1026. //
  1027. ASSERT( Status != STATUS_PENDING );
  1028. return Status;
  1029. }
  1030. NTSTATUS
  1031. NbSstat(
  1032. IN PDNCB pdncb,
  1033. IN PIRP Irp,
  1034. IN PIO_STACK_LOCATION IrpSp,
  1035. IN ULONG Buffer2Length
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. This routine is called to return session status. It uses only structures
  1040. internal to this driver.
  1041. Arguments:
  1042. pdncb - Pointer to the NCB.
  1043. Irp - Pointer to the request packet representing the I/O request.
  1044. IrpSp - Pointer to current IRP stack frame.
  1045. Buffer2Length - User provided buffer length for data.
  1046. Return Value:
  1047. The function value is the status of the operation.
  1048. --*/
  1049. {
  1050. NTSTATUS Status = STATUS_SUCCESS;
  1051. if ( Buffer2Length >= sizeof(SESSION_HEADER) ) {
  1052. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1053. PLANA_INFO plana;
  1054. int index;
  1055. PUSESSION_HEADER pSessionHeader;
  1056. PUSESSION_BUFFER pSessionBuffer;
  1057. ULONG LengthRemaining;
  1058. PAB pab;
  1059. KIRQL OldIrql; // Used when SpinLock held.
  1060. //
  1061. // Prevent indications from the transport, post routines being called
  1062. // and another thread making a request while manipulating the netbios
  1063. // data structures.
  1064. //
  1065. LOCK( pfcb, OldIrql );
  1066. if (pdncb->ncb_lana_num > pfcb->MaxLana ) {
  1067. UNLOCK( pfcb, OldIrql );
  1068. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1069. return STATUS_SUCCESS;
  1070. }
  1071. if (( pfcb == NULL ) ||
  1072. ( pfcb->ppLana[pdncb->ncb_lana_num] == (LANA_INFO *) NULL ) ||
  1073. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  1074. UNLOCK( pfcb, OldIrql );
  1075. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1076. return STATUS_SUCCESS;
  1077. }
  1078. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  1079. if ( pdncb->ncb_name[0] != '*') {
  1080. PPAB ppab = FindAb(pfcb, pdncb, FALSE);
  1081. if ( ppab == NULL) {
  1082. UNLOCK( pfcb, OldIrql );
  1083. pdncb->ncb_retcode = NRC_PENDING;
  1084. NCB_COMPLETE( pdncb, NRC_NOWILD );
  1085. return STATUS_SUCCESS;
  1086. }
  1087. pab = *ppab;
  1088. }
  1089. //
  1090. // Map the users buffer so we can poke around inside
  1091. //
  1092. if (Irp->MdlAddress) {
  1093. pSessionHeader = MmGetSystemAddressForMdl (Irp->MdlAddress);
  1094. } else {
  1095. ASSERT(FALSE);
  1096. }
  1097. pSessionHeader->sess_name = 0;
  1098. pSessionHeader->num_sess = 0;
  1099. pSessionHeader->rcv_dg_outstanding = 0;
  1100. pSessionHeader->rcv_any_outstanding = 0;
  1101. if ( pdncb->ncb_name[0] == '*') {
  1102. for ( index = 0; index <= MAXIMUM_ADDRESS; index++ ) {
  1103. if ( plana->AddressBlocks[index] != NULL ) {
  1104. PLIST_ENTRY Entry;
  1105. pab = plana->AddressBlocks[index];
  1106. for (Entry = pab->ReceiveDatagramList.Flink ;
  1107. Entry != &pab->ReceiveDatagramList ;
  1108. Entry = Entry->Flink) {
  1109. pSessionHeader->rcv_dg_outstanding++ ;
  1110. }
  1111. for (Entry = pab->ReceiveBroadcastDatagramList.Flink ;
  1112. Entry != &pab->ReceiveBroadcastDatagramList ;
  1113. Entry = Entry->Flink) {
  1114. pSessionHeader->rcv_dg_outstanding++ ;
  1115. }
  1116. for (Entry = pab->ReceiveAnyList.Flink ;
  1117. Entry != &pab->ReceiveAnyList ;
  1118. Entry = Entry->Flink) {
  1119. pSessionHeader->rcv_any_outstanding++;
  1120. }
  1121. }
  1122. }
  1123. pSessionHeader->sess_name = MAXIMUM_ADDRESS;
  1124. } else {
  1125. PLIST_ENTRY Entry;
  1126. PAB pab255;
  1127. // Add entries for this name alone.
  1128. for (Entry = pab->ReceiveDatagramList.Flink ;
  1129. Entry != &pab->ReceiveDatagramList ;
  1130. Entry = Entry->Flink) {
  1131. pSessionHeader->rcv_dg_outstanding++ ;
  1132. }
  1133. pab255 = plana->AddressBlocks[MAXIMUM_ADDRESS];
  1134. for (Entry = pab255->ReceiveBroadcastDatagramList.Flink ;
  1135. Entry != &pab255->ReceiveBroadcastDatagramList ;
  1136. Entry = Entry->Flink) {
  1137. PDNCB pdncbEntry = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  1138. if ( pdncbEntry->ncb_num == pab->NameNumber ) {
  1139. pSessionHeader->rcv_dg_outstanding++ ;
  1140. }
  1141. }
  1142. for (Entry = pab->ReceiveAnyList.Flink ;
  1143. Entry != &pab->ReceiveAnyList ;
  1144. Entry = Entry->Flink) {
  1145. pSessionHeader->rcv_any_outstanding++;
  1146. }
  1147. pSessionHeader->sess_name = pab->NameNumber;
  1148. }
  1149. LengthRemaining = Buffer2Length - sizeof(SESSION_HEADER);
  1150. pSessionBuffer = (PUSESSION_BUFFER)( pSessionHeader+1 );
  1151. for ( index=1 ; index <= MAXIMUM_CONNECTION; index++ ) {
  1152. CopySessionStatus( pdncb,
  1153. plana->ConnectionBlocks[index],
  1154. pSessionHeader,
  1155. &pSessionBuffer,
  1156. &LengthRemaining);
  1157. }
  1158. /* Undocumented Netbios 3.0 feature, returned length == requested
  1159. length and not the length of data returned. The following
  1160. expression gives the number of bytes actually used.
  1161. pdncb->ncb_length = (USHORT)
  1162. (sizeof(SESSION_HEADER)+
  1163. (sizeof(SESSION_BUFFER) * pSessionHeader->num_sess));
  1164. */
  1165. UNLOCK( pfcb, OldIrql );
  1166. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1167. } else {
  1168. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  1169. }
  1170. return STATUS_SUCCESS;
  1171. UNREFERENCED_PARAMETER( IrpSp );
  1172. }
  1173. VOID
  1174. CopySessionStatus(
  1175. IN PDNCB pdncb,
  1176. IN PCB pcb,
  1177. IN PUSESSION_HEADER pSessionHeader,
  1178. IN PUSESSION_BUFFER* ppSessionBuffer,
  1179. IN PULONG pLengthRemaining
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. This routine is called to determine if a session should be added
  1184. to the callers buffer and if so it fills in the data. If there is an
  1185. error it records the problem in the callers NCB.
  1186. Arguments:
  1187. pdncb - Pointer to the NCB.
  1188. pcb - Connection Block for a particular session
  1189. pSessionHeader - Start of the callers buffer
  1190. ppSessionBuffer - Next position to fill in inside the users buffer.
  1191. pLengthRemaining - size in bytes remaining to be filled.
  1192. Return Value:
  1193. none.
  1194. --*/
  1195. {
  1196. PAB pab;
  1197. PLIST_ENTRY Entry;
  1198. if ( pcb == NULL ) {
  1199. return;
  1200. }
  1201. pab = *(pcb->ppab);
  1202. if (( pdncb->ncb_name[0] == '*') ||
  1203. (RtlEqualMemory( &pab->Name, pdncb->ncb_name, NCBNAMSZ))) {
  1204. pSessionHeader->num_sess++;
  1205. if ( *pLengthRemaining < sizeof(SESSION_BUFFER) ) {
  1206. NCB_COMPLETE( pdncb, NRC_INCOMP );
  1207. return;
  1208. }
  1209. (*ppSessionBuffer)->lsn = pcb->SessionNumber;
  1210. (*ppSessionBuffer)->state = pcb->Status;
  1211. RtlMoveMemory((*ppSessionBuffer)->local_name, &pab->Name, NCBNAMSZ);
  1212. RtlMoveMemory((*ppSessionBuffer)->remote_name, &pcb->RemoteName, NCBNAMSZ);
  1213. (*ppSessionBuffer)->sends_outstanding = 0;
  1214. (*ppSessionBuffer)->rcvs_outstanding = 0;
  1215. for (Entry = pcb->SendList.Flink ;
  1216. Entry != &pcb->SendList ;
  1217. Entry = Entry->Flink) {
  1218. (*ppSessionBuffer)->sends_outstanding++;
  1219. }
  1220. for (Entry = pcb->ReceiveList.Flink ;
  1221. Entry != &pcb->ReceiveList ;
  1222. Entry = Entry->Flink) {
  1223. (*ppSessionBuffer)->rcvs_outstanding++;
  1224. }
  1225. *ppSessionBuffer +=1;
  1226. *pLengthRemaining -= sizeof(SESSION_BUFFER);
  1227. }
  1228. }
  1229. NTSTATUS
  1230. NbEnum(
  1231. IN PDNCB pdncb,
  1232. IN PIRP Irp,
  1233. IN PIO_STACK_LOCATION IrpSp,
  1234. IN ULONG Buffer2Length
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. This routine is called to discover the available lana numbers.
  1239. Arguments:
  1240. pdncb - Pointer to the NCB.
  1241. Irp - Pointer to the request packet representing the I/O request.
  1242. IrpSp - Pointer to current IRP stack frame.
  1243. Buffer2Length - Length of user provided buffer for data.
  1244. Return Value:
  1245. The function value is the status of the operation.
  1246. --*/
  1247. {
  1248. NTSTATUS Status = STATUS_SUCCESS;
  1249. PUCHAR Buffer2;
  1250. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1251. PAGED_CODE();
  1252. //
  1253. // Map the users buffer so we can poke around inside
  1254. //
  1255. if (Irp->MdlAddress) {
  1256. Buffer2 = MmGetSystemAddressForMdl (Irp->MdlAddress);
  1257. } else {
  1258. //
  1259. // Either a zero byte read/write or the request only has an NCB.
  1260. //
  1261. Buffer2 = NULL;
  1262. Buffer2Length = 0;
  1263. }
  1264. // Copy over as much information as the user allows.
  1265. if ( (ULONG)pfcb->LanaEnum.length + 1 > Buffer2Length ) {
  1266. if ( Buffer2Length > 0 ) {
  1267. RtlMoveMemory( Buffer2, &pfcb->LanaEnum, Buffer2Length);
  1268. }
  1269. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  1270. } else {
  1271. RtlMoveMemory(
  1272. Buffer2,
  1273. &pfcb->LanaEnum,
  1274. (ULONG)pfcb->LanaEnum.length + 1 );
  1275. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1276. }
  1277. return Status;
  1278. }
  1279. NTSTATUS
  1280. NbReset(
  1281. IN PDNCB pdncb,
  1282. IN PIRP Irp,
  1283. IN PIO_STACK_LOCATION IrpSp
  1284. )
  1285. /*++
  1286. Routine Description:
  1287. This routine is called to reset an adapter. Until an adapter is reset,
  1288. no access to the lan is allowed.
  1289. Arguments:
  1290. pdncb - Pointer to the NCB.
  1291. Irp - Pointer to the request packet representing the I/O request.
  1292. IrpSp - Pointer to current IRP stack frame.
  1293. Return Value:
  1294. The function value is the status of the operation.
  1295. --*/
  1296. {
  1297. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1298. PAGED_CODE();
  1299. IF_NBDBG (NB_DEBUG_CALL) {
  1300. NbPrint(( "\n****** Start of NbReset ****** pdncb %lx\n", pdncb ));
  1301. }
  1302. if ( pdncb->ncb_lana_num > pfcb->MaxLana) {
  1303. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1304. return STATUS_SUCCESS;
  1305. }
  1306. // MaxLana is really the last assigned lana number hence > not >=
  1307. if ( pdncb->ncb_lana_num > pfcb->MaxLana) {
  1308. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1309. return STATUS_SUCCESS;
  1310. }
  1311. //
  1312. // Wait till all addnames are completed and prevent any new
  1313. // ones while we reset the lana. Note We lock out addnames for all
  1314. // lanas. This is ok since addnames are pretty rare as are resets.
  1315. //
  1316. ExAcquireResourceExclusive( &pfcb->AddResource, TRUE);
  1317. IF_NBDBG (NB_DEBUG_CALL) {
  1318. NbPrint(( "\nNbReset have resource exclusive\n" ));
  1319. }
  1320. if ( pfcb->ppLana[pdncb->ncb_lana_num] != NULL ) {
  1321. CleanupLana( pfcb, pdncb->ncb_lana_num, TRUE);
  1322. }
  1323. if ( pdncb->ncb_lsn == 0 ) {
  1324. // Allocate resources
  1325. OpenLana( pdncb, Irp, IrpSp );
  1326. } else {
  1327. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1328. }
  1329. // Allow more addnames
  1330. ExReleaseResource( &pfcb->AddResource );
  1331. return STATUS_SUCCESS;
  1332. }
  1333. NTSTATUS
  1334. NbAction(
  1335. IN PDNCB pdncb,
  1336. IN PIRP Irp,
  1337. IN PIO_STACK_LOCATION IrpSp
  1338. )
  1339. /*++
  1340. Routine Description:
  1341. This routine is called to access a transport specific extension. Netbios does not know
  1342. anything about what the extension does.
  1343. Arguments:
  1344. pdncb - Pointer to the NCB.
  1345. Irp - Pointer to the request packet representing the I/O request.
  1346. IrpSp - Pointer to current IRP stack frame.
  1347. Return Value:
  1348. The function value is the status of the operation.
  1349. --*/
  1350. {
  1351. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1352. PCB pcb;
  1353. PDEVICE_OBJECT DeviceObject;
  1354. KIRQL OldIrql; // Used when SpinLock held.
  1355. IF_NBDBG (NB_DEBUG_CALL) {
  1356. NbPrint(( "\n****** Start of NbAction ****** pdncb %lx\n", pdncb ));
  1357. }
  1358. if ( pdncb->ncb_lana_num > pfcb->MaxLana) {
  1359. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1360. return STATUS_SUCCESS;
  1361. }
  1362. //
  1363. // The operation can only be performed on one handle so if the NCB specifies both
  1364. // a connection and an address then reject the request.
  1365. //
  1366. if (( pdncb->ncb_lsn != 0) &&
  1367. ( pdncb->ncb_num != 0)) {
  1368. NCB_COMPLETE( pdncb, NRC_ILLCMD ); // No really good errorcode for this
  1369. return STATUS_SUCCESS;
  1370. }
  1371. if ( pdncb->ncb_length < sizeof(ACTION_HEADER) ) {
  1372. NCB_COMPLETE( pdncb, NRC_BUFLEN );
  1373. return STATUS_SUCCESS;
  1374. }
  1375. if ( (ULONG)pdncb->ncb_buffer & 3 ) {
  1376. NCB_COMPLETE( pdncb, NRC_BADDR ); // Buffer not word aligned
  1377. return STATUS_SUCCESS;
  1378. }
  1379. LOCK( pfcb, OldIrql );
  1380. pdncb->irp = Irp;
  1381. pdncb->pfcb = pfcb;
  1382. if ( pdncb->ncb_lsn != 0) {
  1383. // Use handle associated with this connection
  1384. PPCB ppcb;
  1385. ppcb = FindCb( pfcb, pdncb, FALSE);
  1386. if ( ppcb == NULL ) {
  1387. // FindCb has put the error in the NCB
  1388. UNLOCK( pfcb, OldIrql );
  1389. if ( pdncb->ncb_retcode == NRC_SCLOSED ) {
  1390. // Tell dll to hangup the connection.
  1391. return STATUS_HANGUP_REQUIRED;
  1392. } else {
  1393. return STATUS_SUCCESS;
  1394. }
  1395. }
  1396. pcb = *ppcb;
  1397. if ( (pcb->DeviceObject == NULL) || (pcb->ConnectionObject == NULL)) {
  1398. UNLOCK( pfcb, OldIrql );
  1399. NCB_COMPLETE( pdncb, NRC_SCLOSED );
  1400. return STATUS_SUCCESS;
  1401. }
  1402. TdiBuildAction (Irp,
  1403. pcb->DeviceObject,
  1404. pcb->ConnectionObject,
  1405. NbCompletionPDNCB,
  1406. pdncb,
  1407. Irp->MdlAddress);
  1408. DeviceObject = pcb->DeviceObject;
  1409. UNLOCK( pfcb, OldIrql );
  1410. IoMarkIrpPending( Irp );
  1411. IoCallDriver (DeviceObject, Irp);
  1412. IF_NBDBG (NB_DEBUG_ACTION) {
  1413. NbPrint(( "NB ACTION submit connection: %X\n", Irp->IoStatus.Status ));
  1414. }
  1415. //
  1416. // Transport will complete the request. Return pending so that
  1417. // netbios does not complete as well.
  1418. //
  1419. return STATUS_PENDING;
  1420. } else if ( pdncb->ncb_num != 0) {
  1421. // Use handle associated with this name
  1422. PPAB ppab;
  1423. PAB pab;
  1424. ppab = FindAbUsingNum( pfcb, pdncb, pdncb->ncb_num );
  1425. if ( ppab == NULL ) {
  1426. UNLOCK( pfcb, OldIrql );
  1427. return STATUS_SUCCESS;
  1428. }
  1429. pab = *ppab;
  1430. TdiBuildAction (Irp,
  1431. pab->DeviceObject,
  1432. pab->AddressObject,
  1433. NbCompletionPDNCB,
  1434. pdncb,
  1435. Irp->MdlAddress);
  1436. DeviceObject = pab->DeviceObject;
  1437. UNLOCK( pfcb, OldIrql );
  1438. IoMarkIrpPending( Irp );
  1439. IoCallDriver (DeviceObject, Irp);
  1440. IF_NBDBG (NB_DEBUG_ACTION) {
  1441. NbPrint(( "NB ACTION submit address: %X\n", Irp->IoStatus.Status ));
  1442. }
  1443. //
  1444. // Transport will complete the request. Return pending so that
  1445. // netbios does not complete as well.
  1446. //
  1447. return STATUS_PENDING;
  1448. } else {
  1449. // Use the control channel
  1450. PLANA_INFO plana;
  1451. if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  1452. ( pfcb == NULL ) ||
  1453. ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL) ||
  1454. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  1455. UNLOCK( pfcb, OldIrql );
  1456. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1457. return STATUS_SUCCESS;
  1458. }
  1459. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  1460. TdiBuildAction (Irp,
  1461. plana->ControlDeviceObject,
  1462. plana->ControlFileObject,
  1463. NbCompletionPDNCB,
  1464. pdncb,
  1465. Irp->MdlAddress);
  1466. DeviceObject = plana->ControlDeviceObject;
  1467. UNLOCK( pfcb, OldIrql );
  1468. IoMarkIrpPending( Irp );
  1469. IoCallDriver (DeviceObject, Irp);
  1470. IF_NBDBG (NB_DEBUG_ACTION) {
  1471. NbPrint(( "NB ACTION submit control: %X\n", Irp->IoStatus.Status ));
  1472. }
  1473. //
  1474. // Transport will complete the request. Return pending so that
  1475. // netbios does not complete as well.
  1476. //
  1477. return STATUS_PENDING;
  1478. UNLOCK( pfcb, OldIrql );
  1479. return STATUS_SUCCESS;
  1480. }
  1481. }
  1482. NTSTATUS
  1483. NbCancel(
  1484. IN PDNCB pdncb,
  1485. IN PIRP Irp,
  1486. IN PIO_STACK_LOCATION IrpSp
  1487. )
  1488. /*++
  1489. Routine Description:
  1490. This routine is called to cancel the ncb pointed to by NCB_BUFFER.
  1491. Arguments:
  1492. pdncb - Pointer to the NCB.
  1493. Irp - Pointer to the request packet representing the I/O request.
  1494. IrpSp - Pointer to current IRP stack frame.
  1495. Return Value:
  1496. The function value is the status of the operation.
  1497. --*/
  1498. {
  1499. PFCB pfcb = IrpSp->FileObject->FsContext2;
  1500. PDNCB target; // Mapped in location of the USERS NCB. Not the drivers copy of the DNCB!
  1501. BOOL SpinLockHeld;
  1502. KIRQL OldIrql; // Used when SpinLock held.
  1503. IF_NBDBG (NB_DEBUG_CALL) {
  1504. NbPrint(( "\n****** Start of NbCancel ****** pdncb %lx\n", pdncb ));
  1505. }
  1506. if ( pdncb->ncb_lana_num > pfcb->MaxLana) {
  1507. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1508. return STATUS_SUCCESS;
  1509. }
  1510. LOCK( pfcb, OldIrql );
  1511. SpinLockHeld = TRUE;
  1512. if (( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  1513. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  1514. UNLOCK( pfcb, OldIrql );
  1515. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1516. return STATUS_SUCCESS;
  1517. }
  1518. //
  1519. // Map the users buffer so we can poke around inside
  1520. //
  1521. if (Irp->MdlAddress) {
  1522. target = MmGetSystemAddressForMdl (Irp->MdlAddress);
  1523. } else {
  1524. ASSERT(FALSE);
  1525. UNLOCK( pfcb, OldIrql );
  1526. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1527. return STATUS_SUCCESS;
  1528. }
  1529. IF_NBDBG (NB_DEBUG_CALL) {
  1530. NbDisplayNcb( target );
  1531. }
  1532. try {
  1533. if ( target->ncb_lana_num == pdncb->ncb_lana_num ) {
  1534. switch ( target->ncb_command & ~ASYNCH ) {
  1535. case NCBCALL:
  1536. case NCALLNIU:
  1537. case NCBLISTEN:
  1538. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  1539. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1540. } else {
  1541. //
  1542. // Search for the correct ppcb. We cannot use FindCb
  1543. // because the I/O system will not copy back the ncb_lsn
  1544. // field into target until the I/O request completes.
  1545. //
  1546. PPCB ppcb = FindCallCb( pfcb, (PNCB)pdncb->ncb_buffer);
  1547. if (( ppcb == NULL ) ||
  1548. ((*ppcb)->pdncbCall->ncb_cmd_cplt != NRC_PENDING ) ||
  1549. (( (*ppcb)->Status != CALL_PENDING ) &&
  1550. ( (*ppcb)->Status != LISTEN_OUTSTANDING ))) {
  1551. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1552. } else {
  1553. NCB_COMPLETE( (*ppcb)->pdncbCall, NRC_CMDCAN );
  1554. SpinLockHeld = FALSE;
  1555. (*ppcb)->DisconnectReported = TRUE;
  1556. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1557. CleanupCb( ppcb, NULL );
  1558. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1559. }
  1560. }
  1561. break;
  1562. case NCBHANGUP:
  1563. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  1564. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1565. } else {
  1566. PPCB ppcb = FindCb( pfcb, target, FALSE );
  1567. if (( ppcb != NULL ) &&
  1568. ((*ppcb)->Status == HANGUP_PENDING )) {
  1569. PDNCB pdncbHangup;
  1570. // Restore the session status and remove the hangup.
  1571. (*ppcb)->Status = SESSION_ESTABLISHED;
  1572. pdncbHangup = (*ppcb)->pdncbHangup;
  1573. (*ppcb)->pdncbHangup = NULL;
  1574. if ( pdncbHangup != NULL ) {
  1575. NCB_COMPLETE( pdncbHangup, NRC_CMDCAN );
  1576. pdncbHangup->irp->IoStatus.Information =
  1577. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1578. NbCompleteRequest( pdncbHangup->irp ,STATUS_SUCCESS);
  1579. }
  1580. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1581. } else {
  1582. // Doesn't look like this is a real hangup so refuse.
  1583. NCB_COMPLETE( pdncb, NRC_CANCEL );
  1584. }
  1585. }
  1586. break;
  1587. case NCBASTAT:
  1588. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1589. break;
  1590. case NCBLANSTALERT:
  1591. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  1592. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1593. } else {
  1594. CancelLanAlert( pfcb, pdncb );
  1595. }
  1596. break;
  1597. case NCBRECVANY:
  1598. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  1599. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1600. } else {
  1601. PPAB ppab;
  1602. PLIST_ENTRY Entry;
  1603. ppab = FindAbUsingNum( pfcb, target, target->ncb_num );
  1604. if ( ppab == NULL ) {
  1605. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1606. break;
  1607. }
  1608. for (Entry = (*ppab)->ReceiveAnyList.Flink ;
  1609. Entry != &(*ppab)->ReceiveAnyList;
  1610. Entry = Entry->Flink) {
  1611. PDNCB pReceive = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  1612. if ( pReceive->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  1613. PIRP Irp;
  1614. RemoveEntryList( &pReceive->ncb_next );
  1615. SpinLockHeld = FALSE;
  1616. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1617. Irp = pReceive->irp;
  1618. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  1619. //
  1620. // Remove the cancel request for this IRP. If its cancelled then its
  1621. // ok to just process it because we will be returning it to the caller.
  1622. //
  1623. Irp->Cancel = FALSE;
  1624. IoSetCancelRoutine(Irp, NULL);
  1625. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1626. NCB_COMPLETE( pReceive, NRC_CMDCAN );
  1627. Irp->IoStatus.Status = STATUS_SUCCESS,
  1628. Irp->IoStatus.Information =
  1629. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1630. NbCompleteRequest( Irp, STATUS_SUCCESS );
  1631. // The receive is cancelled, complete the cancel
  1632. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1633. break;
  1634. }
  1635. }
  1636. // Command not in receive list!
  1637. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1638. }
  1639. break;
  1640. case NCBDGRECV:
  1641. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  1642. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1643. } else {
  1644. PPAB ppab;
  1645. PLIST_ENTRY Entry;
  1646. ppab = FindAbUsingNum( pfcb, target, target->ncb_num );
  1647. if ( ppab == NULL ) {
  1648. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1649. break;
  1650. }
  1651. for (Entry = (*ppab)->ReceiveDatagramList.Flink ;
  1652. Entry != &(*ppab)->ReceiveDatagramList;
  1653. Entry = Entry->Flink) {
  1654. PDNCB pReceive = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  1655. if ( pReceive->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  1656. PIRP Irp;
  1657. RemoveEntryList( &pReceive->ncb_next );
  1658. SpinLockHeld = FALSE;
  1659. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1660. Irp = pReceive->irp;
  1661. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  1662. //
  1663. // Remove the cancel request for this IRP. If its cancelled then its
  1664. // ok to just process it because we will be returning it to the caller.
  1665. //
  1666. Irp->Cancel = FALSE;
  1667. IoSetCancelRoutine(Irp, NULL);
  1668. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1669. NCB_COMPLETE( pReceive, NRC_CMDCAN );
  1670. Irp->IoStatus.Status = STATUS_SUCCESS,
  1671. Irp->IoStatus.Information =
  1672. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1673. NbCompleteRequest( Irp, STATUS_SUCCESS );
  1674. // The receive is cancelled, complete the cancel
  1675. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1676. break;
  1677. }
  1678. }
  1679. // Command not in receive list!
  1680. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1681. }
  1682. break;
  1683. case NCBDGRECVBC:
  1684. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  1685. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1686. } else {
  1687. PPAB ppab;
  1688. PLIST_ENTRY Entry;
  1689. ppab = FindAbUsingNum( pfcb, target, MAXIMUM_ADDRESS );
  1690. if ( ppab == NULL ) {
  1691. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1692. break;
  1693. }
  1694. for (Entry = (*ppab)->ReceiveBroadcastDatagramList.Flink ;
  1695. Entry != &(*ppab)->ReceiveBroadcastDatagramList;
  1696. Entry = Entry->Flink) {
  1697. PDNCB pReceive = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  1698. if ( pReceive->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  1699. PIRP Irp;
  1700. RemoveEntryList( &pReceive->ncb_next );
  1701. SpinLockHeld = FALSE;
  1702. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1703. Irp = pReceive->irp;
  1704. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  1705. //
  1706. // Remove the cancel request for this IRP. If its cancelled then its
  1707. // ok to just process it because we will be returning it to the caller.
  1708. //
  1709. Irp->Cancel = FALSE;
  1710. IoSetCancelRoutine(Irp, NULL);
  1711. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1712. NCB_COMPLETE( pReceive, NRC_CMDCAN );
  1713. Irp->IoStatus.Status = STATUS_SUCCESS,
  1714. Irp->IoStatus.Information =
  1715. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1716. NbCompleteRequest( Irp, STATUS_SUCCESS );
  1717. // The receive is cancelled, complete the cancel
  1718. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1719. break;
  1720. }
  1721. }
  1722. // Command not in receive list!
  1723. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1724. }
  1725. break;
  1726. // Session cancels close the connection.
  1727. case NCBRECV:
  1728. case NCBSEND:
  1729. case NCBSENDNA:
  1730. case NCBCHAINSEND:
  1731. case NCBCHAINSENDNA:
  1732. if ( target->ncb_cmd_cplt != NRC_PENDING ) {
  1733. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1734. } else {
  1735. PPCB ppcb;
  1736. ppcb = FindCb( pfcb, target, FALSE);
  1737. if ( ppcb == NULL ) {
  1738. // No such connection
  1739. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1740. } else {
  1741. PDNCB pTarget = NULL;
  1742. PLIST_ENTRY Entry;
  1743. if ((target->ncb_command & ~ASYNCH) == NCBRECV ) {
  1744. for (Entry = (*ppcb)->ReceiveList.Flink ;
  1745. Entry != &(*ppcb)->ReceiveList;
  1746. Entry = Entry->Flink) {
  1747. pTarget = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  1748. if ( pTarget->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  1749. break;
  1750. }
  1751. pTarget = NULL;
  1752. }
  1753. } else {
  1754. for (Entry = (*ppcb)->SendList.Flink ;
  1755. Entry != &(*ppcb)->SendList;
  1756. Entry = Entry->Flink) {
  1757. pTarget = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  1758. if ( pTarget->users_ncb == (PNCB)pdncb->ncb_buffer ) {
  1759. break;
  1760. }
  1761. pTarget = NULL;
  1762. }
  1763. }
  1764. if ( pTarget != NULL ) {
  1765. // pTarget points to the real Netbios drivers DNCB.
  1766. NCB_COMPLETE( pTarget, NRC_CMDCAN );
  1767. SpinLockHeld = FALSE;
  1768. (*ppcb)->DisconnectReported = TRUE;
  1769. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1770. CleanupCb( ppcb, NULL );
  1771. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1772. } else {
  1773. NCB_COMPLETE( pdncb, NRC_CANOCCR );
  1774. }
  1775. }
  1776. }
  1777. break;
  1778. default:
  1779. NCB_COMPLETE( pdncb, NRC_CANCEL ); // Invalid command to cancel
  1780. break;
  1781. }
  1782. } else {
  1783. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1784. }
  1785. } except(EXCEPTION_EXECUTE_HANDLER) {
  1786. if ( SpinLockHeld == TRUE ) {
  1787. UNLOCK( pfcb, OldIrql );
  1788. } else {
  1789. UNLOCK_RESOURCE( pfcb );
  1790. }
  1791. NCB_COMPLETE( pdncb, NRC_INVADDRESS );
  1792. return STATUS_SUCCESS;
  1793. }
  1794. if ( SpinLockHeld == TRUE ) {
  1795. UNLOCK( pfcb, OldIrql );
  1796. } else {
  1797. UNLOCK_RESOURCE( pfcb );
  1798. }
  1799. NCB_COMPLETE( pdncb, NRC_GOODRET );
  1800. return STATUS_SUCCESS;
  1801. UNREFERENCED_PARAMETER( Irp );
  1802. }
  1803. VOID
  1804. QueueRequest(
  1805. IN PLIST_ENTRY List,
  1806. IN PDNCB pdncb,
  1807. IN PIRP Irp,
  1808. IN PFCB pfcb,
  1809. IN KIRQL OldIrql,
  1810. IN BOOLEAN Head)
  1811. /*++
  1812. Routine Description:
  1813. This routine is called to add a dncb to List.
  1814. Note: QueueRequest UNLOCKS the fcb. This means the resource and
  1815. spinlock are owned when this routine is called.
  1816. Arguments:
  1817. List - List of pdncb's.
  1818. pdncb - Pointer to the NCB.
  1819. Irp - Pointer to the request packet representing the I/O request.
  1820. pfcb & OldIrql - Used to free locks
  1821. Head - TRUE if pdncb should be inserted at head of list
  1822. Return Value:
  1823. None.
  1824. --*/
  1825. {
  1826. pdncb->irp = Irp;
  1827. pdncb->pfcb = pfcb;
  1828. IoMarkIrpPending( Irp );
  1829. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  1830. if ( Head == FALSE ) {
  1831. InsertTailList(List, &pdncb->ncb_next);
  1832. } else {
  1833. InsertHeadList(List, &pdncb->ncb_next);
  1834. }
  1835. if (Irp->Cancel) {
  1836. //
  1837. // CancelRoutine will lock the resource & spinlock and try to find the
  1838. // request from scratch. It may fail to find the request if it has
  1839. // been picked up by an indication from the transport.
  1840. //
  1841. UNLOCK( pfcb, OldIrql );
  1842. CancelRoutine (NULL, Irp);
  1843. } else {
  1844. IoSetCancelRoutine(Irp, CancelRoutine);
  1845. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1846. UNLOCK( pfcb, OldIrql );
  1847. }
  1848. }
  1849. PDNCB
  1850. DequeueRequest(
  1851. IN PLIST_ENTRY List
  1852. )
  1853. /*++
  1854. Routine Description:
  1855. This routine is called to remove a dncb from List.
  1856. Assume fcb spinlock held.
  1857. Arguments:
  1858. List - List of pdncb's.
  1859. Return Value:
  1860. PDNCB or NULL.
  1861. --*/
  1862. {
  1863. PIRP Irp;
  1864. PDNCB pdncb;
  1865. PLIST_ENTRY ReceiveEntry;
  1866. if (IsListEmpty(List)) {
  1867. //
  1868. // There are no waiting request announcement FsControls, so
  1869. // return success.
  1870. //
  1871. return NULL;
  1872. }
  1873. ReceiveEntry = RemoveHeadList( List);
  1874. pdncb = CONTAINING_RECORD( ReceiveEntry, DNCB, ncb_next);
  1875. Irp = pdncb->irp;
  1876. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  1877. //
  1878. // Remove the cancel request for this IRP. If its cancelled then its
  1879. // ok to just process it because we will be returning it to the caller.
  1880. //
  1881. Irp->Cancel = FALSE;
  1882. IoSetCancelRoutine(Irp, NULL);
  1883. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1884. return pdncb;
  1885. }
  1886. VOID
  1887. CancelRoutine(
  1888. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  1889. IN PIRP Irp
  1890. )
  1891. /*++
  1892. Routine Description:
  1893. This routine is called when the IO system wants to cancel a queued
  1894. request. The netbios driver queues LanAlerts, Receives and Receive
  1895. Datagrams
  1896. Arguments:
  1897. IN PDEVICE_OBJECT DeviceObject - Ignored.
  1898. IN PIRP Irp - Irp to cancel.
  1899. Return Value:
  1900. None
  1901. --*/
  1902. {
  1903. PFCB pfcb;
  1904. PDNCB pdncb;
  1905. DNCB LocalCopy;
  1906. PLIST_ENTRY List = NULL;
  1907. PPAB ppab;
  1908. PPCB ppcb;
  1909. PFILE_OBJECT FileObject;
  1910. KIRQL OldIrql;
  1911. //
  1912. // Clear the cancel routine from the IRP - It can't be cancelled anymore.
  1913. //
  1914. IoSetCancelRoutine(Irp, NULL);
  1915. //
  1916. // Remove all the info from the pdncb that we will need to find the
  1917. // request. Once we release the cancel spinlock this request could be
  1918. // completed by another action so it is possible that we will not find
  1919. // the request to cancel.
  1920. //
  1921. pdncb = Irp->AssociatedIrp.SystemBuffer;
  1922. RtlMoveMemory( &LocalCopy, pdncb, sizeof( DNCB ) );
  1923. IF_NBDBG (NB_DEBUG_IOCANCEL) {
  1924. NbPrint(( "IoCancel Irp %lx\n", Irp ));
  1925. NbDisplayNcb(&LocalCopy);
  1926. }
  1927. #if DBG
  1928. pdncb = (PDNCB)0xDEADBEEF;
  1929. #endif
  1930. pfcb = LocalCopy.pfcb;
  1931. //
  1932. // Reference the FileObject associated with this Irp. This will stop
  1933. // the callers handle to \device\netbios from closing and therefore
  1934. // the fcb will not get deleted while we try to lock the fcb.
  1935. //
  1936. FileObject = (IoGetCurrentIrpStackLocation (Irp))->FileObject;
  1937. ObReferenceObject(FileObject);
  1938. IoReleaseCancelSpinLock( Irp->CancelIrql );
  1939. LOCK( pfcb, OldIrql );
  1940. //
  1941. // We now have exclusive access to all CB's and AB's with their associated
  1942. // lists.
  1943. //
  1944. switch ( LocalCopy.ncb_command & ~ASYNCH ) {
  1945. case NCBRECV:
  1946. ppcb = FindCb( pfcb, &LocalCopy, TRUE);
  1947. if ( ppcb != NULL ) {
  1948. List = &(*ppcb)->ReceiveList;
  1949. }
  1950. break;
  1951. case NCBRECVANY:
  1952. ppab = FindAbUsingNum( pfcb, &LocalCopy, LocalCopy.ncb_num );
  1953. if ( ppab != NULL ) {
  1954. List = &(*ppab)->ReceiveAnyList;
  1955. }
  1956. break;
  1957. case NCBDGRECVBC:
  1958. ppab = FindAbUsingNum( pfcb, &LocalCopy, MAXIMUM_ADDRESS );
  1959. if ( ppab != NULL ) {
  1960. List = &(*ppab)->ReceiveBroadcastDatagramList;
  1961. }
  1962. break;
  1963. case NCBDGRECV:
  1964. ppab = FindAbUsingNum( pfcb, &LocalCopy, LocalCopy.ncb_num );
  1965. if ( ppab != NULL ) {
  1966. List = &(*ppab)->ReceiveDatagramList;
  1967. }
  1968. break;
  1969. case NCBLANSTALERT:
  1970. List = &(pfcb->ppLana[LocalCopy.ncb_lana_num]->LanAlertList);
  1971. break;
  1972. }
  1973. if ( List != NULL ) {
  1974. // We have a list to scan for canceled pdncb's
  1975. PLIST_ENTRY Entry;
  1976. RestartScan:
  1977. for (Entry = List->Flink ;
  1978. Entry != List ;
  1979. Entry = Entry->Flink) {
  1980. PDNCB p = CONTAINING_RECORD( Entry, DNCB, ncb_next);
  1981. if ( p->irp->Cancel ) {
  1982. RemoveEntryList( &p->ncb_next );
  1983. NCB_COMPLETE( p, NRC_CMDCAN );
  1984. p->irp->IoStatus.Status = STATUS_SUCCESS;
  1985. p->irp->IoStatus.Information =
  1986. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1987. IoCompleteRequest( p->irp, IO_NETWORK_INCREMENT);
  1988. goto RestartScan;
  1989. }
  1990. }
  1991. }
  1992. UNLOCK( pfcb, OldIrql );
  1993. ObDereferenceObject(FileObject);
  1994. }