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

2032 lines
55 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. connect.c
  5. Abstract:
  6. This module contains code which defines the NetBIOS driver's
  7. connection block.
  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. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, NbCall)
  18. #pragma alloc_text(PAGE, NbListen)
  19. #pragma alloc_text(PAGE, NbCallCommon)
  20. #pragma alloc_text(PAGE, NbOpenConnection)
  21. #pragma alloc_text(PAGE, NewCb)
  22. #pragma alloc_text(PAGE, CloseConnection)
  23. #endif
  24. LARGE_INTEGER Timeout = { 0xffffffff, 0xffffffff};
  25. NTSTATUS
  26. NbCall(
  27. IN PDNCB pdncb,
  28. IN PIRP Irp,
  29. IN PIO_STACK_LOCATION IrpSp
  30. )
  31. /*++
  32. Routine Description:
  33. This routine is called to make a VC.
  34. Arguments:
  35. pdncb - Pointer to the NCB.
  36. Irp - Pointer to the request packet representing the I/O request.
  37. IrpSp - Pointer to current IRP stack frame.
  38. Return Value:
  39. The function value is the status of the operation.
  40. --*/
  41. {
  42. PFCB pfcb = IrpSp->FileObject->FsContext2;
  43. PCB pcb;
  44. PPCB ppcb;
  45. PAGED_CODE();
  46. IF_NBDBG (NB_DEBUG_CALL) {
  47. NbPrint(( "\n****** Start of NbCall ****** pdncb %lx\n", pdncb ));
  48. }
  49. LOCK_RESOURCE( pfcb );
  50. ppcb = NbCallCommon( pdncb, IrpSp );
  51. if ( ppcb == NULL ) {
  52. //
  53. // The error has been stored in the copy of the NCB. Return
  54. // success so the NCB gets copied back.
  55. //
  56. UNLOCK_RESOURCE( pfcb );
  57. return STATUS_SUCCESS;
  58. }
  59. pcb = *ppcb;
  60. pcb->Status = CALL_PENDING;
  61. if (( pdncb->ncb_command & ~ASYNCH ) == NCBCALL ) {
  62. PTA_NETBIOS_ADDRESS pConnectBlock =
  63. ExAllocatePoolWithTag ( NonPagedPool, sizeof(TA_NETBIOS_ADDRESS), 'ySBN');
  64. PTDI_ADDRESS_NETBIOS temp;
  65. if ( pConnectBlock == NULL ) {
  66. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  67. (*ppcb)->DisconnectReported = TRUE;
  68. CleanupCb( ppcb, NULL );
  69. UNLOCK_RESOURCE( pfcb );
  70. return STATUS_SUCCESS;
  71. }
  72. pConnectBlock->TAAddressCount = 1;
  73. pConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  74. pConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
  75. temp = pConnectBlock->Address[0].Address;
  76. temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  77. RtlMoveMemory( temp->NetbiosName, pdncb->ncb_callname, NCBNAMSZ );
  78. //
  79. // Post a TdiConnect to the server. This may take a long time so return
  80. // STATUS_PENDING so that the application thread gets free again if
  81. // it specified ASYNC.
  82. //
  83. pdncb->Information.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
  84. sizeof (TDI_ADDRESS_NETBIOS);
  85. pdncb->Information.RemoteAddress = pConnectBlock;
  86. } else {
  87. // XNS NETONE name call
  88. PTA_NETONE_ADDRESS pConnectBlock =
  89. ExAllocatePoolWithTag ( NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
  90. sizeof (TDI_ADDRESS_NETONE), 'xSBN' );
  91. PTDI_ADDRESS_NETONE temp;
  92. if ( pConnectBlock == NULL ) {
  93. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  94. (*ppcb)->DisconnectReported = TRUE;
  95. CleanupCb( ppcb, NULL );
  96. UNLOCK_RESOURCE( pfcb );
  97. return STATUS_SUCCESS;
  98. }
  99. pConnectBlock->TAAddressCount = 1;
  100. pConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETONE;
  101. pConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETONE);
  102. temp = pConnectBlock->Address[0].Address;
  103. temp->NetoneNameType = TDI_ADDRESS_NETONE_TYPE_UNIQUE;
  104. RtlMoveMemory( &temp->NetoneName[0], pdncb->ncb_callname, NCBNAMSZ );
  105. //
  106. // Post a TdiConnect to the server. This may take a long time so return
  107. // STATUS_PENDING so that the application thread gets free again if
  108. // it specified ASYNC.
  109. //
  110. pdncb->Information.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
  111. sizeof (TDI_ADDRESS_NETONE);
  112. pdncb->Information.RemoteAddress = pConnectBlock;
  113. }
  114. pdncb->ReturnInformation.RemoteAddress = NULL;
  115. pdncb->ReturnInformation.RemoteAddressLength = 0;
  116. pdncb->Information.UserDataLength = 0;
  117. pdncb->Information.OptionsLength = 0;
  118. TdiBuildConnect (Irp,
  119. pcb->DeviceObject,
  120. pcb->ConnectionObject,
  121. NbCallCompletion,
  122. pdncb,
  123. &Timeout, // default timeout
  124. &pdncb->Information,
  125. NULL);
  126. IoMarkIrpPending( Irp );
  127. IoCallDriver (pcb->DeviceObject, Irp);
  128. //
  129. // The transport has extracted all information from RequestInformation so we can safely
  130. // exit the current scope.
  131. //
  132. UNLOCK_RESOURCE( pfcb );
  133. return STATUS_PENDING;
  134. }
  135. NTSTATUS
  136. NbCallCompletion(
  137. IN PDEVICE_OBJECT DeviceObject,
  138. IN PIRP Irp,
  139. IN PVOID Context
  140. )
  141. /*++
  142. Routine Description:
  143. This routine completes the Irp after an attempt to perform a TdiConnect
  144. or TdiListen/TdiAccept has been returned by the transport.
  145. Arguments:
  146. DeviceObject - unused.
  147. Irp - Supplies Irp that the transport has finished processing.
  148. Context - Supplies the NCB associated with the Irp.
  149. Return Value:
  150. The final status from the operation (success or an exception).
  151. --*/
  152. {
  153. PDNCB pdncb = (PDNCB) Context;
  154. PFCB pfcb = IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext2;
  155. PPCB ppcb;
  156. NTSTATUS Status;
  157. KIRQL OldIrql; // Used when SpinLock held.
  158. IF_NBDBG (NB_DEBUG_COMPLETE | NB_DEBUG_CALL) {
  159. NbPrint( ("NbCallCompletion pdncb: %lx\n" , Context));
  160. }
  161. if ( pdncb->Information.RemoteAddress != NULL ) {
  162. ExFreePool( pdncb->Information.RemoteAddress );
  163. pdncb->Information.RemoteAddress = NULL;
  164. }
  165. if ( pdncb->ReturnInformation.RemoteAddress != NULL ) {
  166. ExFreePool( pdncb->ReturnInformation.RemoteAddress );
  167. pdncb->ReturnInformation.RemoteAddress = NULL;
  168. }
  169. // Tell application how many bytes were transferred
  170. pdncb->ncb_length = (unsigned short)Irp->IoStatus.Information;
  171. //
  172. // Tell IopCompleteRequest how much to copy back when the request
  173. // completes.
  174. //
  175. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  176. Status = Irp->IoStatus.Status;
  177. LOCK_SPINLOCK( pfcb, OldIrql );
  178. ppcb = FindCb( pfcb, pdncb, FALSE);
  179. if (( ppcb == NULL ) ||
  180. ( (*ppcb)->Status == HANGUP_PENDING )) {
  181. //
  182. // The connection has been closed.
  183. // Repair the Irp so that the NCB gets copied back.
  184. //
  185. Irp->IoStatus.Status = STATUS_SUCCESS;
  186. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  187. Status = STATUS_SUCCESS;
  188. } else {
  189. if ( NT_SUCCESS( Status ) ) {
  190. (*ppcb)->Status = SESSION_ESTABLISHED;
  191. NCB_COMPLETE( pdncb, NRC_GOODRET );
  192. } else {
  193. //
  194. // We need to close down the connection but we are at DPC level
  195. // so tell the dll to insert a hangup.
  196. //
  197. NCB_COMPLETE( pdncb, NbMakeNbError( Irp->IoStatus.Status ) );
  198. (*ppcb)->Status = SESSION_ABORTED;
  199. // repair the Irp so that the NCB gets copied back.
  200. Irp->IoStatus.Status = STATUS_HANGUP_REQUIRED;
  201. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  202. Status = STATUS_HANGUP_REQUIRED;
  203. }
  204. }
  205. if ( ppcb != NULL ) {
  206. (*ppcb)->UsersNcb = NULL;
  207. }
  208. UNLOCK_SPINLOCK( pfcb, OldIrql );
  209. IF_NBDBG (NB_DEBUG_COMPLETE | NB_DEBUG_CALL) {
  210. NbPrint( ("NbCallCompletion exit pdncb: %lx, Status %X\n", pdncb, Status ));
  211. }
  212. NbCheckAndCompleteIrp32(Irp);
  213. //
  214. // Must return a non-error status otherwise the IO system will not copy
  215. // back the NCB into the users buffer.
  216. //
  217. return Status;
  218. UNREFERENCED_PARAMETER( DeviceObject );
  219. }
  220. NTSTATUS
  221. NbListen(
  222. IN PDNCB pdncb,
  223. IN PIRP Irp,
  224. IN PIO_STACK_LOCATION IrpSp
  225. )
  226. /*++
  227. Routine Description:
  228. This routine is called to make a VC by waiting for a call.
  229. Arguments:
  230. pdncb - Pointer to the NCB.
  231. Irp - Pointer to the request packet representing the I/O request.
  232. IrpSp - Pointer to current IRP stack frame.
  233. Return Value:
  234. The function value is the status of the operation.
  235. --*/
  236. {
  237. PFCB pfcb = IrpSp->FileObject->FsContext2;
  238. PCB pcb;
  239. PPCB ppcb;
  240. PTA_NETBIOS_ADDRESS pConnectBlock;
  241. PTDI_ADDRESS_NETBIOS temp;
  242. PAGED_CODE();
  243. IF_NBDBG (NB_DEBUG_CALL) {
  244. NbPrint(( "\n****** Start of NbListen ****** pdncb %lx\n", pdncb ));
  245. }
  246. LOCK_RESOURCE( pfcb );
  247. ppcb = NbCallCommon( pdncb, IrpSp );
  248. if ( ppcb == NULL ) {
  249. //
  250. // The error has been stored in the copy of the NCB. Return
  251. // success so the NCB gets copied back.
  252. //
  253. UNLOCK_RESOURCE( pfcb );
  254. return STATUS_SUCCESS;
  255. }
  256. pcb = *ppcb;
  257. pcb->Status = LISTEN_OUTSTANDING;
  258. //
  259. // Build the listen. We either need to tell the transport which
  260. // address we are prepared to accept a call from or we need to
  261. // supply a buffer for the transport to tell us where the
  262. // call came from.
  263. //
  264. pConnectBlock = ExAllocatePoolWithTag ( NonPagedPool, sizeof(TA_NETBIOS_ADDRESS), 'zSBN');
  265. if ( pConnectBlock == NULL ) {
  266. NCB_COMPLETE( pdncb, NRC_SYSTEM );
  267. (*ppcb)->DisconnectReported = TRUE;
  268. CleanupCb( ppcb, NULL );
  269. UNLOCK_RESOURCE( pfcb );
  270. return STATUS_SUCCESS;
  271. }
  272. pConnectBlock->TAAddressCount = 1;
  273. pConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  274. temp = pConnectBlock->Address[0].Address;
  275. temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  276. pConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
  277. if ( pdncb->ncb_callname[0] == '*' ) {
  278. // If the name starts with an asterisk then we accept anyone.
  279. pdncb->ReturnInformation.RemoteAddress = pConnectBlock;
  280. pdncb->ReturnInformation.RemoteAddressLength =
  281. sizeof (TRANSPORT_ADDRESS) + sizeof (TDI_ADDRESS_NETBIOS);
  282. pdncb->Information.RemoteAddress = NULL;
  283. pdncb->Information.RemoteAddressLength = 0;
  284. } else {
  285. RtlMoveMemory( temp->NetbiosName, pdncb->ncb_callname, NCBNAMSZ );
  286. pdncb->Information.RemoteAddress = pConnectBlock;
  287. pdncb->Information.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
  288. sizeof (TDI_ADDRESS_NETBIOS);
  289. pdncb->ReturnInformation.RemoteAddress = NULL;
  290. pdncb->ReturnInformation.RemoteAddressLength = 0;
  291. }
  292. //
  293. // Post a TdiListen to the server. This may take a long time so return
  294. // STATUS_PENDING so that the application thread gets free again if
  295. // it specified ASYNC.
  296. //
  297. TdiBuildListen (Irp,
  298. pcb->DeviceObject,
  299. pcb->ConnectionObject,
  300. NbListenCompletion,
  301. pdncb,
  302. TDI_QUERY_ACCEPT,
  303. &pdncb->Information,
  304. ( pdncb->ncb_callname[0] == '*' )? &pdncb->ReturnInformation
  305. : NULL
  306. );
  307. IoMarkIrpPending( Irp );
  308. IoCallDriver (pcb->DeviceObject, Irp);
  309. UNLOCK_RESOURCE( pfcb );
  310. return STATUS_PENDING;
  311. }
  312. NTSTATUS
  313. NbListenCompletion(
  314. IN PDEVICE_OBJECT DeviceObject,
  315. IN PIRP Irp,
  316. IN PVOID Context
  317. )
  318. /*++
  319. Routine Description:
  320. This routine is called when a TdiListen has been returned by the transport.
  321. We can either reject or accept the call depending on the remote address.
  322. Arguments:
  323. DeviceObject - unused.
  324. Irp - Supplies Irp that the transport has finished processing.
  325. Context - Supplies the NCB associated with the Irp.
  326. Return Value:
  327. The final status from the operation (success or an exception).
  328. --*/
  329. {
  330. PDNCB pdncb = (PDNCB) Context;
  331. PFCB pfcb = IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext2;
  332. PCB pcb;
  333. PPCB ppcb;
  334. NTSTATUS Status;
  335. KIRQL OldIrql; // Used when SpinLock held.
  336. IF_NBDBG (NB_DEBUG_COMPLETE | NB_DEBUG_CALL) {
  337. NbPrint( ("NbListenCompletion pdncb: %lx status: %X\n" , Context, Irp->IoStatus.Status));
  338. }
  339. //
  340. // bug # : 73260
  341. //
  342. // Added check to see if Status is valid
  343. //
  344. if ( NT_SUCCESS( Irp-> IoStatus.Status ) )
  345. {
  346. if ( pdncb->Information.RemoteAddress != NULL ) {
  347. ExFreePool( pdncb->Information.RemoteAddress );
  348. pdncb->Information.RemoteAddress = NULL;
  349. } else {
  350. //
  351. // This was a listen accepting a call from any address. Return
  352. // the remote address.
  353. //
  354. PTA_NETBIOS_ADDRESS pConnectBlock;
  355. ASSERT( pdncb->ReturnInformation.RemoteAddress != NULL );
  356. pConnectBlock = pdncb->ReturnInformation.RemoteAddress;
  357. RtlMoveMemory(
  358. pdncb->ncb_callname,
  359. pConnectBlock->Address[0].Address->NetbiosName,
  360. NCBNAMSZ );
  361. ExFreePool( pdncb->ReturnInformation.RemoteAddress );
  362. pdncb->ReturnInformation.RemoteAddress = NULL;
  363. }
  364. } else {
  365. if ( pdncb->Information.RemoteAddress != NULL ) {
  366. ExFreePool( pdncb->Information.RemoteAddress );
  367. pdncb->Information.RemoteAddress = NULL;
  368. } else {
  369. ExFreePool( pdncb->ReturnInformation.RemoteAddress );
  370. pdncb->ReturnInformation.RemoteAddress = NULL;
  371. }
  372. }
  373. LOCK_SPINLOCK( pfcb, OldIrql );
  374. ppcb = FindCb( pfcb, pdncb, FALSE );
  375. if (( ppcb == NULL ) ||
  376. ( (*ppcb)->Status == HANGUP_PENDING )) {
  377. UNLOCK_SPINLOCK( pfcb, OldIrql );
  378. //
  379. // The connection has been closed.
  380. // Repair the Irp so that the NCB gets copied back.
  381. //
  382. NCB_COMPLETE( pdncb, NRC_NAMERR );
  383. Irp->IoStatus.Status = STATUS_SUCCESS;
  384. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  385. Status = STATUS_SUCCESS;
  386. }
  387. //
  388. // bug # : 70837
  389. //
  390. // Added check for cancelled listens
  391. //
  392. else if ( ( (*ppcb)-> Status == SESSION_ABORTED ) ||
  393. ( !NT_SUCCESS( Irp-> IoStatus.Status ) ) )
  394. {
  395. UNLOCK_SPINLOCK( pfcb, OldIrql );
  396. if ( (*ppcb)-> Status == SESSION_ABORTED )
  397. {
  398. NCB_COMPLETE( pdncb, NRC_CMDCAN );
  399. }
  400. else
  401. {
  402. (*ppcb)-> Status = SESSION_ABORTED;
  403. NCB_COMPLETE( pdncb, NbMakeNbError( Irp->IoStatus.Status ) );
  404. }
  405. //
  406. // repair the Irp so that the NCB gets copied back.
  407. // Tell the dll to hangup the connection.
  408. //
  409. Irp->IoStatus.Status = STATUS_HANGUP_REQUIRED;
  410. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  411. Status = STATUS_HANGUP_REQUIRED;
  412. }
  413. else
  414. {
  415. PDEVICE_OBJECT DeviceObject;
  416. pcb = *ppcb;
  417. DeviceObject = pcb-> DeviceObject;
  418. // Tell application how many bytes were transferred
  419. pdncb->ncb_length = (unsigned short)Irp->IoStatus.Information;
  420. RtlMoveMemory(
  421. &pcb->RemoteName,
  422. pdncb->ncb_callname,
  423. NCBNAMSZ );
  424. //
  425. // Tell IopCompleteRequest how much to copy back when the request
  426. // completes.
  427. //
  428. Irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  429. TdiBuildAccept (Irp,
  430. pcb->DeviceObject,
  431. pcb->ConnectionObject,
  432. NbCallCompletion,
  433. pdncb,
  434. NULL,
  435. NULL);
  436. UNLOCK_SPINLOCK( pfcb, OldIrql );
  437. IoCallDriver (DeviceObject, Irp);
  438. Status = STATUS_MORE_PROCESSING_REQUIRED;
  439. }
  440. IF_NBDBG (NB_DEBUG_COMPLETE | NB_DEBUG_CALL) {
  441. NbPrint( ("NbListenCompletion exit pdncb: %lx, Status: %X\n" , pdncb, Status));
  442. }
  443. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  444. NbCheckAndCompleteIrp32(Irp);
  445. }
  446. //
  447. // Must return a non-error status otherwise the IO system will not copy
  448. // back the NCB into the users buffer.
  449. //
  450. return Status;
  451. UNREFERENCED_PARAMETER( DeviceObject );
  452. }
  453. PPCB
  454. NbCallCommon(
  455. IN PDNCB pdncb,
  456. IN PIO_STACK_LOCATION IrpSp
  457. )
  458. /*++
  459. Routine Description:
  460. This routine contains the common components used in creating a
  461. connection either by a TdiListen or TdiCall.
  462. Arguments:
  463. pdncb - Pointer to the NCB.
  464. IrpSp - Pointer to current IRP stack frame.
  465. Return Value:
  466. The function value is the address of the pointer in the ConnectionBlocks to
  467. the connection block for this call.
  468. --*/
  469. {
  470. PPCB ppcb = NULL;
  471. PCB pcb = NULL;
  472. PAB pab;
  473. PPAB ppab;
  474. PFCB pfcb = IrpSp->FileObject->FsContext2;
  475. PIRP IIrp;
  476. KEVENT Event1;
  477. NTSTATUS Status;
  478. IO_STATUS_BLOCK Iosb1;
  479. KAPC_STATE ApcState;
  480. BOOLEAN ProcessAttached = FALSE;
  481. PAGED_CODE();
  482. //
  483. // Initialize the lsn so that if we return an error and the application
  484. // ignores it then we will not reuse a valid lsn.
  485. //
  486. pdncb->ncb_lsn = 0;
  487. ppcb = NewCb( IrpSp, pdncb );
  488. if ( ppcb == NULL ) {
  489. IF_NBDBG (NB_DEBUG_CALL) {
  490. NbPrint(( "\n FAILED on create Cb of %s\n", pdncb->ncb_name));
  491. }
  492. return NULL; // NewCb will have filled in the error code.
  493. }
  494. pcb = *ppcb;
  495. ppab = pcb->ppab;
  496. pab = *ppab;
  497. //
  498. // Create an event for the synchronous I/O requests that we'll be issuing.
  499. //
  500. KeInitializeEvent (
  501. &Event1,
  502. SynchronizationEvent,
  503. FALSE);
  504. //
  505. // Open the connection on the transport.
  506. //
  507. Status = NbOpenConnection (&pcb->ConnectionHandle, (PVOID*)&pcb->ConnectionObject, pfcb, ppcb, pdncb);
  508. if (!NT_SUCCESS(Status)) {
  509. IF_NBDBG (NB_DEBUG_CALL) {
  510. NbPrint(( "\n FAILED on open of server Connection: %X ******\n", Status ));
  511. }
  512. NCB_COMPLETE( pdncb, NbMakeNbError( Status ) );
  513. (*ppcb)->DisconnectReported = TRUE;
  514. CleanupCb( ppcb, NULL );
  515. return NULL;
  516. }
  517. IF_NBDBG (NB_DEBUG_CALL) {
  518. NbPrint(( "NbCallCommon: Associate address\n"));
  519. }
  520. pcb->DeviceObject = IoGetRelatedDeviceObject( pcb->ConnectionObject );
  521. if (PsGetCurrentProcess() != NbFspProcess) {
  522. KeStackAttachProcess(NbFspProcess, &ApcState);
  523. ProcessAttached = TRUE;
  524. }
  525. IIrp = TdiBuildInternalDeviceControlIrp (
  526. TDI_ASSOCIATE_ADDRESS,
  527. pcb->DeviceObject,
  528. pcb->ConnectionObject,
  529. &Event1,
  530. &Iosb1);
  531. TdiBuildAssociateAddress (
  532. IIrp,
  533. pcb->DeviceObject,
  534. pcb->ConnectionObject,
  535. NULL,
  536. NULL,
  537. pab->AddressHandle);
  538. Status = IoCallDriver (pcb->DeviceObject, IIrp);
  539. if (Status == STATUS_PENDING) {
  540. //
  541. // Wait for event to be signalled while ignoring alerts
  542. //
  543. do {
  544. Status = KeWaitForSingleObject(
  545. &Event1, Executive, KernelMode, TRUE, NULL
  546. );
  547. } while (Status == STATUS_ALERTED);
  548. if (!NT_SUCCESS(Status)) {
  549. IF_NBDBG (NB_DEBUG_CALL) {
  550. NbPrint(( "\n FAILED Event1 Wait: %X ******\n", Status ));
  551. }
  552. NCB_COMPLETE( pdncb, NbMakeNbError( Status ) );
  553. if (ProcessAttached) {
  554. KeUnstackDetachProcess(&ApcState);
  555. }
  556. (*ppcb)->DisconnectReported = TRUE;
  557. CleanupCb( ppcb, NULL );
  558. return NULL;
  559. }
  560. Status = Iosb1.Status;
  561. }
  562. if (ProcessAttached) {
  563. KeUnstackDetachProcess(&ApcState);
  564. }
  565. if (!NT_SUCCESS(Status)) {
  566. IF_NBDBG (NB_DEBUG_CALL) {
  567. NbPrint(( "\n AssociateAddress FAILED Status: %X ******\n", Status ));
  568. }
  569. NCB_COMPLETE( pdncb, NbMakeNbError( Status ) );
  570. (*ppcb)->DisconnectReported = TRUE;
  571. CleanupCb( ppcb, NULL );
  572. return NULL;
  573. }
  574. IF_NBDBG (NB_DEBUG_CALL) {
  575. NbPrint(( "NbCallCommon: returning ppcb: %lx\n", ppcb ));
  576. }
  577. return ppcb;
  578. }
  579. NTSTATUS
  580. NbHangup(
  581. IN PDNCB pdncb,
  582. IN PIRP Irp,
  583. IN PIO_STACK_LOCATION IrpSp
  584. )
  585. /*++
  586. Routine Description:
  587. This routine is called to hangup a VC. This cancels all receives
  588. and waits for all pending sends to complete before returning. This
  589. functionality is offered directly by the underlying TDI driver so
  590. NetBIOS just passes the Irp down to the transport.
  591. Arguments:
  592. pdncb - Pointer to the NCB.
  593. Irp - Supplies Io request packet describing the Hangup NCB.
  594. IrpSp - Pointer to current IRP stack frame.
  595. Return Value:
  596. The function value is the status of the operation.
  597. --*/
  598. {
  599. PFCB pfcb = IrpSp->FileObject->FsContext2;
  600. PPCB ppcb;
  601. KIRQL OldIrql; // Used when SpinLock held.
  602. NTSTATUS Status;
  603. LOCK( pfcb, OldIrql );
  604. pdncb->pfcb = pfcb;
  605. pdncb->irp = Irp;
  606. ppcb = FindCb( pfcb, pdncb, FALSE );
  607. if ( ppcb == NULL ) {
  608. NCB_COMPLETE( pdncb, NRC_GOODRET );
  609. UNLOCK( pfcb, OldIrql );
  610. return STATUS_SUCCESS; // Connection gone already
  611. }
  612. if ((*ppcb)->Status == SESSION_ESTABLISHED ) {
  613. NCB_COMPLETE( pdncb, NRC_GOODRET );
  614. } else {
  615. if (((*ppcb)->Status == SESSION_ABORTED ) ||
  616. ((*ppcb)->Status == HANGUP_PENDING )) {
  617. NCB_COMPLETE( pdncb, NRC_SCLOSED );
  618. } else {
  619. NCB_COMPLETE( pdncb, NRC_TOOMANY ); // try later
  620. UNLOCK( pfcb, OldIrql );;
  621. return STATUS_SUCCESS;
  622. }
  623. }
  624. (*ppcb)->Status = HANGUP_PENDING;
  625. (*ppcb)->DisconnectReported = TRUE;
  626. UNLOCK_SPINLOCK( pfcb, OldIrql );
  627. Status = CleanupCb( ppcb, pdncb );
  628. UNLOCK_RESOURCE( pfcb );
  629. return Status;
  630. }
  631. NTSTATUS
  632. NbOpenConnection (
  633. OUT PHANDLE FileHandle,
  634. OUT PVOID *Object,
  635. IN PFCB pfcb,
  636. IN PVOID ConnectionContext,
  637. IN PDNCB pdncb
  638. )
  639. /*++
  640. Routine Description:
  641. Makes a call to a remote address.
  642. Arguments:
  643. FileHandle - Pointer to where the handle to the Transport for this virtual
  644. connection should be stored.
  645. *Object - Pointer to where the file object pointer is to be stored
  646. pfcb - Supplies the fcb and therefore the DriverName for this lana.
  647. ConnectionContext - Supplies the Cb to be used with this connection on
  648. all indications from the transport. Its actually the address of
  649. the pcb in the ConnectionBlocks array for this lana.
  650. pdncb - Supplies the ncb requesting the new virtual connection.
  651. Return Value:
  652. Status of the operation.
  653. --*/
  654. {
  655. IO_STATUS_BLOCK IoStatusBlock;
  656. NTSTATUS Status;
  657. OBJECT_ATTRIBUTES ObjectAttributes;
  658. PFILE_FULL_EA_INFORMATION EaBuffer;
  659. KAPC_STATE ApcState;
  660. BOOLEAN ProcessAttached = FALSE;
  661. PAGED_CODE();
  662. InitializeObjectAttributes (
  663. &ObjectAttributes,
  664. &pfcb->pDriverName[pdncb->ncb_lana_num],
  665. 0,
  666. NULL,
  667. NULL);
  668. EaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePoolWithTag (NonPagedPool,
  669. sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  670. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  671. sizeof(CONNECTION_CONTEXT), 'eSBN' );
  672. if (EaBuffer == NULL) {
  673. return STATUS_INSUFFICIENT_RESOURCES;
  674. }
  675. EaBuffer->NextEntryOffset = 0;
  676. EaBuffer->Flags = 0;
  677. EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  678. EaBuffer->EaValueLength = sizeof (CONNECTION_CONTEXT);
  679. RtlMoveMemory( EaBuffer->EaName, TdiConnectionContext, EaBuffer->EaNameLength + 1 );
  680. RtlMoveMemory (
  681. &EaBuffer->EaName[EaBuffer->EaNameLength + 1],
  682. &ConnectionContext,
  683. sizeof (CONNECTION_CONTEXT));
  684. if (PsGetCurrentProcess() != NbFspProcess) {
  685. KeStackAttachProcess(NbFspProcess, &ApcState);
  686. ProcessAttached = TRUE;
  687. }
  688. IF_NBDBG( NB_DEBUG_CALL )
  689. {
  690. NbPrint( (
  691. "NbOpenConnection: Create file invoked on %d for \n",
  692. pdncb-> ncb_lana_num
  693. ) );
  694. NbFormattedDump( pdncb-> ncb_callname, NCBNAMSZ );
  695. }
  696. Status = ZwCreateFile (
  697. FileHandle,
  698. GENERIC_READ | GENERIC_WRITE,
  699. &ObjectAttributes, // object attributes.
  700. &IoStatusBlock, // returned status information.
  701. NULL, // block size (unused).
  702. FILE_ATTRIBUTE_NORMAL, // file attributes.
  703. 0,
  704. FILE_CREATE,
  705. 0, // create options.
  706. EaBuffer, // EA buffer.
  707. sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  708. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  709. sizeof(CONNECTION_CONTEXT) ); // EA length.
  710. ExFreePool( EaBuffer );
  711. if ( NT_SUCCESS( Status )) {
  712. Status = IoStatusBlock.Status;
  713. }
  714. if (NT_SUCCESS( Status )) {
  715. Status = ObReferenceObjectByHandle (
  716. *FileHandle,
  717. 0L,
  718. NULL,
  719. KernelMode,
  720. Object,
  721. NULL);
  722. if (!NT_SUCCESS(Status)) {
  723. NTSTATUS localstatus;
  724. IF_NBDBG( NB_DEBUG_CALL )
  725. {
  726. NbPrint( (
  727. "NbOpenConnection: error : Close file invoked for %d\n",
  728. pdncb-> ncb_lana_num
  729. ) );
  730. }
  731. localstatus = ZwClose( *FileHandle);
  732. ASSERT(NT_SUCCESS(localstatus));
  733. *FileHandle = NULL;
  734. }
  735. }
  736. if (ProcessAttached) {
  737. KeUnstackDetachProcess(&ApcState);
  738. }
  739. IF_NBDBG (NB_DEBUG_CALL) {
  740. NbPrint( ("NbOpenConnection Status:%X, IoStatus:%X.\n", Status, IoStatusBlock.Status));
  741. }
  742. if (!NT_SUCCESS( Status )) {
  743. IF_NBDBG (NB_DEBUG_CALL) {
  744. NbPrint( ("NbOpenConnection: FAILURE, status code=%X.\n", Status));
  745. }
  746. return Status;
  747. }
  748. return Status;
  749. } /* NbOpenConnection */
  750. PPCB
  751. NewCb(
  752. IN PIO_STACK_LOCATION IrpSp,
  753. IN OUT PDNCB pdncb
  754. )
  755. /*++
  756. Routine Description:
  757. Arguments:
  758. IrpSp - Pointer to current IRP stack frame.
  759. pdncb - Supplies the ncb requesting the new virtual connection.
  760. Return Value:
  761. The address of the pointer to the new Cb in the ConnectionBlocks
  762. Array.
  763. --*/
  764. {
  765. NTSTATUS Status = STATUS_SUCCESS;
  766. PFILE_OBJECT FileObject = IrpSp->FileObject;
  767. PCB pcb;
  768. PPCB ppcb = NULL;
  769. PFCB pfcb = FileObject->FsContext2;
  770. PLANA_INFO plana;
  771. int index;
  772. PPAB ppab;
  773. PAGED_CODE();
  774. if (pdncb->ncb_lana_num > pfcb->MaxLana ) {
  775. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  776. return NULL;
  777. }
  778. if (( pfcb == NULL ) ||
  779. ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  780. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  781. IF_NBDBG (NB_DEBUG_CALL) {
  782. if ( pfcb == NULL ) {
  783. NbPrint( ("NewCb pfcb==NULL\n"));
  784. } else {
  785. if ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) {
  786. NbPrint( ("NewCb pfcb->ppLana[%x]==NULL\n",
  787. pdncb->ncb_lana_num));
  788. } else {
  789. NbPrint( ("NewCb pfcb->ppLana[%x]->Status = %x\n",
  790. pdncb->ncb_lana_num,
  791. pfcb->ppLana[pdncb->ncb_lana_num]->Status));
  792. }
  793. }
  794. }
  795. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  796. return NULL;
  797. }
  798. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  799. if ( plana->ConnectionCount == plana->MaximumConnection ) {
  800. NCB_COMPLETE( pdncb, NRC_LOCTFUL );
  801. return NULL;
  802. }
  803. ppab = FindAb( pfcb, pdncb, TRUE );
  804. if ( ppab == NULL ) {
  805. //
  806. // This application is only allowed to use names that have been
  807. // addnamed by this application or the special address 0.
  808. //
  809. return NULL;
  810. }
  811. // FindAb has incremented the number of CurrentUsers for this address block.
  812. //
  813. // Find the appropriate session number to use.
  814. //
  815. index = plana->NextConnection;
  816. while ( plana->ConnectionBlocks[index] != NULL ) {
  817. index++;
  818. if ( index > MAXIMUM_CONNECTION ) {
  819. index = 1;
  820. }
  821. IF_NBDBG (NB_DEBUG_CALL) {
  822. NbPrint( ("NewCb pfcb: %lx, plana: %lx, index: %lx, ppcb: %lx, pcb: %lx\n",
  823. pfcb,
  824. pdncb->ncb_lana_num,
  825. index,
  826. &plana->ConnectionBlocks[index],
  827. plana->ConnectionBlocks[index] ));
  828. }
  829. }
  830. plana->ConnectionCount++;
  831. plana->NextConnection = index + 1;
  832. if ( plana->NextConnection > MAXIMUM_CONNECTION ) {
  833. plana->NextConnection = 1;
  834. }
  835. //
  836. // Fill in the LSN so that the application will be able
  837. // to reference this connection in the future.
  838. //
  839. pdncb->ncb_lsn = (unsigned char)index;
  840. ppcb = &plana->ConnectionBlocks[index];
  841. *ppcb = pcb = ExAllocatePoolWithTag (NonPagedPool, sizeof(CB), 'cSBN');
  842. if (pcb==NULL) {
  843. DEREFERENCE_AB(ppab);
  844. NCB_COMPLETE( pdncb, NbMakeNbError( STATUS_INSUFFICIENT_RESOURCES ) );
  845. return NULL;
  846. }
  847. pcb->ppab = ppab;
  848. pcb->ConnectionHandle = NULL;
  849. pcb->ConnectionObject = NULL;
  850. pcb->DeviceObject = NULL;
  851. pcb->pLana = plana;
  852. pcb->ReceiveIndicated = 0;
  853. pcb->DisconnectReported = FALSE;
  854. InitializeListHead(&pcb->ReceiveList);
  855. InitializeListHead(&pcb->SendList);
  856. RtlMoveMemory( &pcb->RemoteName, pdncb->ncb_callname, NCBNAMSZ);
  857. pcb->Adapter = plana;
  858. pcb->SessionNumber = (UCHAR)index;
  859. pcb->ReceiveTimeout = pdncb->ncb_rto;
  860. pcb->SendTimeout = pdncb->ncb_sto;
  861. //
  862. // Fill in the Users virtual address so we can cancel the Listen/Call
  863. // if the user desires.
  864. //
  865. pcb->UsersNcb = pdncb->users_ncb;
  866. pcb->pdncbCall = pdncb;
  867. pcb->pdncbHangup = NULL;
  868. if (( pcb->ReceiveTimeout != 0 ) ||
  869. ( pcb->SendTimeout != 0 )) {
  870. NbStartTimer( pfcb );
  871. }
  872. pcb->Signature = CB_SIGNATURE;
  873. pcb->Status = 0; // An invalid value!
  874. IF_NBDBG (NB_DEBUG_CALL) {
  875. NbPrint( ("NewCb pfcb: %lx, ppcb: %lx, pcb= %lx, lsn %lx\n",
  876. pfcb,
  877. ppcb,
  878. pcb,
  879. index));
  880. }
  881. return ppcb;
  882. } /* NewCb */
  883. NTSTATUS
  884. CleanupCb(
  885. IN PPCB ppcb,
  886. IN PDNCB pdncb OPTIONAL
  887. )
  888. /*++
  889. Routine Description:
  890. This closes the handles in the Cb and dereferences the objects.
  891. Note: Resource must be held before calling this routine.
  892. Arguments:
  893. ppcb - Address of the pointer to the Cb containing handles and objects.
  894. pdncb - Optional Address of the Hangup DNCB.
  895. Return Value:
  896. STATUS_PENDING if Hangup held due to an outstanding send. Otherwise STATUS_SUCCESS
  897. --*/
  898. {
  899. PCB pcb;
  900. PDNCB pdncbHangup;
  901. PPAB ppab;
  902. KIRQL OldIrql; // Used when SpinLock held.
  903. PFCB pfcb;
  904. PDNCB pdncbtemp;
  905. PDNCB pdncbReceiveAny;
  906. if ( ppcb == NULL ) {
  907. ASSERT( FALSE );
  908. IF_NBDBG (NB_DEBUG_CALL) {
  909. NbPrint( ("CleanupCb ppcb: %lx, pdncb: %lx\n", ppcb, pdncb));
  910. }
  911. return STATUS_SUCCESS;
  912. }
  913. pcb = *ppcb;
  914. pfcb = pcb->pLana->pFcb;
  915. LOCK_SPINLOCK( pfcb, OldIrql );
  916. ppab = (*ppcb)->ppab;
  917. if ( pcb == NULL ) {
  918. ASSERT( FALSE );
  919. IF_NBDBG (NB_DEBUG_CALL) {
  920. NbPrint( ("CleanupCb ppcb: %lx, pcb %lx, pdncb %lx\n", ppcb, pcb, pdncb));
  921. }
  922. UNLOCK_SPINLOCK( pfcb, OldIrql );
  923. return STATUS_SUCCESS;
  924. }
  925. ASSERT( pcb->Signature == CB_SIGNATURE );
  926. //
  927. // Set pcb->pdncbHangup to NULL. This prevents NbCompletionPDNCB from queueing a CleanupCb
  928. // if we Close the connection and cause sends to get returned.
  929. //
  930. pdncbHangup = pcb->pdncbHangup;
  931. pcb->pdncbHangup = NULL;
  932. IF_NBDBG (NB_DEBUG_CALL) {
  933. NbPrint( ("CleanupCb ppcb: %lx, pcb= %lx\n", ppcb, pcb));
  934. }
  935. //
  936. // If this is a Hangup (only time pdncb != NULL
  937. // and we do not have a hangup on this connection
  938. // and there are outstanding sends then delay the hangup.
  939. //
  940. if (( pdncb != NULL ) &&
  941. ( pdncbHangup == NULL ) &&
  942. ( !IsListEmpty(&pcb->SendList) )) {
  943. ASSERT(( pdncb->ncb_command & ~ASYNCH ) == NCBHANGUP );
  944. //
  945. // We must wait up to 20 seconds for the send to complete before removing the
  946. // connection.
  947. //
  948. IF_NBDBG (NB_DEBUG_CALL) {
  949. NbPrint( ("CleanupCb delaying Hangup, waiting for send to complete\n"));
  950. }
  951. pcb->pdncbHangup = pdncb;
  952. // reset retcode so that NCB_COMPLETE will process the next NCB_COMPLETE.
  953. pcb->pdncbHangup->ncb_retcode = NRC_PENDING;
  954. pdncb->tick_count = 40;
  955. UNLOCK_SPINLOCK( pfcb, OldIrql );
  956. NbStartTimer( pfcb );
  957. return STATUS_PENDING;
  958. }
  959. pcb->Status = SESSION_ABORTED;
  960. // Cancel all the receive requests for this connection.
  961. while ( (pdncbtemp = DequeueRequest( &pcb->ReceiveList)) != NULL ) {
  962. NCB_COMPLETE( pdncbtemp, NRC_SCLOSED );
  963. pdncbtemp->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  964. NbCompleteRequest( pdncbtemp->irp, STATUS_SUCCESS );
  965. pcb->DisconnectReported = TRUE;
  966. }
  967. if (pcb->DisconnectReported == FALSE) {
  968. //
  969. // If there is a receive any on the name associated with this connection then
  970. // return one receive any to the application. If there are no receive any's then
  971. // don't worry. The spec says to do this regardless of whether we have told
  972. // the application that the connection is closed using a receive or send.
  973. // Indeed the spec says to do this even if the application gave us a hangup!
  974. //
  975. if ( (pdncbReceiveAny = DequeueRequest( &(*ppab)->ReceiveAnyList)) != NULL ) {
  976. pdncbReceiveAny->ncb_num = (*ppab)->NameNumber;
  977. pdncbReceiveAny->ncb_lsn = pcb->SessionNumber;
  978. NCB_COMPLETE( pdncbReceiveAny, NRC_SCLOSED );
  979. pdncbReceiveAny->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  980. NbCompleteRequest( pdncbReceiveAny->irp, STATUS_SUCCESS );
  981. pcb->DisconnectReported = TRUE;
  982. } else {
  983. PAB pab255 = pcb->Adapter->AddressBlocks[MAXIMUM_ADDRESS];
  984. //
  985. // If there is a receive any for any name then
  986. // return one receive any to the application. If there are no receive any
  987. // any's then don't worry.
  988. //
  989. if ( (pdncbReceiveAny = DequeueRequest( &pab255->ReceiveAnyList)) != NULL ) {
  990. pdncbReceiveAny->ncb_num = (*ppab)->NameNumber;
  991. pdncbReceiveAny->ncb_lsn = pcb->SessionNumber;
  992. NCB_COMPLETE( pdncbReceiveAny, NRC_SCLOSED );
  993. pdncbReceiveAny->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  994. NbCompleteRequest( pdncbReceiveAny->irp, STATUS_SUCCESS );
  995. pcb->DisconnectReported = TRUE;
  996. }
  997. }
  998. }
  999. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1000. CloseConnection( ppcb, 20000 );
  1001. LOCK_SPINLOCK( pfcb, OldIrql );
  1002. //
  1003. // Any sends will have been returned to the caller by now because of the NtClose on the
  1004. // ConnectionHandle. Tell the caller that the hangup is complete if we have a hangup.
  1005. //
  1006. if ( pdncbHangup != NULL ) {
  1007. NCB_COMPLETE( pdncbHangup, NRC_GOODRET );
  1008. pdncbHangup->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1009. NbCompleteRequest( pdncbHangup->irp, STATUS_SUCCESS );
  1010. }
  1011. IF_NBDBG (NB_DEBUG_CALL) {
  1012. NbPrint( ("CleanupCb pcb: %lx, ppab: %lx, AddressHandle: %lx\n",
  1013. pcb,
  1014. ppab,
  1015. (*ppab)->AddressHandle));
  1016. NbFormattedDump( (PUCHAR)&(*ppab)->Name, sizeof(NAME) );
  1017. }
  1018. //
  1019. // IBM test Mif081.c states that it is not necessary to report the disconnection
  1020. // of a session if the name has already been deleted.
  1021. //
  1022. if (( pcb->DisconnectReported == TRUE ) ||
  1023. ( ((*ppab)->Status & 7 ) == DEREGISTERED )) {
  1024. pcb->Adapter->ConnectionCount--;
  1025. *ppcb = NULL;
  1026. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1027. DEREFERENCE_AB( ppab );
  1028. ExFreePool( pcb );
  1029. } else {
  1030. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1031. }
  1032. return STATUS_SUCCESS;
  1033. }
  1034. VOID
  1035. AbandonConnection(
  1036. IN PPCB ppcb
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This routine examines the connection block and attempts to find a request to
  1041. send a session abort status plus it completes the Irp with STATUS_HANGUP_REQUIRED.
  1042. It always changes the status of the connection so that further requests are correctly
  1043. rejected. Upon getting the STATUS_HANGUP_REQUIRED, the dll will submit a hangup NCB
  1044. which will call CleanupCb.
  1045. This round about method is used because of the restrictions caused by being at Dpc or Apc
  1046. level and in the wrong context when the transport indicates that the connection is to
  1047. be cleaned up.
  1048. Arguments:
  1049. ppcb - Address of the pointer to the Cb containing handles and objects.
  1050. Return Value:
  1051. None.
  1052. --*/
  1053. {
  1054. PCB pcb;
  1055. KIRQL OldIrql; // Used when SpinLock held.
  1056. PFCB pfcb;
  1057. PPAB ppab;
  1058. PDNCB pdncb;
  1059. PDNCB pdncbReceiveAny;
  1060. pcb = *ppcb;
  1061. if (pcb != NULL)
  1062. {
  1063. pfcb = pcb->pLana->pFcb;
  1064. LOCK_SPINLOCK( pfcb, OldIrql );
  1065. ASSERT( pcb->Signature == CB_SIGNATURE );
  1066. IF_NBDBG (NB_DEBUG_CALL) {
  1067. NbPrint( ("AbandonConnection ppcb: %lx, pcb= %lx\n", ppcb, pcb));
  1068. }
  1069. pcb->Status = SESSION_ABORTED;
  1070. while ( (pdncb = DequeueRequest( &pcb->ReceiveList)) != NULL ) {
  1071. pcb->DisconnectReported = TRUE;
  1072. NCB_COMPLETE( pdncb, NRC_SCLOSED );
  1073. pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1074. NbCompleteRequest( pdncb->irp, STATUS_HANGUP_REQUIRED );
  1075. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1076. return;
  1077. }
  1078. if ( pcb->pdncbHangup != NULL ) {
  1079. pcb->DisconnectReported = TRUE;
  1080. NCB_COMPLETE( pcb->pdncbHangup, NRC_SCLOSED );
  1081. pcb->pdncbHangup->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1082. NbCompleteRequest( pcb->pdncbHangup->irp, STATUS_HANGUP_REQUIRED );
  1083. pcb->pdncbHangup = NULL;
  1084. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1085. return;
  1086. }
  1087. //
  1088. // If there is a receive any on the name associated with this connection then
  1089. // return one receive any to the application.
  1090. //
  1091. ppab = (*ppcb)->ppab;
  1092. if ( (pdncbReceiveAny = DequeueRequest( &(*ppab)->ReceiveAnyList)) != NULL ) {
  1093. pdncbReceiveAny->ncb_num = (*ppab)->NameNumber;
  1094. pdncbReceiveAny->ncb_lsn = pcb->SessionNumber;
  1095. pcb->DisconnectReported = TRUE;
  1096. NCB_COMPLETE( pdncbReceiveAny, NRC_SCLOSED );
  1097. pdncbReceiveAny->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1098. NbCompleteRequest( pdncbReceiveAny->irp, STATUS_HANGUP_REQUIRED );
  1099. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1100. return;
  1101. }
  1102. //
  1103. // If there is a receive any any with the lana associated with this connection then
  1104. // return one receive any to the application. If there are no receive any's then
  1105. // don't worry.
  1106. ppab = &pcb->Adapter->AddressBlocks[MAXIMUM_ADDRESS];
  1107. if ( (pdncbReceiveAny = DequeueRequest( &(*ppab)->ReceiveAnyList)) != NULL ) {
  1108. pdncbReceiveAny->ncb_num = (*ppab)->NameNumber;
  1109. pdncbReceiveAny->ncb_lsn = pcb->SessionNumber;
  1110. pcb->DisconnectReported = TRUE;
  1111. NCB_COMPLETE( pdncbReceiveAny, NRC_SCLOSED );
  1112. pdncbReceiveAny->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  1113. NbCompleteRequest( pdncbReceiveAny->irp, STATUS_HANGUP_REQUIRED );
  1114. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1115. return;
  1116. }
  1117. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1118. }
  1119. return;
  1120. }
  1121. VOID
  1122. CloseConnection(
  1123. IN PPCB ppcb,
  1124. IN DWORD dwTimeOutInMS
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. This routine examines the connection block and attempts to close the connection
  1129. handle to the transport. This will complete all outstanding requests.
  1130. This routine assumes the spinlock is not held but the resource is.
  1131. Arguments:
  1132. ppcb - Address of the pointer to the Cb containing handles and objects.
  1133. dwTimeOutInMS - Timeout value in milliseconds for Disconnect
  1134. Return Value:
  1135. None.
  1136. --*/
  1137. {
  1138. PCB pcb;
  1139. NTSTATUS localstatus;
  1140. PAGED_CODE();
  1141. pcb = *ppcb;
  1142. ASSERT( pcb->Signature == CB_SIGNATURE );
  1143. IF_NBDBG (NB_DEBUG_CALL) {
  1144. NbPrint( ("CloseConnection ppcb: %lx, pcb= %lx\n", ppcb, pcb));
  1145. }
  1146. if ( pcb->ConnectionHandle ) {
  1147. HANDLE Handle;
  1148. Handle = pcb->ConnectionHandle;
  1149. pcb->ConnectionHandle = NULL;
  1150. //
  1151. // If we have a connection, request an orderly disconnect.
  1152. //
  1153. if ( pcb->ConnectionObject != NULL ) {
  1154. PIRP Irp;
  1155. LARGE_INTEGER DisconnectTimeout;
  1156. DisconnectTimeout.QuadPart = Int32x32To64( dwTimeOutInMS, -10000 );
  1157. Irp = IoAllocateIrp( pcb->DeviceObject->StackSize, FALSE);
  1158. //
  1159. // If we cannot allocate an Irp, the ZwClose will cause a disorderly
  1160. // disconnect.
  1161. //
  1162. if (Irp != NULL) {
  1163. TdiBuildDisconnect(
  1164. Irp,
  1165. pcb->DeviceObject,
  1166. pcb->ConnectionObject,
  1167. NULL,
  1168. NULL,
  1169. &DisconnectTimeout,
  1170. TDI_DISCONNECT_RELEASE,
  1171. NULL,
  1172. NULL);
  1173. SubmitTdiRequest(pcb->ConnectionObject, Irp);
  1174. IoFreeIrp(Irp);
  1175. }
  1176. // Remove reference put on in NbOpenConnection
  1177. ObDereferenceObject( pcb->ConnectionObject );
  1178. pcb->DeviceObject = NULL;
  1179. pcb->ConnectionObject = NULL;
  1180. }
  1181. IF_NBDBG( NB_DEBUG_CALL )
  1182. {
  1183. NbPrint( (
  1184. "CloseConnection : Close file invoked for \n"
  1185. ) );
  1186. NbFormattedDump( (PUCHAR) &pcb-> RemoteName, sizeof( NAME ) );
  1187. }
  1188. if (PsGetCurrentProcess() != NbFspProcess) {
  1189. KAPC_STATE ApcState;
  1190. KeStackAttachProcess(NbFspProcess, &ApcState);
  1191. localstatus = ZwClose( Handle);
  1192. ASSERT(NT_SUCCESS(localstatus));
  1193. KeUnstackDetachProcess(&ApcState);
  1194. } else {
  1195. localstatus = ZwClose( Handle);
  1196. ASSERT(NT_SUCCESS(localstatus));
  1197. }
  1198. }
  1199. return;
  1200. }
  1201. PPCB
  1202. FindCb(
  1203. IN PFCB pfcb,
  1204. IN PDNCB pdncb,
  1205. IN BOOLEAN IgnoreState
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. This routine uses the callers lana number and LSN to find the Cb.
  1210. Arguments:
  1211. pfcb - Supplies a pointer to the Fcb that Cb is chained onto.
  1212. pdncb - Supplies the connection id from the applications point of view.
  1213. IgnoreState - Return even if connection in error.
  1214. Return Value:
  1215. The address of the pointer to the connection block or NULL.
  1216. --*/
  1217. {
  1218. PPCB ppcb;
  1219. UCHAR Status;
  1220. IF_NBDBG (NB_DEBUG_CALL) {
  1221. NbPrint( ("FindCb pfcb: %lx, lana: %lx, lsn: %lx\n",
  1222. pfcb,
  1223. pdncb->ncb_lana_num,
  1224. pdncb->ncb_lsn));
  1225. }
  1226. if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  1227. ( pfcb == NULL ) ||
  1228. ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  1229. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED)) {
  1230. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1231. return NULL;
  1232. }
  1233. if (( pdncb->ncb_lsn > MAXIMUM_CONNECTION ) ||
  1234. ( pfcb->ppLana[pdncb->ncb_lana_num]->ConnectionBlocks[pdncb->ncb_lsn] == NULL)) {
  1235. IF_NBDBG (NB_DEBUG_CALL) {
  1236. NbPrint( (" not found\n"));
  1237. }
  1238. NCB_COMPLETE( pdncb, NRC_SNUMOUT );
  1239. return NULL;
  1240. }
  1241. ppcb = &(pfcb->ppLana[pdncb->ncb_lana_num]->ConnectionBlocks[pdncb->ncb_lsn]);
  1242. Status = (*ppcb)->Status;
  1243. //
  1244. // Hangup and session status can be requested whatever state the
  1245. // connections in. Call and Listen use FindCb only to find and modify
  1246. // the Status so they are allowed also.
  1247. //
  1248. if (( Status != SESSION_ESTABLISHED ) &&
  1249. ( !IgnoreState )) {
  1250. IF_NBDBG (NB_DEBUG_CALL) {
  1251. NbPrint( ("FindCb Status %x\n", Status));
  1252. }
  1253. if (( pdncb->ncb_retcode == NRC_PENDING ) &&
  1254. (( pdncb->ncb_command & ~ASYNCH) != NCBHANGUP ) &&
  1255. (( pdncb->ncb_command & ~ASYNCH) != NCBSSTAT ) &&
  1256. (( pdncb->ncb_command & ~ASYNCH) != NCBCALL ) &&
  1257. (( pdncb->ncb_command & ~ASYNCH) != NCALLNIU ) &&
  1258. (( pdncb->ncb_command & ~ASYNCH) != NCBLISTEN )) {
  1259. if ( Status == SESSION_ABORTED ) {
  1260. (*ppcb)->DisconnectReported = TRUE;
  1261. NCB_COMPLETE( pdncb, NRC_SCLOSED );
  1262. } else {
  1263. NCB_COMPLETE( pdncb, NRC_TOOMANY ); // Try again later
  1264. }
  1265. //
  1266. // On hangup we want to pass the connection back to give
  1267. // cleanupcb a chance to destroy the connection. For all
  1268. // other requests return NULL.
  1269. //
  1270. if (( pdncb->ncb_command & ~ASYNCH) != NCBHANGUP ) {
  1271. return NULL;
  1272. }
  1273. }
  1274. }
  1275. IF_NBDBG (NB_DEBUG_CALL) {
  1276. NbPrint( (", ppcb= %lx\n", ppcb ));
  1277. }
  1278. ASSERT( (*ppcb)->Signature == CB_SIGNATURE );
  1279. return ppcb;
  1280. }
  1281. BOOL
  1282. FindActiveSession(
  1283. IN PFCB pfcb,
  1284. IN PDNCB pdncb OPTIONAL,
  1285. IN PPAB ppab
  1286. )
  1287. /*++
  1288. Routine Description:
  1289. Arguments:
  1290. pfcb - Supplies a pointer to the callers Fcb.
  1291. pdncb - Supplies the ncb requesting the Delete Name.
  1292. ppab - Supplies (indirectly) the TDI handle to scan for.
  1293. Return Value:
  1294. TRUE iff there is an active session found using this handle.
  1295. --*/
  1296. {
  1297. PPCB ppcb = NULL;
  1298. PLANA_INFO plana = (*ppab)->pLana;
  1299. int index;
  1300. if ( ARGUMENT_PRESENT(pdncb) ) {
  1301. if ( pdncb->ncb_lana_num > pfcb->MaxLana ) {
  1302. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1303. return FALSE;
  1304. }
  1305. if (( pfcb == NULL ) ||
  1306. ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  1307. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED)) {
  1308. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1309. return FALSE;
  1310. }
  1311. }
  1312. ASSERT( pfcb->Signature == FCB_SIGNATURE );
  1313. for ( index=1 ; index <= MAXIMUM_CONNECTION; index++ ) {
  1314. if ( plana->ConnectionBlocks[index] == NULL ) {
  1315. continue;
  1316. }
  1317. IF_NBDBG (NB_DEBUG_CALL) {
  1318. NbPrint( ("FindActiveSession index:%x connections ppab: %lx = ppab: %lx state: %x\n",
  1319. index,
  1320. plana->ConnectionBlocks[index]->ppab,
  1321. ppab,
  1322. plana->ConnectionBlocks[index]->Status));
  1323. }
  1324. // Look for active sessions on this address.
  1325. if (( plana->ConnectionBlocks[index]->ppab == ppab ) &&
  1326. ( plana->ConnectionBlocks[index]->Status == SESSION_ESTABLISHED )) {
  1327. return TRUE;
  1328. }
  1329. }
  1330. return FALSE;
  1331. }
  1332. VOID
  1333. CloseListens(
  1334. IN PFCB pfcb,
  1335. IN PPAB ppab
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. Arguments:
  1340. pfcb - Supplies a pointer to the callers Fcb.
  1341. ppab - All listens using this address are to be closed.
  1342. Return Value:
  1343. none.
  1344. --*/
  1345. {
  1346. PLANA_INFO plana;
  1347. int index;
  1348. KIRQL OldIrql; // Used when SpinLock held.
  1349. ASSERT( pfcb->Signature == FCB_SIGNATURE );
  1350. plana = (*ppab)->pLana;
  1351. LOCK_SPINLOCK( pfcb, OldIrql );
  1352. for ( index=1 ; index <= MAXIMUM_CONNECTION; index++ ) {
  1353. if ( plana->ConnectionBlocks[index] == NULL ) {
  1354. continue;
  1355. }
  1356. IF_NBDBG (NB_DEBUG_CALL) {
  1357. NbPrint( ("CloseListen index:%x connections ppab: %lx = ppab: %lx state: %x\n",
  1358. index,
  1359. plana->ConnectionBlocks[index]->ppab,
  1360. ppab,
  1361. plana->ConnectionBlocks[index]->Status));
  1362. }
  1363. // Look for a listen on this address.
  1364. if (( plana->ConnectionBlocks[index]->ppab == ppab ) &&
  1365. ( plana->ConnectionBlocks[index]->Status == LISTEN_OUTSTANDING )) {
  1366. PDNCB pdncb = plana->ConnectionBlocks[index]->pdncbCall;
  1367. NCB_COMPLETE( pdncb, NRC_NAMERR );
  1368. plana->ConnectionBlocks[index]->DisconnectReported = TRUE;
  1369. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1370. CleanupCb( &plana->ConnectionBlocks[index], NULL);
  1371. LOCK_SPINLOCK( pfcb, OldIrql );
  1372. }
  1373. }
  1374. UNLOCK_SPINLOCK( pfcb, OldIrql );
  1375. }
  1376. PPCB
  1377. FindCallCb(
  1378. IN PFCB pfcb,
  1379. IN PNCB pncb,
  1380. IN UCHAR ucLana
  1381. )
  1382. /*++
  1383. Routine Description:
  1384. Arguments:
  1385. pfcb - Supplies a pointer to the callers Fcb.
  1386. pncb - Supplies the USERS VIRTUAL address CALL or LISTEN ncb to be
  1387. cancelled.
  1388. Return Value:
  1389. The address of the pointer to the connection block or NULL.
  1390. --*/
  1391. {
  1392. PPCB ppcb = NULL;
  1393. PLANA_INFO plana;
  1394. int index;
  1395. if ( ucLana > pfcb->MaxLana ) {
  1396. return NULL;
  1397. }
  1398. if (( pfcb == NULL ) ||
  1399. ( pfcb->ppLana[ucLana] == NULL ) ||
  1400. ( pfcb->ppLana[ucLana]->Status != NB_INITIALIZED)) {
  1401. return NULL;
  1402. }
  1403. ASSERT( pfcb->Signature == FCB_SIGNATURE );
  1404. plana = pfcb->ppLana[ucLana];
  1405. for ( index=1 ; index <= MAXIMUM_CONNECTION; index++ ) {
  1406. if (( plana->ConnectionBlocks[index] != NULL ) &&
  1407. ( plana->ConnectionBlocks[index]->UsersNcb == pncb )) {
  1408. return &plana->ConnectionBlocks[index];
  1409. }
  1410. }
  1411. return NULL;
  1412. }
  1413. PPCB
  1414. FindReceiveIndicated(
  1415. IN PFCB pfcb,
  1416. IN PDNCB pdncb,
  1417. IN PPAB ppab
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. Find either a connection with a receive indicated or one that has been
  1422. disconnected but not reported yet.
  1423. Arguments:
  1424. pfcb - Supplies a pointer to the callers Fcb.
  1425. pdncb - Supplies the ncb with the receive any.
  1426. ppab - Supplies (indirectly) the TDI handle to scan for.
  1427. Return Value:
  1428. PPCB - returns the connection with the indicated receive.
  1429. --*/
  1430. {
  1431. PPCB ppcb = NULL;
  1432. PLANA_INFO plana;
  1433. int index;
  1434. if (( pfcb == NULL ) ||
  1435. ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) ||
  1436. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  1437. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  1438. return NULL;
  1439. }
  1440. ASSERT( pfcb->Signature == FCB_SIGNATURE );
  1441. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  1442. for ( index=0 ; index <= MAXIMUM_CONNECTION; index++ ) {
  1443. if ( plana->ConnectionBlocks[index] == NULL ) {
  1444. continue;
  1445. }
  1446. if ( pdncb->ncb_num == MAXIMUM_ADDRESS) {
  1447. // ReceiveAny on Any address
  1448. if (( plana->ConnectionBlocks[index]->ReceiveIndicated != 0 ) ||
  1449. (( plana->ConnectionBlocks[index]->Status == SESSION_ABORTED ) &&
  1450. ( plana->ConnectionBlocks[index]->DisconnectReported == FALSE ))) {
  1451. PPAB ppab;
  1452. pdncb->ncb_lsn = (UCHAR)index;
  1453. ppab = plana->ConnectionBlocks[index]->ppab;
  1454. pdncb->ncb_num = (*ppab)->NameNumber;
  1455. return &plana->ConnectionBlocks[index];
  1456. }
  1457. } else {
  1458. if ( plana->ConnectionBlocks[index]->ppab == ppab ) {
  1459. // This connection is using the correct address.
  1460. if (( plana->ConnectionBlocks[index]->ReceiveIndicated != 0 ) ||
  1461. (( plana->ConnectionBlocks[index]->Status == SESSION_ABORTED ) &&
  1462. ( plana->ConnectionBlocks[index]->DisconnectReported == FALSE ))) {
  1463. pdncb->ncb_lsn = (UCHAR)index;
  1464. return &plana->ConnectionBlocks[index];
  1465. }
  1466. }
  1467. }
  1468. }
  1469. return NULL;
  1470. }
  1471. NTSTATUS
  1472. NbTdiDisconnectHandler (
  1473. PVOID EventContext,
  1474. PVOID ConnectionContext,
  1475. ULONG DisconnectDataLength,
  1476. PVOID DisconnectData,
  1477. ULONG DisconnectInformationLength,
  1478. PVOID DisconnectInformation,
  1479. ULONG DisconnectIndicators
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. This routine is called when a session is disconnected from a remote
  1484. machine.
  1485. Arguments:
  1486. IN PVOID EventContext,
  1487. IN PCONNECTION_CONTEXT ConnectionContext,
  1488. IN ULONG DisconnectDataLength,
  1489. IN PVOID DisconnectData,
  1490. IN ULONG DisconnectInformationLength,
  1491. IN PVOID DisconnectInformation,
  1492. IN ULONG DisconnectIndicators
  1493. Return Value:
  1494. NTSTATUS - Status of event indicator
  1495. --*/
  1496. {
  1497. IF_NBDBG (NB_DEBUG_CALL) {
  1498. PPCB ppcb = ConnectionContext;
  1499. NbPrint( ("NbTdiDisconnectHandler ppcb: %lx, pcb %lx\n", ppcb, (*ppcb)));
  1500. }
  1501. AbandonConnection( (PPCB)ConnectionContext );
  1502. return STATUS_SUCCESS;
  1503. UNREFERENCED_PARAMETER(EventContext);
  1504. UNREFERENCED_PARAMETER(DisconnectDataLength);
  1505. UNREFERENCED_PARAMETER(DisconnectData);
  1506. UNREFERENCED_PARAMETER(DisconnectInformationLength);
  1507. UNREFERENCED_PARAMETER(DisconnectInformation);
  1508. UNREFERENCED_PARAMETER(DisconnectIndicators);
  1509. }