Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1385 lines
37 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. address.c
  5. Abstract:
  6. This module contains code which defines the NetBIOS driver's
  7. address object.
  8. Author:
  9. Colin Watson (ColinW) 13-Mar-1991
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "nb.h"
  15. //nclude <zwapi.h>
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, NbAddName)
  18. #pragma alloc_text(PAGE, NbOpenAddress)
  19. #pragma alloc_text(PAGE, NbAddressClose)
  20. #pragma alloc_text(PAGE, NbSetEventHandler)
  21. #pragma alloc_text(PAGE, SubmitTdiRequest)
  22. #pragma alloc_text(PAGE, NewAb)
  23. #endif
  24. NTSTATUS
  25. NbAddName(
  26. IN PDNCB pdncb,
  27. IN PIO_STACK_LOCATION IrpSp
  28. )
  29. /*++
  30. Routine Description:
  31. This routine is called to add a name to the name table so that the
  32. name is available for listens etc. If the name is already in the table
  33. then reject the request. If an error is found by NewAb then it is
  34. recorded directly in the NCB.
  35. Arguments:
  36. pdncb - Pointer to the NCB.
  37. Irp - Pointer to the request packet representing the I/O request.
  38. IrpSp - Pointer to current IRP stack frame.
  39. Return Value:
  40. The function value is the status of the operation. This is always
  41. STATUS_SUCCESS because the operations called by this routine are all
  42. synchronous. We must never return an error status since this would
  43. prevent the ncb from being copied back.
  44. --*/
  45. {
  46. PFCB pfcb = IrpSp->FileObject->FsContext2;
  47. PSZ Name = pdncb->ncb_name;
  48. PAGED_CODE();
  49. IF_NBDBG (NB_DEBUG_ADDRESS) {
  50. NbPrint(( "\n** AAAAADDDDDDName *** pdncb %lx\n", pdncb ));
  51. }
  52. //
  53. // NewAb is used in file.c to add the reserved name. Check here
  54. // for an application using a special name.
  55. //
  56. if (( pdncb->ncb_name[0] == '*' ) ||
  57. ( pdncb->ncb_name[0] == '\0' )) {
  58. NCB_COMPLETE( pdncb, NRC_NOWILD );
  59. } else {
  60. NewAb( IrpSp, pdncb );
  61. }
  62. return STATUS_SUCCESS;
  63. }
  64. NTSTATUS
  65. NbDeleteName(
  66. IN PDNCB pdncb,
  67. IN PIO_STACK_LOCATION IrpSp
  68. )
  69. /*++
  70. Routine Description:
  71. This routine is called to delete a name. To perform this operation
  72. the AddressHandle to the transport is closed and the Address Block
  73. is deleted.
  74. Arguments:
  75. pdncb - Pointer to the NCB.
  76. Irp - Pointer to the request packet representing the I/O request.
  77. IrpSp - Pointer to current IRP stack frame.
  78. Return Value:
  79. The function value is the status of the operation.
  80. --*/
  81. {
  82. PFCB pfcb = IrpSp->FileObject->FsContext2;
  83. PPAB ppab;
  84. KIRQL OldIrql; // Used when SpinLock held.
  85. IF_NBDBG (NB_DEBUG_ADDRESS) {
  86. NbPrint( ("[NETBIOS] NbDeleteName : FCB : %lx lana: %lx Address:\n",
  87. pfcb, pdncb->ncb_lana_num ));
  88. NbFormattedDump( (PUCHAR) pdncb->ncb_name, sizeof(NAME) );
  89. }
  90. if (( pdncb->ncb_name[0] == '*' ) ||
  91. ( pdncb->ncb_name[0] == '\0' )) {
  92. NCB_COMPLETE( pdncb, NRC_NOWILD );
  93. return STATUS_SUCCESS;
  94. }
  95. LOCK( pfcb, OldIrql );
  96. ppab = FindAb( pfcb, pdncb, FALSE );
  97. if ( ppab != NULL ) {
  98. if (( (*ppab)->NameNumber == 0) ||
  99. ( (*ppab)->NameNumber == MAXIMUM_ADDRESS)) {
  100. UNLOCK( pfcb, OldIrql );
  101. NCB_COMPLETE( pdncb, NRC_NAMERR );
  102. } else {
  103. if ( ((*ppab)->Status & 0x7) != REGISTERED) {
  104. UNLOCK( pfcb, OldIrql );
  105. NCB_COMPLETE( pdncb, NRC_TOOMANY ); // Try later.
  106. } else {
  107. if ( FindActiveSession( pfcb, pdncb, ppab ) == TRUE ) {
  108. // When all the sessions close, the name will be deleted.
  109. UNLOCK_SPINLOCK( pfcb, OldIrql );
  110. CleanupAb( ppab, FALSE );
  111. UNLOCK_RESOURCE( pfcb );
  112. NCB_COMPLETE( pdncb, NRC_ACTSES );
  113. } else {
  114. UNLOCK_SPINLOCK( pfcb, OldIrql );
  115. CleanupAb( ppab, TRUE );
  116. UNLOCK_RESOURCE( pfcb );
  117. NCB_COMPLETE( pdncb, NRC_GOODRET );
  118. }
  119. }
  120. }
  121. } else {
  122. UNLOCK( pfcb, OldIrql );
  123. // FindAb has already set the completion code.
  124. }
  125. return STATUS_SUCCESS;
  126. }
  127. NTSTATUS
  128. NbOpenAddress (
  129. OUT PHANDLE FileHandle,
  130. OUT PVOID *Object,
  131. IN PUNICODE_STRING pusDeviceName,
  132. IN UCHAR LanNumber,
  133. IN PDNCB pdncb OPTIONAL
  134. )
  135. /*++
  136. Routine Description:
  137. This routine uses the transport to create an entry in the NetBIOS
  138. table with the value of "Name". It will re-use an existing entry if
  139. "Name" already exists.
  140. Note: This synchronous call may take a number of seconds. If this matters
  141. then the caller should specify ASYNCH and a post routine so that it is
  142. performed by the thread created by the netbios dll routines.
  143. If pdncb == NULL then a special handle is returned that is capable of
  144. administering the transport. For example to execute an ASTAT.
  145. Arguments:
  146. FileHandle - Pointer to where the filehandle is to be returned.
  147. *Object - Pointer to where the file object pointer is to be stored
  148. pfcb - supplies the device names for the lana number.
  149. LanNumber - supplies the network adapter to be opened.
  150. pdncb - Pointer to either an NCB or NULL.
  151. Return Value:
  152. The function value is the status of the operation.
  153. --*/
  154. {
  155. IO_STATUS_BLOCK IoStatusBlock;
  156. NTSTATUS Status;
  157. OBJECT_ATTRIBUTES ObjectAttributes;
  158. PFILE_FULL_EA_INFORMATION EaBuffer;
  159. ULONG EaLength;
  160. TA_NETBIOS_ADDRESS Address;
  161. ULONG ShareAccess;
  162. KAPC_STATE ApcState;
  163. BOOLEAN ProcessAttached = FALSE;
  164. PAGED_CODE();
  165. IF_NBDBG (NB_DEBUG_ADDRESS) {
  166. if ( pdncb ) {
  167. NbPrint( ("NbOpenAddress: Opening lana: %lx, Address:\n",
  168. LanNumber ));
  169. NbFormattedDump( pdncb->ncb_name, NCBNAMSZ );
  170. if ( pdncb->ncb_command == NCBADDBROADCAST ) {
  171. NbPrint (("NbOpenAddress: Opening Broadcast Address length: %x\n",
  172. pdncb->ncb_length));
  173. }
  174. } else {
  175. NbPrint( ("NbOpenAddress: Opening lana: %lx Control Channel\n",
  176. LanNumber));
  177. }
  178. }
  179. InitializeObjectAttributes (
  180. &ObjectAttributes,
  181. pusDeviceName,
  182. 0,
  183. NULL,
  184. NULL);
  185. if ( ARGUMENT_PRESENT( pdncb ) ) {
  186. EaLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  187. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  188. sizeof(TA_NETBIOS_ADDRESS); // EA length
  189. EaBuffer = (PFILE_FULL_EA_INFORMATION)
  190. ExAllocatePoolWithTag( NonPagedPool, EaLength, 'eSBN' );
  191. if (EaBuffer == NULL) {
  192. return STATUS_INSUFFICIENT_RESOURCES;
  193. }
  194. EaBuffer->NextEntryOffset = 0;
  195. EaBuffer->Flags = 0;
  196. EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  197. EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS);
  198. RtlMoveMemory( EaBuffer->EaName, TdiTransportAddress, EaBuffer->EaNameLength + 1 );
  199. //
  200. // Create a copy of the NETBIOS address descriptor in a local
  201. // first, in order to avoid alignment problems.
  202. //
  203. Address.TAAddressCount = 1;
  204. Address.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  205. if ( pdncb->ncb_command == NCBADDBROADCAST ) {
  206. Address.Address[0].AddressLength = pdncb->ncb_length;
  207. } else {
  208. Address.Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
  209. }
  210. if (((pdncb->ncb_command & ~ASYNCH) == NCBADDNAME) ||
  211. ((pdncb->ncb_command & ~ASYNCH) == NCBQUICKADDNAME)) {
  212. ShareAccess = 0; // Exclusive access
  213. if ((pdncb->ncb_command & ~ASYNCH) == NCBQUICKADDNAME) {
  214. Address.Address[0].Address[0].NetbiosNameType =
  215. TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE;
  216. } else {
  217. Address.Address[0].Address[0].NetbiosNameType =
  218. TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  219. }
  220. } else {
  221. if ((pdncb->ncb_command & ~ASYNCH) == NCBADDRESERVED) {
  222. //
  223. // NB30 non-conformance!
  224. // We allow multiple applications to use name number 1. This is so that we can
  225. // conveniently run multiple dos applications which all have address 1.
  226. //
  227. ShareAccess = FILE_SHARE_WRITE; // Non-exclusive access
  228. Address.Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  229. } else {
  230. // Group names and Broadcast addresses.
  231. ShareAccess = FILE_SHARE_WRITE; // Non-exclusive access
  232. if ((pdncb->ncb_command & ~ASYNCH) == NCBQUICKADDGRNAME) {
  233. Address.Address[0].Address[0].NetbiosNameType =
  234. TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP;
  235. } else {
  236. Address.Address[0].Address[0].NetbiosNameType =
  237. TDI_ADDRESS_NETBIOS_TYPE_GROUP;
  238. }
  239. }
  240. }
  241. RtlMoveMemory(
  242. Address.Address[0].Address[0].NetbiosName,
  243. pdncb->ncb_name,
  244. NCBNAMSZ
  245. );
  246. RtlMoveMemory (
  247. &EaBuffer->EaName[EaBuffer->EaNameLength + 1],
  248. &Address,
  249. sizeof(TA_NETBIOS_ADDRESS)
  250. );
  251. } else {
  252. ShareAccess = FILE_SHARE_WRITE; // Non-exclusive access
  253. EaBuffer = NULL;
  254. EaLength = 0;
  255. }
  256. if (PsGetCurrentProcess() != NbFspProcess) {
  257. KeStackAttachProcess(NbFspProcess, &ApcState);
  258. ProcessAttached = TRUE;
  259. }
  260. IF_NBDBG( NB_DEBUG_ADDRESS )
  261. {
  262. if ( ARGUMENT_PRESENT( pdncb ) )
  263. {
  264. NbPrint( (
  265. "NbOpenAddress : Create file invoked on lana for : %d\n",
  266. pdncb-> ncb_lana_num
  267. ) );
  268. NbFormattedDump( pdncb-> ncb_name, NCBNAMSZ );
  269. }
  270. else
  271. {
  272. NbPrint( (
  273. "NbOpenAddress : Create file invoked for \n"
  274. ) );
  275. NbPrint( ( "Control channel\n" ) );
  276. }
  277. }
  278. Status = ZwCreateFile (
  279. FileHandle,
  280. GENERIC_READ | GENERIC_WRITE, // desired access.
  281. &ObjectAttributes, // object attributes.
  282. &IoStatusBlock, // returned status information.
  283. NULL, // Allocation size (unused).
  284. FILE_ATTRIBUTE_NORMAL, // file attributes.
  285. ShareAccess,
  286. FILE_CREATE,
  287. 0, // create options.
  288. EaBuffer,
  289. EaLength
  290. );
  291. if ( NT_SUCCESS( Status )) {
  292. Status = IoStatusBlock.Status;
  293. }
  294. // Obtain a referenced pointer to the file object.
  295. if (NT_SUCCESS( Status )) {
  296. Status = ObReferenceObjectByHandle (
  297. *FileHandle,
  298. 0,
  299. NULL,
  300. KernelMode,
  301. Object,
  302. NULL
  303. );
  304. if (!NT_SUCCESS(Status)) {
  305. NTSTATUS localstatus;
  306. IF_NBDBG( NB_DEBUG_ADDRESS )
  307. {
  308. if ( ARGUMENT_PRESENT( pdncb ) )
  309. {
  310. NbPrint( (
  311. "NbOpenAddress : error : file closed on lana %d for \n",
  312. pdncb-> ncb_lana_num
  313. ) );
  314. NbFormattedDump( pdncb-> ncb_name, NCBNAMSZ );
  315. }
  316. else
  317. {
  318. NbPrint( (
  319. "NbOpenAddress : error : file closed on lana for \n"
  320. ) );
  321. NbPrint( ( "Control channel\n" ) );
  322. }
  323. }
  324. localstatus = ZwClose( *FileHandle);
  325. ASSERT(NT_SUCCESS(localstatus));
  326. *FileHandle = NULL;
  327. }
  328. }
  329. if (ProcessAttached) {
  330. KeUnstackDetachProcess(&ApcState);
  331. }
  332. if ( EaBuffer ) {
  333. ExFreePool( EaBuffer );
  334. }
  335. IF_NBDBG (NB_DEBUG_ADDRESS ) {
  336. NbPrint( ("NbOpenAddress Status:%X, IoStatus:%X.\n", Status, IoStatusBlock.Status));
  337. }
  338. if ( NT_SUCCESS( Status )) {
  339. Status = IoStatusBlock.Status;
  340. }
  341. if (!NT_SUCCESS( Status )) {
  342. IF_NBDBG (NB_DEBUG_ADDRESS) {
  343. NbPrint( ("NbOpenAddress: FAILURE, status code=%X.\n", Status));
  344. }
  345. return Status;
  346. }
  347. return Status;
  348. }
  349. PAB
  350. NewAb(
  351. IN PIO_STACK_LOCATION IrpSp,
  352. IN OUT PDNCB pdncb
  353. )
  354. /*++
  355. Routine Description:
  356. Arguments:
  357. `
  358. IrpSp - Pointer to current IRP stack frame.
  359. pdncb - Pointer to the ncb being processed.
  360. Return Value:
  361. The new Cb.
  362. --*/
  363. {
  364. NTSTATUS Status = STATUS_SUCCESS;
  365. PFILE_OBJECT FileObject = IrpSp->FileObject;
  366. PAB pab;
  367. PFCB pfcb = FileObject->FsContext2;
  368. PLANA_INFO plana;
  369. int index;
  370. ULONG NameLength;
  371. UNICODE_STRING usDeviceName;
  372. HANDLE hFileHandle = NULL;
  373. PFILE_OBJECT pfoFileObject = NULL;
  374. PAGED_CODE();
  375. RtlInitUnicodeString( &usDeviceName, NULL);
  376. KeEnterCriticalRegion();
  377. // Prevent resets while we add the name
  378. ExAcquireResourceSharedLite ( &pfcb->AddResource, TRUE );
  379. LOCK_RESOURCE( pfcb );
  380. IF_NBDBG (NB_DEBUG_ADDRESS) {
  381. NbPrint( ("[NETBIOS] NewAb: FCB : %lx lana: %lx Address:\n", pfcb,
  382. pdncb->ncb_lana_num ));
  383. NbFormattedDump( (PUCHAR) pdncb->ncb_name, sizeof(NAME) );
  384. }
  385. if ( ( pfcb == NULL ) ||
  386. ( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  387. ( pfcb-> pDriverName[ pdncb-> ncb_lana_num ].MaximumLength == 0 ) ||
  388. ( pfcb-> pDriverName[ pdncb-> ncb_lana_num ].Buffer == NULL ) ) {
  389. // no such adapter
  390. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  391. UNLOCK_RESOURCE( pfcb );
  392. ExReleaseResourceLite( &pfcb->AddResource );
  393. KeLeaveCriticalRegion();
  394. return NULL;
  395. }
  396. if ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) {
  397. // adapter not installed
  398. NCB_COMPLETE( pdncb, NRC_ENVNOTDEF );
  399. UNLOCK_RESOURCE( pfcb );
  400. ExReleaseResourceLite( &pfcb->AddResource );
  401. KeLeaveCriticalRegion();
  402. return NULL;
  403. }
  404. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  405. if ( pdncb->ncb_command == NCBADDRESERVED ) {
  406. index = 1;
  407. NameLength = NCBNAMSZ;
  408. } else {
  409. if ( pdncb->ncb_command == NCBADDBROADCAST ) {
  410. index = MAXIMUM_ADDRESS;
  411. NameLength = pdncb->ncb_length;
  412. } else {
  413. //
  414. // Ensure that the user has not added too many names or attempted to
  415. // add the same name twice. If not then scan the address table looking
  416. // for the next available slot.
  417. //
  418. IF_NBDBG (NB_DEBUG_ADDRESS) {
  419. NbPrint( ("NewAb: AddressCount: %lx, MaximumAddress %lx\n",
  420. plana->AddressCount,
  421. plana->MaximumAddresses ));
  422. }
  423. //
  424. // If the application has added the number of names requested
  425. // or has filled the table, refuse the request.
  426. //
  427. if ( plana->MaximumAddresses == plana->AddressCount) {
  428. NCB_COMPLETE( pdncb, NRC_NAMTFUL );
  429. UNLOCK_RESOURCE( pfcb );
  430. ExReleaseResourceLite( &pfcb->AddResource );
  431. KeLeaveCriticalRegion();
  432. return NULL;
  433. }
  434. //
  435. // Scan the name table and ensure that the name isn't already
  436. // there.
  437. //
  438. if (( FindAb(pfcb, pdncb, FALSE) != NULL) ||
  439. ( pdncb->ncb_retcode != NRC_NOWILD)) {
  440. //
  441. // error is set to DUPNAME iff FindAb found the name
  442. // in all other cases FindAb sets the error code and sets
  443. // returns the address block.
  444. //
  445. NCB_COMPLETE( pdncb, NRC_DUPNAME );
  446. UNLOCK_RESOURCE( pfcb );
  447. ExReleaseResourceLite( &pfcb->AddResource );
  448. KeLeaveCriticalRegion();
  449. return NULL;
  450. }
  451. //
  452. // Find the appropriate name number to use.
  453. //
  454. index = plana->NextAddress;
  455. while ( plana->AddressBlocks[index] != NULL ) {
  456. index++;
  457. if ( index == MAXIMUM_ADDRESS ) {
  458. index = 2;
  459. }
  460. }
  461. // reset retcode so that NCB_COMPLETE will process the NCB.
  462. pdncb->ncb_retcode = NRC_PENDING;
  463. NameLength = NCBNAMSZ;
  464. }
  465. }
  466. if ( plana->AddressBlocks[index] != NULL ) {
  467. NCB_COMPLETE( pdncb, NRC_DUPNAME );
  468. UNLOCK_RESOURCE( pfcb );
  469. ExReleaseResourceLite( &pfcb->AddResource );
  470. KeLeaveCriticalRegion();
  471. return NULL;
  472. }
  473. pab = ExAllocatePoolWithTag (NonPagedPool, sizeof(AB), 'aSBN');
  474. if (pab==NULL) {
  475. NCB_COMPLETE( pdncb, NbMakeNbError( STATUS_INSUFFICIENT_RESOURCES ) );
  476. UNLOCK_RESOURCE( pfcb );
  477. ExReleaseResourceLite( &pfcb->AddResource );
  478. KeLeaveCriticalRegion();
  479. return NULL;
  480. }
  481. pab->AddressHandle = NULL;
  482. pab->AddressObject = NULL;
  483. pab->DeviceObject = NULL;
  484. pab->NameNumber = (UCHAR)index;
  485. pab->pLana = plana;
  486. InitializeListHead(&pab->ReceiveAnyList);
  487. InitializeListHead(&pab->ReceiveDatagramList);
  488. InitializeListHead(&pab->ReceiveBroadcastDatagramList);
  489. pab->NameLength = (UCHAR)NameLength;
  490. RtlMoveMemory( &pab->Name, pdncb->ncb_name, NCBNAMSZ);
  491. if (((pdncb->ncb_command & ~ASYNCH) == NCBADDNAME) ||
  492. ((pdncb->ncb_command & ~ASYNCH) == NCBQUICKADDNAME)) {
  493. pab->Status = REGISTERING | UNIQUE_NAME;
  494. } else {
  495. pab->Status = REGISTERING | GROUP_NAME;
  496. }
  497. pab->CurrentUsers = 1;
  498. plana->AddressBlocks[index] = pab;
  499. pab->Signature = AB_SIGNATURE;
  500. if (( pdncb->ncb_command != NCBADDRESERVED ) &&
  501. ( pdncb->ncb_command != NCBADDBROADCAST )) {
  502. plana->AddressCount++;
  503. plana->NextAddress = index + 1;
  504. if ( plana->NextAddress == MAXIMUM_ADDRESS ) {
  505. plana->NextAddress = 2;
  506. }
  507. }
  508. Status = AllocateAndCopyUnicodeString(
  509. &usDeviceName, &pfcb-> pDriverName[ pdncb-> ncb_lana_num ]
  510. );
  511. if ( !NT_SUCCESS( Status ) )
  512. {
  513. NCB_COMPLETE( pdncb, NRC_NORESOURCES);
  514. ExFreePool( pab );
  515. plana->AddressBlocks[index] = NULL;
  516. if (( pdncb->ncb_command != NCBADDRESERVED ) &&
  517. ( pdncb->ncb_command != NCBADDBROADCAST )) {
  518. plana->AddressCount--;
  519. }
  520. UNLOCK_RESOURCE( pfcb );
  521. ExReleaseResourceLite( &pfcb->AddResource );
  522. KeLeaveCriticalRegion();
  523. return NULL;
  524. }
  525. // Unlock so other Ncb's can be processed while adding the name.
  526. UNLOCK_RESOURCE( pfcb );
  527. Status = NbOpenAddress (
  528. &hFileHandle,
  529. (PVOID *)&pfoFileObject,
  530. &usDeviceName,
  531. pdncb->ncb_lana_num,
  532. pdncb
  533. );
  534. LOCK_RESOURCE( pfcb );
  535. //
  536. // In the interval when no locks were held it is possible that
  537. // the Lana could have been unbound. Verify that Lana is still
  538. // present before accessing it.
  539. //
  540. if (!NT_SUCCESS(Status)) {
  541. IF_NBDBG (NB_DEBUG_ADDRESS) {
  542. NbPrint(( "\n FAILED on open of %s %X ******\n",
  543. pdncb->ncb_name,
  544. Status ));
  545. }
  546. if ( pfcb->ppLana[pdncb->ncb_lana_num] == plana )
  547. {
  548. //
  549. // Lana is still available. Do normal error processing
  550. //
  551. NCB_COMPLETE( pdncb, NbMakeNbError( Status ) );
  552. ExFreePool( pab );
  553. plana->AddressBlocks[index] = NULL;
  554. if (( pdncb->ncb_command != NCBADDRESERVED ) &&
  555. ( pdncb->ncb_command != NCBADDBROADCAST )) {
  556. plana->AddressCount--;
  557. }
  558. }
  559. UNLOCK_RESOURCE( pfcb );
  560. ExReleaseResourceLite( &pfcb->AddResource );
  561. KeLeaveCriticalRegion();
  562. if ( usDeviceName.Buffer != NULL )
  563. {
  564. ExFreePool( usDeviceName.Buffer );
  565. }
  566. return NULL;
  567. }
  568. else
  569. {
  570. //
  571. // NbOpenAddress succeeded. Make sure Lana is still there.
  572. //
  573. if ( plana == pfcb->ppLana[pdncb->ncb_lana_num] )
  574. {
  575. //
  576. // assume if lana is uncahnged pab points to a valid address
  577. // block entry. Update the fields.
  578. //
  579. pab-> AddressHandle = hFileHandle;
  580. pab-> AddressObject = pfoFileObject;
  581. }
  582. else
  583. {
  584. //
  585. // Lana presumed to be removed on account of an unbind.
  586. //
  587. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  588. UNLOCK_RESOURCE( pfcb );
  589. ExReleaseResourceLite( &pfcb->AddResource );
  590. KeLeaveCriticalRegion();
  591. NbAddressClose( hFileHandle, (PVOID) pfoFileObject );
  592. if ( usDeviceName.Buffer != NULL )
  593. {
  594. ExFreePool( usDeviceName.Buffer );
  595. }
  596. return NULL;
  597. }
  598. }
  599. // Inform the application of the address number.
  600. pdncb->ncb_num = (UCHAR) index;
  601. //
  602. // Register the event handlers for this address.
  603. //
  604. // Get the address of the device object for the endpoint.
  605. pab->DeviceObject = IoGetRelatedDeviceObject(pab->AddressObject);
  606. //
  607. // No connections are made using the broadcast address so don't register disconnect or
  608. // receive indication handlers. The ReceiveDatagram handler will get registered if the
  609. // application requests a receive broadcast datagram. This will cut down the cpu load
  610. // when the application is not interested in broadcasts. We always register the error
  611. // indication handler on the broadcast address because it is the only address which is
  612. // always open to the transport.
  613. //
  614. if ( pdncb->ncb_command != NCBADDBROADCAST ) {
  615. Status = NbSetEventHandler( pab->DeviceObject,
  616. pab->AddressObject,
  617. TDI_EVENT_RECEIVE,
  618. (PVOID)NbTdiReceiveHandler,
  619. pab);
  620. ASSERT( NT_SUCCESS(Status) || (Status == STATUS_INVALID_DEVICE_STATE) || (Status == STATUS_INSUFFICIENT_RESOURCES));
  621. Status = NbSetEventHandler( pab->DeviceObject,
  622. pab->AddressObject,
  623. TDI_EVENT_DISCONNECT,
  624. (PVOID)NbTdiDisconnectHandler,
  625. pab);
  626. ASSERT( NT_SUCCESS(Status) || (Status == STATUS_INVALID_DEVICE_STATE) || (Status == STATUS_INSUFFICIENT_RESOURCES));
  627. Status = NbSetEventHandler( pab->DeviceObject,
  628. pab->AddressObject,
  629. TDI_EVENT_RECEIVE_DATAGRAM,
  630. (PVOID)NbTdiDatagramHandler,
  631. pab);
  632. ASSERT( NT_SUCCESS(Status) || (Status == STATUS_INVALID_DEVICE_STATE) || (Status == STATUS_INSUFFICIENT_RESOURCES));
  633. pab->ReceiveDatagramRegistered = TRUE;
  634. } else {
  635. Status = NbSetEventHandler( pab->DeviceObject,
  636. pab->AddressObject,
  637. TDI_EVENT_ERROR,
  638. (PVOID)NbTdiErrorHandler,
  639. plana);
  640. ASSERT( NT_SUCCESS(Status) || (Status == STATUS_INVALID_DEVICE_STATE) || (Status == STATUS_INSUFFICIENT_RESOURCES));
  641. pab->ReceiveDatagramRegistered = FALSE;
  642. }
  643. pab->Status |= REGISTERED;
  644. UNLOCK_RESOURCE( pfcb );
  645. ExReleaseResourceLite( &pfcb->AddResource );
  646. KeLeaveCriticalRegion();
  647. if ( usDeviceName.Buffer != NULL )
  648. {
  649. ExFreePool( usDeviceName.Buffer );
  650. }
  651. NCB_COMPLETE( pdncb, NRC_GOODRET );
  652. return pab;
  653. }
  654. VOID
  655. CleanupAb(
  656. IN PPAB ppab,
  657. IN BOOLEAN CloseAddress
  658. )
  659. /*++
  660. Routine Description:
  661. This closes the handles in the Ab and deletes the Address Block.
  662. During this routine we need the spinlock held to prevent an indication accessing
  663. a Receive while we are cancelling it.
  664. Note: Resource must be held before calling this routine.
  665. Arguments:
  666. pab - Address of the pointer to the Ab to be destroyed.
  667. CloseAddress - TRUE if Address block is to be destroyed immediately.
  668. Return Value:
  669. nothing.
  670. --*/
  671. {
  672. PAB pab = *ppab;
  673. PAB pab255;
  674. PFCB pfcb = (*ppab)->pLana->pFcb;
  675. PLANA_INFO plana = (*ppab)->pLana;
  676. KIRQL OldIrql; // Used when SpinLock held.
  677. PLIST_ENTRY ReceiveEntry;
  678. LOCK_SPINLOCK( pfcb, OldIrql );
  679. ASSERT( pab->Signature == AB_SIGNATURE );
  680. IF_NBDBG (NB_DEBUG_ADDRESS) {
  681. NbPrint( ("CleanupAb ppab: %lx, pab: %lx, CurrentUsers: %lx, State: %x\n",
  682. ppab,
  683. pab,
  684. pab->CurrentUsers,
  685. pab->Status));
  686. NbFormattedDump( (PUCHAR)&pab->Name, sizeof(NAME) );
  687. }
  688. if ( (pab->Status & 0x7) != DEREGISTERED ) {
  689. PDNCB pdncb;
  690. pab->Status |= DEREGISTERED;
  691. //
  692. // This is the first time through so cancel all the receive datagram
  693. // requests for this address.
  694. while ( (pdncb = DequeueRequest( &pab->ReceiveDatagramList)) != NULL ) {
  695. UNLOCK_SPINLOCK( pfcb, OldIrql );
  696. NCB_COMPLETE( pdncb, NRC_NAMERR );
  697. pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  698. NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
  699. LOCK_SPINLOCK( pfcb, OldIrql );
  700. }
  701. while ( (pdncb = DequeueRequest( &pab->ReceiveBroadcastDatagramList)) != NULL ) {
  702. UNLOCK_SPINLOCK( pfcb, OldIrql );
  703. NCB_COMPLETE( pdncb, NRC_NAMERR );
  704. pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  705. NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
  706. LOCK_SPINLOCK( pfcb, OldIrql );
  707. }
  708. while ( (pdncb = DequeueRequest( &pab->ReceiveAnyList)) != NULL ) {
  709. UNLOCK_SPINLOCK( pfcb, OldIrql );
  710. NCB_COMPLETE( pdncb, NRC_NAMERR );
  711. pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  712. NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
  713. LOCK_SPINLOCK( pfcb, OldIrql );
  714. }
  715. // The IBM Mif081 test requires ReceiveBroadcast Any with this name to be cancelled.
  716. pab255 = plana->AddressBlocks[MAXIMUM_ADDRESS];
  717. //
  718. // check for null pointer. Added to fix stress bug
  719. //
  720. // V Raman
  721. //
  722. if ( pab255 != NULL )
  723. {
  724. ReceiveEntry = pab255->ReceiveBroadcastDatagramList.Flink;
  725. while ( ReceiveEntry != &pab255->ReceiveBroadcastDatagramList ) {
  726. PLIST_ENTRY NextReceiveEntry = ReceiveEntry->Flink;
  727. PDNCB pdncb = CONTAINING_RECORD( ReceiveEntry, DNCB, ncb_next);
  728. if ( pab->NameNumber == pdncb->ncb_num ) {
  729. PIRP Irp;
  730. RemoveEntryList( &pdncb->ncb_next );
  731. Irp = pdncb->irp;
  732. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  733. //
  734. // Remove the cancel request for this IRP. If its cancelled then its
  735. // ok to just process it because we will be returning it to the caller.
  736. //
  737. Irp->Cancel = FALSE;
  738. IoSetCancelRoutine(Irp, NULL);
  739. IoReleaseCancelSpinLock(Irp->CancelIrql);
  740. UNLOCK_SPINLOCK( pfcb, OldIrql );
  741. NCB_COMPLETE( pdncb, NRC_NAMERR );
  742. pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  743. NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
  744. LOCK_SPINLOCK( pfcb, OldIrql );
  745. }
  746. ReceiveEntry = NextReceiveEntry;
  747. }
  748. }
  749. UNLOCK_SPINLOCK( pfcb, OldIrql );
  750. CloseListens( pfcb, ppab );
  751. LOCK_SPINLOCK( pfcb, OldIrql );
  752. }
  753. UNLOCK_SPINLOCK( pfcb, OldIrql );
  754. if ( ( pab->AddressHandle != NULL ) &&
  755. (( CloseAddress == TRUE ) || ( pab->CurrentUsers == 1 )) ){
  756. IF_NBDBG( NB_DEBUG_ADDRESS )
  757. {
  758. NbPrint( (
  759. "CleanupAb : Close file invoked for \n"
  760. ) );
  761. NbFormattedDump( (PUCHAR) &pab-> Name, sizeof( NAME ) );
  762. }
  763. NbAddressClose( pab->AddressHandle, pab->AddressObject );
  764. pab->AddressHandle = NULL;
  765. }
  766. DEREFERENCE_AB(ppab);
  767. }
  768. VOID
  769. NbAddressClose(
  770. IN HANDLE AddressHandle,
  771. IN PVOID Object
  772. )
  773. /*++
  774. Routine Description:
  775. Remove close the handle and dereference the address.
  776. Arguments:
  777. AddressHandle
  778. Object
  779. Return Value:
  780. None.
  781. --*/
  782. {
  783. NTSTATUS localstatus;
  784. KAPC_STATE ApcState;
  785. PAGED_CODE();
  786. ObDereferenceObject( Object );
  787. if (PsGetCurrentProcess() != NbFspProcess) {
  788. KeStackAttachProcess(NbFspProcess, &ApcState);
  789. localstatus = ZwClose( AddressHandle);
  790. ASSERT(NT_SUCCESS(localstatus));
  791. KeUnstackDetachProcess(&ApcState);
  792. } else {
  793. localstatus = ZwClose( AddressHandle);
  794. ASSERT(NT_SUCCESS(localstatus));
  795. }
  796. }
  797. PPAB
  798. FindAb(
  799. IN PFCB pfcb,
  800. IN PDNCB pdncb,
  801. IN BOOLEAN IncrementUsers
  802. )
  803. /*++
  804. Routine Description:
  805. This routine uses the callers lana number and Name to find the Address
  806. Block that corresponds to the Ncb. Note, it returns the address of the
  807. relevant plana->AddressBlocks entry so that deletion of the address
  808. block is simpler.
  809. Arguments:
  810. pfcb - Supplies a pointer to the Fcb that Ab is chained onto.
  811. pdncb - Supplies the connection id from the applications point of view.
  812. IncrementUsers - TRUE iff performing a listen or call so increment CurrentUsers
  813. Return Value:
  814. Address of the pointer to the address block or NULL.
  815. --*/
  816. {
  817. PLANA_INFO plana;
  818. PAB pab;
  819. int index;
  820. if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  821. ( pfcb == NULL ) ||
  822. ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL) ||
  823. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  824. IF_NBDBG (NB_DEBUG_ADDRESS) {
  825. NbPrint( ("FindAb pfcb: %lx, lana: %lx Failed, returning NULL\n",
  826. pfcb,
  827. pdncb->ncb_lana_num));
  828. }
  829. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  830. return NULL;
  831. }
  832. ASSERT( pfcb->Signature == FCB_SIGNATURE );
  833. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  834. IF_NBDBG (NB_DEBUG_ADDRESS) {
  835. NbPrint( ("FindAb pfcb: %lx, lana: %lx, lsn: %lx\n",
  836. pfcb,
  837. pdncb->ncb_lana_num,
  838. pdncb->ncb_lsn));
  839. }
  840. for ( index = 0; index <= MAXIMUM_ADDRESS; index++ ) {
  841. pab = plana->AddressBlocks[index];
  842. if (( pab != NULL ) &&
  843. (RtlEqualMemory( &pab->Name, pdncb->ncb_name, NCBNAMSZ))) {
  844. ASSERT( pab->Signature == AB_SIGNATURE );
  845. IF_NBDBG (NB_DEBUG_ADDRESS) {
  846. NbPrint( ("ppab %lx, pab: %lx, state:%x\n",
  847. &plana->AddressBlocks[index],
  848. plana->AddressBlocks[index],
  849. pab->Status));
  850. NbFormattedDump( (PUCHAR)&pab->Name, sizeof(NAME) );
  851. }
  852. if ( (pab->Status & 0x07) != REGISTERED ) {
  853. NCB_COMPLETE( pdncb, NRC_NOWILD );
  854. //
  855. // The name is in a bad state. Tell NewAb not to add the name by
  856. // returning non-null. Don't reference the AB.
  857. //
  858. if (( (pdncb->ncb_command & ~ ASYNCH) == NCBADDNAME ) ||
  859. ( (pdncb->ncb_command & ~ ASYNCH) == NCBQUICKADDNAME ) ||
  860. ( (pdncb->ncb_command & ~ ASYNCH) == NCBQUICKADDGRNAME ) ||
  861. ( (pdncb->ncb_command & ~ ASYNCH) == NCBADDGRNAME )) {
  862. return &plana->AddressBlocks[index];
  863. } else {
  864. // Not NewAb so return Null as usual.
  865. return NULL;
  866. }
  867. }
  868. if ( IncrementUsers == TRUE ) {
  869. REFERENCE_AB(pab);
  870. }
  871. return &plana->AddressBlocks[index];
  872. }
  873. }
  874. IF_NBDBG (NB_DEBUG_ADDRESS) {
  875. NbPrint( ("Failed return NULL\n"));
  876. }
  877. NCB_COMPLETE( pdncb, NRC_NOWILD );
  878. return NULL;
  879. }
  880. PPAB
  881. FindAbUsingNum(
  882. IN PFCB pfcb,
  883. IN PDNCB pdncb,
  884. IN UCHAR NameNumber
  885. )
  886. /*++
  887. Routine Description:
  888. This routine uses the callers lana number and name number to find the
  889. Address Block that corresponds to the Ncb.
  890. Note, it returns the address of the relevant plana->AddressBlocks entry
  891. so that deletion of the address block is simpler.
  892. Arguments:
  893. pfcb - Supplies a pointer to the Fcb that Ab is chained onto.
  894. pdncb - Supplies the applications NCB.
  895. NameNumber - Supplies the name number to look for. This is not equal to pdncb->ncb_num
  896. when manipulating broadcast datagrams.
  897. Return Value:
  898. Address of the pointer to the address block or NULL.
  899. --*/
  900. {
  901. PLANA_INFO plana;
  902. if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
  903. ( pfcb == NULL ) ||
  904. ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL) ||
  905. ( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
  906. IF_NBDBG (NB_DEBUG_ADDRESS) {
  907. NbPrint( ("FindAbUsingNum pfcb: %lx, lana: %lx Failed, returning NULL\n",
  908. pfcb,
  909. pdncb->ncb_lana_num));
  910. }
  911. NCB_COMPLETE( pdncb, NRC_BRIDGE );
  912. return NULL;
  913. }
  914. ASSERT( pfcb->Signature == FCB_SIGNATURE );
  915. plana = pfcb->ppLana[pdncb->ncb_lana_num];
  916. IF_NBDBG (NB_DEBUG_ADDRESS) {
  917. NbPrint( ("FindAbUsingNum pfcb: %lx, lana: %lx, num: %lx\n",
  918. pfcb,
  919. pdncb->ncb_lana_num,
  920. NameNumber));
  921. }
  922. if (( NameNumber < (UCHAR)MAXIMUM_ADDRESS ) &&
  923. ( plana->AddressBlocks[NameNumber] != NULL) &&
  924. (( plana->AddressBlocks[NameNumber]->Status & 0x7) == REGISTERED )) {
  925. return &plana->AddressBlocks[NameNumber];
  926. }
  927. //
  928. // The user is allowed to receive any and receive broadcast
  929. // datagrams on address 255.
  930. //
  931. if ((( NameNumber == MAXIMUM_ADDRESS ) &&
  932. ( plana->AddressBlocks[NameNumber] != NULL)) &&
  933. (( (pdncb->ncb_command & ~ASYNCH) == NCBRECVANY ) ||
  934. ( (pdncb->ncb_command & ~ASYNCH) == NCBDGRECVBC ) ||
  935. ( (pdncb->ncb_command & ~ASYNCH) == NCBDGSENDBC ) ||
  936. ( (pdncb->ncb_command & ~ASYNCH) == NCBDGRECV ))) {
  937. return &plana->AddressBlocks[NameNumber];
  938. }
  939. IF_NBDBG (NB_DEBUG_ADDRESS) {
  940. NbPrint( ("Failed return NULL\n"));
  941. }
  942. NCB_COMPLETE( pdncb, NRC_ILLNN );
  943. return NULL;
  944. }
  945. NTSTATUS
  946. NbSetEventHandler (
  947. IN PDEVICE_OBJECT DeviceObject,
  948. IN PFILE_OBJECT FileObject,
  949. IN ULONG EventType,
  950. IN PVOID EventHandler,
  951. IN PVOID Context
  952. )
  953. /*++
  954. Routine Description:
  955. This routine registers an event handler with a TDI transport provider.
  956. Arguments:
  957. IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
  958. IN PFILE_OBJECT FileObject - Supplies the address object's file object.
  959. IN ULONG EventType, - Supplies the type of event.
  960. IN PVOID EventHandler - Supplies the event handler.
  961. IN PVOID Context - Supplies the PAB or PLANA_INFO associated with this event.
  962. Return Value:
  963. NTSTATUS - Final status of the set event operation
  964. --*/
  965. {
  966. NTSTATUS Status;
  967. PIRP Irp;
  968. PAGED_CODE();
  969. Irp = IoAllocateIrp(IoGetRelatedDeviceObject(FileObject)->StackSize, FALSE);
  970. if (Irp == NULL) {
  971. return(STATUS_INSUFFICIENT_RESOURCES);
  972. }
  973. TdiBuildSetEventHandler(Irp, DeviceObject, FileObject,
  974. NULL, NULL,
  975. EventType, EventHandler, Context);
  976. Status = SubmitTdiRequest(FileObject, Irp);
  977. IoFreeIrp(Irp);
  978. return Status;
  979. }
  980. NTSTATUS
  981. SubmitTdiRequest (
  982. IN PFILE_OBJECT FileObject,
  983. IN PIRP Irp
  984. )
  985. /*++
  986. Routine Description:
  987. This routine submits a request to TDI and waits for it to complete.
  988. Arguments:
  989. IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
  990. IN PIRP Irp - TDI request to submit.
  991. Return Value:
  992. NTSTATUS - Final status of request.
  993. --*/
  994. {
  995. KEVENT Event;
  996. NTSTATUS Status;
  997. PAGED_CODE();
  998. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  999. IoSetCompletionRoutine(Irp, NbCompletionEvent, &Event, TRUE, TRUE, TRUE);
  1000. Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
  1001. //
  1002. // If it failed immediately, return now, otherwise wait.
  1003. //
  1004. if (!NT_SUCCESS(Status)) {
  1005. return Status;
  1006. }
  1007. if (Status == STATUS_PENDING) {
  1008. Status = KeWaitForSingleObject(&Event, // Object to wait on.
  1009. Executive, // Reason for waiting
  1010. KernelMode, // Processor mode
  1011. FALSE, // Alertable
  1012. NULL); // Timeout
  1013. if (!NT_SUCCESS(Status)) {
  1014. IoFreeIrp ( Irp );
  1015. return Status;
  1016. }
  1017. Status = Irp->IoStatus.Status;
  1018. }
  1019. return(Status);
  1020. }