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.

2972 lines
82 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. network.c
  5. Abstract:
  6. This module contains routines for interfacing the LAN Manager server
  7. to the network.
  8. Author:
  9. Chuck Lenzmeier (chuckl) 7-Oct-1989
  10. Environment:
  11. File System Process, kernel mode only
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #include "network.tmh"
  16. #pragma hdrstop
  17. #include <ntddip.h>
  18. #include <ntddtcp.h>
  19. #include <ipfltdrv.h>
  20. #include <tcpinfo.h>
  21. #include <tdiinfo.h>
  22. #include <nbtioctl.h>
  23. #define BugCheckFileId SRV_FILE_NETWORK
  24. //
  25. // Local declarations
  26. //
  27. NTSTATUS
  28. GetNetworkAddress (
  29. IN PENDPOINT Endpoint
  30. );
  31. NTSTATUS
  32. OpenEndpoint (
  33. OUT PENDPOINT *Endpoint,
  34. IN PUNICODE_STRING NetworkName,
  35. IN PUNICODE_STRING TransportName,
  36. IN PANSI_STRING TransportAddress,
  37. IN PUNICODE_STRING DomainName,
  38. IN ULONG TransportAddFlags,
  39. IN BOOLEAN AlternateEndpoint
  40. );
  41. NTSTATUS
  42. OpenNetbiosAddress (
  43. IN OUT PENDPOINT Endpoint,
  44. IN PVOID DeviceName,
  45. IN PVOID NetbiosName
  46. );
  47. NTSTATUS
  48. OpenNetbiosExAddress (
  49. IN OUT PENDPOINT Endpoint,
  50. IN PVOID DeviceName,
  51. IN PVOID NetbiosName
  52. );
  53. NTSTATUS
  54. OpenNonNetbiosAddress (
  55. IN OUT PENDPOINT Endpoint,
  56. IN PVOID DeviceName,
  57. IN PVOID NetbiosName
  58. );
  59. NTSTATUS
  60. OpenIpxSocket (
  61. OUT PHANDLE Handle,
  62. OUT PFILE_OBJECT *FileObject,
  63. OUT PDEVICE_OBJECT *DeviceObject,
  64. IN PVOID DeviceName,
  65. IN USHORT Socket
  66. );
  67. #ifdef ALLOC_PRAGMA
  68. #pragma alloc_text( PAGE, SrvAddServedNet )
  69. #pragma alloc_text( PAGE, SrvDeleteServedNet )
  70. #pragma alloc_text( PAGE, SrvDoDisconnect )
  71. #pragma alloc_text( PAGE, GetNetworkAddress )
  72. #pragma alloc_text( PAGE, OpenEndpoint )
  73. #pragma alloc_text( PAGE, OpenNetbiosAddress )
  74. #pragma alloc_text( PAGE, OpenNonNetbiosAddress )
  75. #pragma alloc_text( PAGE, OpenIpxSocket )
  76. #pragma alloc_text( PAGE, SrvRestartAccept )
  77. #pragma alloc_text( PAGE, RestartStartSend )
  78. #pragma alloc_text( PAGE, GetIpxMaxBufferSize )
  79. #endif
  80. #if 0
  81. NOT PAGEABLE -- SrvOpenConnection
  82. NOT PAGEABLE -- SrvPrepareReceiveWorkItem
  83. NOT PAGEABLE -- SrvStartSend
  84. NOT PAGEABLE -- SrvStartSend2
  85. #endif
  86. NTSTATUS
  87. SrvAddServedNet(
  88. IN PUNICODE_STRING NetworkName,
  89. IN PUNICODE_STRING TransportName,
  90. IN PANSI_STRING TransportAddress,
  91. IN PUNICODE_STRING DomainName,
  92. IN ULONG TransportAddFlags,
  93. IN DWORD PasswordLength,
  94. IN PBYTE Password
  95. )
  96. /*++
  97. Routine Description:
  98. This function initializes the server on a network. This
  99. involves making the server known by creating a transport endpoint,
  100. posting a Listen request, and setting up event handlers.
  101. Arguments:
  102. NetworkName - The administrative name of the network (e.g., NET1)
  103. TransportName - The fully qualified name of the transport device.
  104. For example, "\Device\Nbf".
  105. TransportAddress - The fully qualified address (or name ) of the
  106. server's endpoint. This name is used exactly as specified. For
  107. NETBIOS-compatible networks, the caller must upcase and
  108. blank-fill the name. For example, "NTSERVERbbbbbbbb".
  109. DomainName - The name of the domain to service
  110. Password/PasswordLength - used for mutual authentication (optional)
  111. Return Value:
  112. NTSTATUS - Indicates whether the network was successfully started.
  113. --*/
  114. {
  115. NTSTATUS status;
  116. PENDPOINT endpoint;
  117. PAGED_CODE( );
  118. IF_DEBUG(TRACE1) KdPrint(( "SrvAddServedNet entered\n" ));
  119. //
  120. // Call OpenEndpoint to open the transport provider, bind to the
  121. // server address, and register the FSD receive event handler.
  122. //
  123. status = OpenEndpoint(
  124. &endpoint,
  125. NetworkName,
  126. TransportName,
  127. TransportAddress,
  128. DomainName,
  129. TransportAddFlags,
  130. FALSE); // primary endpoint
  131. if ( !NT_SUCCESS(status) ) {
  132. IF_DEBUG(ERRORS) {
  133. KdPrint(( "SrvAddServedNet: unable to open endpoint %wZ for addr %z, status %X\n", TransportName, (PCSTRING)TransportAddress, status ));
  134. }
  135. return status;
  136. }
  137. //
  138. // Dereference the endpoint. (When it was created, the reference
  139. // count was incremented to account for our pointer.)
  140. //
  141. SrvDereferenceEndpoint( endpoint );
  142. //
  143. // Call OpenEndpoint to open the transport provider, bind to the
  144. // server address, and register the FSD receive event handler. This is
  145. // the auxillary endpoint registration in the new TDI address format. Since
  146. // this is not supported by all the transports it cannot be deemed an error.
  147. //
  148. //
  149. status = OpenEndpoint(
  150. &endpoint,
  151. NetworkName,
  152. TransportName,
  153. TransportAddress,
  154. DomainName,
  155. TransportAddFlags,
  156. TRUE); // Alternate endpoint
  157. if ( NT_SUCCESS( status ) ) {
  158. SrvDereferenceEndpoint( endpoint );
  159. }
  160. if( PasswordLength ) {
  161. SrvAddSecurityCredentials( TransportAddress, DomainName, PasswordLength, Password );
  162. }
  163. return STATUS_SUCCESS;
  164. } // SrvAddServedNet
  165. NTSTATUS
  166. SrvDeleteServedNet(
  167. IN PUNICODE_STRING TransportName,
  168. IN PANSI_STRING TransportAddress
  169. )
  170. /*++
  171. Routine Description:
  172. This function causes the server to stop listening to a network.
  173. Arguments:
  174. TransportAddress - the transport address (e.g. \Device\Nbf\POPCORN
  175. of the endpoint to delete.
  176. Return Value:
  177. NTSTATUS - Indicates whether the network was successfully stopped.
  178. --*/
  179. {
  180. PLIST_ENTRY listEntry;
  181. PENDPOINT endpoint;
  182. BOOLEAN match;
  183. NTSTATUS status = STATUS_NONEXISTENT_NET_NAME;
  184. PAGED_CODE( );
  185. IF_DEBUG(TRACE1) KdPrint(( "SrvDeleteServedNet entered\n" ));
  186. //
  187. // Find the endpoint block with the specified name.
  188. //
  189. top:
  190. ACQUIRE_LOCK( &SrvEndpointLock );
  191. listEntry = SrvEndpointList.ListHead.Flink;
  192. while ( listEntry != &SrvEndpointList.ListHead ) {
  193. endpoint = CONTAINING_RECORD(
  194. listEntry,
  195. ENDPOINT,
  196. GlobalEndpointListEntry
  197. );
  198. if( GET_BLOCK_STATE(endpoint) == BlockStateActive ) {
  199. //
  200. // We have a match if the transport name is correct and we either
  201. // haven't specified a transport address, or if the transport
  202. // address matches
  203. //
  204. match = (BOOLEAN)(
  205. RtlEqualUnicodeString(
  206. TransportName,
  207. &endpoint->TransportName,
  208. TRUE // case insensitive compare
  209. )
  210. &&
  211. (
  212. TransportAddress->Length == 0 ||
  213. RtlEqualString(
  214. (PSTRING)TransportAddress,
  215. (PSTRING)&endpoint->TransportAddress,
  216. TRUE // case insensitive compare
  217. )
  218. )
  219. );
  220. if ( match ) {
  221. //
  222. // The specified network name (endpoint) exists. Close the
  223. // endpoint. This releases the endpoint lock.
  224. //
  225. SrvCloseEndpoint( endpoint );
  226. status = STATUS_SUCCESS;
  227. //
  228. // Restart this loop, since this endpoint may have vaporized and
  229. // the list might have changed because we dropped SrvEndpointLock.
  230. //
  231. // SrvCloseEndpoint will have marked this endpoint as BlockStateClosing,
  232. // so we will not be in an infinite loop!
  233. //
  234. goto top;
  235. }
  236. }
  237. //
  238. // Go to the next one.
  239. //
  240. listEntry = listEntry->Flink;
  241. }
  242. //
  243. // We are done. If we successfully matched an endpoint, we return STATUS_SUCCESS
  244. //
  245. RELEASE_LOCK( &SrvEndpointLock );
  246. return status;
  247. } // SrvDeleteServedNet
  248. NTSTATUS
  249. SrvDoDisconnect (
  250. IN OUT PCONNECTION Connection
  251. )
  252. /*++
  253. Routine Description:
  254. This function issues a Disconnect request on a network. The request
  255. is performed synchronously -- control is not returned to the caller
  256. until the request completes.
  257. Arguments:
  258. Connection - Supplies a pointer to an Connection Block
  259. Return Value:
  260. NTSTATUS - Indicates whether the disconnect was successful.
  261. --*/
  262. {
  263. NTSTATUS status;
  264. PAGED_CODE( );
  265. IF_DEBUG(TRACE2) KdPrint(( "SrvDoDisconnect entered\n" ));
  266. #if SRVDBG29
  267. UpdateConnectionHistory( "SDSC", Connection->Endpoint, Connection );
  268. #endif
  269. ASSERT( !Connection->Endpoint->IsConnectionless );
  270. //
  271. // Issue the disconnect request.
  272. //
  273. status = SrvIssueDisconnectRequest(
  274. Connection->FileObject,
  275. &Connection->DeviceObject,
  276. TDI_DISCONNECT_ABORT
  277. );
  278. if ( !NT_SUCCESS(status) ) {
  279. INTERNAL_ERROR(
  280. ERROR_LEVEL_EXPECTED,
  281. "SrvDoDisconnect: NtDeviceIoControlFile failed: %X",
  282. status,
  283. NULL
  284. );
  285. #if SRVDBG29
  286. if (status != STATUS_LINK_FAILED && status != STATUS_REMOTE_DISCONNECT) {
  287. KdPrint(( "SRV: SrvDoDisconnect: SrvIssueDisconnectRequest failed\n" ));
  288. DbgBreakPoint();
  289. }
  290. #endif
  291. //
  292. // Mark the connection as not reusable, because the transport
  293. // probably still thinks it's active.
  294. //
  295. Connection->NotReusable = TRUE;
  296. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  297. }
  298. //
  299. // Return the status of the I/O operation.
  300. //
  301. return status;
  302. } // SrvDoDisconnect
  303. NTSTATUS
  304. SrvOpenConnection (
  305. IN PENDPOINT Endpoint
  306. )
  307. /*++
  308. Routine Description:
  309. This function opens a connection for an endpoint and queues it to
  310. the endpoint's free connection list.
  311. Arguments:
  312. Endpoint - Supplies a pointer to an Endpoint Block
  313. Return Value:
  314. NTSTATUS - Indicates whether the connection was successfully opened.
  315. --*/
  316. {
  317. NTSTATUS status;
  318. PCONNECTION connection;
  319. PPAGED_CONNECTION pagedConnection;
  320. CHAR eaBuffer[sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  321. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  322. sizeof(CONNECTION_CONTEXT)];
  323. PFILE_FULL_EA_INFORMATION ea;
  324. CONNECTION_CONTEXT UNALIGNED *ctx;
  325. OBJECT_ATTRIBUTES objectAttributes;
  326. IO_STATUS_BLOCK iosb;
  327. KIRQL oldIrql;
  328. PTABLE_HEADER tableHeader;
  329. SHORT sidIndex;
  330. USHORT i;
  331. PTABLE_ENTRY entry = NULL;
  332. TDI_PROVIDER_INFO providerInfo;
  333. //
  334. // Allocate a connection block.
  335. //
  336. SrvAllocateConnection( &connection );
  337. if ( connection == NULL ) {
  338. return STATUS_INSUFF_SERVER_RESOURCES;
  339. }
  340. pagedConnection = connection->PagedConnection;
  341. //
  342. // Allocate an entry in the endpoint's connection table.
  343. //
  344. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  345. for ( i = 1; i < ENDPOINT_LOCK_COUNT ; i++ ) {
  346. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  347. }
  348. tableHeader = &Endpoint->ConnectionTable;
  349. if ( tableHeader->FirstFreeEntry == -1 &&
  350. SrvGrowTable(
  351. tableHeader,
  352. 8,
  353. 0x7fff,
  354. NULL ) == FALSE ) {
  355. for ( i = ENDPOINT_LOCK_COUNT-1 ; i > 0 ; i-- ) {
  356. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  357. }
  358. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  359. status = STATUS_INSUFF_SERVER_RESOURCES;
  360. goto cleanup;
  361. }
  362. sidIndex = tableHeader->FirstFreeEntry;
  363. entry = &tableHeader->Table[sidIndex];
  364. tableHeader->FirstFreeEntry = entry->NextFreeEntry;
  365. DEBUG entry->NextFreeEntry = -2;
  366. if ( tableHeader->LastFreeEntry == sidIndex ) {
  367. tableHeader->LastFreeEntry = -1;
  368. }
  369. for ( i = ENDPOINT_LOCK_COUNT-1 ; i > 0 ; i-- ) {
  370. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  371. }
  372. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  373. if ( !Endpoint->IsConnectionless ) {
  374. //
  375. // Create the EA for the connection context.
  376. //
  377. ea = (PFILE_FULL_EA_INFORMATION)eaBuffer;
  378. ea->NextEntryOffset = 0;
  379. ea->Flags = 0;
  380. ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  381. ea->EaValueLength = sizeof(CONNECTION_CONTEXT);
  382. RtlCopyMemory( ea->EaName, StrConnectionContext, ea->EaNameLength + 1 );
  383. ctx = (CONNECTION_CONTEXT UNALIGNED *)&ea->EaName[ea->EaNameLength + 1];
  384. *ctx = connection;
  385. //
  386. // Create the connection file object.
  387. //
  388. SrvInitializeObjectAttributes_U(
  389. &objectAttributes,
  390. &Endpoint->TransportName,
  391. OBJ_CASE_INSENSITIVE,
  392. NULL,
  393. NULL
  394. );
  395. status = NtCreateFile(
  396. &pagedConnection->ConnectionHandle,
  397. 0,
  398. &objectAttributes,
  399. &iosb,
  400. NULL,
  401. 0,
  402. 0,
  403. 0,
  404. 0,
  405. eaBuffer,
  406. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  407. ea->EaNameLength + 1 + ea->EaValueLength
  408. );
  409. if ( !NT_SUCCESS(status) ) {
  410. IF_DEBUG(ERRORS) {
  411. KdPrint(( "SrvOpenConnection: NtCreateFile failed: %X\n", status ));
  412. }
  413. goto cleanup;
  414. }
  415. SRVDBG_CLAIM_HANDLE( pagedConnection->ConnectionHandle, "CON", 7, connection );
  416. //
  417. // Obtain a referenced pointer to the file object.
  418. //
  419. status = ObReferenceObjectByHandle(
  420. pagedConnection->ConnectionHandle,
  421. 0,
  422. (POBJECT_TYPE) NULL,
  423. KernelMode,
  424. (PVOID *)&connection->FileObject,
  425. NULL
  426. );
  427. if ( !NT_SUCCESS(status) ) {
  428. SrvLogServiceFailure( SRV_SVC_OB_REF_BY_HANDLE, status );
  429. //
  430. // This internal error bugchecks the system.
  431. //
  432. INTERNAL_ERROR(
  433. ERROR_LEVEL_IMPOSSIBLE,
  434. "SrvOpenConnection: ObReferenceObjectByHandle failed: %X",
  435. status,
  436. NULL
  437. );
  438. goto cleanup;
  439. }
  440. //
  441. // Get the address of the device object for the endpoint.
  442. //
  443. connection->DeviceObject = IoGetRelatedDeviceObject(
  444. connection->FileObject
  445. );
  446. //
  447. // Associate the connection with the endpoint's address.
  448. //
  449. status = SrvIssueAssociateRequest(
  450. connection->FileObject,
  451. &connection->DeviceObject,
  452. Endpoint->EndpointHandle
  453. );
  454. if ( !NT_SUCCESS(status) ) {
  455. INTERNAL_ERROR(
  456. ERROR_LEVEL_UNEXPECTED,
  457. "SrvOpenConnection: SrvIssueAssociateRequest failed: %X",
  458. status,
  459. NULL
  460. );
  461. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  462. goto cleanup;
  463. }
  464. IF_DEBUG(NET1) {
  465. KdPrint(( "SrvOpenConnection: Connection on %p %z opened; handle %p, pointer %p\n", Endpoint,
  466. (PCSTRING)&Endpoint->TransportAddress,
  467. connection->PagedConnection->ConnectionHandle,
  468. connection->FileObject ));
  469. }
  470. //
  471. // Initialize the MaximumSendSize for the transport that we're using
  472. //
  473. status = SrvIssueTdiQuery(
  474. connection->FileObject,
  475. &connection->DeviceObject,
  476. (PCHAR)&providerInfo,
  477. sizeof(providerInfo),
  478. TDI_QUERY_PROVIDER_INFO
  479. );
  480. //
  481. // If we got the provider info, make sure the maximum send size is at
  482. // least 1K-1. If we have no provider info, then maximum send size is 64KB.
  483. //
  484. if ( NT_SUCCESS(status) ) {
  485. connection->MaximumSendSize = providerInfo.MaxSendSize;
  486. if ( connection->MaximumSendSize < MIN_SEND_SIZE ) {
  487. connection->MaximumSendSize = MIN_SEND_SIZE;
  488. }
  489. } else {
  490. connection->MaximumSendSize = MAX_PARTIAL_BUFFER_SIZE;
  491. }
  492. } else { // if ( Endpoint->IsConnectionless )
  493. if (sidIndex > 0xfff) {
  494. // The IPXSID index can only span 12 bits
  495. // Code needs to be added to ensure that we can try to locate
  496. // an index less than 0xfff
  497. status = STATUS_INSUFF_SERVER_RESOURCES;
  498. goto cleanup;
  499. }
  500. // Give this the default initialization
  501. connection->MaximumSendSize = MAX_PARTIAL_BUFFER_SIZE;
  502. }
  503. //
  504. // Set the reference count on the connection to zero, in order to
  505. // put it on the free list. (SrvAllocateConnection initialized the
  506. // count to two.)
  507. //
  508. connection->BlockHeader.ReferenceCount = 0;
  509. UPDATE_REFERENCE_HISTORY( connection, TRUE );
  510. UPDATE_REFERENCE_HISTORY( connection, TRUE );
  511. //
  512. // Reference the endpoint and link the connection into the
  513. // endpoint's free connection list.
  514. //
  515. connection->Endpoint = Endpoint;
  516. connection->EndpointSpinLock =
  517. &ENDPOINT_SPIN_LOCK(sidIndex & ENDPOINT_LOCK_MASK);
  518. ACQUIRE_LOCK( &SrvEndpointLock );
  519. SrvReferenceEndpoint( Endpoint );
  520. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  521. INCREMENT_IPXSID_SEQUENCE( entry->SequenceNumber );
  522. if ( sidIndex == 0 && entry->SequenceNumber == 0 ) {
  523. INCREMENT_IPXSID_SEQUENCE( entry->SequenceNumber );
  524. }
  525. connection->Sid = MAKE_IPXSID( sidIndex, entry->SequenceNumber );
  526. connection->SidIndex = sidIndex;
  527. entry->Owner = connection;
  528. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  529. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  530. SrvInsertTailList(
  531. &Endpoint->FreeConnectionList,
  532. &connection->EndpointFreeListEntry
  533. );
  534. #if SRVDBG29
  535. UpdateConnectionHistory( "OPEN", Endpoint, connection );
  536. #endif
  537. Endpoint->FreeConnectionCount++;
  538. Endpoint->TotalConnectionCount++;
  539. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  540. IF_DEBUG(TDI) {
  541. KdPrint(( "SrvOpenConnection created connection %p for endpoint %p; free %ld, total %ld\n", connection, Endpoint,
  542. Endpoint->FreeConnectionCount,
  543. Endpoint->TotalConnectionCount ));
  544. }
  545. RELEASE_LOCK( &SrvEndpointLock );
  546. //
  547. // The connection open was successful.
  548. //
  549. IF_DEBUG(TRACE1) {
  550. KdPrint(( "SrvOpenConnection complete: %X\n", STATUS_SUCCESS ));
  551. }
  552. return STATUS_SUCCESS;
  553. //
  554. // Out-of-line error cleanup.
  555. //
  556. cleanup:
  557. //
  558. // Something failed. Clean up as appropriate.
  559. //
  560. if ( !Endpoint->IsConnectionless ) {
  561. if ( connection->FileObject != NULL ) {
  562. ObDereferenceObject( connection->FileObject );
  563. }
  564. if ( pagedConnection->ConnectionHandle != NULL ) {
  565. SRVDBG_RELEASE_HANDLE( pagedConnection->ConnectionHandle, "CON", 12, connection );
  566. SrvNtClose( pagedConnection->ConnectionHandle, FALSE );
  567. }
  568. }
  569. if ( entry != NULL ) {
  570. SrvRemoveEntryTable( tableHeader, sidIndex );
  571. }
  572. SrvFreeConnection( connection );
  573. return status;
  574. } // SrvOpenConnection
  575. NTSTATUS
  576. GetNetworkAddress (
  577. IN PENDPOINT Endpoint
  578. )
  579. {
  580. NTSTATUS status;
  581. PCHAR adapterStatus;
  582. PCHAR adapterAddress;
  583. ANSI_STRING ansiString;
  584. CHAR addressData[12+1];
  585. ULONG i;
  586. struct {
  587. ULONG ActivityCount;
  588. TA_IPX_ADDRESS LocalAddress;
  589. } addressInfo;
  590. PAGED_CODE( );
  591. if ( !Endpoint->IsConnectionless ) {
  592. //
  593. // Allocate a buffer to receive adapter information.
  594. //
  595. // *** We want to get the ADAPTER_STATUS structure, but it is
  596. // defined in the windows header file sdk\inc\nb30.h.
  597. // Rather than including all the windows header files, just
  598. // allocate about a page, which should always be enough for
  599. // that structure.
  600. //
  601. adapterStatus = ALLOCATE_NONPAGED_POOL( 4080, BlockTypeAdapterStatus );
  602. if ( adapterStatus == NULL ) {
  603. return STATUS_INSUFF_SERVER_RESOURCES;
  604. }
  605. status = SrvIssueTdiQuery(
  606. Endpoint->FileObject,
  607. &Endpoint->DeviceObject,
  608. adapterStatus,
  609. 4080,
  610. TDI_QUERY_ADAPTER_STATUS
  611. );
  612. if ( !NT_SUCCESS(status) ) {
  613. INTERNAL_ERROR(
  614. ERROR_LEVEL_UNEXPECTED,
  615. "GetNetworkAddress: SrvIssueTdiQuery failed: %X\n",
  616. status,
  617. NULL
  618. );
  619. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  620. DEALLOCATE_NONPAGED_POOL( adapterStatus );
  621. return status;
  622. }
  623. adapterAddress = adapterStatus;
  624. } else {
  625. status = SrvIssueTdiQuery(
  626. Endpoint->NameSocketFileObject,
  627. &Endpoint->NameSocketDeviceObject,
  628. (PCHAR)&addressInfo,
  629. sizeof(addressInfo),
  630. TDI_QUERY_ADDRESS_INFO
  631. );
  632. if ( !NT_SUCCESS(status) ) {
  633. INTERNAL_ERROR(
  634. ERROR_LEVEL_UNEXPECTED,
  635. "GetNetworkAddress: SrvIssueTdiQuery failed: %X\n",
  636. status,
  637. NULL
  638. );
  639. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  640. return status;
  641. }
  642. Endpoint->LocalAddress = addressInfo.LocalAddress.Address[0].Address[0];
  643. adapterAddress = addressInfo.LocalAddress.Address[0].Address[0].NodeAddress;
  644. }
  645. //
  646. // Get an ANSI string that contains the adapter address.
  647. //
  648. ansiString.Buffer = addressData;
  649. ansiString.Length = 12;
  650. ansiString.MaximumLength = 13;
  651. #define tohexdigit(a) ((CHAR)( (a) > 9 ? ((a) + 'a' - 0xA) : ((a) + '0') ))
  652. for ( i = 0; i < 6; i++ ) {
  653. addressData[2*i] = tohexdigit( (adapterAddress[i] >> 4) & 0x0F );
  654. addressData[2*i+1] = tohexdigit( adapterAddress[i] & 0x0F );
  655. }
  656. addressData[12] = '\0';
  657. //
  658. // Convert the address string to Unicode.
  659. //
  660. status = RtlAnsiStringToUnicodeString(
  661. &Endpoint->NetworkAddress,
  662. &ansiString,
  663. FALSE
  664. );
  665. ASSERT( NT_SUCCESS(status) );
  666. if ( !Endpoint->IsConnectionless ) {
  667. DEALLOCATE_NONPAGED_POOL( adapterStatus );
  668. }
  669. return STATUS_SUCCESS;
  670. } // GetNetworkAddress
  671. NTSTATUS
  672. OpenEndpoint (
  673. OUT PENDPOINT *Endpoint,
  674. IN PUNICODE_STRING NetworkName,
  675. IN PUNICODE_STRING TransportName,
  676. IN PANSI_STRING TransportAddress,
  677. IN PUNICODE_STRING DomainName,
  678. IN DWORD TransportAddFlags,
  679. IN BOOLEAN AlternateEndpoint
  680. )
  681. /*++
  682. Routine Description:
  683. This function opens a transport provider, simultaneously binding the
  684. server's address to the transport endpoint, and registers a Receive
  685. event handler for the endpoint.
  686. Arguments:
  687. Endpoint - Returns a pointer to an Endpoint Block
  688. NetworkName - Supplies the administrative name of the network (e.g.,
  689. NET1).
  690. TransportName - The fully qualified name of the transport device.
  691. For example, "\Device\Nbf".
  692. TransportAddress - The exact name of the server to be used on the
  693. specified transport. For NETBIOS-compatible networks, the
  694. caller must upcase and blank-fill the name. For example,
  695. "NTSERVERbbbbbbbb".
  696. DomainName - name of domain to serve
  697. Return Value:
  698. NTSTATUS - Indicates whether the network was successfully opened.
  699. --*/
  700. {
  701. NTSTATUS status = STATUS_SUCCESS;
  702. PENDPOINT endpoint = NULL; // local copy of Endpoint
  703. PAGED_CODE( );
  704. IF_DEBUG(TRACE1) KdPrint(( "OpenEndpoint %wZ entered\n", TransportName ));
  705. //
  706. // Allocate an endpoint block.
  707. //
  708. SrvAllocateEndpoint(
  709. &endpoint,
  710. NetworkName,
  711. TransportName,
  712. TransportAddress,
  713. DomainName
  714. );
  715. if ( endpoint == NULL ) {
  716. IF_DEBUG(ERRORS) {
  717. KdPrint(( "OpenEndpoint complete: %X\n",
  718. STATUS_INSUFF_SERVER_RESOURCES ));
  719. }
  720. return STATUS_INSUFF_SERVER_RESOURCES;
  721. }
  722. if( TransportAddFlags & SRP_XADD_PRIMARY_MACHINE ) {
  723. endpoint->IsPrimaryName = 1;
  724. if( SrvComputerName.Buffer == NULL ) {
  725. status = RtlAnsiStringToUnicodeString( &SrvComputerName, TransportAddress, TRUE );
  726. if( NT_SUCCESS( status ) ) {
  727. //
  728. // Trim off the trailing spaces
  729. //
  730. while( SrvComputerName.Buffer[(SrvComputerName.Length-sizeof(WCHAR))/sizeof(WCHAR)]
  731. == L' ' ) {
  732. SrvComputerName.Length -= sizeof(WCHAR);
  733. }
  734. }
  735. }
  736. }
  737. if( NT_SUCCESS( status ) ) {
  738. if( TransportAddFlags & SRP_XADD_REMAP_PIPE_NAMES ) {
  739. endpoint->RemapPipeNames = 1;
  740. }
  741. if (AlternateEndpoint) {
  742. status = OpenNetbiosExAddress(
  743. endpoint,
  744. TransportName,
  745. TransportAddress->Buffer);
  746. endpoint->AlternateAddressFormat = TRUE;
  747. } else {
  748. endpoint->AlternateAddressFormat = FALSE;
  749. //
  750. // Assume that the transport is a NetBIOS provider, and try to
  751. // open the server's address using the NetBIOS name.
  752. //
  753. status = OpenNetbiosAddress(
  754. endpoint,
  755. TransportName,
  756. TransportAddress->Buffer
  757. );
  758. //
  759. // We could not open the transport as a NetBIOS provider. We will now try
  760. // to see if it is a direct host IPX provider. However, if we have been
  761. // configured to use Security Signatures, do not attempt direct host IPX since
  762. // security signatures are not supported for direct host IPX transports
  763. //
  764. if ( !NT_SUCCESS(status) && SrvSmbSecuritySignaturesRequired == FALSE ) {
  765. BOOLEAN isDuplicate = FALSE;
  766. PLIST_ENTRY listEntry;
  767. //
  768. // Apparently the transport is not a NetBIOS provider. We can
  769. // not open multiple connectionless providers through the same
  770. // TransportName.
  771. //
  772. ACQUIRE_LOCK( &SrvEndpointLock );
  773. for( listEntry = SrvEndpointList.ListHead.Flink;
  774. listEntry != &SrvEndpointList.ListHead;
  775. listEntry = listEntry->Flink ) {
  776. PENDPOINT tmpEndpoint;
  777. tmpEndpoint = CONTAINING_RECORD( listEntry, ENDPOINT, GlobalEndpointListEntry );
  778. if( GET_BLOCK_STATE( tmpEndpoint ) == BlockStateActive &&
  779. tmpEndpoint->IsConnectionless &&
  780. RtlCompareUnicodeString( &tmpEndpoint->TransportName, TransportName, TRUE ) == 0 ) {
  781. IF_DEBUG(ERRORS) {
  782. KdPrint(( "OpenEndpoint: Only one connectionless endpoint on %wZ allowed!\n",
  783. TransportName ));
  784. }
  785. isDuplicate = TRUE;
  786. status = STATUS_TOO_MANY_NODES;
  787. break;
  788. }
  789. }
  790. RELEASE_LOCK( &SrvEndpointLock );
  791. //
  792. // Try to open it as a connectionless provider.
  793. //
  794. if( isDuplicate == FALSE ) {
  795. NTSTATUS status2;
  796. status2 = OpenNonNetbiosAddress(
  797. endpoint,
  798. TransportName,
  799. TransportAddress->Buffer
  800. );
  801. if( NT_SUCCESS( status2 ) ) {
  802. status = status2;
  803. }
  804. }
  805. }
  806. }
  807. }
  808. if ( !NT_SUCCESS(status) ) {
  809. //
  810. // We couldn't open the provider as either a NetBIOS provider
  811. // or as a connectionless provider.
  812. //
  813. IF_DEBUG(ERRORS) {
  814. KdPrint(( "OpenEndpoint: OpenAddress failed: %X\n", status ));
  815. }
  816. //
  817. // Close all free connections.
  818. //
  819. EmptyFreeConnectionList( endpoint );
  820. SrvFreeEndpoint( endpoint );
  821. ACQUIRE_LOCK( &SrvEndpointLock );
  822. SrvEndpointCount--;
  823. RELEASE_LOCK( &SrvEndpointLock );
  824. return status;
  825. }
  826. //
  827. // Query the provider for the send entry point
  828. //
  829. SrvQuerySendEntryPoint(
  830. endpoint->FileObject,
  831. &endpoint->DeviceObject,
  832. IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER,
  833. (PVOID*)&endpoint->FastTdiSend
  834. );
  835. //
  836. // Query the provider for the send entry point
  837. //
  838. SrvQuerySendEntryPoint(
  839. endpoint->FileObject,
  840. &endpoint->DeviceObject,
  841. IOCTL_TDI_QUERY_DIRECT_SENDDG_HANDLER,
  842. (PVOID*)&endpoint->FastTdiSendDatagram
  843. );
  844. //
  845. // The network open was successful. Link the new endpoint into the
  846. // list of active endpoints. Return with a success status. (We
  847. // don't dereference the endpoint because we're returning a pointer
  848. // to the endpoint.)
  849. //
  850. SrvInsertEntryOrderedList( &SrvEndpointList, endpoint );
  851. *Endpoint = endpoint;
  852. IF_DEBUG(TRACE1) {
  853. KdPrint(( "OpenEndpoint complete: %wZ %X\n", TransportName, STATUS_SUCCESS ));
  854. }
  855. return STATUS_SUCCESS;
  856. } // OpenEndpoint
  857. NTSTATUS
  858. SetupConnectionEndpointHandlers(
  859. IN OUT PENDPOINT Endpoint)
  860. {
  861. NTSTATUS status;
  862. ULONG i;
  863. Endpoint->IsConnectionless = FALSE;
  864. status = SrvVerifyDeviceStackSize(
  865. Endpoint->EndpointHandle,
  866. TRUE,
  867. &Endpoint->FileObject,
  868. &Endpoint->DeviceObject,
  869. NULL
  870. );
  871. if ( !NT_SUCCESS( status ) ) {
  872. INTERNAL_ERROR(
  873. ERROR_LEVEL_EXPECTED,
  874. "OpenNetbiosAddress: Verify Device Stack Size failed: %X\n",
  875. status,
  876. NULL
  877. );
  878. goto cleanup;
  879. }
  880. //
  881. // Find the network address of the adapter used by corresponding to
  882. // this endpoint.
  883. //
  884. GetNetworkAddress( Endpoint );
  885. //
  886. // Register the server's Receive event handler.
  887. //
  888. status = SrvIssueSetEventHandlerRequest(
  889. Endpoint->FileObject,
  890. &Endpoint->DeviceObject,
  891. TDI_EVENT_RECEIVE,
  892. (PVOID)SrvFsdTdiReceiveHandler,
  893. Endpoint
  894. );
  895. if ( !NT_SUCCESS(status) ) {
  896. INTERNAL_ERROR(
  897. ERROR_LEVEL_EXPECTED,
  898. "OpenNetbiosAddress: set receive event handler failed: %X",
  899. status,
  900. NULL
  901. );
  902. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  903. goto cleanup;
  904. }
  905. //
  906. // Register the server's Disconnect event handler.
  907. //
  908. status = SrvIssueSetEventHandlerRequest(
  909. Endpoint->FileObject,
  910. &Endpoint->DeviceObject,
  911. TDI_EVENT_DISCONNECT,
  912. (PVOID)SrvFsdTdiDisconnectHandler,
  913. Endpoint
  914. );
  915. if ( !NT_SUCCESS(status) ) {
  916. INTERNAL_ERROR(
  917. ERROR_LEVEL_UNEXPECTED,
  918. "OpenNetbiosAddress: set disconnect event handler failed: %X",
  919. status,
  920. NULL
  921. );
  922. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  923. goto cleanup;
  924. }
  925. //
  926. // Create a number of free connections for the endpoint. These
  927. // connections will be used to service Connect events.
  928. //
  929. // *** If we fail in an attempt to create a connection, but we can
  930. // successfully create at least one, we keep the endpoint. The
  931. // cleanup code below depends on this behavior.
  932. //
  933. for ( i = 0; i < SrvFreeConnectionMinimum; i++ ) {
  934. status = SrvOpenConnection( Endpoint );
  935. if ( !NT_SUCCESS(status) ) {
  936. INTERNAL_ERROR(
  937. ERROR_LEVEL_EXPECTED,
  938. "OpenNetbiosAddress: SrvOpenConnection failed: %X",
  939. status,
  940. NULL
  941. );
  942. if ( i == 0 ) {
  943. goto cleanup;
  944. } else {
  945. break;
  946. }
  947. }
  948. }
  949. //
  950. // Register the server's Connect event handler.
  951. //
  952. // *** Note that Connect events can be delivered IMMEDIATELY upon
  953. // completion of this request!
  954. //
  955. status = SrvIssueSetEventHandlerRequest(
  956. Endpoint->FileObject,
  957. &Endpoint->DeviceObject,
  958. TDI_EVENT_CONNECT,
  959. (PVOID)SrvFsdTdiConnectHandler,
  960. Endpoint
  961. );
  962. if ( !NT_SUCCESS(status) ) {
  963. INTERNAL_ERROR(
  964. ERROR_LEVEL_UNEXPECTED,
  965. "OpenNetbiosAddress: set connect event handler failed: %X",
  966. status,
  967. NULL
  968. );
  969. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  970. goto cleanup;
  971. }
  972. return STATUS_SUCCESS;
  973. //
  974. // Out-of-line error cleanup.
  975. //
  976. cleanup:
  977. //
  978. // Something failed. Clean up as appropriate.
  979. //
  980. if ( Endpoint->FileObject != NULL ) {
  981. ObDereferenceObject( Endpoint->FileObject );
  982. Endpoint->FileObject = NULL;
  983. }
  984. if ( Endpoint->EndpointHandle != NULL ) {
  985. SRVDBG_RELEASE_HANDLE( Endpoint->EndpointHandle, "END", 14, Endpoint );
  986. SrvNtClose( Endpoint->EndpointHandle, FALSE );
  987. Endpoint->EndpointHandle = NULL;
  988. }
  989. return status;
  990. }
  991. NTSTATUS
  992. OpenNetbiosAddress (
  993. IN OUT PENDPOINT Endpoint,
  994. IN PVOID DeviceName,
  995. IN PVOID NetbiosName
  996. )
  997. {
  998. NTSTATUS status;
  999. ULONG i;
  1000. CHAR eaBuffer[sizeof(FILE_FULL_EA_INFORMATION) +
  1001. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  1002. sizeof(TA_NETBIOS_ADDRESS)];
  1003. PAGED_CODE( );
  1004. status = TdiOpenNetbiosAddress(
  1005. &Endpoint->EndpointHandle,
  1006. eaBuffer,
  1007. DeviceName,
  1008. NetbiosName
  1009. );
  1010. if ( !NT_SUCCESS(status) ) {
  1011. IF_DEBUG( ERRORS ) {
  1012. KdPrint(( "TdiOpenNetbiosAddress( %wZ ) status %X\n", DeviceName, status ));
  1013. }
  1014. return status;
  1015. }
  1016. status = SetupConnectionEndpointHandlers(Endpoint);
  1017. return status;
  1018. } // OpenNetbiosAddress
  1019. NTSTATUS
  1020. OpenNetbiosExAddress(
  1021. IN OUT PENDPOINT Endpoint,
  1022. IN PVOID DeviceName,
  1023. IN PVOID NetbiosName
  1024. )
  1025. {
  1026. NTSTATUS status;
  1027. PFILE_FULL_EA_INFORMATION ea;
  1028. OBJECT_ATTRIBUTES objectAttributes;
  1029. IO_STATUS_BLOCK iosb;
  1030. ULONG length;
  1031. CHAR buffer[sizeof(FILE_FULL_EA_INFORMATION) +
  1032. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  1033. sizeof(TA_NETBIOS_EX_ADDRESS)];
  1034. TA_NETBIOS_EX_ADDRESS NetbiosExAddress;
  1035. PTDI_ADDRESS_NETBIOS_EX pTdiNetbiosExAddress;
  1036. PTDI_ADDRESS_NETBIOS pNetbiosAddress;
  1037. ULONG NetbiosExAddressLength;
  1038. PAGED_CODE( );
  1039. //
  1040. // Build the NETBIOS Extended address.
  1041. //
  1042. NetbiosExAddress.TAAddressCount = 1;
  1043. NetbiosExAddress.Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS_EX;
  1044. NetbiosExAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS_EX;
  1045. pTdiNetbiosExAddress = NetbiosExAddress.Address[0].Address;
  1046. pNetbiosAddress = &pTdiNetbiosExAddress->NetbiosAddress;
  1047. pNetbiosAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1048. NetbiosExAddressLength = FIELD_OFFSET(TRANSPORT_ADDRESS,Address)
  1049. + FIELD_OFFSET(TA_ADDRESS,Address)
  1050. + FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,NetbiosAddress)
  1051. + TDI_ADDRESS_LENGTH_NETBIOS;
  1052. RtlCopyMemory(
  1053. pNetbiosAddress->NetbiosName,
  1054. NetbiosName,
  1055. NETBIOS_NAME_LEN);
  1056. // Copy the default endpoint name onto the NETBIOS Extended address.
  1057. RtlCopyMemory(
  1058. pTdiNetbiosExAddress->EndpointName,
  1059. SMBSERVER_LOCAL_ENDPOINT_NAME,
  1060. NETBIOS_NAME_LEN);
  1061. length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  1062. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  1063. NetbiosExAddressLength;
  1064. ea = (PFILE_FULL_EA_INFORMATION)buffer;
  1065. ea->NextEntryOffset = 0;
  1066. ea->Flags = 0;
  1067. ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  1068. ea->EaValueLength = (USHORT)NetbiosExAddressLength;
  1069. RtlCopyMemory( ea->EaName, StrTransportAddress, ea->EaNameLength + 1 );
  1070. RtlCopyMemory(
  1071. &ea->EaName[ea->EaNameLength + 1],
  1072. &NetbiosExAddress,
  1073. NetbiosExAddressLength
  1074. );
  1075. InitializeObjectAttributes( &objectAttributes, DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL );
  1076. status = NtCreateFile (
  1077. &Endpoint->EndpointHandle,
  1078. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access
  1079. &objectAttributes, // object attributes
  1080. &iosb, // returned status information
  1081. NULL, // block size (unused)
  1082. 0, // file attributes
  1083. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  1084. FILE_CREATE, // create disposition
  1085. 0, // create options
  1086. buffer, // EA buffer
  1087. length // EA length
  1088. );
  1089. if ( !NT_SUCCESS(status) ) {
  1090. IF_DEBUG( ERRORS ) {
  1091. KdPrint(("NtCreateFile %wZ NETBIOS_EX address status %X\n", DeviceName, status ));
  1092. }
  1093. return status;
  1094. }
  1095. Endpoint->IsNoNetBios = TRUE;
  1096. status = SetupConnectionEndpointHandlers(Endpoint);
  1097. IF_DEBUG( ERRORS ) {
  1098. if( !NT_SUCCESS( status ) ) {
  1099. KdPrint(("SetupConnectionEndpointHandlers failed, status %X\n", status ));
  1100. }
  1101. }
  1102. return status;
  1103. }
  1104. NTSTATUS
  1105. OpenNonNetbiosAddress (
  1106. IN OUT PENDPOINT Endpoint,
  1107. IN PVOID DeviceName,
  1108. IN PVOID NetbiosName
  1109. )
  1110. {
  1111. NTSTATUS status;
  1112. ULONG i;
  1113. ULONG numAdapters;
  1114. PULONG maxPktArray = NULL;
  1115. UCHAR buffer[sizeof(NWLINK_ACTION) + sizeof(IPX_ADDRESS_DATA) - 1];
  1116. PNWLINK_ACTION action;
  1117. PIPX_ADDRESS_DATA ipxAddressData;
  1118. PAGED_CODE( );
  1119. //
  1120. // Open the NetBIOS name socket.
  1121. //
  1122. status = OpenIpxSocket(
  1123. &Endpoint->NameSocketHandle,
  1124. &Endpoint->NameSocketFileObject,
  1125. &Endpoint->NameSocketDeviceObject,
  1126. DeviceName,
  1127. SMB_IPX_NAME_SOCKET
  1128. );
  1129. if ( !NT_SUCCESS(status) ) {
  1130. goto cleanup;
  1131. }
  1132. Endpoint->IsConnectionless = TRUE;
  1133. action = (PNWLINK_ACTION)buffer;
  1134. //
  1135. // Put the endpoint in broadcast reception mode.
  1136. //
  1137. action->Header.TransportId = 'XPIM'; // "MIPX"
  1138. action->Header.ActionCode = 0;
  1139. action->Header.Reserved = 0;
  1140. action->OptionType = NWLINK_OPTION_ADDRESS;
  1141. action->BufferLength = sizeof(action->Option);
  1142. action->Option = MIPX_RCVBCAST;
  1143. status = SrvIssueTdiAction(
  1144. Endpoint->NameSocketFileObject,
  1145. &Endpoint->NameSocketDeviceObject,
  1146. (PCHAR)action,
  1147. sizeof(NWLINK_ACTION)
  1148. );
  1149. if ( !NT_SUCCESS(status) ) {
  1150. goto cleanup;
  1151. }
  1152. //
  1153. // Tell the transport to give you the extended receive info
  1154. //
  1155. action->Header.TransportId = 'XPIM'; // "MIPX"
  1156. action->Header.ActionCode = 0;
  1157. action->Header.Reserved = 0;
  1158. action->OptionType = NWLINK_OPTION_ADDRESS;
  1159. action->BufferLength = sizeof(action->Option);
  1160. action->Option = MIPX_SETRCVFLAGS;
  1161. status = SrvIssueTdiAction(
  1162. Endpoint->NameSocketFileObject,
  1163. &Endpoint->NameSocketDeviceObject,
  1164. (PCHAR)action,
  1165. sizeof(NWLINK_ACTION)
  1166. );
  1167. if ( !NT_SUCCESS(status) ) {
  1168. goto cleanup;
  1169. }
  1170. //
  1171. // Get the max adapter number
  1172. //
  1173. action->Header.TransportId = 'XPIM'; // "MIPX"
  1174. action->Header.ActionCode = 0;
  1175. action->Header.Reserved = 0;
  1176. action->OptionType = NWLINK_OPTION_ADDRESS;
  1177. action->BufferLength = sizeof(action->Option) + sizeof(ULONG);
  1178. action->Option = MIPX_ADAPTERNUM2;
  1179. status = SrvIssueTdiAction(
  1180. Endpoint->NameSocketFileObject,
  1181. &Endpoint->NameSocketDeviceObject,
  1182. (PCHAR)action,
  1183. sizeof(NWLINK_ACTION) + sizeof(ULONG) - 1
  1184. );
  1185. if ( !NT_SUCCESS(status) ) {
  1186. goto cleanup;
  1187. }
  1188. numAdapters = *((PULONG)action->Data);
  1189. //
  1190. // Allocate an array to store the max pkt size for each adapter
  1191. //
  1192. maxPktArray = ALLOCATE_HEAP( numAdapters * sizeof(ULONG), BlockTypeBuffer );
  1193. if ( maxPktArray == NULL ) {
  1194. status = STATUS_INSUFF_SERVER_RESOURCES;
  1195. goto cleanup;
  1196. }
  1197. Endpoint->IpxMaxPacketSizeArray = maxPktArray;
  1198. Endpoint->MaxAdapters = numAdapters;
  1199. //
  1200. // Query the max pkt size for each adapter
  1201. //
  1202. action->Header.TransportId = 'XPIM'; // "MIPX"
  1203. action->Header.ActionCode = 0;
  1204. action->Header.Reserved = 0;
  1205. action->OptionType = NWLINK_OPTION_ADDRESS;
  1206. action->BufferLength = sizeof(action->Option) + sizeof(IPX_ADDRESS_DATA);
  1207. action->Option = MIPX_GETCARDINFO2;
  1208. ipxAddressData = (PIPX_ADDRESS_DATA)action->Data;
  1209. for ( i = 0; i < numAdapters; i++ ) {
  1210. ipxAddressData->adapternum = i;
  1211. status = SrvIssueTdiAction(
  1212. Endpoint->NameSocketFileObject,
  1213. &Endpoint->NameSocketDeviceObject,
  1214. (PCHAR)action,
  1215. sizeof(NWLINK_ACTION) + sizeof(IPX_ADDRESS_DATA) - 1
  1216. );
  1217. if ( !NT_SUCCESS(status) ) {
  1218. goto cleanup;
  1219. }
  1220. //
  1221. // If this is a wan link, then we need to query the length each
  1222. // time we get a connection.
  1223. //
  1224. if ( ipxAddressData->wan ) {
  1225. maxPktArray[i] = 0;
  1226. } else {
  1227. maxPktArray[i] = ipxAddressData->maxpkt;
  1228. }
  1229. }
  1230. //
  1231. // Find the network address of the adapter used by corresponding to
  1232. // this endpoint.
  1233. //
  1234. GetNetworkAddress( Endpoint );
  1235. //
  1236. // Register the name claim Receive Datagram event handler.
  1237. //
  1238. status = SrvIssueSetEventHandlerRequest(
  1239. Endpoint->NameSocketFileObject,
  1240. &Endpoint->NameSocketDeviceObject,
  1241. TDI_EVENT_RECEIVE_DATAGRAM,
  1242. (PVOID)SrvIpxNameDatagramHandler,
  1243. Endpoint
  1244. );
  1245. if ( !NT_SUCCESS(status) ) {
  1246. INTERNAL_ERROR(
  1247. ERROR_LEVEL_EXPECTED,
  1248. "OpenNonNetbiosAddress: set receive datagram event handler failed: %X",
  1249. status,
  1250. NULL
  1251. );
  1252. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  1253. goto cleanup;
  1254. }
  1255. //
  1256. // Claim the server name.
  1257. //
  1258. status = SrvIpxClaimServerName( Endpoint, NetbiosName );
  1259. if ( !NT_SUCCESS(status) ) {
  1260. goto cleanup;
  1261. }
  1262. //
  1263. // Open the server socket.
  1264. //
  1265. status = OpenIpxSocket(
  1266. &Endpoint->EndpointHandle,
  1267. &Endpoint->FileObject,
  1268. &Endpoint->DeviceObject,
  1269. DeviceName,
  1270. SMB_IPX_SERVER_SOCKET
  1271. );
  1272. if ( !NT_SUCCESS(status) ) {
  1273. goto cleanup;
  1274. }
  1275. //
  1276. // Create a number of free connections for the endpoint. These
  1277. // connections will be used to service Connect events.
  1278. //
  1279. // *** If we fail in an attempt to create a connection, but we can
  1280. // successfully create at least one, we keep the endpoint. The
  1281. // cleanup code below depends on this behavior.
  1282. //
  1283. for ( i = 0; i < SrvFreeConnectionMinimum; i++ ) {
  1284. status = SrvOpenConnection( Endpoint );
  1285. if ( !NT_SUCCESS(status) ) {
  1286. INTERNAL_ERROR(
  1287. ERROR_LEVEL_EXPECTED,
  1288. "OpenNonNetbiosAddress: SrvOpenConnection failed: %X",
  1289. status,
  1290. NULL
  1291. );
  1292. if ( i == 0 ) {
  1293. goto cleanup;
  1294. } else {
  1295. break;
  1296. }
  1297. }
  1298. }
  1299. //
  1300. // Register the server Receive Datagram event handler.
  1301. //
  1302. status = SrvIssueSetEventHandlerRequest(
  1303. Endpoint->FileObject,
  1304. &Endpoint->DeviceObject,
  1305. TDI_EVENT_RECEIVE_DATAGRAM,
  1306. (PVOID)SrvIpxServerDatagramHandler,
  1307. Endpoint
  1308. );
  1309. if ( !NT_SUCCESS(status) ) {
  1310. INTERNAL_ERROR(
  1311. ERROR_LEVEL_EXPECTED,
  1312. "OpenNonNetbiosAddress: set receive datagram event handler failed: %X",
  1313. status,
  1314. NULL
  1315. );
  1316. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  1317. goto cleanup;
  1318. }
  1319. //
  1320. // Register the server Chained Receive Datagram event handler.
  1321. //
  1322. status = SrvIssueSetEventHandlerRequest(
  1323. Endpoint->FileObject,
  1324. &Endpoint->DeviceObject,
  1325. TDI_EVENT_CHAINED_RECEIVE_DATAGRAM,
  1326. (PVOID)SrvIpxServerChainedDatagramHandler,
  1327. Endpoint
  1328. );
  1329. if ( !NT_SUCCESS(status) ) {
  1330. INTERNAL_ERROR(
  1331. ERROR_LEVEL_EXPECTED,
  1332. "OpenNonNetbiosAddress: set chained receive datagram event handler failed: %X",
  1333. status,
  1334. NULL
  1335. );
  1336. SrvLogServiceFailure( SRV_SVC_NT_IOCTL_FILE, status );
  1337. goto cleanup;
  1338. }
  1339. return STATUS_SUCCESS;
  1340. //
  1341. // Out-of-line error cleanup.
  1342. //
  1343. cleanup:
  1344. //
  1345. // Something failed. Clean up as appropriate.
  1346. //
  1347. if ( maxPktArray != NULL ) {
  1348. Endpoint->IpxMaxPacketSizeArray = NULL;
  1349. FREE_HEAP( maxPktArray );
  1350. }
  1351. if ( Endpoint->FileObject != NULL ) {
  1352. ObDereferenceObject( Endpoint->FileObject );
  1353. Endpoint->FileObject = NULL;
  1354. }
  1355. if ( Endpoint->EndpointHandle != NULL ) {
  1356. SRVDBG_RELEASE_HANDLE( Endpoint->EndpointHandle, "END", 14, Endpoint );
  1357. SrvNtClose( Endpoint->EndpointHandle, FALSE );
  1358. Endpoint->FileObject = NULL;
  1359. }
  1360. if ( Endpoint->NameSocketFileObject != NULL ) {
  1361. ObDereferenceObject( Endpoint->NameSocketFileObject );
  1362. Endpoint->NameSocketFileObject = NULL;
  1363. }
  1364. if ( Endpoint->NameSocketHandle != NULL ) {
  1365. SRVDBG_RELEASE_HANDLE( Endpoint->NameSocketHandle, "END", 14, Endpoint );
  1366. SrvNtClose( Endpoint->NameSocketHandle, FALSE );
  1367. Endpoint->NameSocketHandle = NULL;
  1368. }
  1369. return status;
  1370. } // OpenNonNetbiosAddress
  1371. NTSTATUS
  1372. OpenIpxSocket (
  1373. OUT PHANDLE Handle,
  1374. OUT PFILE_OBJECT *FileObject,
  1375. OUT PDEVICE_OBJECT *DeviceObject,
  1376. IN PVOID DeviceName,
  1377. IN USHORT Socket
  1378. )
  1379. {
  1380. NTSTATUS status;
  1381. ULONG length;
  1382. PFILE_FULL_EA_INFORMATION ea;
  1383. TA_IPX_ADDRESS ipxAddress;
  1384. OBJECT_ATTRIBUTES objectAttributes;
  1385. IO_STATUS_BLOCK iosb;
  1386. CHAR buffer[sizeof(FILE_FULL_EA_INFORMATION) +
  1387. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  1388. sizeof(TA_IPX_ADDRESS)];
  1389. PAGED_CODE( );
  1390. //
  1391. // Build the IPX socket address.
  1392. //
  1393. length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  1394. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  1395. sizeof(TA_IPX_ADDRESS);
  1396. ea = (PFILE_FULL_EA_INFORMATION)buffer;
  1397. ea->NextEntryOffset = 0;
  1398. ea->Flags = 0;
  1399. ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  1400. ea->EaValueLength = sizeof (TA_IPX_ADDRESS);
  1401. RtlCopyMemory( ea->EaName, StrTransportAddress, ea->EaNameLength + 1 );
  1402. //
  1403. // Create a copy of the NETBIOS address descriptor in a local
  1404. // first, in order to avoid alignment problems.
  1405. //
  1406. ipxAddress.TAAddressCount = 1;
  1407. ipxAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
  1408. ipxAddress.Address[0].AddressLength = sizeof (TDI_ADDRESS_IPX);
  1409. ipxAddress.Address[0].Address[0].Socket = Socket;
  1410. RtlCopyMemory(
  1411. &ea->EaName[ea->EaNameLength + 1],
  1412. &ipxAddress,
  1413. sizeof(TA_IPX_ADDRESS)
  1414. );
  1415. InitializeObjectAttributes( &objectAttributes, DeviceName, 0, NULL, NULL );
  1416. status = NtCreateFile (
  1417. Handle,
  1418. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access
  1419. &objectAttributes, // object attributes
  1420. &iosb, // returned status information
  1421. NULL, // block size (unused)
  1422. 0, // file attributes
  1423. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  1424. FILE_CREATE, // create disposition
  1425. 0, // create options
  1426. buffer, // EA buffer
  1427. length // EA length
  1428. );
  1429. if ( !NT_SUCCESS(status) ) {
  1430. return status;
  1431. }
  1432. status = SrvVerifyDeviceStackSize(
  1433. *Handle,
  1434. TRUE,
  1435. FileObject,
  1436. DeviceObject,
  1437. NULL
  1438. );
  1439. if ( !NT_SUCCESS( status ) ) {
  1440. INTERNAL_ERROR(
  1441. ERROR_LEVEL_EXPECTED,
  1442. "OpenIpxSocket: Verify Device Stack Size failed: %X\n",
  1443. status,
  1444. NULL
  1445. );
  1446. return status;
  1447. }
  1448. return STATUS_SUCCESS;
  1449. } // OpenIpxSocket
  1450. VOID
  1451. SrvPrepareReceiveWorkItem (
  1452. IN OUT PWORK_CONTEXT WorkContext,
  1453. IN BOOLEAN QueueItemToFreeList
  1454. )
  1455. /*++
  1456. Routine Description:
  1457. This routine initializes a Receive work item and optionally queues
  1458. it to a list anchored in the server FSD device object. The
  1459. transport receive event handler in the FSD dequeues work items from
  1460. this list and passes their associated IRPS to the transport
  1461. provider.
  1462. Arguments:
  1463. WorkContext - Supplies a pointer to the preallocated work context
  1464. block that represents the work item.
  1465. QueueItemToFreeList - If TRUE queue this work item on the receive
  1466. free queue.
  1467. Return Value:
  1468. None.
  1469. --*/
  1470. {
  1471. PSMB_HEADER header;
  1472. IF_DEBUG(TRACE2) KdPrint(( "SrvPrepareReceiveWorkItem entered\n" ));
  1473. //
  1474. // Set up pointers to the SMB header and parameters for the request
  1475. // and the response. Note that we currently write the response over
  1476. // the request. SMB processors must be able to handle this. We
  1477. // maintain separate request and response pointers so that we can
  1478. // use a separate buffer if necessary. Maintaining separate request
  1479. // and response parameter pointers also allows us to process AndX
  1480. // SMBs without having to pack the AndX commands as we go.
  1481. //
  1482. WorkContext->ResponseBuffer = WorkContext->RequestBuffer;
  1483. header = (PSMB_HEADER)WorkContext->RequestBuffer->Buffer;
  1484. WorkContext->RequestHeader = header;
  1485. WorkContext->RequestParameters = (PVOID)(header + 1);
  1486. WorkContext->ResponseHeader = header;
  1487. WorkContext->ResponseParameters = (PVOID)(header + 1);
  1488. //
  1489. // Set up the restart routine in the work context.
  1490. //
  1491. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1492. WorkContext->FspRestartRoutine = SrvRestartReceive;
  1493. if ( QueueItemToFreeList ) {
  1494. //
  1495. // Queue the prepared receive work item to the FSD list.
  1496. //
  1497. GET_SERVER_TIME( WorkContext->CurrentWorkQueue, &WorkContext->Timestamp );
  1498. RETURN_FREE_WORKITEM( WorkContext );
  1499. } else {
  1500. //
  1501. // Make the work item look like it's in use by setting its
  1502. // reference count to 1.
  1503. //
  1504. ASSERT( WorkContext->BlockHeader.ReferenceCount == 0 );
  1505. WorkContext->BlockHeader.ReferenceCount = 1;
  1506. }
  1507. return;
  1508. } // SrvPrepareReceiveWorkItem
  1509. VOID SRVFASTCALL
  1510. SrvRestartAccept (
  1511. IN OUT PWORK_CONTEXT WorkContext
  1512. )
  1513. /*++
  1514. Routine Description:
  1515. This function is the worker thread restart routine for Accept
  1516. requests. If the endpoint on which the connection was established
  1517. is no longer active, this routine disconnects the connection. This
  1518. is necessary because the connect indication handler cannot
  1519. atomically verify that the endpoint is active and install the active
  1520. connection. (This is because the handler runs at DPC level.)
  1521. This routine also checks the status of the TdiAccept. In case of
  1522. an error, it frees the connection.
  1523. If all is well, but the endpoint is short of free connections, a new
  1524. one is created.
  1525. Arguments:
  1526. WorkContext - Supplies a pointer to the work context block describing
  1527. server-specific context for the request.
  1528. Return Value:
  1529. None.
  1530. --*/
  1531. {
  1532. PCONNECTION connection;
  1533. PENDPOINT endpoint;
  1534. PIRP irp;
  1535. NTSTATUS status;
  1536. PAGED_CODE( );
  1537. IF_DEBUG(WORKER1) KdPrint(( " - SrvRestartAccept\n" ));
  1538. connection = WorkContext->Connection;
  1539. endpoint = WorkContext->Endpoint;
  1540. irp = WorkContext->Irp;
  1541. IF_DEBUG(TRACE2) {
  1542. KdPrint(( " connection %p, endpoint %p, IRP %p\n",
  1543. connection, endpoint, irp ));
  1544. }
  1545. //
  1546. // If the I/O request failed or was canceled, or if the endpoint
  1547. // block is closing, clean up.
  1548. //
  1549. ACQUIRE_LOCK( &SrvEndpointLock );
  1550. if ( irp->Cancel ||
  1551. !NT_SUCCESS(irp->IoStatus.Status) ||
  1552. (GET_BLOCK_STATE(endpoint) != BlockStateActive) ) {
  1553. RELEASE_LOCK( &SrvEndpointLock );
  1554. DEBUG {
  1555. KdPrint(( "SrvRestartAccept: Accept failed!" ));
  1556. if ( irp->Cancel ) {
  1557. KdPrint(( " I/O canceled\n" ));
  1558. } else if ( !NT_SUCCESS(irp->IoStatus.Status) ) {
  1559. KdPrint(( " I/O failed: %X\n", irp->IoStatus.Status ));
  1560. } else {
  1561. KdPrint(( " Endpoint no longer active\n" ));
  1562. }
  1563. }
  1564. //
  1565. // Close the connection. If the Accept succeeded, we need to
  1566. // issue a Disconnect.
  1567. //
  1568. #if SRVDBG29
  1569. if (irp->Cancel) {
  1570. UpdateConnectionHistory( "ACC1", endpoint, connection );
  1571. } else if (!NT_SUCCESS(irp->IoStatus.Status)) {
  1572. UpdateConnectionHistory( "ACC2", endpoint, connection );
  1573. } else {
  1574. UpdateConnectionHistory( "ACC3", endpoint, connection );
  1575. }
  1576. #endif
  1577. connection->DisconnectReason = DisconnectAcceptFailedOrCancelled;
  1578. SrvCloseConnection(
  1579. connection,
  1580. (BOOLEAN)(irp->Cancel || !NT_SUCCESS(irp->IoStatus.Status) ?
  1581. TRUE : FALSE) // RemoteDisconnect
  1582. );
  1583. } else {
  1584. PNBT_ADDRESS_PAIR_INFO AddressPairInfo;
  1585. UNICODE_STRING clientMachineName;
  1586. //
  1587. // The Accept worked, and the endpoint is still active. Create
  1588. // a new free connection, if necessary.
  1589. //
  1590. if ( endpoint->FreeConnectionCount < SrvFreeConnectionMinimum ) {
  1591. (VOID)SrvOpenConnection( endpoint );
  1592. }
  1593. RELEASE_LOCK( &SrvEndpointLock );
  1594. //
  1595. // Get the IP address of the client (if it has one)
  1596. //
  1597. AddressPairInfo = WorkContext->RequestBuffer->Buffer;
  1598. AddressPairInfo = (PNBT_ADDRESS_PAIR_INFO)(((ULONG_PTR)AddressPairInfo + 7) & ~7);
  1599. //
  1600. // Get the IP address of the client, if appropriate
  1601. //
  1602. status = SrvIssueTdiQuery( connection->FileObject,
  1603. &connection->DeviceObject,
  1604. (PCHAR)AddressPairInfo, sizeof( *AddressPairInfo ),
  1605. TDI_QUERY_ADDRESS_INFO
  1606. );
  1607. if( NT_SUCCESS( status ) &&
  1608. AddressPairInfo->AddressPair.TAAddressCount == 2 &&
  1609. AddressPairInfo->AddressPair.AddressIP.AddressType == TDI_ADDRESS_TYPE_IP ) {
  1610. PTCP_REQUEST_SET_INFORMATION_EX tcpSetInfo;
  1611. struct TCPKeepalive *keepAlive;
  1612. IO_STATUS_BLOCK iosb;
  1613. connection->ClientIPAddress = AddressPairInfo->AddressPair.AddressIP.Address.in_addr;
  1614. //
  1615. // We have an IP client. Set a reasonable keepalive interval.
  1616. //
  1617. tcpSetInfo = ALLOCATE_HEAP( sizeof(*tcpSetInfo) + sizeof( *keepAlive ), BlockTypeMisc );
  1618. if( tcpSetInfo != NULL ) {
  1619. RtlZeroMemory( tcpSetInfo, sizeof( *tcpSetInfo ) + sizeof( *keepAlive ) );
  1620. tcpSetInfo->ID.toi_entity.tei_entity = CO_TL_ENTITY;
  1621. tcpSetInfo->ID.toi_class = INFO_CLASS_PROTOCOL;
  1622. tcpSetInfo->ID.toi_type = INFO_TYPE_CONNECTION;
  1623. tcpSetInfo->ID.toi_id = TCP_SOCKET_KEEPALIVE_VALS;
  1624. tcpSetInfo->BufferSize = sizeof( *keepAlive );
  1625. keepAlive = (TCPKeepalive *)(&tcpSetInfo->Buffer[0]);
  1626. keepAlive->onoff = TRUE; // turn on keepalives
  1627. //
  1628. // keepalive time is the time to first keepalive transmission, by default it
  1629. // is 2 hours (7,200,000 milliseconds) for TCP. If there is no data transfer between
  1630. // client and server for keepalive time, the server will send first keepalive
  1631. // probe. Successive probes are determined by keepalive interval. If there is any
  1632. // data transfer, timer is reset to keepalive time.
  1633. //
  1634. // keepalive interval is the interval in milliseconds between keepalive transmissions
  1635. // until a response is received, by default it is 1000. Server sends a total of 10
  1636. // keepalive probes, keepalive interval apart, and if there is no response from the
  1637. // client, the connection is terminated.
  1638. //
  1639. keepAlive->keepalivetime = 2 * (60 * 1000); // 2 minutes
  1640. keepAlive->keepaliveinterval = 2 * 1000; // 2 seconds
  1641. //
  1642. // Set the keepalive values
  1643. //
  1644. (VOID)NtDeviceIoControlFile(
  1645. connection->PagedConnection->ConnectionHandle,
  1646. 0,
  1647. NULL,
  1648. NULL,
  1649. &iosb,
  1650. IOCTL_NETBT_SET_TCP_CONNECTION_INFO,
  1651. tcpSetInfo, sizeof( *tcpSetInfo ) + sizeof( *keepAlive ),
  1652. NULL, 0
  1653. );
  1654. FREE_HEAP( tcpSetInfo );
  1655. }
  1656. } else {
  1657. connection->ClientIPAddress = 0;
  1658. }
  1659. //
  1660. // Convert the client machine name to unicode
  1661. //
  1662. clientMachineName.Buffer = connection->PagedConnection->ClientMachineName;
  1663. clientMachineName.MaximumLength =
  1664. (USHORT)(COMPUTER_NAME_LENGTH+1)*sizeof(WCHAR);
  1665. (VOID)RtlOemStringToUnicodeString(
  1666. &clientMachineName,
  1667. &connection->OemClientMachineNameString,
  1668. FALSE
  1669. );
  1670. //
  1671. // Add the double backslashes to the length
  1672. //
  1673. connection->PagedConnection->ClientMachineNameString.Length =
  1674. (USHORT)(clientMachineName.Length + 2*sizeof(WCHAR));
  1675. }
  1676. SrvDereferenceWorkItem( WorkContext );
  1677. IF_DEBUG(TRACE2) KdPrint(( "SrvRestartAccept complete\n" ));
  1678. return;
  1679. } // SrvRestartAccept
  1680. VOID
  1681. SrvStartSend (
  1682. IN OUT PWORK_CONTEXT WorkContext,
  1683. IN PIO_COMPLETION_ROUTINE SendCompletionRoutine,
  1684. IN PMDL Mdl OPTIONAL,
  1685. IN ULONG SendOptions
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. This function starts a Send request. It is started as an
  1690. asynchronous I/O request. When the Send completes, it is delivered
  1691. via the I/O completion routine to the server FSD, which routes it to
  1692. the specified FsdRestartRoutine. (This may be
  1693. SrvQueueWorkToFspAtDpcLevel, which queues the work item to the FSP
  1694. at the FspRestartRoutine.)
  1695. Partial sends and chained sends are supported. A partial send is one
  1696. that is not the last segment of a "message" or "record". A chained
  1697. send is one made up of multiple virtually discontiguous buffers.
  1698. Arguments:
  1699. WorkContext - Supplies a pointer to a Work Context block. The
  1700. following fields of this structure must be valid:
  1701. TdiRequest
  1702. Irp (optional; actual address copied here)
  1703. Endpoint
  1704. Endpoint->FileObject
  1705. Endpoint->DeviceObject
  1706. Connection
  1707. Connection->ConnectionId
  1708. Mdl - Supplies a pointer to the first (or only) MDL describing the
  1709. data that is to be sent. To effect a chained send, the Next
  1710. pointer of each MDL in the chain must point to the next MDL;
  1711. the end of the chain is indicated by the NULL Next pointer.
  1712. The total length of the send is calculated by summing the
  1713. ByteCount fields of each MDL in the chain.
  1714. This parameter is optional. If it is omitted, a zero-length
  1715. message is sent.
  1716. SendOptions - Supplied TDI send options, which indicate whether this
  1717. send is the last (or only) in a "chain" of partial sends.
  1718. Return Value:
  1719. None.
  1720. --*/
  1721. {
  1722. PTDI_REQUEST_KERNEL_SEND parameters;
  1723. PIO_STACK_LOCATION irpSp;
  1724. PIRP irp;
  1725. ULONG sendLength;
  1726. PDEVICE_OBJECT deviceObject;
  1727. PFILE_OBJECT fileObject;
  1728. IF_DEBUG(TRACE2) KdPrint(( "SrvStartSend entered\n" ));
  1729. ASSERT( !WorkContext->Endpoint->IsConnectionless );
  1730. //
  1731. // Set ProcessingCount to zero so this send cannot be cancelled.
  1732. // This is used together with setting the cancel flag to false below.
  1733. //
  1734. // WARNING: This still presents us with a tiny window where this
  1735. // send could be cancelled.
  1736. //
  1737. WorkContext->ProcessingCount = 0;
  1738. //
  1739. // Get the irp, device, and file objects
  1740. //
  1741. irp = WorkContext->Irp;
  1742. deviceObject = WorkContext->Connection->DeviceObject;
  1743. fileObject = WorkContext->Connection->FileObject;
  1744. CHECKIRP( irp );
  1745. if( irp->AssociatedIrp.SystemBuffer &&
  1746. (irp->Flags & IRP_DEALLOCATE_BUFFER) ) {
  1747. ExFreePool( irp->AssociatedIrp.SystemBuffer );
  1748. irp->Flags &= ~IRP_DEALLOCATE_BUFFER;
  1749. }
  1750. sendLength = WorkContext->ResponseBuffer->DataLength;
  1751. //
  1752. // Build the I/O request packet.
  1753. //
  1754. // *** Note that the connection block is not referenced to account
  1755. // for this I/O request. The WorkContext block already has a
  1756. // referenced pointer to the connection, and this pointer is not
  1757. // dereferenced until after the I/O completes.
  1758. //
  1759. ASSERT( irp->StackCount >= deviceObject->StackSize );
  1760. irp->Tail.Overlay.OriginalFileObject = fileObject;
  1761. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1762. DEBUG irp->RequestorMode = KernelMode;
  1763. //
  1764. // Get a pointer to the next stack location. This one is used to
  1765. // hold the parameters for the device I/O control request.
  1766. //
  1767. irpSp = IoGetNextIrpStackLocation( irp );
  1768. //
  1769. // Set up the completion routine.
  1770. //
  1771. IoSetCompletionRoutine(
  1772. irp,
  1773. SendCompletionRoutine,
  1774. (PVOID)WorkContext,
  1775. TRUE,
  1776. TRUE,
  1777. TRUE
  1778. );
  1779. irpSp->FileObject = fileObject;
  1780. parameters = (PTDI_REQUEST_KERNEL_SEND)&irpSp->Parameters;
  1781. parameters->SendFlags = SendOptions;
  1782. parameters->SendLength = sendLength;
  1783. //
  1784. // For these two cases, InputBuffer is the buffered I/O "system
  1785. // buffer". Build an MDL for either read or write access,
  1786. // depending on the method, for the output buffer.
  1787. //
  1788. irp->MdlAddress = Mdl;
  1789. //
  1790. // If statistics are to be gathered for this work item, do so now.
  1791. //
  1792. UPDATE_STATISTICS(
  1793. WorkContext,
  1794. sendLength,
  1795. WorkContext->ResponseHeader->Command
  1796. );
  1797. #if DBG
  1798. if( sendLength >= sizeof( SMB_HEADER ) && sendLength <= 0xffff && Mdl ) {
  1799. PSMB_HEADER Smb = MmGetSystemAddressForMdl( Mdl );
  1800. if ( SmbGetAlignedUlong( (PULONG)Smb->Protocol ) == SMB_HEADER_PROTOCOL ) {
  1801. ULONG len;
  1802. PMDL tmpMdl;
  1803. //
  1804. // For debugging purposes, put extra data in the response smb. This will help us figure
  1805. // out what went wrong if the client detects an SMB format error
  1806. //
  1807. //
  1808. // Put the send length in PidHigh
  1809. //
  1810. SmbPutUshort( &Smb->PidHigh, (USHORT)sendLength );
  1811. //
  1812. // Put the overall MDL length in Pid. The transport is only supposed to transmit SendLength -- so
  1813. // this will help us figure out if the transport is sending too much data.
  1814. //
  1815. for( len = 0, tmpMdl = Mdl; tmpMdl != NULL; tmpMdl = tmpMdl->Next ) {
  1816. len += MmGetMdlByteCount( tmpMdl );
  1817. }
  1818. SmbPutUshort( &Smb->Pid, (USHORT)len );
  1819. }
  1820. }
  1821. #endif
  1822. //
  1823. // If we are doing security signatures, we need to sign this packet
  1824. //
  1825. if( sendLength &&
  1826. WorkContext->Connection &&
  1827. WorkContext->Connection->SmbSecuritySignatureActive == TRUE &&
  1828. WorkContext->NoResponseSmbSecuritySignature == FALSE ) {
  1829. SrvAddSmbSecuritySignature( WorkContext, Mdl, sendLength );
  1830. }
  1831. //
  1832. // Pass the request to the transport provider.
  1833. //
  1834. IF_DEBUG(TRACE2) {
  1835. KdPrint(( "SrvStartSend posting Send IRP %p\n", irp ));
  1836. }
  1837. //
  1838. // If SmbTrace is active and we're in a context where the SmbTrace
  1839. // shared section isn't accessible, send this off to the FSP.
  1840. //
  1841. WorkContext->Irp->Cancel = FALSE;
  1842. if ( SmbTraceActive[SMBTRACE_SERVER] ) {
  1843. if ((KeGetCurrentIrql() == DISPATCH_LEVEL) ||
  1844. (IoGetCurrentProcess() != SrvServerProcess) ) {
  1845. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1846. irpSp->MinorFunction = TDI_SEND;
  1847. irp->AssociatedIrp.SystemBuffer = NULL;
  1848. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  1849. WorkContext->Parameters2.StartSend.FspRestartRoutine =
  1850. WorkContext->FspRestartRoutine;
  1851. WorkContext->Parameters2.StartSend.SendLength = sendLength;
  1852. WorkContext->FspRestartRoutine = RestartStartSend;
  1853. SrvQueueWorkToFsp( WorkContext );
  1854. return;
  1855. } else {
  1856. SMBTRACE_SRV( Mdl );
  1857. }
  1858. }
  1859. //
  1860. // Increment the pending operation count
  1861. //
  1862. InterlockedIncrement( &WorkContext->Connection->OperationsPendingOnTransport );
  1863. //
  1864. // Set the cancel flag to FALSE in case this was cancelled by
  1865. // the SrvSmbNtCancel routine.
  1866. //
  1867. if ( WorkContext->Endpoint->FastTdiSend ) {
  1868. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.DirectSendsAttempted );
  1869. irpSp->MinorFunction = TDI_DIRECT_SEND;
  1870. DEBUG irpSp->DeviceObject = deviceObject;
  1871. IoSetNextIrpStackLocation( irp );
  1872. WorkContext->Endpoint->FastTdiSend( deviceObject, irp );
  1873. } else {
  1874. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1875. irpSp->MinorFunction = TDI_SEND;
  1876. irp->AssociatedIrp.SystemBuffer = NULL;
  1877. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  1878. (VOID)IoCallDriver( deviceObject, irp );
  1879. }
  1880. IF_DEBUG(TRACE2) KdPrint(( "SrvStartSend complete\n" ));
  1881. return;
  1882. } // SrvStartSend
  1883. VOID
  1884. SrvStartSend2 (
  1885. IN OUT PWORK_CONTEXT WorkContext,
  1886. IN PIO_COMPLETION_ROUTINE SendCompletionRoutine
  1887. )
  1888. /*++
  1889. Routine Description:
  1890. This function starts a Send request. It is started as an
  1891. asynchronous I/O request. When the Send completes, it is delivered
  1892. via the I/O completion routine to the server FSD, which routes it to
  1893. the specified FsdRestartRoutine. (This may be
  1894. SrvQueueWorkToFspAtDpcLevel, which queues the work item to the FSP
  1895. at the FspRestartRoutine.)
  1896. Partial sends and chained sends are supported. A partial send is one
  1897. that is not the last segment of a "message" or "record". A chained
  1898. send is one made up of multiple virtually discontiguous buffers.
  1899. ** This is identical to SrvStartSend except that the parameter mdl
  1900. is assumed to be ResponseBuffer->Mdl and sendOptions is assumed to be
  1901. 0 **
  1902. Arguments:
  1903. WorkContext - Supplies a pointer to a Work Context block. The
  1904. following fields of this structure must be valid:
  1905. TdiRequest
  1906. Irp (optional; actual address copied here)
  1907. Endpoint
  1908. Endpoint->FileObject
  1909. Endpoint->DeviceObject
  1910. Connection
  1911. Connection->ConnectionId
  1912. Return Value:
  1913. None.
  1914. --*/
  1915. {
  1916. PTDI_REQUEST_KERNEL_SEND parameters;
  1917. PIO_STACK_LOCATION irpSp;
  1918. PIRP irp;
  1919. PDEVICE_OBJECT deviceObject;
  1920. PFILE_OBJECT fileObject;
  1921. PMDL mdl = WorkContext->ResponseBuffer->Mdl;
  1922. ULONG sendLength = WorkContext->ResponseBuffer->DataLength;
  1923. IF_DEBUG(TRACE2) KdPrint(( "SrvStartSend2 entered\n" ));
  1924. ASSERT( !WorkContext->Endpoint->IsConnectionless );
  1925. //
  1926. // Set ProcessingCount to zero so this send cannot be cancelled.
  1927. // This is used together with setting the cancel flag to false below.
  1928. //
  1929. // WARNING: This still presents us with a tiny window where this
  1930. // send could be cancelled.
  1931. //
  1932. WorkContext->ProcessingCount = 0;
  1933. //
  1934. // Get the irp, device, and file objects
  1935. //
  1936. irp = WorkContext->Irp;
  1937. deviceObject = WorkContext->Connection->DeviceObject;
  1938. fileObject = WorkContext->Connection->FileObject;
  1939. CHECKIRP( irp );
  1940. if( irp->AssociatedIrp.SystemBuffer &&
  1941. (irp->Flags & IRP_DEALLOCATE_BUFFER) ) {
  1942. ExFreePool( irp->AssociatedIrp.SystemBuffer );
  1943. irp->Flags &= ~IRP_DEALLOCATE_BUFFER;
  1944. }
  1945. //
  1946. // Build the I/O request packet.
  1947. //
  1948. // *** Note that the connection block is not referenced to account
  1949. // for this I/O request. The WorkContext block already has a
  1950. // referenced pointer to the connection, and this pointer is not
  1951. // dereferenced until after the I/O completes.
  1952. //
  1953. ASSERT( irp->StackCount >= deviceObject->StackSize );
  1954. irp->Tail.Overlay.OriginalFileObject = fileObject;
  1955. irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
  1956. DEBUG irp->RequestorMode = KernelMode;
  1957. //
  1958. // Get a pointer to the next stack location. This one is used to
  1959. // hold the parameters for the device I/O control request.
  1960. //
  1961. irpSp = IoGetNextIrpStackLocation( irp );
  1962. //
  1963. // Set up the completion routine.
  1964. //
  1965. IoSetCompletionRoutine(
  1966. irp,
  1967. SendCompletionRoutine,
  1968. (PVOID)WorkContext,
  1969. TRUE,
  1970. TRUE,
  1971. TRUE
  1972. );
  1973. irpSp->FileObject = fileObject;
  1974. parameters = (PTDI_REQUEST_KERNEL_SEND)&irpSp->Parameters;
  1975. parameters->SendFlags = 0;
  1976. parameters->SendLength = sendLength;
  1977. //
  1978. // For these two cases, InputBuffer is the buffered I/O "system
  1979. // buffer". Build an MDL for either read or write access,
  1980. // depending on the method, for the output buffer.
  1981. //
  1982. irp->MdlAddress = mdl;
  1983. //
  1984. // If statistics are to be gathered for this work item, do so now.
  1985. //
  1986. UPDATE_STATISTICS(
  1987. WorkContext,
  1988. sendLength,
  1989. WorkContext->ResponseHeader->Command
  1990. );
  1991. #if DBG
  1992. if( sendLength >= sizeof( SMB_HEADER ) && sendLength <= 0xffff && mdl ) {
  1993. PSMB_HEADER Smb = MmGetSystemAddressForMdl( mdl );
  1994. if ( SmbGetAlignedUlong( (PULONG)Smb->Protocol ) == SMB_HEADER_PROTOCOL ) {
  1995. ULONG len;
  1996. PMDL tmpMdl;
  1997. //
  1998. // For debugging purposes, put extra data in the response smb. This
  1999. // will help us figure out what went wrong if the client detects an
  2000. // SMB format error
  2001. //
  2002. //
  2003. // Put the send length in PidHigh
  2004. //
  2005. SmbPutUshort( &Smb->PidHigh, (USHORT)sendLength );
  2006. //
  2007. // Put the overall MDL length in Pid. The transport is only supposed
  2008. // to transmit SendLength -- so this will help us figure out if the
  2009. // transport is sending too much data.
  2010. //
  2011. for( len = 0, tmpMdl = mdl; tmpMdl != NULL; tmpMdl = tmpMdl->Next ) {
  2012. len += MmGetMdlByteCount( tmpMdl );
  2013. }
  2014. SmbPutUshort( &Smb->Pid, (USHORT)len );
  2015. }
  2016. }
  2017. #endif
  2018. //
  2019. // If we are doing security signatures, we need to sign this packet
  2020. //
  2021. if( sendLength &&
  2022. WorkContext->Connection &&
  2023. WorkContext->Connection->SmbSecuritySignatureActive == TRUE &&
  2024. WorkContext->NoResponseSmbSecuritySignature == FALSE ) {
  2025. SrvAddSmbSecuritySignature( WorkContext, mdl, sendLength );
  2026. }
  2027. //
  2028. // Pass the request to the transport provider.
  2029. //
  2030. IF_DEBUG(TRACE2) {
  2031. KdPrint(( "SrvStartSend2 posting Send IRP %p\n", irp ));
  2032. }
  2033. //
  2034. // If SmbTrace is active and we're in a context where the SmbTrace
  2035. // shared section isn't accessible, send this off to the FSP.
  2036. //
  2037. WorkContext->Irp->Cancel = FALSE;
  2038. if ( SmbTraceActive[SMBTRACE_SERVER] ) {
  2039. if ((KeGetCurrentIrql() == DISPATCH_LEVEL) ||
  2040. (IoGetCurrentProcess() != SrvServerProcess) ) {
  2041. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  2042. irpSp->MinorFunction = TDI_SEND;
  2043. irp->AssociatedIrp.SystemBuffer = NULL;
  2044. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  2045. WorkContext->Parameters2.StartSend.FspRestartRoutine =
  2046. WorkContext->FspRestartRoutine;
  2047. WorkContext->Parameters2.StartSend.SendLength = sendLength;
  2048. WorkContext->FspRestartRoutine = RestartStartSend;
  2049. SrvQueueWorkToFsp( WorkContext );
  2050. return;
  2051. } else {
  2052. SMBTRACE_SRV( mdl );
  2053. }
  2054. }
  2055. //
  2056. // Increment the pending operation count
  2057. //
  2058. InterlockedIncrement( &WorkContext->Connection->OperationsPendingOnTransport );
  2059. //
  2060. // Set the cancel flag to FALSE in case this was cancelled by
  2061. // the SrvSmbNtCancel routine.
  2062. //
  2063. if ( WorkContext->Endpoint->FastTdiSend ) {
  2064. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.DirectSendsAttempted );
  2065. irpSp->MinorFunction = TDI_DIRECT_SEND;
  2066. DEBUG irpSp->DeviceObject = deviceObject;
  2067. IoSetNextIrpStackLocation( irp );
  2068. WorkContext->Endpoint->FastTdiSend( deviceObject, irp );
  2069. } else {
  2070. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  2071. irpSp->MinorFunction = TDI_SEND;
  2072. irp->AssociatedIrp.SystemBuffer = NULL;
  2073. irp->Flags = (ULONG)IRP_BUFFERED_IO;
  2074. (VOID)IoCallDriver( deviceObject, irp );
  2075. }
  2076. IF_DEBUG(TRACE2) KdPrint(( "SrvStartSend2 complete\n" ));
  2077. return;
  2078. } // SrvStartSend2
  2079. VOID SRVFASTCALL
  2080. RestartStartSend (
  2081. IN OUT PWORK_CONTEXT WorkContext
  2082. )
  2083. /*++
  2084. Routine Description:
  2085. Arguments:
  2086. WorkContext - Supplies a pointer to a Work Context block.
  2087. Return Value:
  2088. None.
  2089. --*/
  2090. {
  2091. PAGED_CODE( );
  2092. WorkContext->FspRestartRoutine =
  2093. WorkContext->Parameters2.StartSend.FspRestartRoutine;
  2094. SMBTRACE_SRV( WorkContext->Irp->MdlAddress );
  2095. //
  2096. // Increment the pending operation count
  2097. //
  2098. InterlockedIncrement( &WorkContext->Connection->OperationsPendingOnTransport );
  2099. //
  2100. // Set the cancel flag to FALSE in case this was cancelled by
  2101. // the SrvSmbNtCancel routine.
  2102. //
  2103. WorkContext->Irp->Cancel = FALSE;
  2104. (VOID)IoCallDriver(
  2105. IoGetNextIrpStackLocation( WorkContext->Irp )->DeviceObject,
  2106. WorkContext->Irp
  2107. );
  2108. IF_DEBUG(TRACE2) KdPrint(( "SrvRestartStartSend complete\n" ));
  2109. return;
  2110. } // RestartStartSend
  2111. ULONG
  2112. GetIpxMaxBufferSize(
  2113. PENDPOINT Endpoint,
  2114. ULONG AdapterNumber,
  2115. ULONG DefaultMaxBufferSize
  2116. )
  2117. /*++
  2118. Routine Description:
  2119. This routine computes the max buffer size the server negotiates
  2120. with the client. It takes the smaller of DefaultMaxBufferSize
  2121. and the max packet length returned by the ipx transport.
  2122. Arguments:
  2123. Endpoint - pointer to the endpoint corresponding to the ipx transport
  2124. AdapterNumber - the adapter number for which the max buffer size is to
  2125. be computed for.
  2126. DefaultMaxBufferSize - the maximum size that can be returned by this
  2127. routine.
  2128. Return Value:
  2129. The max buffer size to be negotiated by the server.
  2130. --*/
  2131. {
  2132. NTSTATUS status;
  2133. ULONG maxBufferSize;
  2134. PNWLINK_ACTION action;
  2135. PIPX_ADDRESS_DATA ipxAddressData;
  2136. UCHAR buffer[sizeof(NWLINK_ACTION) + sizeof(IPX_ADDRESS_DATA) - 1];
  2137. PAGED_CODE( );
  2138. action = (PNWLINK_ACTION)buffer;
  2139. //
  2140. // Verify that the adapter number is within bounds
  2141. //
  2142. if ( AdapterNumber > Endpoint->MaxAdapters ) {
  2143. return DefaultMaxBufferSize;
  2144. }
  2145. //
  2146. // If value in array is non-zero, then this is not a wan link.
  2147. // Use that value.
  2148. //
  2149. if ( Endpoint->IpxMaxPacketSizeArray[AdapterNumber-1] != 0 ) {
  2150. maxBufferSize = MIN(
  2151. Endpoint->IpxMaxPacketSizeArray[AdapterNumber-1],
  2152. DefaultMaxBufferSize
  2153. );
  2154. return (maxBufferSize & ~3);
  2155. }
  2156. //
  2157. // This is a wan link, query the max packet size.
  2158. //
  2159. action->Header.TransportId = 'XPIM'; // "MIPX"
  2160. action->Header.ActionCode = 0;
  2161. action->Header.Reserved = 0;
  2162. action->OptionType = NWLINK_OPTION_ADDRESS;
  2163. action->BufferLength = sizeof(action->Option) + sizeof(IPX_ADDRESS_DATA);
  2164. action->Option = MIPX_GETCARDINFO2;
  2165. ipxAddressData = (PIPX_ADDRESS_DATA)action->Data;
  2166. ipxAddressData->adapternum = AdapterNumber - 1;
  2167. status = SrvIssueTdiAction(
  2168. Endpoint->NameSocketFileObject,
  2169. &Endpoint->NameSocketDeviceObject,
  2170. (PCHAR)action,
  2171. sizeof(NWLINK_ACTION) + sizeof(IPX_ADDRESS_DATA) - 1
  2172. );
  2173. if ( !NT_SUCCESS(status) ) {
  2174. return DefaultMaxBufferSize;
  2175. }
  2176. ASSERT( ipxAddressData->wan );
  2177. maxBufferSize = MIN(
  2178. (ULONG)ipxAddressData->maxpkt,
  2179. DefaultMaxBufferSize
  2180. );
  2181. return (maxBufferSize & ~3);
  2182. } // GetMaxIpxPacketSize
  2183. VOID
  2184. SrvpNotifyChangesToNetBt(
  2185. IN TDI_PNP_OPCODE PnPOpcode,
  2186. IN PUNICODE_STRING DeviceName,
  2187. IN PWSTR MultiSZBindList)
  2188. /*++
  2189. Routine Description:
  2190. This routine should not be part of srv. It has been introduced into this
  2191. component to overcome current limitations in NetBt. The NetBt transport
  2192. exposes two kinds of devices -- the traditional NetBt device and the
  2193. new non Netbios device which make use of the NetBt framing code without the
  2194. name resolution aspects of it. The current implementation in NetBt exposes
  2195. the former devices on a per adapter basis while the second category of device
  2196. is exposed on a global basis ( one for all the adapters ). This poses
  2197. problems in disabling/enabling srv on a given adapter.
  2198. The correct solution is to expose the second category of devices on a per
  2199. adapter basis. Till it is done this workaround is reqd. With this workaround
  2200. whenever the server is notified of any changes to the binding string it turns
  2201. around and notifies the NetBt transport about these changes.
  2202. This routine is based upon the following assumptions ...
  2203. 1) The notification from TDI is not done at raised IRQL.
  2204. 2) The thread on which this notification occurs has enough access rights.
  2205. 3) The notification to NetBt is done asynchronously with srv's reaction
  2206. to the change. The srv handles the PNP notification by passing it off to
  2207. user mode and have it come through the server service.
  2208. Arguments:
  2209. PNPOpcode - the PNP opcode
  2210. DeviceName - the transport for which this opcode is intended
  2211. MultiSZBindList - the binding list
  2212. Return Value:
  2213. None.
  2214. --*/
  2215. {
  2216. NTSTATUS Status;
  2217. OBJECT_ATTRIBUTES ObjectAttributes;
  2218. HANDLE NetbioslessSmbHandle;
  2219. IO_STATUS_BLOCK IoStatusBlock;
  2220. UNICODE_STRING NetbioslessSmbName = {36,36, L"\\device\\NetbiosSmb"};
  2221. InitializeObjectAttributes(
  2222. &ObjectAttributes,
  2223. &NetbioslessSmbName,
  2224. OBJ_CASE_INSENSITIVE,
  2225. NULL,
  2226. NULL );
  2227. Status = ZwCreateFile (
  2228. &NetbioslessSmbHandle,
  2229. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access
  2230. &ObjectAttributes, // object attributes
  2231. &IoStatusBlock, // returned status information
  2232. NULL, // block size (unused)
  2233. 0, // file attributes
  2234. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  2235. FILE_CREATE, // create disposition
  2236. 0, // create options
  2237. NULL, // EA buffer
  2238. 0 // EA length
  2239. );
  2240. if ( NT_SUCCESS(Status) ) {
  2241. NETBT_SMB_BIND_REQUEST NetBtNotificationParameters;
  2242. NetBtNotificationParameters.RequestType = SMB_SERVER;
  2243. NetBtNotificationParameters.PnPOpCode = PnPOpcode;
  2244. NetBtNotificationParameters.pDeviceName = DeviceName;
  2245. NetBtNotificationParameters.MultiSZBindList = MultiSZBindList;
  2246. Status = ZwDeviceIoControlFile(
  2247. NetbioslessSmbHandle,
  2248. NULL,
  2249. NULL,
  2250. NULL,
  2251. &IoStatusBlock,
  2252. IOCTL_NETBT_SET_SMBDEVICE_BIND_INFO,
  2253. &NetBtNotificationParameters,
  2254. sizeof(NetBtNotificationParameters),
  2255. NULL,
  2256. 0);
  2257. IF_DEBUG( ERRORS ) {
  2258. KdPrint(("NtFsControlFile %wZ in SrvpNotifyChangesToNetBt status %X\n", &NetbioslessSmbName, Status ));
  2259. }
  2260. Status = ZwClose(NetbioslessSmbHandle);
  2261. IF_DEBUG( ERRORS ) {
  2262. KdPrint(("NtCloseFile %wZ in SrvpNotifyChangesToNetBt status %X\n", &NetbioslessSmbName, Status ));
  2263. }
  2264. } else {
  2265. IF_DEBUG( ERRORS ) {
  2266. KdPrint(("NtCreateFile %wZ in SrvpNotifyChangesToNetBt status %X\n", &NetbioslessSmbName, Status ));
  2267. }
  2268. }
  2269. }